From 2e8f826287e2d431b818e5bc58da34b1091dd1f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 17 Nov 2021 10:53:49 +0100 Subject: [PATCH] JIT: Fix incorrect code generation for div/rem sequence The type-based optimizations introduced in 3617610fbc40 (#5316) could cause `int` and `rem` instructions to be fused when it was not safe. Closes #5401. --- erts/emulator/beam/predicates.tab | 9 ++++++++- erts/emulator/test/op_SUITE.erl | 30 ++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/erts/emulator/beam/predicates.tab b/erts/emulator/beam/predicates.tab index 239b76317469..da65e9e09171 100644 --- a/erts/emulator/beam/predicates.tab +++ b/erts/emulator/beam/predicates.tab @@ -217,5 +217,12 @@ pred.map_key_sort(Size, Rest) { // Test that the two registers are distinct. pred.distinct(Reg1, Reg2) { - return Reg1.type != Reg2.type || Reg1.val != Reg2.val; + if (Reg1.type != Reg2.type) { + return 1; + } else if (Reg1.type == TAG_x || Reg1.type == TAG_y) { + /* We must not compare the type indices (if any). */ + return (Reg1.val & REG_MASK) != (Reg2.val & REG_MASK); + } else { + return Reg1.val != Reg2.val; + } } diff --git a/erts/emulator/test/op_SUITE.erl b/erts/emulator/test/op_SUITE.erl index fae8b6b11a1d..17dc7039702a 100644 --- a/erts/emulator/test/op_SUITE.erl +++ b/erts/emulator/test/op_SUITE.erl @@ -23,7 +23,8 @@ -include_lib("common_test/include/ct.hrl"). -export([all/0, suite/0, - bsl_bsr/1,logical/1,t_not/1,relop_simple/1,relop/1,complex_relop/1]). + bsl_bsr/1,logical/1,t_not/1,relop_simple/1,relop/1, + complex_relop/1,unsafe_fusing/1]). -export([]). -import(lists, [foldl/3,flatmap/2]). @@ -34,7 +35,7 @@ suite() -> all() -> [bsl_bsr, logical, t_not, relop_simple, relop, - complex_relop]. + complex_relop, unsafe_fusing]. %% Test the bsl and bsr operators. bsl_bsr(Config) when is_list(Config) -> @@ -424,6 +425,31 @@ eval(E0) -> {value,Val,_Bs} -> Val end. +unsafe_fusing(_Config) -> + 0 = usec_to_seconds(id(1)), + 234_567 = usec_to_seconds(id(1_234_567_890*1_000)), + ok. + +usec_to_seconds(Usec) when is_integer(Usec) -> + %% The introduction of typed operands caused the loader + %% to incorrectly fuse the following instrutions because + %% the result register ({x,0}) from the 'div' instruction + %% seemed to be distinct from both operands of the 'rem' + %% instruction: + %% + %% {gc_bif,'div', + %% {f,0}, + %% 1, + %% [{tr,{x,0},{t_integer,any}},{integer,1000000}], + %% {x,0}}. + %% {gc_bif,'rem', + %% {f,0}, + %% 1, + %% [{tr,{x,0},{t_integer,any}},{integer,1000000}], + %% {x,0}}. + Sec = Usec div 1000000, + Sec rem 1000000. + unvalue(V) -> Abstr = erl_parse:abstract(V), erl_parse:anno_to_term(Abstr).