%% -*- Erlang -*-
%% -*- erlang-indent-level: 2 -*-
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%%----------------------------------------------------------------------
%% File : hipe_rtl_arith.inc
%% Created : Feb 2004
%% Purpose : Implements arithmetic which is parameterized by the size
%% of the word of the target architecture (given as defines).
%%----------------------------------------------------------------------
%% Returns a tuple
%% {Res, Sign, Zero, Overflow, Carry}
%% Res will be a number in the range
%% MAX_UNSIGNED_INT >= Res >= 0
%% The other four values are flags that are either true or false
%%
eval_alu(Op, Arg1, Arg2)
when Arg1 =< ?MAX_UNSIGNED_INT,
Arg1 >= ?MIN_SIGNED_INT,
Arg2 =< ?MAX_UNSIGNED_INT,
Arg2 >= ?MIN_SIGNED_INT ->
Sign1 = sign_bit(Arg1),
Sign2 = sign_bit(Arg2),
case Op of
'sub' ->
Res = (Arg1 - Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = (Sign1 andalso (not Sign2) andalso (not N))
or
((not Sign1) andalso Sign2 andalso N),
C = ((not Sign1) andalso Sign2)
or
(N andalso ((not Sign1) orelse Sign2)),
{Res, N, Z, V, C};
'add' ->
Res = (Arg1 + Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = (Sign1 andalso Sign2 andalso (not N))
or
((not Sign1) andalso (not Sign2) andalso N),
C = (Sign1 andalso Sign2)
or
((not N) andalso (Sign1 orelse Sign2)),
{Res, N, Z, V, C};
'mul' ->
FullRes = Arg1 * Arg2,
Res = FullRes band ?WORDMASK,
ResHi = FullRes bsr ?BITS,
N = sign_bit(Res),
Z = zero(Res),
V = (N andalso (ResHi =/= -1)) orelse ((not N) andalso (ResHi =/= 0)),
C = V,
{Res, N, Z, V, C};
'sra' ->
Res = (Arg1 bsr Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0,
{Res, N, Z, V, C};
'srl' ->
Res = (Arg1 bsr Arg2) band shiftmask(Arg2),
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0,
{Res, N, Z, V, C};
'sll' ->
Res = (Arg1 bsl Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0,
{Res, N, Z, V, C};
'or' ->
Res = (Arg1 bor Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0,
{Res, N, Z, V, C};
'and' ->
Res = (Arg1 band Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0,
{Res, N, Z, V, C};
'xor' ->
Res = (Arg1 bxor Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0,
{Res, N, Z, V, C};
Op ->
?EXIT({"unknown alu op", Op})
end;
eval_alu(Op, Arg1, Arg2) ->
?EXIT({argument_overflow, Op, Arg1, Arg2}).
%% Björn & Bjarni:
%% We need to be able to do evaluations based only on the bits, since
%% there are cases where we can evaluate a subset of the bits, but
%% cannot do a full eval-alub call (eg. a + 0 gives no carry)
%%
-spec eval_cond_bits(hipe_rtl:alub_cond(), boolean(),
boolean(), boolean(), boolean()) -> boolean().
eval_cond_bits(Cond, N, Z, V, C) ->
case Cond of
'eq' ->
Z;
'ne' ->
not Z;
'gt' ->
not (Z orelse (N xor V));
'gtu' ->
not (C orelse Z);
'ge' ->
not (N xor V);
'geu'->
not C;
'lt' ->
N xor V;
'ltu'->
C;
'le' ->
Z orelse (N xor V);
'leu'->
C orelse Z;
'overflow' ->
V;
'not_overflow' ->
not V
end.
eval_alub(Op, Cond, Arg1, Arg2) ->
{Res, N, Z, V, C} = eval_alu(Op, Arg1, Arg2),
{Res, eval_cond_bits(Cond, N, Z, V, C)}.
eval_cond(Cond, Arg1, Arg2) ->
{_, Bool} = eval_alub('sub', Cond, Arg1, Arg2),
Bool.
sign_bit(Val) ->
((Val bsr ?SIGN_BIT) band 1) =:= 1.
shiftmask(Arg) ->
Setbits = ?BITS - Arg,
(1 bsl Setbits) - 1.
zero(Val) ->
Val =:= 0.