1use std::collections::HashSet;
84
85use rucc_base::Symbol;
86use rucc_ir::{
87 AttrSet, Attrs, Def, Extra, Flags, Func, Imm, Inst, MemInfo, Meta, Opcode, Restrict, Type,
88 Value,
89};
90
91use crate::outside::Outside;
92
93const CHASE_LIMIT: u32 = 64;
100
101const TREE_LIMIT: u32 = 32;
107
108#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
112pub enum Reason {
113 Distinct,
115 Escape,
117 Offset,
119 Tbaa,
121 Restrict,
123 Attribute,
125 Plane,
127}
128
129impl Reason {
130 pub const ALL: [Self; 7] = [
132 Self::Distinct,
133 Self::Escape,
134 Self::Offset,
135 Self::Tbaa,
136 Self::Restrict,
137 Self::Attribute,
138 Self::Plane,
139 ];
140
141 pub const COUNT: usize = Self::ALL.len();
143
144 #[must_use]
146 pub const fn index(self) -> usize {
147 match self {
148 Self::Distinct => 0,
149 Self::Escape => 1,
150 Self::Offset => 2,
151 Self::Tbaa => 3,
152 Self::Restrict => 4,
153 Self::Attribute => 5,
154 Self::Plane => 6,
155 }
156 }
157
158 #[must_use]
160 pub const fn name(self) -> &'static str {
161 match self {
162 Self::Distinct => "distinct",
163 Self::Escape => "escape",
164 Self::Offset => "offset",
165 Self::Tbaa => "tbaa",
166 Self::Restrict => "restrict",
167 Self::Attribute => "attribute",
168 Self::Plane => "plane",
169 }
170 }
171
172 #[must_use]
174 pub const fn describe(self) -> &'static str {
175 match self {
176 Self::Distinct => "they are two different objects",
177 Self::Escape => "the address of that local never leaves this function",
178 Self::Offset => "they are parts of one object that do not overlap",
179 Self::Tbaa => "no object has both of those types",
180 Self::Restrict => "restrict says those two pointers do not reach the same object",
181 Self::Attribute => "the callee is declared not to touch memory that way",
182 Self::Plane => "that one touches only the planes, which the program cannot name",
183 }
184 }
185}
186
187#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
189pub enum Answer {
190 May,
192 No(Reason),
194}
195
196impl Answer {
197 #[must_use]
199 pub const fn is_no(self) -> bool {
200 matches!(self, Self::No(_))
201 }
202
203 #[must_use]
205 pub const fn reason(self) -> Option<Reason> {
206 match self {
207 Self::No(reason) => Some(reason),
208 Self::May => None,
209 }
210 }
211}
212
213#[derive(Clone, Copy, Debug, PartialEq, Eq)]
219pub struct Options {
220 pub strict_aliasing: bool,
223}
224
225impl Default for Options {
226 fn default() -> Self {
227 Self { strict_aliasing: true }
228 }
229}
230
231#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
239pub enum Origin {
240 Local(Inst),
243 Global(Symbol),
245 Unknown(Value),
248}
249
250impl Origin {
251 #[must_use]
253 pub const fn is_object(self) -> bool {
254 matches!(self, Self::Local(_) | Self::Global(_))
255 }
256}
257
258#[must_use]
264pub fn origin(func: &Func, mut value: Value) -> (Origin, Option<i64>) {
265 let mut offset = Some(0i64);
266 for _ in 0..CHASE_LIMIT {
267 let Def::Result { inst, .. } = func[value].def else {
268 return (Origin::Unknown(value), offset);
270 };
271 let data = func[inst];
272 match data.opcode {
273 Opcode::Alloca => return (Origin::Local(inst), offset),
274 Opcode::GlobalAddr => {
275 let Extra::Symbol(name) = data.extra else {
276 return (Origin::Unknown(value), offset);
277 };
278 return (Origin::Global(name), offset);
279 }
280 Opcode::PtrAdd => {
281 let args = &func[data.args];
282 let (base, by) = (args[0], args[1]);
283 offset = offset
284 .and_then(|so_far| Some((so_far, constant(func, by)?)))
285 .and_then(|(so_far, by)| so_far.checked_add(by));
286 value = base;
287 }
288 Opcode::Bitcast => value = func[data.args][0],
291 _ => return (Origin::Unknown(value), offset),
292 }
293 }
294 (Origin::Unknown(value), None)
295}
296
297#[derive(Clone, Copy, Debug, PartialEq, Eq)]
303pub struct Access {
304 pub origin: Origin,
306 pub offset: Option<i64>,
308 pub size: Option<u64>,
310 pub tbaa: Option<Meta>,
312 pub restrict: Restrict,
314 pub volatile: bool,
316}
317
318impl Access {
319 #[must_use]
325 pub fn through(func: &Func, pointer: Value) -> Self {
326 let (origin, offset) = origin(func, pointer);
327 Self { origin, offset, size: None, tbaa: None, restrict: Restrict::NONE, volatile: false }
328 }
329
330 #[must_use]
332 pub fn range(&self) -> Option<(i128, i128)> {
333 let (offset, size) = (self.offset?, self.size?);
334 let start = i128::from(offset);
335 Some((start, start + i128::from(size)))
336 }
337}
338
339#[derive(Clone, Debug, Default)]
351pub struct Escapes {
352 escaped: HashSet<Inst>,
353}
354
355impl Escapes {
356 #[must_use]
358 pub fn of(func: &Func) -> Self {
359 let mut escaped = HashSet::new();
360 for block in func.blocks() {
361 for inst in func.insts(block) {
362 let data = func[inst];
363 for (index, &arg) in func[data.args].iter().enumerate() {
364 if keeps_address(data.opcode, index) {
365 continue;
366 }
367 if let (Origin::Local(local), _) = origin(func, arg) {
368 escaped.insert(local);
369 }
370 }
371 for call in func.successors(inst) {
374 for &arg in &func[call.args] {
375 if let (Origin::Local(local), _) = origin(func, arg) {
376 escaped.insert(local);
377 }
378 }
379 }
380 }
381 }
382 Self { escaped }
383 }
384
385 #[must_use]
387 pub fn escaped(&self, local: Inst) -> bool {
388 self.escaped.contains(&local)
389 }
390
391 #[must_use]
393 pub fn count(&self) -> usize {
394 self.escaped.len()
395 }
396}
397
398#[must_use]
402pub const fn keeps_address(opcode: Opcode, index: usize) -> bool {
403 match (opcode, index) {
404 (Opcode::Load | Opcode::AtomicLoad, 0)
406 | (Opcode::Store | Opcode::AtomicStore, 1)
407 | (Opcode::AtomicRmw | Opcode::Cmpxchg, 0)
408 | (Opcode::Memcpy | Opcode::Memmove, 0 | 1)
409 | (Opcode::Memset | Opcode::Prefetch, 0) => true,
410 (Opcode::PtrAdd | Opcode::Bitcast, 0) => true,
413 (Opcode::ICmp, 0 | 1) => true,
416 _ => false,
417 }
418}
419
420#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
426pub struct Counts {
427 queries: u64,
428 answered: [u64; Reason::COUNT],
429}
430
431impl Counts {
432 #[must_use]
434 pub const fn queries(&self) -> u64 {
435 self.queries
436 }
437
438 #[must_use]
440 pub const fn answered(&self, reason: Reason) -> u64 {
441 self.answered[reason.index()]
442 }
443
444 #[must_use]
446 pub fn total(&self) -> u64 {
447 self.answered.iter().sum()
448 }
449}
450
451#[derive(Debug)]
462pub struct Alias<'a> {
463 func: &'a Func,
464 outside: &'a Outside,
465 options: Options,
466 escapes: Escapes,
467 counts: Counts,
468}
469
470impl<'a> Alias<'a> {
471 #[must_use]
473 pub fn new(func: &'a Func, outside: &'a Outside) -> Self {
474 Self::with(func, outside, Options::default())
475 }
476
477 #[must_use]
479 pub fn with(func: &'a Func, outside: &'a Outside, options: Options) -> Self {
480 Self { func, outside, options, escapes: Escapes::of(func), counts: Counts::default() }
481 }
482
483 #[must_use]
485 pub const fn escapes(&self) -> &Escapes {
486 &self.escapes
487 }
488
489 #[must_use]
491 pub const fn counts(&self) -> &Counts {
492 &self.counts
493 }
494
495 #[must_use]
497 pub fn reads(&self, inst: Inst) -> Option<Access> {
498 let data = self.func[inst];
499 let args = &self.func[data.args];
500 let info = self.mem(inst);
501 let (pointer, size) = match data.opcode {
502 Opcode::Load | Opcode::AtomicLoad => (args[0], self.width(self.result_type(inst)?)),
503 Opcode::Memcpy | Opcode::Memmove => (args[1], Some(info?.size)),
505 Opcode::AtomicRmw => (args[0], self.width(self.func[args[1]].ty)),
508 Opcode::Cmpxchg => (args[0], self.width(self.func[args[1]].ty)),
509 Opcode::VaObject => (args[0], Some(info?.size)),
510 _ => return None,
511 };
512 Some(self.access(pointer, size, info, data.flags))
513 }
514
515 #[must_use]
517 pub fn writes(&self, inst: Inst) -> Option<Access> {
518 let data = self.func[inst];
519 let args = &self.func[data.args];
520 let info = self.mem(inst);
521 let (pointer, size) = match data.opcode {
522 Opcode::Store | Opcode::AtomicStore => (args[1], self.width(self.func[args[0]].ty)),
523 Opcode::Memcpy | Opcode::Memmove | Opcode::Memset => (args[0], Some(info?.size)),
524 Opcode::AtomicRmw | Opcode::Cmpxchg => (args[0], self.width(self.func[args[1]].ty)),
525 _ => return None,
526 };
527 Some(self.access(pointer, size, info, data.flags))
528 }
529
530 pub fn query(&mut self, a: &Access, b: &Access) -> Answer {
532 self.counts.queries += 1;
533 let answer = self.decide(a, b);
534 if let Answer::No(reason) = answer {
535 self.counts.answered[reason.index()] += 1;
536 }
537 answer
538 }
539
540 pub fn clobbered_by(&mut self, reference: &Access, call: Inst) -> Answer {
548 self.touched_by(reference, call, true)
549 }
550
551 pub fn read_by(&mut self, reference: &Access, call: Inst) -> Answer {
555 self.touched_by(reference, call, false)
556 }
557
558 fn decide(&self, a: &Access, b: &Access) -> Answer {
561 if a.volatile && b.volatile {
565 return Answer::May;
566 }
567
568 if a.origin.is_object() && b.origin.is_object() {
576 if self.distinct(a.origin, b.origin) {
577 return Answer::No(Reason::Distinct);
578 }
579 if a.origin == b.origin {
580 return by_offset(a, b);
581 }
582 return Answer::May;
583 }
584
585 if let Some(local) = self.private(a).or_else(|| self.private(b)) {
588 let _ = local;
589 return Answer::No(Reason::Escape);
590 }
591
592 if a.restrict.disjoint(b.restrict) {
593 return Answer::No(Reason::Restrict);
594 }
595
596 if self.options.strict_aliasing {
597 if let (Some(one), Some(other)) = (a.tbaa, b.tbaa) {
598 if !self.types_conflict(one, other) {
599 return Answer::No(Reason::Tbaa);
600 }
601 }
602 }
603
604 if a.origin == b.origin {
606 return by_offset(a, b);
607 }
608
609 Answer::May
610 }
611
612 fn private(&self, reference: &Access) -> Option<Inst> {
615 match reference.origin {
616 Origin::Local(local) if !self.escapes.escaped(local) => Some(local),
617 _ => None,
618 }
619 }
620
621 fn distinct(&self, a: Origin, b: Origin) -> bool {
623 match (a, b) {
624 (Origin::Local(one), Origin::Local(other)) => one != other,
625 (Origin::Local(_), Origin::Global(_)) | (Origin::Global(_), Origin::Local(_)) => true,
627 (Origin::Global(one), Origin::Global(other)) => {
628 one != other && self.one_object(one) && self.one_object(other)
629 }
630 _ => false,
631 }
632 }
633
634 fn one_object(&self, name: Symbol) -> bool {
641 self.outside.one_object(name)
642 }
643
644 fn types_conflict(&self, one: Meta, other: Meta) -> bool {
650 self.at_or_below(one, other) || self.at_or_below(other, one)
651 }
652
653 fn at_or_below(&self, mut node: Meta, ancestor: Meta) -> bool {
655 for _ in 0..TREE_LIMIT {
656 if node == ancestor {
657 return true;
658 }
659 match self.outside.parent(node) {
660 Some(up) => node = up,
661 None => return false,
662 }
663 }
664 true
667 }
668
669 fn touched_by(&mut self, reference: &Access, call: Inst, writing: bool) -> Answer {
670 self.counts.queries += 1;
671 let answer = self.decide_call(reference, call, writing);
672 if let Answer::No(reason) = answer {
673 self.counts.answered[reason.index()] += 1;
674 }
675 answer
676 }
677
678 fn decide_call(&self, reference: &Access, call: Inst, writing: bool) -> Answer {
679 if self.func[call].opcode.touches_only_planes() {
685 return Answer::No(Reason::Plane);
686 }
687
688 if self.private(reference).is_some() {
692 return Answer::No(Reason::Escape);
693 }
694
695 let Some(attrs) = self.callee(call) else {
696 return Answer::May;
697 };
698 if attrs.set.contains(AttrSet::READNONE)
700 || (writing && attrs.set.contains(AttrSet::READONLY))
701 {
702 return Answer::No(Reason::Attribute);
703 }
704
705 if attrs.set.contains(AttrSet::ARGMEM_ONLY) {
712 let args = &self.func[self.func[call].args];
713 let mut all = true;
714 for &arg in args {
715 if !self.func[arg].ty.is_ptr() {
716 continue;
717 }
718 let through = Access::through(self.func, arg);
719 all &= self.decide(reference, &through).is_no();
720 }
721 if all {
722 return Answer::No(Reason::Attribute);
723 }
724 }
725
726 Answer::May
727 }
728
729 fn callee(&self, call: Inst) -> Option<Attrs> {
734 let Extra::Call(info) = self.func[call].extra else {
735 return None;
736 };
737 let name = self.func[info].callee?;
738 self.outside.attrs(name)
739 }
740
741 fn mem(&self, inst: Inst) -> Option<MemInfo> {
742 match self.func[inst].extra {
743 Extra::Mem(info) | Extra::Rmw(_, info) => Some(self.func[info]),
744 Extra::VaObject(object) => Some(self.func[self.func[object].mem]),
745 _ => None,
746 }
747 }
748
749 fn result_type(&self, inst: Inst) -> Option<Type> {
750 self.func[inst].results().next().map(|value| self.func[value].ty)
751 }
752
753 fn access(
754 &self,
755 pointer: Value,
756 size: Option<u64>,
757 info: Option<MemInfo>,
758 flags: Flags,
759 ) -> Access {
760 let (origin, offset) = origin(self.func, pointer);
761 Access {
762 origin,
763 offset,
764 size,
765 tbaa: info.and_then(|info| info.tbaa),
766 restrict: info.map_or(Restrict::NONE, |info| info.restrict),
767 volatile: flags.contains(Flags::VOLATILE),
768 }
769 }
770
771 fn width(&self, ty: Type) -> Option<u64> {
774 if ty.is_ptr() {
775 return self.outside.pointer_bytes();
776 }
777 let bits = u64::from(ty.bits()) * u64::from(ty.lanes());
778 (bits > 0).then(|| bits.div_ceil(8))
779 }
780}
781
782fn by_offset(a: &Access, b: &Access) -> Answer {
784 let (Some((a_start, a_end)), Some((b_start, b_end))) = (a.range(), b.range()) else {
785 return Answer::May;
786 };
787 if a_end <= b_start || b_end <= a_start {
788 return Answer::No(Reason::Offset);
789 }
790 Answer::May
791}
792
793fn constant(func: &Func, value: Value) -> Option<i64> {
795 let Def::Result { inst, .. } = func[value].def else {
796 return None;
797 };
798 let data = func[inst];
799 if data.opcode != Opcode::IConst {
800 return None;
801 }
802 let Extra::Imm(imm) = data.extra else {
803 return None;
804 };
805 i64::try_from(Imm::signed(func[imm], func[value].ty)).ok()
806}
807
808#[cfg(test)]
809mod tests {
810 use rucc_base::{Interner, Symbol};
811 use rucc_ir::{
812 AttrSet, Attrs, Builder, CallInfo, Extra, Flags, Func, Global, InstData, IntPred, MemInfo,
813 MemOrder, MetaNode, Module, Opcode, Restrict, Signature, TbaaNode, Type, Value,
814 };
815 use rucc_target::{TargetInfo, Triple};
816
817 use super::*;
818
819 fn module(names: &mut Interner) -> Module {
821 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().unwrap());
822 Module::new(names.intern("t.c"), &target)
823 }
824
825 fn func(names: &mut Interner, params: &[Type]) -> Func {
827 let mut func = Func::new(names.intern("f"), Signature::new().with_params(params));
828 let entry = func.create_block();
829 for &ty in params {
830 func.append_param(entry, ty);
831 }
832 func
833 }
834
835 fn builder(func: &mut Func) -> Builder<'_> {
837 let entry = func.entry().expect("the function has an entry block");
838 Builder::new(func, entry)
839 }
840
841 fn param(func: &Func, index: usize) -> Value {
842 let entry = func.entry().expect("the function has an entry block");
843 func[entry].params[index]
844 }
845
846 fn plain(align: u32) -> MemInfo {
847 MemInfo {
848 size: 0,
849 align,
850 order: MemOrder::NotAtomic,
851 tbaa: None,
852 owns: 0,
853 restrict: Restrict::NONE,
854 }
855 }
856
857 fn sized(size: u64, align: u32) -> MemInfo {
858 MemInfo { size, ..plain(align) }
859 }
860
861 fn local(build: &mut Builder<'_>, size: u64) -> Value {
863 let mem = build.func().add_mem(sized(size, 8));
864 build.value(InstData { extra: Extra::Mem(mem), ..InstData::new(Opcode::Alloca) }, Type::PTR)
865 }
866
867 fn at(build: &mut Builder<'_>, base: Value, offset: i64) -> Value {
869 let by = build.iconst(Type::int(64), i128::from(offset));
870 build.binary(Opcode::PtrAdd, base, by, Flags::NONE)
871 }
872
873 fn global(build: &mut Builder<'_>, module: &mut Module, name: Symbol) -> Value {
875 module.add_global(Global::new(name, 16, 8));
876 build.value(
877 InstData { extra: Extra::Symbol(name), ..InstData::new(Opcode::GlobalAddr) },
878 Type::PTR,
879 )
880 }
881
882 #[test]
883 fn two_different_locals_are_two_objects() {
884 let mut names = Interner::new();
885 let module = module(&mut names);
886 let mut f = func(&mut names, &[]);
887 let mut build = builder(&mut f);
888 let one = local(&mut build, 16);
889 let other = local(&mut build, 16);
890 let read = build.load(Type::int(32), one, plain(4), Flags::NONE);
891 build.store(read, other, plain(4), Flags::NONE);
892 build.ret(&[]);
893
894 let outside = Outside::of(&module);
895 let mut alias = Alias::new(&f, &outside);
896 let (a, b) = two(&alias, &f);
897 assert_eq!(alias.query(&a, &b), Answer::No(Reason::Distinct));
898 assert_eq!(alias.counts().answered(Reason::Distinct), 1);
899 assert_eq!(alias.counts().queries(), 1);
900 }
901
902 fn two(alias: &Alias<'_>, func: &Func) -> (Access, Access) {
904 let mut read = None;
905 let mut written = None;
906 for block in func.blocks() {
907 for inst in func.insts(block) {
908 if read.is_none() {
909 read = alias.reads(inst);
910 }
911 if written.is_none() {
912 written = alias.writes(inst);
913 }
914 }
915 }
916 (read.expect("a read"), written.expect("a write"))
917 }
918
919 #[test]
920 fn a_local_and_a_global_are_two_objects() {
921 let mut names = Interner::new();
922 let mut module = module(&mut names);
923 let x = names.intern("x");
924 let mut f = func(&mut names, &[]);
925 let mut build = builder(&mut f);
926 let one = local(&mut build, 16);
927 let other = global(&mut build, &mut module, x);
928 let read = build.load(Type::int(32), one, plain(4), Flags::NONE);
929 build.store(read, other, plain(4), Flags::NONE);
930 build.ret(&[]);
931
932 let outside = Outside::of(&module);
933 let mut alias = Alias::new(&f, &outside);
934 let (a, b) = two(&alias, &f);
935 assert_eq!(alias.query(&a, &b), Answer::No(Reason::Distinct));
936 }
937
938 #[test]
939 fn two_different_globals_are_two_objects() {
940 let mut names = Interner::new();
941 let mut module = module(&mut names);
942 let (x, y) = (names.intern("x"), names.intern("y"));
943 let mut f = func(&mut names, &[]);
944 let mut build = builder(&mut f);
945 let one = global(&mut build, &mut module, x);
946 let other = global(&mut build, &mut module, y);
947 let read = build.load(Type::int(32), one, plain(4), Flags::NONE);
948 build.store(read, other, plain(4), Flags::NONE);
949 build.ret(&[]);
950
951 let outside = Outside::of(&module);
952 let mut alias = Alias::new(&f, &outside);
953 let (a, b) = two(&alias, &f);
954 assert_eq!(alias.query(&a, &b), Answer::No(Reason::Distinct));
955 }
956
957 #[test]
958 fn a_global_the_module_does_not_have_is_not_argued_about() {
959 let mut names = Interner::new();
962 let mut module = module(&mut names);
963 let (x, y) = (names.intern("x"), names.intern("y"));
964 let mut f = func(&mut names, &[]);
965 let mut build = builder(&mut f);
966 let one = global(&mut build, &mut module, x);
967 let other = build.value(
968 InstData { extra: Extra::Symbol(y), ..InstData::new(Opcode::GlobalAddr) },
969 Type::PTR,
970 );
971 let read = build.load(Type::int(32), one, plain(4), Flags::NONE);
972 build.store(read, other, plain(4), Flags::NONE);
973 build.ret(&[]);
974
975 let outside = Outside::of(&module);
976 let mut alias = Alias::new(&f, &outside);
977 let (a, b) = two(&alias, &f);
978 assert_eq!(alias.query(&a, &b), Answer::May);
979 }
980
981 #[test]
982 fn two_parts_of_one_object_that_do_not_overlap_are_disjoint() {
983 let mut names = Interner::new();
984 let module = module(&mut names);
985 let mut f = func(&mut names, &[]);
986 let mut build = builder(&mut f);
987 let object = local(&mut build, 16);
988 let first = at(&mut build, object, 0);
989 let second = at(&mut build, object, 4);
990 let read = build.load(Type::int(32), first, plain(4), Flags::NONE);
991 build.store(read, second, plain(4), Flags::NONE);
992 build.ret(&[]);
993
994 let outside = Outside::of(&module);
995 let mut alias = Alias::new(&f, &outside);
996 let (a, b) = two(&alias, &f);
997 assert_eq!(alias.query(&a, &b), Answer::No(Reason::Offset));
998 }
999
1000 #[test]
1001 fn two_parts_of_one_object_that_do_overlap_are_not() {
1002 let mut names = Interner::new();
1003 let module = module(&mut names);
1004 let mut f = func(&mut names, &[]);
1005 let mut build = builder(&mut f);
1006 let object = local(&mut build, 16);
1007 let first = at(&mut build, object, 0);
1008 let second = at(&mut build, object, 2);
1009 let read = build.load(Type::int(32), first, plain(4), Flags::NONE);
1010 build.store(read, second, plain(4), Flags::NONE);
1011 build.ret(&[]);
1012
1013 let outside = Outside::of(&module);
1014 let mut alias = Alias::new(&f, &outside);
1015 let (a, b) = two(&alias, &f);
1016 assert_eq!(alias.query(&a, &b), Answer::May);
1017 }
1018
1019 #[test]
1020 fn an_offset_nobody_knows_gives_up_the_offset_and_keeps_the_object() {
1021 let mut names = Interner::new();
1022 let module = module(&mut names);
1023 let mut f = func(&mut names, &[Type::int(64)]);
1024 let n = param(&f, 0);
1025 let mut build = builder(&mut f);
1026 let object = local(&mut build, 16);
1027 let somewhere = build.binary(Opcode::PtrAdd, object, n, Flags::NONE);
1028 let read = build.load(Type::int(32), somewhere, plain(4), Flags::NONE);
1029 build.store(read, object, plain(4), Flags::NONE);
1030 build.ret(&[]);
1031
1032 let outside = Outside::of(&module);
1033 let mut alias = Alias::new(&f, &outside);
1034 let (a, b) = two(&alias, &f);
1035 assert_eq!(a.origin, b.origin, "both are still that one object");
1036 assert_eq!(a.offset, None);
1037 assert_eq!(alias.query(&a, &b), Answer::May);
1038 }
1039
1040 #[test]
1041 fn a_local_whose_address_stays_here_is_not_what_a_parameter_points_at() {
1042 let mut names = Interner::new();
1043 let module = module(&mut names);
1044 let mut f = func(&mut names, &[Type::PTR]);
1045 let outside = param(&f, 0);
1046 let mut build = builder(&mut f);
1047 let object = local(&mut build, 16);
1048 let read = build.load(Type::int(32), object, plain(4), Flags::NONE);
1049 build.store(read, outside, plain(4), Flags::NONE);
1050 build.ret(&[]);
1051
1052 let outside = Outside::of(&module);
1053 let mut alias = Alias::new(&f, &outside);
1054 assert_eq!(alias.escapes().count(), 0);
1055 let (a, b) = two(&alias, &f);
1056 assert_eq!(alias.query(&a, &b), Answer::No(Reason::Escape));
1057 }
1058
1059 #[test]
1060 fn a_local_whose_address_was_stored_somewhere_is() {
1061 let mut names = Interner::new();
1062 let module = module(&mut names);
1063 let mut f = func(&mut names, &[Type::PTR]);
1064 let outside = param(&f, 0);
1065 let mut build = builder(&mut f);
1066 let object = local(&mut build, 16);
1067 build.store(object, outside, plain(8), Flags::NONE);
1070 let read = build.load(Type::int(32), object, plain(4), Flags::NONE);
1071 build.store(read, outside, plain(4), Flags::NONE);
1072 build.ret(&[]);
1073
1074 let outside = Outside::of(&module);
1075 let mut alias = Alias::new(&f, &outside);
1076 assert_eq!(alias.escapes().count(), 1);
1077 let read = first(&f, Opcode::Load);
1078 let write = last(&f, Opcode::Store);
1079 let a = alias.reads(read).unwrap();
1080 let b = alias.writes(write).unwrap();
1081 assert_eq!(alias.query(&a, &b), Answer::May);
1082 }
1083
1084 fn first(func: &Func, opcode: Opcode) -> Inst {
1085 func.blocks()
1086 .flat_map(|block| func.insts(block))
1087 .find(|&inst| func[inst].opcode == opcode)
1088 .expect("an instruction with that opcode")
1089 }
1090
1091 fn last(func: &Func, opcode: Opcode) -> Inst {
1092 func.blocks()
1093 .flat_map(|block| func.insts(block))
1094 .filter(|&inst| func[inst].opcode == opcode)
1095 .last()
1096 .expect("an instruction with that opcode")
1097 }
1098
1099 #[test]
1100 fn an_address_carried_through_a_block_parameter_has_left_the_function() {
1101 let mut names = Interner::new();
1102 let module = module(&mut names);
1103 let mut f = func(&mut names, &[]);
1104 let start = f.entry().expect("an entry block");
1105 let next = f.create_block();
1106 f.append_param(next, Type::PTR);
1107
1108 let mut build = Builder::new(&mut f, start);
1109 let object = local(&mut build, 16);
1110 build.jump(next, &[object]);
1111 let mut build = Builder::new(&mut f, next);
1112 build.ret(&[]);
1113
1114 let outside = Outside::of(&module);
1115 let alias = Alias::new(&f, &outside);
1116 assert!(alias.escapes().escaped(first(&f, Opcode::Alloca)));
1117 }
1118
1119 #[test]
1120 fn comparing_two_addresses_does_not_let_either_of_them_out() {
1121 let mut names = Interner::new();
1122 let module = module(&mut names);
1123 let mut f = func(&mut names, &[Type::PTR]);
1124 let outside = param(&f, 0);
1125 let mut build = builder(&mut f);
1126 let object = local(&mut build, 16);
1127 build.icmp(IntPred::Eq, object, outside);
1128 build.ret(&[]);
1129
1130 let outside = Outside::of(&module);
1131 let alias = Alias::new(&f, &outside);
1132 assert_eq!(alias.escapes().count(), 0);
1133 }
1134
1135 #[test]
1136 fn an_address_turned_into_a_number_has_left_the_function() {
1137 let mut names = Interner::new();
1140 let module = module(&mut names);
1141 let mut f = func(&mut names, &[]);
1142 let mut build = builder(&mut f);
1143 let object = local(&mut build, 16);
1144 build.unary(Opcode::PtrToInt, object, Type::int(64));
1145 build.ret(&[]);
1146
1147 let outside = Outside::of(&module);
1148 let alias = Alias::new(&f, &outside);
1149 assert!(alias.escapes().escaped(first(&f, Opcode::Alloca)));
1150 }
1151
1152 #[test]
1153 fn two_restrict_pointers_in_one_scope_do_not_reach_the_same_object() {
1154 let mut names = Interner::new();
1155 let module = module(&mut names);
1156 let mut f = func(&mut names, &[Type::PTR, Type::PTR]);
1157 let (one, other) = (param(&f, 0), param(&f, 1));
1158 let mut build = builder(&mut f);
1159 let mut info = plain(4);
1160 info.restrict = Restrict { clique: 1, base: 1 };
1161 let read = build.load(Type::int(32), one, info, Flags::NONE);
1162 info.restrict = Restrict { clique: 1, base: 2 };
1163 build.store(read, other, info, Flags::NONE);
1164 build.ret(&[]);
1165
1166 let outside = Outside::of(&module);
1167 let mut alias = Alias::new(&f, &outside);
1168 let (a, b) = two(&alias, &f);
1169 assert_eq!(alias.query(&a, &b), Answer::No(Reason::Restrict));
1170 }
1171
1172 #[test]
1173 fn two_restrict_pointers_in_different_scopes_say_nothing_about_each_other() {
1174 let mut names = Interner::new();
1175 let module = module(&mut names);
1176 let mut f = func(&mut names, &[Type::PTR, Type::PTR]);
1177 let (one, other) = (param(&f, 0), param(&f, 1));
1178 let mut build = builder(&mut f);
1179 let mut info = plain(4);
1180 info.restrict = Restrict { clique: 1, base: 1 };
1181 let read = build.load(Type::int(32), one, info, Flags::NONE);
1182 info.restrict = Restrict { clique: 2, base: 1 };
1183 build.store(read, other, info, Flags::NONE);
1184 build.ret(&[]);
1185
1186 let outside = Outside::of(&module);
1187 let mut alias = Alias::new(&f, &outside);
1188 let (a, b) = two(&alias, &f);
1189 assert_eq!(alias.query(&a, &b), Answer::May);
1190 }
1191
1192 fn types(module: &mut Module, names: &mut Interner) -> (Meta, Meta, Meta) {
1194 let root = module.add_meta(MetaNode::Tbaa(TbaaNode {
1195 name: names.intern("char"),
1196 parent: None,
1197 offset: 0,
1198 }));
1199 let int = module.add_meta(MetaNode::Tbaa(TbaaNode {
1200 name: names.intern("int"),
1201 parent: Some(root),
1202 offset: 0,
1203 }));
1204 let float = module.add_meta(MetaNode::Tbaa(TbaaNode {
1205 name: names.intern("float"),
1206 parent: Some(root),
1207 offset: 0,
1208 }));
1209 (root, int, float)
1210 }
1211
1212 #[test]
1213 fn two_unrelated_types_describe_no_object_in_common() {
1214 let mut names = Interner::new();
1215 let mut module = module(&mut names);
1216 let (_, int, float) = types(&mut module, &mut names);
1217 let mut f = func(&mut names, &[Type::PTR, Type::PTR]);
1218 let (one, other) = (param(&f, 0), param(&f, 1));
1219 let mut build = builder(&mut f);
1220 let mut info = plain(4);
1221 info.tbaa = Some(int);
1222 let read = build.load(Type::int(32), one, info, Flags::NONE);
1223 info.tbaa = Some(float);
1224 build.store(read, other, info, Flags::NONE);
1225 build.ret(&[]);
1226
1227 let outside = Outside::of(&module);
1228 let mut alias = Alias::new(&f, &outside);
1229 let (a, b) = two(&alias, &f);
1230 assert_eq!(alias.query(&a, &b), Answer::No(Reason::Tbaa));
1231 }
1232
1233 #[test]
1234 fn an_access_through_char_conflicts_with_everything() {
1235 let mut names = Interner::new();
1236 let mut module = module(&mut names);
1237 let (root, int, _) = types(&mut module, &mut names);
1238 let mut f = func(&mut names, &[Type::PTR, Type::PTR]);
1239 let (one, other) = (param(&f, 0), param(&f, 1));
1240 let mut build = builder(&mut f);
1241 let mut info = plain(4);
1242 info.tbaa = Some(int);
1243 let read = build.load(Type::int(32), one, info, Flags::NONE);
1244 info.tbaa = Some(root);
1245 build.store(read, other, info, Flags::NONE);
1246 build.ret(&[]);
1247
1248 let outside = Outside::of(&module);
1249 let mut alias = Alias::new(&f, &outside);
1250 let (a, b) = two(&alias, &f);
1251 assert_eq!(alias.query(&a, &b), Answer::May);
1252 }
1253
1254 #[test]
1255 fn turning_strict_aliasing_off_turns_off_that_layer_and_no_other() {
1256 let mut names = Interner::new();
1257 let mut module = module(&mut names);
1258 let (_, int, float) = types(&mut module, &mut names);
1259 let mut f = func(&mut names, &[Type::PTR, Type::PTR]);
1260 let (one, other) = (param(&f, 0), param(&f, 1));
1261 let mut build = builder(&mut f);
1262 let mut info = plain(4);
1263 info.tbaa = Some(int);
1264 info.restrict = Restrict { clique: 1, base: 1 };
1265 let read = build.load(Type::int(32), one, info, Flags::NONE);
1266 info.tbaa = Some(float);
1267 info.restrict = Restrict { clique: 1, base: 2 };
1268 build.store(read, other, info, Flags::NONE);
1269 build.ret(&[]);
1270
1271 let options = Options { strict_aliasing: false };
1272 let outside = Outside::of(&module);
1273 let mut alias = Alias::with(&f, &outside, options);
1274 let (a, b) = two(&alias, &f);
1275 assert_eq!(alias.query(&a, &b), Answer::No(Reason::Restrict));
1278
1279 let mut without = Alias::with(&f, &outside, options);
1280 let plainer = Access { restrict: Restrict::NONE, ..a };
1281 let other = Access { restrict: Restrict::NONE, ..b };
1282 assert_eq!(without.query(&plainer, &other), Answer::May);
1283
1284 let mut with = Alias::new(&f, &outside);
1285 assert_eq!(with.query(&plainer, &other), Answer::No(Reason::Tbaa));
1286 }
1287
1288 #[test]
1289 fn writing_one_member_of_a_union_and_reading_another_is_one_object() {
1290 let mut names = Interner::new();
1295 let mut module = module(&mut names);
1296 let (_, int, float) = types(&mut module, &mut names);
1297 let mut f = func(&mut names, &[]);
1298 let mut build = builder(&mut f);
1299 let object = local(&mut build, 4);
1300 let mut info = plain(4);
1301 info.tbaa = Some(float);
1302 let read = build.load(Type::int(32), object, info, Flags::NONE);
1303 info.tbaa = Some(int);
1304 build.store(read, object, info, Flags::NONE);
1305 build.ret(&[]);
1306
1307 let outside = Outside::of(&module);
1308 let mut alias = Alias::new(&f, &outside);
1309 let (a, b) = two(&alias, &f);
1310 assert_eq!(alias.query(&a, &b), Answer::May);
1311 }
1312
1313 #[test]
1314 fn two_volatile_accesses_conflict_whatever_else_is_true_of_them() {
1315 let mut names = Interner::new();
1316 let module = module(&mut names);
1317 let mut f = func(&mut names, &[]);
1318 let mut build = builder(&mut f);
1319 let one = local(&mut build, 16);
1320 let other = local(&mut build, 16);
1321 let read = build.load(Type::int(32), one, plain(4), Flags::VOLATILE);
1322 build.store(read, other, plain(4), Flags::VOLATILE);
1323 build.ret(&[]);
1324
1325 let outside = Outside::of(&module);
1326 let mut alias = Alias::new(&f, &outside);
1327 let (a, b) = two(&alias, &f);
1328 assert_eq!(alias.query(&a, &b), Answer::May);
1331 }
1332
1333 #[test]
1334 fn one_volatile_access_and_one_ordinary_one_are_argued_about_as_usual() {
1335 let mut names = Interner::new();
1336 let module = module(&mut names);
1337 let mut f = func(&mut names, &[]);
1338 let mut build = builder(&mut f);
1339 let one = local(&mut build, 16);
1340 let other = local(&mut build, 16);
1341 let read = build.load(Type::int(32), one, plain(4), Flags::VOLATILE);
1342 build.store(read, other, plain(4), Flags::NONE);
1343 build.ret(&[]);
1344
1345 let outside = Outside::of(&module);
1346 let mut alias = Alias::new(&f, &outside);
1347 let (a, b) = two(&alias, &f);
1348 assert_eq!(alias.query(&a, &b), Answer::No(Reason::Distinct));
1349 }
1350
1351 #[test]
1352 fn a_copy_reads_its_source_and_writes_its_destination() {
1353 let mut names = Interner::new();
1354 let module = module(&mut names);
1355 let mut f = func(&mut names, &[]);
1356 let mut build = builder(&mut f);
1357 let to = local(&mut build, 16);
1358 let from = local(&mut build, 16);
1359 let mem = build.func().add_mem(sized(16, 8));
1360 let args = build.func().push_values(&[to, from]);
1361 build.inst(InstData { args, extra: Extra::Mem(mem), ..InstData::new(Opcode::Memcpy) }, &[]);
1362 build.ret(&[]);
1363
1364 let outside = Outside::of(&module);
1365 let alias = Alias::new(&f, &outside);
1366 let copy = first(&f, Opcode::Memcpy);
1367 let read = alias.reads(copy).expect("a copy reads");
1368 let written = alias.writes(copy).expect("a copy writes");
1369 assert_eq!(read.size, Some(16));
1370 assert_eq!(written.size, Some(16));
1371 assert_ne!(read.origin, written.origin);
1372 }
1373
1374 fn call_to(
1376 names: &mut Interner,
1377 module: &mut Module,
1378 f: &mut Func,
1379 attrs: Attrs,
1380 args: &[Value],
1381 ) -> Inst {
1382 let name = names.intern("g");
1383 let params: Vec<Type> = args.iter().map(|_| Type::PTR).collect();
1384 let mut callee = Func::new(name, Signature::new().with_params(¶ms));
1385 callee.attrs = attrs;
1386 module.add_func(callee);
1387 let signature = f.add_signature(Signature::new().with_params(¶ms));
1388 let mut build = builder(f);
1389 build.call(name, signature, args)
1390 }
1391
1392 fn attrs(set: AttrSet) -> Attrs {
1393 Attrs { set, ..Attrs::NONE }
1394 }
1395
1396 #[test]
1397 fn a_call_cannot_touch_a_local_whose_address_stayed_here() {
1398 let mut names = Interner::new();
1399 let mut module = module(&mut names);
1400 let mut f = func(&mut names, &[Type::PTR]);
1401 let outside = param(&f, 0);
1402 let mut build = builder(&mut f);
1403 let object = local(&mut build, 16);
1404 let read = build.load(Type::int(32), object, plain(4), Flags::NONE);
1405 let _ = read;
1406 let call = call_to(&mut names, &mut module, &mut f, Attrs::NONE, &[outside]);
1407 let mut build = builder(&mut f);
1408 build.ret(&[]);
1409
1410 let outside = Outside::of(&module);
1411 let mut alias = Alias::new(&f, &outside);
1412 let reference = alias.reads(first(&f, Opcode::Load)).unwrap();
1413 assert_eq!(alias.clobbered_by(&reference, call), Answer::No(Reason::Escape));
1414 assert_eq!(alias.read_by(&reference, call), Answer::No(Reason::Escape));
1415 }
1416
1417 #[test]
1418 fn a_call_can_touch_a_local_it_was_handed() {
1419 let mut names = Interner::new();
1420 let mut module = module(&mut names);
1421 let mut f = func(&mut names, &[]);
1422 let mut build = builder(&mut f);
1423 let object = local(&mut build, 16);
1424 build.load(Type::int(32), object, plain(4), Flags::NONE);
1425 let call = call_to(&mut names, &mut module, &mut f, Attrs::NONE, &[object]);
1426 let mut build = builder(&mut f);
1427 build.ret(&[]);
1428
1429 let outside = Outside::of(&module);
1430 let mut alias = Alias::new(&f, &outside);
1431 let reference = alias.reads(first(&f, Opcode::Load)).unwrap();
1432 assert_eq!(alias.clobbered_by(&reference, call), Answer::May);
1433 }
1434
1435 #[test]
1436 fn a_pure_callee_reads_memory_and_writes_none() {
1437 let mut names = Interner::new();
1438 let mut module = module(&mut names);
1439 let mut f = func(&mut names, &[Type::PTR]);
1440 let outside = param(&f, 0);
1441 let mut build = builder(&mut f);
1442 build.load(Type::int(32), outside, plain(4), Flags::NONE);
1443 let call = call_to(&mut names, &mut module, &mut f, attrs(AttrSet::READONLY), &[outside]);
1444 let mut build = builder(&mut f);
1445 build.ret(&[]);
1446
1447 let outside = Outside::of(&module);
1448 let mut alias = Alias::new(&f, &outside);
1449 let reference = alias.reads(first(&f, Opcode::Load)).unwrap();
1450 assert_eq!(alias.clobbered_by(&reference, call), Answer::No(Reason::Attribute));
1451 assert_eq!(alias.read_by(&reference, call), Answer::May);
1452 }
1453
1454 #[test]
1455 fn a_plane_write_is_not_a_write_to_the_address_it_names() {
1456 let mut names = Interner::new();
1462 let module = module(&mut names);
1463 let mut f = func(&mut names, &[Type::PTR]);
1464 let outside = param(&f, 0);
1465 let mut build = builder(&mut f);
1466 build.load(Type::int(32), outside, plain(4), Flags::NONE);
1467 let width = build.iconst(Type::int(64), 4);
1468 let args = build.func().push_values(&[outside, width]);
1469 build.inst(InstData { args, ..InstData::new(Opcode::MetaInit) }, &[]);
1470 build.ret(&[]);
1471
1472 let outside = Outside::of(&module);
1473 let mut alias = Alias::new(&f, &outside);
1474 let reference = alias.reads(first(&f, Opcode::Load)).unwrap();
1475 let plane = first(&f, Opcode::MetaInit);
1476 assert_eq!(alias.clobbered_by(&reference, plane), Answer::No(Reason::Plane));
1477 assert_eq!(alias.read_by(&reference, plane), Answer::No(Reason::Plane));
1479 }
1480
1481 #[test]
1482 fn a_check_reads_a_plane_and_not_what_it_is_about() {
1483 let mut names = Interner::new();
1487 let module = module(&mut names);
1488 let mut f = func(&mut names, &[Type::PTR]);
1489 let outside = param(&f, 0);
1490 let mut build = builder(&mut f);
1491 build.load(Type::int(32), outside, plain(4), Flags::NONE);
1492 let width = build.iconst(Type::int(64), 4);
1493 let args = build.func().push_values(&[outside, width]);
1494 build.inst(InstData { args, ..InstData::new(Opcode::CheckBounds) }, &[]);
1495 build.ret(&[]);
1496
1497 let outside = Outside::of(&module);
1498 let mut alias = Alias::new(&f, &outside);
1499 let reference = alias.reads(first(&f, Opcode::Load)).unwrap();
1500 let check = first(&f, Opcode::CheckBounds);
1501 assert_eq!(alias.clobbered_by(&reference, check), Answer::No(Reason::Plane));
1502 assert_eq!(alias.read_by(&reference, check), Answer::No(Reason::Plane));
1503 }
1504
1505 #[test]
1506 fn a_const_callee_touches_no_memory_at_all() {
1507 let mut names = Interner::new();
1508 let mut module = module(&mut names);
1509 let mut f = func(&mut names, &[Type::PTR]);
1510 let outside = param(&f, 0);
1511 let mut build = builder(&mut f);
1512 build.load(Type::int(32), outside, plain(4), Flags::NONE);
1513 let call = call_to(&mut names, &mut module, &mut f, attrs(AttrSet::READNONE), &[outside]);
1514 let mut build = builder(&mut f);
1515 build.ret(&[]);
1516
1517 let outside = Outside::of(&module);
1518 let mut alias = Alias::new(&f, &outside);
1519 let reference = alias.reads(first(&f, Opcode::Load)).unwrap();
1520 assert_eq!(alias.clobbered_by(&reference, call), Answer::No(Reason::Attribute));
1521 assert_eq!(alias.read_by(&reference, call), Answer::No(Reason::Attribute));
1522 }
1523
1524 #[test]
1525 fn a_callee_that_touches_only_its_arguments_leaves_a_global_it_was_not_passed_alone() {
1526 let mut names = Interner::new();
1527 let mut module = module(&mut names);
1528 let x = names.intern("x");
1529 let mut f = func(&mut names, &[Type::PTR]);
1530 let outside = param(&f, 0);
1531 let mut build = builder(&mut f);
1532 let object = global(&mut build, &mut module, x);
1533 build.load(Type::int(32), object, plain(4), Flags::NONE);
1534 let call =
1535 call_to(&mut names, &mut module, &mut f, attrs(AttrSet::ARGMEM_ONLY), &[outside]);
1536 let mut build = builder(&mut f);
1537 build.ret(&[]);
1538
1539 let outside = Outside::of(&module);
1540 let mut alias = Alias::new(&f, &outside);
1541 let reference = alias.reads(first(&f, Opcode::Load)).unwrap();
1542 assert_eq!(alias.clobbered_by(&reference, call), Answer::May);
1545 }
1546
1547 #[test]
1548 fn a_callee_that_touches_only_its_arguments_and_was_handed_one_object_leaves_the_other() {
1549 let mut names = Interner::new();
1550 let mut module = module(&mut names);
1551 let (x, y) = (names.intern("x"), names.intern("y"));
1552 let mut f = func(&mut names, &[]);
1553 let mut build = builder(&mut f);
1554 let watched = global(&mut build, &mut module, x);
1555 let handed = global(&mut build, &mut module, y);
1556 build.load(Type::int(32), watched, plain(4), Flags::NONE);
1557 let call = call_to(&mut names, &mut module, &mut f, attrs(AttrSet::ARGMEM_ONLY), &[handed]);
1558 let mut build = builder(&mut f);
1559 build.ret(&[]);
1560
1561 let outside = Outside::of(&module);
1562 let mut alias = Alias::new(&f, &outside);
1563 let reference = alias.reads(first(&f, Opcode::Load)).unwrap();
1564 assert_eq!(alias.clobbered_by(&reference, call), Answer::No(Reason::Attribute));
1565 }
1566
1567 #[test]
1568 fn an_indirect_call_is_not_argued_about() {
1569 let mut names = Interner::new();
1570 let module = module(&mut names);
1571 let mut f = func(&mut names, &[Type::PTR, Type::PTR]);
1572 let (target, outside) = (param(&f, 0), param(&f, 1));
1573 let mut build = builder(&mut f);
1574 build.load(Type::int(32), outside, plain(4), Flags::NONE);
1575 let signature = build.func().add_signature(Signature::new().with_params(&[Type::PTR]));
1576 let varargs = build.func().push_abis(&[]);
1577 let info = build.func().add_call(CallInfo { callee: None, signature, varargs });
1578 let args = build.func().push_values(&[target, outside]);
1579 let call = build.inst(
1580 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::CallIndirect) },
1581 &[],
1582 );
1583 build.ret(&[]);
1584
1585 let outside = Outside::of(&module);
1586 let mut alias = Alias::new(&f, &outside);
1587 let reference = alias.reads(first(&f, Opcode::Load)).unwrap();
1588 assert_eq!(alias.clobbered_by(&reference, call), Answer::May);
1589 }
1590
1591 #[test]
1592 fn every_reason_has_a_name_and_a_sentence() {
1593 for reason in Reason::ALL {
1594 assert!(!reason.name().is_empty());
1595 assert!(!reason.describe().is_empty());
1596 assert_eq!(Reason::ALL[reason.index()], reason);
1597 }
1598 assert_eq!(Reason::ALL.len(), Reason::COUNT);
1599 assert_eq!(Answer::No(Reason::Offset).reason(), Some(Reason::Offset));
1600 assert!(Answer::No(Reason::Offset).is_no());
1601 assert_eq!(Answer::May.reason(), None);
1602 assert!(!Answer::May.is_no());
1603 }
1604}