aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Lång <[email protected]>2016-10-10 15:38:39 +0200
committerMagnus Lång <[email protected]>2016-11-16 17:22:04 +0100
commite98df8fac977350b56319df621c65a823bfe86f4 (patch)
treee67ceafe4d37333c29cf451fc2f6914feed78e8e
parente1b9f467fbdb09aac9871e6064b67f87c8e59a47 (diff)
downloadotp-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.erl49
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