## machine-int.pkg
#
# How to evaluate constants for various widths.
#
# Internally, we represent machine_int as a signed integer.
# So when we do bit or unsigned operations we have to convert to
# the unsigned representation first.
# Compiled by:
#
src/lib/compiler/back/low/lib/lowhalf.lib### "What we need are notions, not notations."
###
### -- Carl Friedrich Gauss
stipulate
package ntr = multiword_int; # multiword_int is from
src/lib/std/multiword-int.pkg package str = string; # string is from
src/lib/std/string.pkg package ns = number_string; # number_string is from
src/lib/std/src/number-string.pkg package rwv = rw_vector; # rw_vector is from
src/lib/std/src/rw-vector.pkg #
max_size = 65;
herein
package machine_int
: (weak) Machine_Int # Machine_Int is from
src/lib/compiler/back/low/treecode/machine-int.api {
Machine_Int = ntr::Int;
Sz = Int;
Div_Rounding_Mode
= DIV_TO_ZERO
| DIV_TO_NEGINF
;
itow = unt::from_int;
# Parse hex or binary, but not octal: # XXX BUGGO FIXME
hex_to_int = ns::scan_string (ntr::scan ns::HEX);
bin_to_int = ns::scan_string (ntr::scan ns::BINARY);
# Precompute some tables for faster arithmetic
#
stipulate
pow2table = rwv::from_fn
(
max_size,
\\ n = ntr::(<<) (1, itow n) # 2^n
);
masktable = rwv::from_fn
(
max_size,
\\ n = ntr::(-) (ntr::(<<) (1, itow n), 1) # 2^n-1
);
maxtable = rwv::from_fn
(
max_size+1,
\\ 0 => 0;
n => ntr::(-) (ntr::(<<) (1, itow (n - 1)), 1); # 2^{ n-1 }-1
end
);
mintable = rwv::from_fn
(
max_size+1,
\\ 0 => 0;
n => ntr::neg (ntr::(<<) (1, itow (n - 1))); # -2^{ n-1 }
end
);
herein
fun pow2 i = if (i < max_size) rwv::get (pow2table, i);
else ntr::(<<) (1, itow i);
fi;
fun mask_of size = if (size < max_size) rwv::get (masktable, size);
else ntr::(-) (ntr::(<<) (1, itow size), 1);
fi;
fun max_of_size size = if (size < max_size) rwv::get (maxtable, size);
else ntr::(-) (ntr::(<<) (1, itow (size - 1)), 1);
fi;
fun min_of_size size = if (size < max_size) rwv::get (mintable, size);
else ntr::neg (ntr::(<<) (1, itow (size - 1)));
fi;
end;
# Queries:
#
fun is_neg i = ntr::sign i < 0;
fun is_pos i = ntr::sign i > 0;
fun is_zero i = ntr::sign i == 0;
fun is_non_neg i = ntr::sign i >= 0;
fun is_non_pos i = ntr::sign i <= 0;
#
fun is_even i = is_zero (ntr::rem (i, 2));
fun is_odd i = not (is_even i);
# To unsigned representation:
#
fun unsigned (size, i)
=
if (is_neg i) ntr::(+) (i, pow2 size);
else i;
fi;
# To signed representation:
#
fun signed (size, i)
=
if (ntr::(>) (i, max_of_size size)) ntr::(-) (i, pow2 size);
else i;
fi;
# Narrow to the representation
# of a given type:
#
fun narrow (size, i)
=
signed (size, ntr::bitwise_and (i, mask_of size));
# Recognize 0x and 0b prefix
# and do the right thing:
#
fun from_string (size, s)
=
{ n = str::length_in_bytes s;
#
fun conv (i, negate)
=
if (n >= 2+i
and
str::get_byte_as_char (s, i) == '0'
)
case (str::get_byte_as_char (s, i+1))
#
'x' => (hex_to_int (str::substring (s, 2+i, n - 2-i)), negate);
'b' => (bin_to_int (str::substring (s, 2+i, n - 2-i)), negate);
_ => (ntr::from_string s, FALSE);
esac;
else
(ntr::from_string s, FALSE);
fi;
my (result, negate)
=
if (s == "") (NULL, FALSE);
elif (str::get_byte_as_char (s, 0) == '-') conv (1, TRUE );
else conv (0, FALSE);
fi;
case (result, negate)
#
(THE n, TRUE ) => THE (narrow (size, ntr::neg n));
(THE n, FALSE) => THE (narrow (size, n));
(NULL, _ ) => NULL;
esac;
};
# Convert types into 'integer'
# without losing precision:
#
package convert {
#
package w = unt; # unt is from
src/lib/std/unt.pkg package w32= one_word_unt; # one_word_unt is from
src/lib/std/one-word-unt.pkg wtoi = w::to_int_x;
w32toi = w32::to_int_x;
from_int = ntr::from_int;
from_int1 = one_word_int::to_multiword_int;
fun from_unt w = ntr::from_multiword_int (unt::to_multiword_int w);
fun from_unt1 w = ntr::(+) (ntr::(<<) (ntr::from_int (w32toi((w32::(>>))(w, 0u16))), 0u16),
ntr::from_int (w32toi (w32::bitwise_and (w, 0uxffff))));
};
# machine_int <-> other types
#
fun from_int (size, i) = narrow (size, convert::from_int i);
fun from_int1 (size, i) = narrow (size, convert::from_int1 i);
fun from_unt (size, w) = narrow (size, convert::from_unt w);
fun from_unt1 (size, w) = narrow (size, convert::from_unt1 w);
#
fun to_string (size, i) = ntr::to_string i;
to_hex = ntr::format ns::HEX;
to_bin = ntr::format ns::BINARY;
fun to_hex_string (size, i) = "0x" + to_hex (unsigned (size, i));
fun to_bin_string (size, i) = "0b" + to_bin (unsigned (size, i));
fun to_int (size, i) = ntr::to_int (narrow (size, i));
fun to_unt (size, i) = unt::from_multiword_int (ntr::to_multiword_int (unsigned (size, i)));
fun to_unt1 (size, i)
=
{ i = unsigned (size, i);
lo = ntr::bitwise_and (i, 0xffff);
hi = ntr::(>>>) (i, 0u16);
fun tow32 i
=
one_word_unt::from_multiword_int (ntr::to_multiword_int i);
tow32 lo + (one_word_unt::(<<))(tow32 hi, 0u16);
};
fun to_int1 (size, i)
=
one_word_int::from_multiword_int (narrow (size, i));
fun hash i
=
unt::from_int (ntr::to_int (ntr::bitwise_and (i, 0x1fffffff)));
fun is_in_range (size, i)
=
ntr::(<=) (min_of_size size, i) and ntr::(<=) (i, max_of_size size);
fun signed_bin_op f (size, i, j)
=
narrow (size, f (i, j));
fun signed_unary_op f (size, i)
=
narrow (size, f i);
fun unsigned_bin_op f (size, i, j)
=
narrow (size, f (unsigned (size, i), unsigned (size, j)));
fun trapping_unary_op f (size, i)
=
{ x = f i;
if (is_in_range (size, x) ) x;
else raise exception OVERFLOW;fi;
};
fun trapping_bin_op f (size, i, j)
=
{ x = f (i, j);
if (is_in_range (size, x) ) x;
else raise exception OVERFLOW;fi;
};
# two's complement operators
neg = signed_unary_op ntr::neg ;
abs = signed_unary_op ntr::abs ;
add = signed_bin_op ntr::(+) ;
sub = signed_bin_op ntr::(-) ;
muls = signed_bin_op ntr::(*) ;
fun divs (DIV_TO_ZERO, type, x, y) => signed_bin_op ntr::quot (type, x, y);
divs (DIV_TO_NEGINF, type, x, y) => signed_bin_op ntr::(/) (type, x, y);
end;
fun rems (DIV_TO_ZERO, type, x, y) => signed_bin_op ntr::rem (type, x, y);
rems (DIV_TO_NEGINF, type, x, y) => signed_bin_op ntr::(%) (type, x, y);
end;
mulu = unsigned_bin_op ntr::(*) ;
divu = unsigned_bin_op ntr::(/) ;
/*
quotu = unsignedBinOp ntr::quot ;
*/
remu = unsigned_bin_op ntr::rem ;
negt = trapping_unary_op ntr::neg ;
abst = trapping_unary_op ntr::abs ;
addt = trapping_bin_op ntr::(+) ;
subt = trapping_bin_op ntr::(-) ;
mult = trapping_bin_op ntr::(*) ;
fun divt (DIV_TO_ZERO, type, x, y) => trapping_bin_op ntr::quot (type, x, y);
divt (DIV_TO_NEGINF, type, x, y) => trapping_bin_op ntr::(/) (type, x, y);
end;
fun bitwise_not (size, x) = narrow (size, ntr::bitwise_not x);
fun eqvb (size, x, y) = narrow (size, ntr::bitwise_xor (ntr::bitwise_not x, y));
fun bitwise_and (size, x, y) = narrow (size, ntr::bitwise_and (x, y));
fun bitwise_or (size, x, y) = narrow (size, ntr::bitwise_or (x, y));
fun bitwise_xor (size, x, y) = narrow (size, ntr::bitwise_xor (x, y));
fun sll (size, x, y) = narrow (size, ntr::(<<) (x, y));
fun srl (size, x, y) = narrow (size, ntr::(>>>) (unsigned (size, x), y));
fun sra (size, x, y) = narrow (size, ntr::(>>>) (x, y));
fun sll_x (size, x, y) = sll (size, x, to_unt (size, y));
fun srl_x (size, x, y) = srl (size, x, to_unt (size, y));
fun sra_x (size, x, y) = sra (size, x, to_unt (size, y));
fun bitslice (size, sl, x)
=
{ fun slice ([], n) => n;
slice ((from, to) ! sl, n)
=>
slice (sl, bitwise_or (size, narrow (to-from+1,
srl (size, x, unt::from_int from)), n));
end;
slice (sl, 0);
};
fun bit_of (size, i, b)
=
to_unt (1, narrow (1, srl (size, i, unt::from_int b)));
fun byte_of (size, i, b)
=
to_unt (8, narrow (8, srl (size, i, unt::from_int (b*8))));
fun half_of (size, i, h)
=
to_unt (16, narrow (16, srl (size, i, unt::from_int (h*16))));
fun word_of (size, i, w)
=
to_unt1 (32, narrow (32, srl (size, i, unt::from_int (w*32))));
# type promotion
#
fun sx (to_size, from_size, i) = narrow (to_size, narrow (from_size, i));
fun zx (to_size, from_size, i) = narrow (to_size, unsigned (from_size, narrow (from_size, i)));
# Comparisions
#
fun eq (size, i: ntr::Int, j) = i == j;
fun ne (size, i: ntr::Int, j) = i != j;
fun gt (size, i: ntr::Int, j) = i > j;
fun ge (size, i: ntr::Int, j) = i >= j;
fun lt (size, i: ntr::Int, j) = i < j;
fun le (size, i: ntr::Int, j) = i <= j;
fun ltu (size, i, j) = unsigned (size, i) < unsigned (size, j);
fun gtu (size, i, j) = unsigned (size, i) > unsigned (size, j);
fun leu (size, i, j) = unsigned (size, i) <= unsigned (size, j);
fun geu (size, i, j) = unsigned (size, i) >= unsigned (size, j);
# Split an integer "i" of size "size" into words of size "word_size"
#
fun split { size, word_size, i }
=
loop (size, unsigned (size, i), [])
where
fun loop (size, i, ws)
=
if (size <= 0)
#
reverse ws;
else
w = narrow (word_size, i);
i = multiword_int::(>>>) (i, unt::from_int word_size);
loop (size - word_size, i, w ! ws);
fi;
end;
}; # package machine_int
end; # stipulate