Skip to content

Commit 7f1dec6

Browse files
committed
Fix a bug in a corner case; tighten invariants a bit
1 parent 691d3ca commit 7f1dec6

File tree

2 files changed

+120
-34
lines changed

2 files changed

+120
-34
lines changed

middle_end/flambda/types/env/aliases.ml

Lines changed: 113 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -455,20 +455,72 @@ type add_result = {
455455
let invariant_add_result ~original_t { canonical_element; alias_of_demoted_element; t; } =
456456
if !Clflags.flambda_invariant_checks then begin
457457
invariant t;
458-
if not (Simple.equal canonical_element alias_of_demoted_element) then begin
459-
if not (defined_earlier t canonical_element ~than:alias_of_demoted_element) then begin
460-
Misc.fatal_errorf "Canonical element %a should be defined earlier \
461-
than %a after alias addition.@ Original alias tracker:@ %a@ \
458+
if not (defined_earlier t canonical_element ~than:alias_of_demoted_element) then begin
459+
Misc.fatal_errorf "Canonical element %a should be defined earlier \
460+
than %a after alias addition.@ Original alias tracker:@ %a@ \
461+
Resulting alias tracker:@ %a"
462+
Simple.print canonical_element
463+
Simple.print alias_of_demoted_element
464+
print original_t
465+
print t
466+
end;
467+
match canonical t alias_of_demoted_element with
468+
| Is_canonical _ ->
469+
Misc.fatal_errorf "Alias %a must not be must not be canonical \
470+
anymore.@ \
471+
Original alias tracker:@ %a@ \
462472
Resulting alias tracker:@ %a"
463-
Simple.print canonical_element
464473
Simple.print alias_of_demoted_element
465474
print original_t
466475
print t
467-
end
468-
end
476+
| Alias_of_canonical _ -> ()
469477
end
470478

479+
(*
480+
let debugging () = !Clflags.dump_rawflambda
481+
let andop = "\u{2227}"
482+
let canonop = "\u{21e5}"
483+
484+
let debugf fmt =
485+
let k go = if debugging () then go Format.err_formatter else () in
486+
Format.kdprintf k fmt
487+
*)
488+
471489
let add_alias t element1 element2 =
490+
(*
491+
debugf "@[<hv2>add_alias@ ~element1:%a@ ~element2:%a@]@."
492+
Simple.print element1
493+
Simple.print element2;
494+
(fun ({ canonical_element; alias_of_demoted_element = alias_of; t = _ } as ans) ->
495+
debugf "Decision: %a %s %a@."
496+
Simple.print alias_of
497+
canonop
498+
Simple.print canonical_element;
499+
ans
500+
) @@ begin
501+
begin match canonical t element1, canonical t element2 with
502+
| Is_canonical canonical_element1, Is_canonical canonical_element2
503+
| Alias_of_canonical
504+
{ element = _; canonical_element = canonical_element1; },
505+
Is_canonical canonical_element2
506+
| Is_canonical canonical_element1,
507+
Alias_of_canonical
508+
{ element = _; canonical_element = canonical_element2; }
509+
| Alias_of_canonical
510+
{ element = _; canonical_element = canonical_element1; },
511+
Alias_of_canonical
512+
{ element = _; canonical_element = canonical_element2; }
513+
->
514+
debugf "@[<hv2>%a %s %a@ %s@ %a %s %a@]@."
515+
Simple.print element1
516+
canonop
517+
Simple.print canonical_element1
518+
andop
519+
Simple.print element2
520+
canonop
521+
Simple.print canonical_element2;
522+
end;
523+
*)
472524
match canonical t element1, canonical t element2 with
473525
| Is_canonical canonical_element1, Is_canonical canonical_element2
474526
| Alias_of_canonical
@@ -482,40 +534,67 @@ let add_alias t element1 element2 =
482534
Alias_of_canonical
483535
{ element = _; canonical_element = canonical_element2; }
484536
->
485-
let canonical_element, to_be_demoted, alias_of_demoted_element =
486-
let which_element =
487-
choose_canonical_element_to_be_demoted t
488-
~canonical_element1 ~canonical_element2
537+
if Simple.equal canonical_element1 canonical_element2
538+
then
539+
let canonical_element = canonical_element1 in
540+
(* According to the contract for [add], [alias_of_demoted_element] must
541+
not be canonical. Usually this is fine, but what if [element1] or
542+
[element2] is *itself* canonical? This is true iff that element is
543+
equal to [canonical_element1]. In that case, we can safely pick the
544+
other element. (They cannot both be canonical because then they'd both
545+
be equal to [canonical_element1] and we assume that [element1] and
546+
[element2] are different.) *)
547+
(* CR lmaurer: We should just bail out in this case; since [element1] and
548+
[element2] have the same canonical, they're already aliases, so
549+
[Typing_env.add_equation] doesn't actually need to do anything at all
550+
IIUC. *)
551+
let alias_of_demoted_element =
552+
if Simple.equal element1 canonical_element then element2 else element1
489553
in
490-
match which_element with
491-
| Demote_canonical_element1 ->
492-
canonical_element2, canonical_element1, element1
493-
| Demote_canonical_element2 ->
494-
canonical_element1, canonical_element2, element2
495-
in
496-
let t =
497-
add_alias_between_canonical_elements t ~canonical_element
498-
~to_be_demoted
499-
in
500-
{ t;
501-
canonical_element;
502-
alias_of_demoted_element;
503-
}
554+
{ t; canonical_element; alias_of_demoted_element; }
555+
else
556+
let canonical_element, to_be_demoted, alias_of_demoted_element =
557+
let which_element =
558+
choose_canonical_element_to_be_demoted t
559+
~canonical_element1 ~canonical_element2
560+
in
561+
match which_element with
562+
| Demote_canonical_element1 ->
563+
canonical_element2, canonical_element1, element1
564+
| Demote_canonical_element2 ->
565+
canonical_element1, canonical_element2, element2
566+
in
567+
let t =
568+
add_alias_between_canonical_elements t ~canonical_element
569+
~to_be_demoted
570+
in
571+
{ t;
572+
canonical_element;
573+
alias_of_demoted_element;
574+
}
575+
(*
576+
end
577+
*)
504578

505579
let add t element1 binding_time_and_mode1
506580
element2 binding_time_and_mode2 =
507-
Simple.pattern_match element1
508-
~name:(fun _ -> ())
509-
~const:(fun const1 ->
510-
Simple.pattern_match element2
511-
~name:(fun _ -> ())
512-
~const:(fun const2 ->
513-
if not (Const.equal const1 const2) then begin
581+
if !Clflags.flambda_invariant_checks then begin
582+
if Simple.equal element1 element2 then begin
583+
Misc.fatal_errorf
584+
"Cannot alias an element to itself: %a" Simple.print element1
585+
end;
586+
Simple.pattern_match element1
587+
~name:(fun _ -> ())
588+
~const:(fun const1 ->
589+
Simple.pattern_match element2
590+
~name:(fun _ -> ())
591+
~const:(fun const2 ->
514592
Misc.fatal_errorf
515-
"Cannot add alias between two non-equal consts: %a <> %a"
593+
"Cannot add alias between two consts: %a, %a"
516594
Const.print const1
517595
Const.print const2
518-
end));
596+
));
597+
end;
519598
let original_t = t in
520599
let element1 = Simple.without_rec_info element1 in
521600
let element2 = Simple.without_rec_info element2 in

middle_end/flambda/types/env/aliases.mli

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ type add_result = private {
3434
alias_of_demoted_element : Simple.t;
3535
}
3636

37+
(** Add an alias relationship to the tracker. The two simple expressions
38+
must be different and not both constants. If [add t s1 mode1 s2 mode2]
39+
returns [{ t = t'; canonical_element; alias_of_demoted_element }], then
40+
according to [t'],
41+
- [canonical_element] is the canonical element of both [s1] and [s2];
42+
- [alias_of_demoted_element] is either [s1] or [s2]; and
43+
- [alias_of_demoted_element] is no longer canonical. *)
3744
val add
3845
: t
3946
-> Simple.t

0 commit comments

Comments
 (0)