diff options
author | Magnus Lång <[email protected]> | 2016-10-10 15:38:39 +0200 |
---|---|---|
committer | Magnus Lång <[email protected]> | 2016-11-16 17:22:04 +0100 |
commit | e98df8fac977350b56319df621c65a823bfe86f4 (patch) | |
tree | e67ceafe4d37333c29cf451fc2f6914feed78e8e | |
parent | e1b9f467fbdb09aac9871e6064b67f87c8e59a47 (diff) | |
download | otp-e98df8fac977350b56319df621c65a823bfe86f4.tar.gz otp-e98df8fac977350b56319df621c65a823bfe86f4.tar.bz2 otp-e98df8fac977350b56319df621c65a823bfe86f4.zip |
hipe_tagscheme: Improve fixnum_addsub with imm
The addsub sequence was suboptimal when one of the arguments was
immediate, because it became an immediate alu followed by an immediate
alub, and the optimisers would not combine them due to the risk of
altering the branch. However, in this case we know that such a rewrite
is safe, and do it directly in hipe_tagscheme:fixnum_addsub/5 instead.
-rw-r--r-- | lib/hipe/rtl/hipe_tagscheme.erl | 49 |
1 files changed, 32 insertions, 17 deletions
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl index 305aacb571..1d9861da7a 100644 --- a/lib/hipe/rtl/hipe_tagscheme.erl +++ b/lib/hipe/rtl/hipe_tagscheme.erl @@ -509,33 +509,48 @@ unsafe_fixnum_sub(Arg1, Arg2, Res) -> %%% (16X+tag)+((16Y+tag)-tag) = 16X+tag+16Y = 16(X+Y)+tag %%% (16X+tag)-((16Y+tag)-tag) = 16X+tag-16Y = 16(X-Y)+tag -fixnum_addsub(AluOp, Arg1, Arg2, Res, OtherLab) -> +fixnum_addsub(AluOp, Arg1, Arg2, FinalRes, OtherLab) -> NoOverflowLab = hipe_rtl:mk_new_label(), %% XXX: Consider moving this test to the users of fixnum_addsub. - case Arg1 =/= Res andalso Arg2 =/= Res of - true -> - %% Args differ from res. + {Res, Tail} = + case Arg1 =/= FinalRes andalso Arg2 =/= FinalRes of + true -> + %% Args differ from res. + {FinalRes, [NoOverflowLab]}; + false -> + %% At least one of the arguments is the same as Res. + Tmp = hipe_rtl:mk_new_reg_gcsafe(), + {Tmp, [NoOverflowLab, hipe_rtl:mk_move(FinalRes, Tmp)]} + end, + case (hipe_rtl:is_imm(Arg1) andalso AluOp =:= 'add') + orelse hipe_rtl:is_imm(Arg2) + of + true -> + %% Pre-compute the untagged immediate. The optimisers won't do this for us + %% since they don't know that the untag never underflows. + {Var, Imm0} = + case hipe_rtl:is_imm(Arg2) of + true -> {Arg1, Arg2}; + false -> {Arg2, Arg1} + end, + Imm = hipe_rtl:mk_imm(hipe_rtl:imm_value(Imm0) - ?TAG_IMMED1_SMALL), + [hipe_rtl:mk_alub(Res, Var, AluOp, Imm, not_overflow, + hipe_rtl:label_name(NoOverflowLab), + hipe_rtl:label_name(OtherLab), 0.99) + |Tail]; + false -> %% Commute add to save a move on x86 {UntagFirst, Lhs, Rhs} = case AluOp of 'add' -> {Arg1, Res, Arg2}; 'sub' -> {Arg2, Arg1, Res} end, - [hipe_rtl:mk_alu(Res, UntagFirst, sub, hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)), + [hipe_rtl:mk_alu(Res, UntagFirst, sub, + hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)), hipe_rtl:mk_alub(Res, Lhs, AluOp, Rhs, not_overflow, hipe_rtl:label_name(NoOverflowLab), - hipe_rtl:label_name(OtherLab), 0.99), - NoOverflowLab]; - false -> - %% At least one of the arguments is the same as Res. - Tmp = hipe_rtl:mk_new_reg_gcsafe(), - Tmp2 = hipe_rtl:mk_new_var(), % XXX: shouldn't this var be a reg? - [hipe_rtl:mk_alu(Tmp, Arg2, sub, hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)), - hipe_rtl:mk_alub(Tmp2, Arg1, AluOp, Tmp, not_overflow, - hipe_rtl:label_name(NoOverflowLab), - hipe_rtl:label_name(OtherLab), 0.99), - NoOverflowLab, - hipe_rtl:mk_move(Res, Tmp2)] + hipe_rtl:label_name(OtherLab), 0.99) + |Tail] end. %%% ((16X+tag) div 16) * ((16Y+tag)-tag) + tag = X*16Y+tag = 16(XY)+tag |