1use std::ops::{Index, IndexMut};
30
31use rucc_base::{Idx, Symbol};
32use rucc_diag::Span;
33use rucc_target::Slot;
34
35use crate::inst::{
36 Abi, AbiList, AsmInfo, Block, BlockCall, BlockCallList, BlockData, CallInfo, Def, Extra, Imm,
37 ImmList, Inst, InstData, InstLayout, MemInfo, Sig, Signature, SlotList, SwitchInfo, VaInfo,
38 Value, ValueData, ValueList,
39};
40use crate::module::{Linkage, Visibility};
41use crate::{Attrs, Facts, Flags, FloatPred, IntPred, MemOrder, Opcode, RmwOp, Type};
42
43#[derive(Debug)]
45pub struct Func {
46 pub name: Symbol,
48 pub linkage: Linkage,
50 pub visibility: Visibility,
52 pub section: Option<Symbol>,
55 pub align: Option<u32>,
62 pub attrs: Attrs,
65
66 values: Vec<ValueData>,
67 insts: Vec<InstData>,
68 inst_layout: Vec<InstLayout>,
69 inst_spans: Vec<Span>,
70 blocks: Vec<BlockData>,
71
72 value_pool: Vec<Value>,
73 block_calls: Vec<BlockCall>,
74 imms: Vec<Imm>,
75 mem: Vec<MemInfo>,
76 calls: Vec<CallInfo>,
77 abis: Vec<Abi>,
78 switches: Vec<SwitchInfo>,
79 asms: Vec<AsmInfo>,
80 slots: Vec<Slot>,
81 va_objects: Vec<VaInfo>,
82 signatures: Vec<Signature>,
83 facts: Vec<(Value, Facts)>,
84
85 first_block: Option<Block>,
86 last_block: Option<Block>,
87}
88
89impl Func {
90 #[must_use]
97 pub fn new(name: Symbol, signature: Signature) -> Self {
98 Self {
99 name,
100 linkage: Linkage::External,
101 visibility: Visibility::Default,
102 section: None,
103 align: None,
104 attrs: Attrs::NONE,
105 values: Vec::new(),
106 insts: Vec::new(),
107 inst_layout: Vec::new(),
108 inst_spans: Vec::new(),
109 blocks: Vec::new(),
110 value_pool: Vec::new(),
111 block_calls: Vec::new(),
112 imms: Vec::new(),
113 mem: Vec::new(),
114 calls: Vec::new(),
115 abis: Vec::new(),
116 switches: Vec::new(),
117 asms: Vec::new(),
118 slots: Vec::new(),
119 va_objects: Vec::new(),
120 signatures: vec![signature],
121 facts: Vec::new(),
122 first_block: None,
123 last_block: None,
124 }
125 }
126
127 #[must_use]
129 pub fn signature(&self) -> &Signature {
130 &self.signatures[0]
131 }
132
133 pub fn set_signature(&mut self, signature: Signature) {
143 self.signatures[0] = signature;
144 }
145
146 pub fn signatures(&self) -> impl Iterator<Item = &Signature> {
148 self.signatures.iter()
149 }
150
151 pub fn add_signature(&mut self, signature: Signature) -> Sig {
153 self.signatures.push(signature);
154 Idx::from_usize(self.signatures.len() - 1)
155 }
156
157 #[must_use]
162 pub fn entry(&self) -> Option<Block> {
163 self.first_block
164 }
165
166 #[must_use]
173 pub fn is_declaration(&self) -> bool {
174 self.first_block.is_none()
175 }
176
177 pub fn create_block(&mut self) -> Block {
181 let block = Idx::from_usize(self.blocks.len());
182 self.blocks.push(BlockData { prev: self.last_block, ..BlockData::default() });
183 match self.last_block {
184 Some(last) => self.blocks[last.index()].next = Some(block),
185 None => self.first_block = Some(block),
186 }
187 self.last_block = Some(block);
188 block
189 }
190
191 pub fn remove_block(&mut self, block: Block) {
204 assert!(self.first_block != Some(block), "the entry block is not removable");
205 let (prev, next) = (self.blocks[block.index()].prev, self.blocks[block.index()].next);
206 match prev {
207 Some(prev) => self.blocks[prev.index()].next = next,
208 None => self.first_block = next,
209 }
210 match next {
211 Some(next) => self.blocks[next.index()].prev = prev,
212 None => self.last_block = prev,
213 }
214 let insts: Vec<Inst> = self.insts(block).collect();
218 for inst in insts {
219 self.inst_layout[inst.index()] = InstLayout::default();
220 }
221 self.blocks[block.index()] = BlockData::default();
222 }
223
224 pub fn append_param(&mut self, block: Block, ty: Type) -> Value {
233 let index = u32::try_from(self.blocks[block.index()].params.len())
234 .expect("a block with four billion parameters");
235 let value = self.add_value(ValueData { ty, def: Def::Param { block, index } });
236 self.blocks[block.index()].params.push(value);
237 value
238 }
239
240 pub fn retain_params(&mut self, block: Block, mut keep: impl FnMut(Value) -> bool) {
252 let mut params = std::mem::take(&mut self.blocks[block.index()].params);
253 params.retain(|&value| keep(value));
254 for (index, &value) in params.iter().enumerate() {
255 let index = u32::try_from(index).expect("a block with four billion parameters");
256 self.values[value.index()].def = Def::Param { block, index };
257 }
258 self.blocks[block.index()].params = params;
259 }
260
261 pub fn retype(&mut self, value: Value, ty: Type) {
273 self.values[value.index()].ty = ty;
274 }
275
276 pub fn values(&self) -> impl Iterator<Item = Value> + use<'_> {
281 (0..self.values.len()).map(Idx::from_usize)
282 }
283
284 pub fn blocks(&self) -> impl Iterator<Item = Block> + use<'_> {
286 std::iter::successors(self.first_block, move |&block| self.blocks[block.index()].next)
287 }
288
289 pub fn insts(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
291 std::iter::successors(self.blocks[block.index()].first, move |&inst| {
292 self.inst_layout[inst.index()].next
293 })
294 }
295
296 pub fn insts_backwards(&self, block: Block) -> impl Iterator<Item = Inst> + use<'_> {
302 std::iter::successors(self.blocks[block.index()].last, move |&inst| {
303 self.inst_layout[inst.index()].prev
304 })
305 }
306
307 #[must_use]
309 pub fn terminator(&self, block: Block) -> Option<Inst> {
310 self.blocks[block.index()].last.filter(|&inst| self.is_terminator(inst))
311 }
312
313 #[must_use]
319 pub fn is_terminator(&self, inst: Inst) -> bool {
320 let data = &self[inst];
321 match data.extra {
322 Extra::Asm(info) => {
323 data.opcode.is_terminator() || !self.asms[info.index()].targets.is_empty()
324 }
325 _ => data.opcode.is_terminator(),
326 }
327 }
328
329 pub fn create_inst(&mut self, mut data: InstData, results: &[Type], span: Span) -> Inst {
340 let inst = Idx::from_usize(self.insts.len());
341 data.results = u8::try_from(results.len()).expect("an instruction with too many results");
342 data.first_result = results.first().map(|_| Idx::from_usize(self.values.len()));
343 for (index, &ty) in results.iter().enumerate() {
344 let index = u8::try_from(index).expect("checked just above");
345 self.add_value(ValueData { ty, def: Def::Result { inst, index } });
346 }
347 self.insts.push(data);
348 self.inst_layout.push(InstLayout::default());
349 self.inst_spans.push(span);
350 inst
351 }
352
353 pub fn append_inst(&mut self, block: Block, inst: Inst) {
360 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
361 let last = self.blocks[block.index()].last;
362 self.inst_layout[inst.index()] = InstLayout { block: Some(block), prev: last, next: None };
363 match last {
364 Some(last) => self.inst_layout[last.index()].next = Some(inst),
365 None => self.blocks[block.index()].first = Some(inst),
366 }
367 self.blocks[block.index()].last = Some(inst);
368 }
369
370 pub fn insert_before(&mut self, inst: Inst, before: Inst) {
376 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
377 let at = self.inst_layout[before.index()];
378 let block = at.block.expect("the instruction to insert before is not in a block");
379 self.inst_layout[inst.index()] =
380 InstLayout { block: Some(block), prev: at.prev, next: Some(before) };
381 self.inst_layout[before.index()].prev = Some(inst);
382 match at.prev {
383 Some(prev) => self.inst_layout[prev.index()].next = Some(inst),
384 None => self.blocks[block.index()].first = Some(inst),
385 }
386 }
387
388 pub fn insert_after(&mut self, inst: Inst, after: Inst) {
400 assert!(self.inst_layout[inst.index()].block.is_none(), "the instruction is in a block");
401 let at = self.inst_layout[after.index()];
402 let block = at.block.expect("the instruction to insert after is not in a block");
403 assert!(at.next.is_some(), "nothing goes after a terminator");
404 self.inst_layout[inst.index()] =
405 InstLayout { block: Some(block), prev: Some(after), next: at.next };
406 self.inst_layout[after.index()].next = Some(inst);
407 if let Some(next) = at.next {
408 self.inst_layout[next.index()].prev = Some(inst);
409 }
410 }
411
412 pub fn remove_inst(&mut self, inst: Inst) {
422 let at = self.inst_layout[inst.index()];
423 let block = at.block.expect("the instruction is not in a block");
424 match at.prev {
425 Some(prev) => self.inst_layout[prev.index()].next = at.next,
426 None => self.blocks[block.index()].first = at.next,
427 }
428 match at.next {
429 Some(next) => self.inst_layout[next.index()].prev = at.prev,
430 None => self.blocks[block.index()].last = at.prev,
431 }
432 self.inst_layout[inst.index()] = InstLayout::default();
433 }
434
435 #[must_use]
437 pub fn block_of(&self, inst: Inst) -> Option<Block> {
438 self.inst_layout[inst.index()].block
439 }
440
441 #[must_use]
453 pub fn mem_in(&self, inst: Inst) -> Option<Value> {
454 let args = &self[self[inst].args];
455 args.last().copied().filter(|&arg| self[arg].ty.is_mem())
456 }
457
458 #[must_use]
468 pub fn mem_out(&self, inst: Inst) -> Option<Value> {
469 self[inst].results().last().filter(|&result| self[result].ty.is_mem())
470 }
471
472 #[must_use]
474 pub fn carries_mem(&self, inst: Inst) -> bool {
475 self.mem_in(inst).is_some() || self.mem_out(inst).is_some()
476 }
477
478 pub fn with_mem(&mut self, inst: Inst, incoming: Value) -> Inst {
494 assert!(self[incoming].ty.is_mem(), "the incoming version of memory is not memory");
495 assert!(self[inst].opcode.touches_memory(), "this does not touch memory");
496 assert!(self.mem_in(inst).is_none(), "this is already on the memory chain");
497 let data = self[inst];
498 let mut args = self[data.args].to_vec();
499 args.push(incoming);
500 let mut results: Vec<Type> = data.results().map(|result| self[result].ty).collect();
501 if data.opcode.writes_memory() {
502 results.push(Type::MEM);
503 }
504 let span = self.span(inst);
505 let args = self.push_values(&args);
506 self.create_inst(InstData { args, ..data }, &results, span)
507 }
508
509 #[must_use]
511 pub fn span(&self, inst: Inst) -> Span {
512 self.inst_spans[inst.index()]
513 }
514
515 pub fn successors(&self, inst: Inst) -> impl Iterator<Item = BlockCall> + use<'_> {
520 self.block_calls[self.target_list(inst).as_usize_range()].iter().copied()
521 }
522
523 #[must_use]
530 pub fn target_list(&self, inst: Inst) -> BlockCallList {
531 match self[inst].extra {
532 Extra::Targets(targets) => targets,
533 Extra::Switch(info) => self.switches[info.index()].targets,
534 Extra::Asm(info) => self.asms[info.index()].targets,
535 _ => BlockCallList::EMPTY,
536 }
537 }
538
539 pub fn push_values(&mut self, values: &[Value]) -> ValueList {
543 let start = Idx::from_usize(self.value_pool.len());
544 self.value_pool.extend_from_slice(values);
545 ValueList::new(start, Idx::from_usize(self.value_pool.len()))
546 }
547
548 pub fn append_arg(&mut self, list: ValueList, value: Value) -> ValueList {
555 let range = list.as_usize_range();
556 if range.end == self.value_pool.len() {
557 self.value_pool.push(value);
558 return ValueList::new(Idx::from_usize(range.start), Idx::from_usize(range.end + 1));
559 }
560 let start = self.value_pool.len();
561 self.value_pool.extend_from_within(range);
562 self.value_pool.push(value);
563 ValueList::new(Idx::from_usize(start), Idx::from_usize(self.value_pool.len()))
564 }
565
566 pub fn rewrite(&mut self, list: ValueList, mut with: impl FnMut(Value) -> Value) {
571 for value in &mut self.value_pool[list.as_usize_range()] {
572 *value = with(*value);
573 }
574 }
575
576 pub fn push_block_calls(&mut self, calls: &[BlockCall]) -> BlockCallList {
578 let start = Idx::from_usize(self.block_calls.len());
579 self.block_calls.extend_from_slice(calls);
580 BlockCallList::new(start, Idx::from_usize(self.block_calls.len()))
581 }
582
583 pub fn set_block_call(&mut self, at: Idx<BlockCall>, call: BlockCall) {
585 self.block_calls[at.index()] = call;
586 }
587
588 pub fn push_imms(&mut self, imms: &[Imm]) -> ImmList {
590 let start = Idx::from_usize(self.imms.len());
591 self.imms.extend_from_slice(imms);
592 ImmList::new(start, Idx::from_usize(self.imms.len()))
593 }
594
595 pub fn add_imm(&mut self, imm: Imm) -> Idx<Imm> {
597 self.imms.push(imm);
598 Idx::from_usize(self.imms.len() - 1)
599 }
600
601 pub fn push_slots(&mut self, slots: &[Slot]) -> SlotList {
603 let start = Idx::from_usize(self.slots.len());
604 self.slots.extend_from_slice(slots);
605 SlotList::new(start, Idx::from_usize(self.slots.len()))
606 }
607
608 pub fn add_va_object(&mut self, info: VaInfo) -> Idx<VaInfo> {
610 self.va_objects.push(info);
611 Idx::from_usize(self.va_objects.len() - 1)
612 }
613
614 pub fn add_mem(&mut self, info: MemInfo) -> Idx<MemInfo> {
616 self.mem.push(info);
617 Idx::from_usize(self.mem.len() - 1)
618 }
619
620 pub fn push_abis(&mut self, abis: &[Abi]) -> AbiList {
622 let start = Idx::from_usize(self.abis.len());
623 self.abis.extend_from_slice(abis);
624 AbiList::new(start, Idx::from_usize(self.abis.len()))
625 }
626
627 pub fn add_call(&mut self, info: CallInfo) -> Idx<CallInfo> {
629 self.calls.push(info);
630 Idx::from_usize(self.calls.len() - 1)
631 }
632
633 pub fn add_switch(&mut self, info: SwitchInfo) -> Idx<SwitchInfo> {
635 self.switches.push(info);
636 Idx::from_usize(self.switches.len() - 1)
637 }
638
639 pub fn add_asm(&mut self, info: AsmInfo) -> Idx<AsmInfo> {
641 self.asms.push(info);
642 Idx::from_usize(self.asms.len() - 1)
643 }
644
645 #[must_use]
648 pub fn counts(&self) -> Counts {
649 Counts { values: self.values.len(), insts: self.insts.len(), blocks: self.blocks.len() }
650 }
651
652 #[must_use]
658 pub fn facts(&self, value: Value) -> Facts {
659 match self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw()) {
660 Ok(at) => self.facts[at].1,
661 Err(_) => Facts::NONE,
662 }
663 }
664
665 pub fn set_facts(&mut self, value: Value, facts: Facts) {
670 let found = self.facts.binary_search_by_key(&value.raw(), |&(at, _)| at.raw());
671 match (found, facts.is_empty()) {
672 (Ok(at), true) => drop(self.facts.remove(at)),
673 (Ok(at), false) => self.facts[at].1 = facts,
674 (Err(_), true) => {}
675 (Err(at), false) => self.facts.insert(at, (value, facts)),
676 }
677 }
678
679 pub fn known(&self) -> impl Iterator<Item = (Value, Facts)> + '_ {
681 self.facts.iter().copied()
682 }
683
684 fn add_value(&mut self, data: ValueData) -> Value {
685 self.values.push(data);
686 Idx::from_usize(self.values.len() - 1)
687 }
688}
689
690#[derive(Clone, Copy, Debug, PartialEq, Eq)]
692pub struct Counts {
693 pub values: usize,
695 pub insts: usize,
697 pub blocks: usize,
699}
700
701impl Index<Value> for Func {
704 type Output = ValueData;
705
706 fn index(&self, value: Value) -> &ValueData {
707 &self.values[value.index()]
708 }
709}
710
711impl Index<Inst> for Func {
712 type Output = InstData;
713
714 fn index(&self, inst: Inst) -> &InstData {
715 &self.insts[inst.index()]
716 }
717}
718
719impl IndexMut<Inst> for Func {
720 fn index_mut(&mut self, inst: Inst) -> &mut InstData {
721 &mut self.insts[inst.index()]
722 }
723}
724
725impl Index<Block> for Func {
726 type Output = BlockData;
727
728 fn index(&self, block: Block) -> &BlockData {
729 &self.blocks[block.index()]
730 }
731}
732
733impl Index<Sig> for Func {
734 type Output = Signature;
735
736 fn index(&self, sig: Sig) -> &Signature {
737 &self.signatures[sig.index()]
738 }
739}
740
741impl Index<ValueList> for Func {
742 type Output = [Value];
743
744 fn index(&self, list: ValueList) -> &[Value] {
745 &self.value_pool[list.as_usize_range()]
746 }
747}
748
749impl Index<BlockCallList> for Func {
750 type Output = [BlockCall];
751
752 fn index(&self, list: BlockCallList) -> &[BlockCall] {
753 &self.block_calls[list.as_usize_range()]
754 }
755}
756
757impl Index<Idx<BlockCall>> for Func {
758 type Output = BlockCall;
759
760 fn index(&self, at: Idx<BlockCall>) -> &BlockCall {
761 &self.block_calls[at.index()]
762 }
763}
764
765impl Index<ImmList> for Func {
766 type Output = [Imm];
767
768 fn index(&self, list: ImmList) -> &[Imm] {
769 &self.imms[list.as_usize_range()]
770 }
771}
772
773impl Index<Idx<Imm>> for Func {
774 type Output = Imm;
775
776 fn index(&self, at: Idx<Imm>) -> &Imm {
777 &self.imms[at.index()]
778 }
779}
780
781impl Index<Idx<MemInfo>> for Func {
782 type Output = MemInfo;
783
784 fn index(&self, at: Idx<MemInfo>) -> &MemInfo {
785 &self.mem[at.index()]
786 }
787}
788
789impl Index<AbiList> for Func {
790 type Output = [Abi];
791
792 fn index(&self, list: AbiList) -> &[Abi] {
793 &self.abis[list.as_usize_range()]
794 }
795}
796
797impl Index<SlotList> for Func {
798 type Output = [Slot];
799
800 fn index(&self, list: SlotList) -> &[Slot] {
801 &self.slots[list.as_usize_range()]
802 }
803}
804
805impl Index<Idx<VaInfo>> for Func {
806 type Output = VaInfo;
807
808 fn index(&self, at: Idx<VaInfo>) -> &VaInfo {
809 &self.va_objects[at.index()]
810 }
811}
812
813impl Index<Idx<CallInfo>> for Func {
814 type Output = CallInfo;
815
816 fn index(&self, at: Idx<CallInfo>) -> &CallInfo {
817 &self.calls[at.index()]
818 }
819}
820
821impl Index<Idx<SwitchInfo>> for Func {
822 type Output = SwitchInfo;
823
824 fn index(&self, at: Idx<SwitchInfo>) -> &SwitchInfo {
825 &self.switches[at.index()]
826 }
827}
828
829impl Index<Idx<AsmInfo>> for Func {
830 type Output = AsmInfo;
831
832 fn index(&self, at: Idx<AsmInfo>) -> &AsmInfo {
833 &self.asms[at.index()]
834 }
835}
836
837#[derive(Debug)]
844pub struct Builder<'a> {
845 func: &'a mut Func,
846 block: Block,
847 span: Span,
848}
849
850impl<'a> Builder<'a> {
851 pub fn new(func: &'a mut Func, block: Block) -> Self {
853 Self { func, block, span: Span::DUMMY }
854 }
855
856 #[must_use]
858 pub fn at(mut self, span: Span) -> Self {
859 self.span = span;
860 self
861 }
862
863 pub fn set_span(&mut self, span: Span) {
865 self.span = span;
866 }
867
868 pub fn func(&mut self) -> &mut Func {
870 self.func
871 }
872
873 #[must_use]
875 pub fn block(&self) -> Block {
876 self.block
877 }
878
879 pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst {
881 let inst = self.func.create_inst(data, results, self.span);
882 self.func.append_inst(self.block, inst);
883 inst
884 }
885
886 pub fn value(&mut self, data: InstData, ty: Type) -> Value {
892 let inst = self.inst(data, &[ty]);
893 self.func[inst].first_result.expect("one result was asked for")
894 }
895
896 pub fn iconst(&mut self, ty: Type, value: i128) -> Value {
902 let imm = self.func.add_imm(Imm::int(value, ty.lane()));
903 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::IConst) }, ty)
904 }
905
906 pub fn fconst(&mut self, ty: Type, bits: u128) -> Value {
908 let imm = self.func.add_imm(Imm::from_bits(bits));
909 self.value(InstData { extra: Extra::Imm(imm), ..InstData::new(Opcode::FConst) }, ty)
910 }
911
912 pub fn binary(&mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags) -> Value {
914 let ty = self.func[lhs].ty;
915 let args = self.func.push_values(&[lhs, rhs]);
916 self.value(InstData { args, flags, ..InstData::new(opcode) }, ty)
917 }
918
919 pub fn checked(&mut self, opcode: Opcode, lhs: Value, rhs: Value) -> (Value, Value) {
932 let ty = self.func[lhs].ty;
933 let args = self.func.push_values(&[lhs, rhs]);
934 let results = [ty, ty.with_lane(Type::I1)];
935 let inst = self.inst(InstData { args, ..InstData::new(opcode) }, &results);
936 let mut answers = self.func[inst].results();
937 let value = answers.next().expect("two results were asked for");
938 let wrapped = answers.next().expect("two results were asked for");
939 (value, wrapped)
940 }
941
942 pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value {
944 let args = self.func.push_values(&[arg]);
945 self.value(InstData { args, ..InstData::new(opcode) }, ty)
946 }
947
948 pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value {
950 let ty = self.func[lhs].ty.with_lane(Type::I1);
951 let args = self.func.push_values(&[lhs, rhs]);
952 self.value(
953 InstData { args, extra: Extra::IntPred(pred), ..InstData::new(Opcode::ICmp) },
954 ty,
955 )
956 }
957
958 pub fn select(&mut self, cond: Value, then: Value, other: Value) -> Value {
964 let ty = self.func[then].ty;
965 let args = self.func.push_values(&[cond, then, other]);
966 self.value(InstData { args, ..InstData::new(Opcode::Select) }, ty)
967 }
968
969 pub fn fcmp(&mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags) -> Value {
971 let ty = self.func[lhs].ty.with_lane(Type::I1);
972 let args = self.func.push_values(&[lhs, rhs]);
973 self.value(
974 InstData { args, flags, extra: Extra::FloatPred(pred), ..InstData::new(Opcode::FCmp) },
975 ty,
976 )
977 }
978
979 pub fn mem_entry(&mut self) -> Value {
983 self.value(InstData::new(Opcode::MemEntry), Type::MEM)
984 }
985
986 pub fn load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
988 let mem = self.func.add_mem(info);
989 let args = self.func.push_values(&[addr]);
990 self.value(
991 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Load) },
992 ty,
993 )
994 }
995
996 pub fn store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
998 let mem = self.func.add_mem(info);
999 let args = self.func.push_values(&[value, addr]);
1000 self.inst(
1001 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Store) },
1002 &[],
1003 )
1004 }
1005
1006 pub fn atomic_load(&mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags) -> Value {
1014 let mem = self.func.add_mem(info);
1015 let args = self.func.push_values(&[addr]);
1016 self.value(
1017 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicLoad) },
1018 ty,
1019 )
1020 }
1021
1022 pub fn atomic_store(&mut self, value: Value, addr: Value, info: MemInfo, flags: Flags) -> Inst {
1024 let mem = self.func.add_mem(info);
1025 let args = self.func.push_values(&[value, addr]);
1026 self.inst(
1027 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::AtomicStore) },
1028 &[],
1029 )
1030 }
1031
1032 pub fn cmpxchg(
1039 &mut self,
1040 addr: Value,
1041 expected: Value,
1042 desired: Value,
1043 info: MemInfo,
1044 flags: Flags,
1045 ) -> (Value, Value) {
1046 let ty = self.func[expected].ty;
1047 let mem = self.func.add_mem(info);
1048 let args = self.func.push_values(&[addr, expected, desired]);
1049 let inst = self.inst(
1050 InstData { args, flags, extra: Extra::Mem(mem), ..InstData::new(Opcode::Cmpxchg) },
1051 &[ty, Type::I1],
1052 );
1053 let results: Vec<Value> = self.func[inst].results().collect();
1054 let [old, exchanged] = results[..] else { unreachable!("two results were asked for") };
1055 (old, exchanged)
1056 }
1057
1058 pub fn atomic_rmw(
1066 &mut self,
1067 op: RmwOp,
1068 addr: Value,
1069 operand: Value,
1070 info: MemInfo,
1071 flags: Flags,
1072 ) -> Value {
1073 let ty = self.func[operand].ty;
1074 let mem = self.func.add_mem(info);
1075 let args = self.func.push_values(&[addr, operand]);
1076 self.value(
1077 InstData {
1078 args,
1079 flags,
1080 extra: Extra::Rmw(op, mem),
1081 ..InstData::new(Opcode::AtomicRmw)
1082 },
1083 ty,
1084 )
1085 }
1086
1087 pub fn fence(&mut self, order: MemOrder) -> Inst {
1089 self.inst(InstData { extra: Extra::Order(order), ..InstData::new(Opcode::Fence) }, &[])
1090 }
1091
1092 pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst {
1094 let call = self.block_call(target, args);
1095 let targets = self.func.push_block_calls(&[call]);
1096 self.inst(InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::Jump) }, &[])
1097 }
1098
1099 pub fn block_addr(&mut self, target: Block) -> Value {
1105 let call = self.block_call(target, &[]);
1106 let targets = self.func.push_block_calls(&[call]);
1107 self.value(
1108 InstData { extra: Extra::Targets(targets), ..InstData::new(Opcode::BlockAddr) },
1109 Type::PTR,
1110 )
1111 }
1112
1113 pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst {
1119 let calls: Vec<BlockCall> =
1120 targets.iter().map(|&target| self.block_call(target, &[])).collect();
1121 let targets = self.func.push_block_calls(&calls);
1122 let args = self.func.push_values(&[addr]);
1123 self.inst(
1124 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::IndirectBr) },
1125 &[],
1126 )
1127 }
1128
1129 pub fn br_if(
1131 &mut self,
1132 cond: Value,
1133 then_block: Block,
1134 then_args: &[Value],
1135 else_block: Block,
1136 else_args: &[Value],
1137 ) -> Inst {
1138 let then_call = self.block_call(then_block, then_args);
1139 let else_call = self.block_call(else_block, else_args);
1140 let targets = self.func.push_block_calls(&[then_call, else_call]);
1141 let args = self.func.push_values(&[cond]);
1142 self.inst(
1143 InstData { args, extra: Extra::Targets(targets), ..InstData::new(Opcode::BrIf) },
1144 &[],
1145 )
1146 }
1147
1148 pub fn switch(&mut self, value: Value, default: Block, cases: &[(i128, Block)]) -> Inst {
1155 let ty = self.func[value].ty.lane();
1156 let mut calls = vec![self.block_call(default, &[])];
1157 let mut values = Vec::with_capacity(cases.len());
1158 for &(value, block) in cases {
1159 calls.push(self.block_call(block, &[]));
1160 values.push(Imm::int(value, ty));
1161 }
1162 let targets = self.func.push_block_calls(&calls);
1163 let cases = self.func.push_imms(&values);
1164 let info = self.func.add_switch(SwitchInfo { targets, cases });
1165 let args = self.func.push_values(&[value]);
1166 self.inst(
1167 InstData { args, extra: Extra::Switch(info), ..InstData::new(Opcode::Switch) },
1168 &[],
1169 )
1170 }
1171
1172 pub fn ret(&mut self, values: &[Value]) -> Inst {
1174 let args = self.func.push_values(values);
1175 self.inst(InstData { args, ..InstData::new(Opcode::Return) }, &[])
1176 }
1177
1178 pub fn unreachable(&mut self) -> Inst {
1180 self.inst(InstData::new(Opcode::Unreachable), &[])
1181 }
1182
1183 pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst {
1185 self.call_varargs(callee, signature, args, &[])
1186 }
1187
1188 pub fn call_varargs(
1194 &mut self,
1195 callee: Symbol,
1196 signature: Sig,
1197 args: &[Value],
1198 varargs: &[Abi],
1199 ) -> Inst {
1200 let varargs = self.func.push_abis(varargs);
1201 let info = self.func.add_call(CallInfo { callee: Some(callee), signature, varargs });
1202 let returns: Vec<Type> = self.func[signature].return_types().collect();
1203 let args = self.func.push_values(args);
1204 self.inst(
1205 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::Call) },
1206 &returns,
1207 )
1208 }
1209
1210 pub fn inline_asm(
1216 &mut self,
1217 info: AsmInfo,
1218 args: &[Value],
1219 results: &[Type],
1220 flags: Flags,
1221 ) -> Inst {
1222 let info = self.func.add_asm(info);
1223 let args = self.func.push_values(args);
1224 self.inst(
1225 InstData { args, flags, extra: Extra::Asm(info), ..InstData::new(Opcode::InlineAsm) },
1226 results,
1227 )
1228 }
1229
1230 fn block_call(&mut self, block: Block, args: &[Value]) -> BlockCall {
1231 BlockCall { block, args: self.func.push_values(args) }
1232 }
1233}
1234
1235#[cfg(test)]
1236mod tests {
1237 use rucc_base::Interner;
1238
1239 use super::*;
1240 use crate::inst::BlockCallList;
1241 use crate::{MemOrder, Restrict};
1242
1243 fn sum() -> (Func, Block, Block, Block) {
1245 let mut names = Interner::new();
1246 let i32_ = Type::int(32);
1247 let mut func = Func::new(
1248 names.intern("sum"),
1249 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
1250 );
1251
1252 let entry = func.create_block();
1253 let n = func.append_param(entry, i32_);
1254 let header = func.create_block();
1255 let acc = func.append_param(header, i32_);
1256 let i = func.append_param(header, i32_);
1257 let exit = func.create_block();
1258 let result = func.append_param(exit, i32_);
1259
1260 let mut b = Builder::new(&mut func, entry);
1261 let zero = b.iconst(i32_, 0);
1262 let cmp = b.icmp(IntPred::Sle, n, zero);
1263 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
1264
1265 let mut b = Builder::new(&mut func, header);
1266 let one = b.iconst(i32_, 1);
1267 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
1268 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
1269 let done = b.icmp(IntPred::Sge, next, n);
1270 b.br_if(done, exit, &[total], header, &[total, next]);
1271
1272 let mut b = Builder::new(&mut func, exit);
1273 b.ret(&[result]);
1274
1275 (func, entry, header, exit)
1276 }
1277
1278 #[test]
1279 fn the_blocks_come_back_in_the_order_they_were_made() {
1280 let (func, entry, header, exit) = sum();
1281 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, header, exit]);
1282 assert_eq!(func.entry(), Some(entry));
1283 }
1284
1285 #[test]
1286 fn a_removed_block_is_gone_from_the_layout_and_so_is_what_was_in_it() {
1287 let (mut func, entry, header, exit) = sum();
1288 let inside: Vec<Inst> = func.insts(header).collect();
1289 func.remove_block(header);
1290 assert_eq!(func.blocks().collect::<Vec<_>>(), [entry, exit]);
1291 assert_eq!(func.entry(), Some(entry));
1292 assert_eq!(func[entry].next, Some(exit));
1293 assert_eq!(func[exit].prev, Some(entry));
1294 assert!(inside.iter().all(|&inst| func.block_of(inst).is_none()));
1296 assert!(func.insts(header).next().is_none());
1297 }
1298
1299 #[test]
1300 fn each_block_holds_what_was_appended_to_it() {
1301 let (func, entry, header, exit) = sum();
1302 let opcodes =
1303 |block| func.insts(block).map(|inst| func[inst].opcode.name()).collect::<Vec<_>>();
1304 assert_eq!(opcodes(entry), ["iconst", "icmp", "br_if"]);
1305 assert_eq!(opcodes(header), ["iconst", "add", "add", "icmp", "br_if"]);
1306 assert_eq!(opcodes(exit), ["return"]);
1307 }
1308
1309 #[test]
1310 fn asm_ends_a_block_when_it_has_labels_and_not_otherwise() {
1311 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1314 let block = func.create_block();
1315 let plain = func.add_asm(AsmInfo {
1316 template: Symbol::from_raw(0),
1317 constraints: Symbol::from_raw(0),
1318 clobbers: Symbol::from_raw(0),
1319 targets: BlockCallList::EMPTY,
1320 });
1321 let call = BlockCall { block, args: ValueList::EMPTY };
1322 let targets = func.push_block_calls(&[call]);
1323 let labelled = func.add_asm(AsmInfo {
1324 template: Symbol::from_raw(0),
1325 constraints: Symbol::from_raw(0),
1326 clobbers: Symbol::from_raw(0),
1327 targets,
1328 });
1329
1330 let mut make = |extra| {
1331 let data = InstData { extra, ..InstData::new(Opcode::InlineAsm) };
1332 func.create_inst(data, &[], Span::DUMMY)
1333 };
1334 let plain = make(Extra::Asm(plain));
1335 let labelled = make(Extra::Asm(labelled));
1336 assert!(!func.is_terminator(plain));
1337 assert!(func.is_terminator(labelled));
1338 }
1339
1340 #[test]
1341 fn every_block_ends_in_its_terminator() {
1342 let (func, entry, header, exit) = sum();
1343 for block in [entry, header, exit] {
1344 let last = func.terminator(block).expect("a terminator");
1345 assert_eq!(Some(last), func.insts(block).last());
1346 }
1347 }
1348
1349 #[test]
1350 fn a_branch_carries_the_arguments_the_block_takes() {
1351 let (func, entry, header, _) = sum();
1352 let br = func.terminator(entry).expect("a terminator");
1353 let calls: Vec<BlockCall> = func.successors(br).collect();
1354 assert_eq!(calls.len(), 2);
1355 assert_eq!(calls[1].block, header);
1357 assert_eq!(func[calls[1].args].len(), 2);
1358 assert_eq!(func[header].params.len(), 2);
1359 assert_eq!(func[calls[0].args].len(), 1);
1360 }
1361
1362 #[test]
1363 fn a_value_knows_what_defined_it() {
1364 let (func, entry, _, _) = sum();
1365 let first = func.insts(entry).next().expect("an instruction");
1366 let value = func[first].first_result.expect("a result");
1367 assert_eq!(func[value].def, Def::Result { inst: first, index: 0 });
1368 assert_eq!(func[value].ty, Type::int(32));
1369
1370 let param = func[entry].params[0];
1371 assert_eq!(func[param].def, Def::Param { block: entry, index: 0 });
1372 }
1373
1374 #[test]
1375 fn a_comparison_produces_one_bit() {
1376 let (func, entry, _, _) = sum();
1377 let cmp = func.insts(entry).nth(1).expect("the comparison");
1378 let value = func[cmp].first_result.expect("a result");
1379 assert_eq!(func[value].ty, Type::I1);
1380 assert_eq!(func[cmp].extra, Extra::IntPred(IntPred::Sle));
1381 }
1382
1383 #[test]
1384 fn flags_ride_along_on_the_instruction_that_was_given_them() {
1385 let (func, _, header, _) = sum();
1386 let add = func.insts(header).nth(1).expect("the addition");
1387 assert_eq!(func[add].flags, Flags::NSW);
1388 let cmp = func.insts(header).nth(3).expect("the comparison");
1389 assert_eq!(func[cmp].flags, Flags::NONE);
1390 }
1391
1392 #[test]
1393 fn removing_an_instruction_takes_it_out_of_the_middle() {
1394 let (mut func, _, header, _) = sum();
1395 let add = func.insts(header).nth(1).expect("the addition");
1396 func.remove_inst(add);
1397 let opcodes: Vec<&str> = func.insts(header).map(|inst| func[inst].opcode.name()).collect();
1398 assert_eq!(opcodes, ["iconst", "add", "icmp", "br_if"]);
1399 assert_eq!(func.block_of(add), None);
1400 }
1401
1402 #[test]
1403 fn removing_the_first_and_the_last_keeps_the_ends_right() {
1404 let (mut func, entry, _, _) = sum();
1405 let first = func.insts(entry).next().expect("an instruction");
1406 let last = func.terminator(entry).expect("a terminator");
1407 func.remove_inst(first);
1408 func.remove_inst(last);
1409 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1410 assert_eq!(opcodes, ["icmp"]);
1411 assert_eq!(func[entry].first, func[entry].last);
1412 }
1413
1414 #[test]
1415 fn removing_the_only_instruction_empties_the_block() {
1416 let (mut func, _, _, exit) = sum();
1417 let only = func.insts(exit).next().expect("an instruction");
1418 func.remove_inst(only);
1419 assert_eq!(func.insts(exit).count(), 0);
1420 assert_eq!(func[exit].first, None);
1421 assert_eq!(func[exit].last, None);
1422 }
1423
1424 #[test]
1425 fn inserting_before_puts_it_in_the_right_place() {
1426 let (mut func, entry, _, _) = sum();
1427 let cmp = func.insts(entry).nth(1).expect("the comparison");
1428 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1429 func.insert_before(made, cmp);
1430 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1431 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1432 }
1433
1434 #[test]
1435 fn inserting_before_the_first_makes_it_the_first() {
1436 let (mut func, entry, _, _) = sum();
1437 let first = func.insts(entry).next().expect("an instruction");
1438 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1439 func.insert_before(made, first);
1440 assert_eq!(func.insts(entry).next(), Some(made));
1441 assert_eq!(func[entry].first, Some(made));
1442 }
1443
1444 #[test]
1445 fn inserting_after_puts_it_in_the_right_place() {
1446 let (mut func, entry, _, _) = sum();
1447 let first = func.insts(entry).next().expect("an instruction");
1448 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1449 func.insert_after(made, first);
1450 let opcodes: Vec<&str> = func.insts(entry).map(|inst| func[inst].opcode.name()).collect();
1451 assert_eq!(opcodes, ["iconst", "unreachable", "icmp", "br_if"]);
1452 assert_eq!(func[entry].first, Some(first));
1453 }
1454
1455 #[test]
1456 #[should_panic(expected = "nothing goes after a terminator")]
1457 fn inserting_after_the_terminator_is_refused() {
1458 let (mut func, entry, _, _) = sum();
1461 let last = func.insts(entry).last().expect("a terminator");
1462 let made = func.create_inst(InstData::new(Opcode::Unreachable), &[], Span::DUMMY);
1463 func.insert_after(made, last);
1464 }
1465
1466 #[test]
1467 fn a_list_grows_in_place_while_it_is_the_last_thing_in_the_pool() {
1468 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1469 let block = func.create_block();
1470 let a = func.append_param(block, Type::int(32));
1471 let b = func.append_param(block, Type::int(32));
1472 let list = func.push_values(&[a]);
1473 let grown = func.append_arg(list, b);
1474 assert_eq!(func[grown], [a, b]);
1475 assert_eq!(grown.as_usize_range().start, list.as_usize_range().start);
1476 }
1477
1478 #[test]
1479 fn a_list_is_copied_when_something_is_behind_it() {
1480 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1481 let block = func.create_block();
1482 let a = func.append_param(block, Type::int(32));
1483 let b = func.append_param(block, Type::int(32));
1484 let list = func.push_values(&[a, a]);
1485 let behind = func.push_values(&[b]);
1486 let grown = func.append_arg(list, b);
1487 assert_eq!(func[grown], [a, a, b]);
1488 assert_eq!(func[list], [a, a], "the old run is still readable");
1489 assert_eq!(func[behind], [b], "and so is what was behind it");
1490 assert_ne!(grown.as_usize_range().start, list.as_usize_range().start);
1491 }
1492
1493 #[test]
1494 fn a_parameter_added_late_is_the_next_one_along() {
1495 let (mut func, entry, header, _) = sum();
1499 let extra = func.append_param(header, Type::int(32));
1500 assert_eq!(func[header].params.len(), 3);
1501 assert_eq!(func[extra].def, Def::Param { block: header, index: 2 });
1502
1503 let br = func.terminator(entry).expect("a terminator");
1504 let call = func.successors(br).nth(1).expect("the branch to the header");
1505 let grown = func.append_arg(call.args, extra);
1506 assert_eq!(func[grown].len(), 3);
1507 }
1508
1509 #[test]
1510 fn a_span_rides_along_with_the_instruction() {
1511 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1512 let block = func.create_block();
1513 let span = Span::new(10, 20);
1514 let mut b = Builder::new(&mut func, block).at(span);
1515 let value = b.iconst(Type::int(32), 7);
1516 let inst = match func[value].def {
1517 Def::Result { inst, .. } => inst,
1518 Def::Param { .. } => unreachable!("a constant is not a parameter"),
1519 };
1520 assert_eq!(func.span(inst), span);
1521 }
1522
1523 #[test]
1524 fn a_store_produces_nothing_and_a_load_produces_one_value() {
1525 let mut func = Func::new(Symbol::from_raw(0), Signature::new());
1526 let block = func.create_block();
1527 let addr = func.append_param(block, Type::PTR);
1528 let info = MemInfo {
1529 size: 4,
1530 align: 4,
1531 order: MemOrder::NotAtomic,
1532 tbaa: None,
1533 owns: 0,
1534 restrict: Restrict::NONE,
1535 };
1536 let mut b = Builder::new(&mut func, block);
1537 let value = b.load(Type::int(32), addr, info, Flags::NONE);
1538 let store = b.store(value, addr, info, Flags::VOLATILE);
1539 assert_eq!(func[store].results, 0);
1540 assert_eq!(func[store].flags, Flags::VOLATILE);
1541 assert_eq!(func[value].ty, Type::int(32));
1542 }
1543
1544 #[test]
1545 fn a_call_produces_what_its_signature_returns() {
1546 let mut names = Interner::new();
1547 let mut func = Func::new(names.intern("caller"), Signature::new());
1548 let sig = func.add_signature(
1549 Signature::new().with_params(&[Type::int(32)]).with_returns(&[Type::int(64)]),
1550 );
1551 let block = func.create_block();
1552 let arg = func.append_param(block, Type::int(32));
1553 let callee = names.intern("callee");
1554 let mut b = Builder::new(&mut func, block);
1555 let call = b.call(callee, sig, &[arg]);
1556 assert_eq!(func[call].results, 1);
1557 let value = func[call].first_result.expect("a result");
1558 assert_eq!(func[value].ty, Type::int(64));
1559 assert_eq!(func[call].extra, Extra::Call(Idx::new(0)));
1560 }
1561
1562 #[test]
1563 fn the_counts_are_what_was_made() {
1564 let (func, _, _, _) = sum();
1565 let counts = func.counts();
1566 assert_eq!(counts.blocks, 3);
1567 assert_eq!(counts.insts, 9);
1568 assert_eq!(counts.values, 4 + 6);
1571 }
1572
1573 #[test]
1574 #[should_panic(expected = "the instruction is in a block")]
1575 fn appending_an_instruction_twice_is_refused() {
1576 let (mut func, entry, _, _) = sum();
1577 let first = func.insts(entry).next().expect("an instruction");
1578 func.append_inst(entry, first);
1579 }
1580
1581 #[test]
1582 #[should_panic(expected = "the instruction is not in a block")]
1583 fn removing_an_instruction_twice_is_refused() {
1584 let (mut func, entry, _, _) = sum();
1585 let first = func.insts(entry).next().expect("an instruction");
1586 func.remove_inst(first);
1587 func.remove_inst(first);
1588 }
1589
1590 fn threaded() -> (Func, Inst, Inst) {
1592 let mut names = Interner::new();
1593 let i32_ = Type::int(32);
1594 let mut func = Func::new(
1595 names.intern("thread"),
1596 Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]),
1597 );
1598 let entry = func.create_block();
1599 let addr = func.append_param(entry, Type::PTR);
1600 let info = MemInfo {
1601 size: 4,
1602 align: 4,
1603 order: MemOrder::NotAtomic,
1604 tbaa: None,
1605 owns: 0,
1606 restrict: Restrict::NONE,
1607 };
1608
1609 let mut b = Builder::new(&mut func, entry);
1610 let start = b.mem_entry();
1611 let seven = b.iconst(i32_, 7);
1612 let store = b.store(seven, addr, info, Flags::NONE);
1613 let value = b.load(i32_, addr, info, Flags::NONE);
1614 let Def::Result { inst: load, .. } = func[value].def else {
1615 panic!("the load produced it");
1616 };
1617
1618 let store = func.with_mem(store, start);
1619 let after = func.mem_out(store).expect("a store makes a new version");
1620 let load = func.with_mem(load, after);
1621 (func, store, load)
1622 }
1623
1624 #[test]
1625 fn threading_memory_puts_it_last_and_leaves_everything_else_where_it_was() {
1626 let (func, store, load) = threaded();
1627 assert_eq!(func.mem_in(store), func.mem_out(store).map(|_| func[func[store].args][2]));
1628 assert_eq!(func[func[store].args].len(), 3);
1629 assert!(func.carries_mem(store));
1630 assert!(func.carries_mem(load));
1631
1632 assert_eq!(func[func[load].args][0], func[func.entry().expect("an entry")].params[0]);
1635 assert_eq!(func.mem_in(load), func.mem_out(store));
1636 assert_eq!(func.mem_out(load), None);
1637 }
1638
1639 #[test]
1640 #[should_panic(expected = "this is already on the memory chain")]
1641 fn threading_memory_through_the_same_instruction_twice_is_refused() {
1642 let (mut func, store, _) = threaded();
1643 let start = func.mem_in(store).expect("it was threaded");
1644 func.with_mem(store, start);
1645 }
1646}