%% -*- Erlang -*-
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% 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.
%%
%% %CopyrightEnd%
%%
%%----------------------------------------------------------------------
%% 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_SIGNED_INT >= Res >= MIN_SIGNED_INT
%% The other four values are flags that are either true or false
%%
eval_alu(Op, Arg1, Arg2)
when Arg1 =< ?MAX_SIGNED_INT,
Arg1 >= ?MIN_SIGNED_INT,
Arg2 =< ?MAX_SIGNED_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 and (not Sign2) and (not N))
or
((not Sign1) and Sign2 and N),
C = ((not Sign1) and Sign2)
or
(N and ((not Sign1) or Sign2));
'add' ->
Res = (Arg1 + Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = (Sign1 and Sign2 and (not N))
or
((not Sign1) and (not Sign2) and N),
C = (Sign1 and Sign2)
or
((not N) and (Sign1 or Sign2));
'mul' ->
FullRes = Arg1 * Arg2,
Res = FullRes band ?WORDMASK,
ResHi = FullRes bsr ?BITS,
N = sign_bit(Res),
Z = zero(Res),
V = (N and (ResHi =/= -1)) or ((not N) and (ResHi =/= 0)),
C = V;
'sra' ->
Res = (Arg1 bsr Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0;
'srl' ->
Res = (Arg1 bsr Arg2) band shiftmask(Arg2),
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0;
'sll' ->
Res = (Arg1 bsl Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0;
'or' ->
Res = (Arg1 bor Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0;
'and' ->
Res = (Arg1 band Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0;
'xor' ->
Res = (Arg1 bxor Arg2) band ?WORDMASK,
N = sign_bit(Res),
Z = zero(Res),
V = 0,
C = 0;
Op ->
Res = N = Z = V = C = 0,
?EXIT({"unknown alu op", Op})
end,
{two_comp_to_erl(Res), N, Z, V, C};
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 can
%% not 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 or (N xor V));
'gtu' ->
not (C or Z);
'ge' ->
not (N xor V);
'geu'->
not C;
'lt' ->
N xor V;
'ltu'->
C;
'le' ->
Z or (N xor V);
'leu'->
C or 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.
two_comp_to_erl(V) ->
if V > ?MAX_SIGNED_INT ->
- ((?MAX_UNSIGNED_INT + 1) - V);
true -> V
end.
shiftmask(Arg) ->
Setbits = ?BITS - Arg,
(1 bsl Setbits) - 1.
zero(Val) ->
Val =:= 0.