ack/util/int/do_intar.c

268 lines
4.7 KiB
C
Raw Normal View History

2019-03-17 14:42:00 +00:00
/** @file
* Sources of the "INTEGER ARITHMETIC" group instructions
1988-06-22 16:57:09 +00:00
*/
1994-06-24 11:31:16 +00:00
/* $Id$ */
1988-06-22 16:57:09 +00:00
2019-03-17 14:42:00 +00:00
#include "em_abs.h"
1988-06-22 16:57:09 +00:00
#include "logging.h"
#include "global.h"
#include "log.h"
#include "mem.h"
#include "trap.h"
#include "warn.h"
#include "text.h"
#include "fra.h"
PRIVATE long adi(long, long, size), sbi(long, long, size), dvi(long, long, size);
2019-03-17 14:42:00 +00:00
PRIVATE long mli(long, long, size), rmi(long, long), ngi(long, size);
PRIVATE long sli(long, long, size), sri(long, long, size);
1988-06-22 16:57:09 +00:00
2019-03-17 14:42:00 +00:00
/** ADI w: Addition (*) */
void DoADI(register size l)
1988-06-22 16:57:09 +00:00
{
register long t = spop(arg_wi(l));
LOG(("@I6 DoADI(%ld)", l));
1988-06-22 16:57:09 +00:00
spoilFRA();
npush(adi(spop(l), t, l), l);
}
2019-03-17 14:42:00 +00:00
/** SBI w: Subtraction (*) */
void DoSBI(register size l)
1988-06-22 16:57:09 +00:00
{
register long t = spop(arg_wi(l));
LOG(("@I6 DoSBI(%ld)", l));
1988-06-22 16:57:09 +00:00
spoilFRA();
npush(sbi(spop(l), t, l), l);
}
2019-03-17 14:42:00 +00:00
/** MLI w: Multiplication (*) */
void DoMLI(register size l)
1988-06-22 16:57:09 +00:00
{
register long t = spop(arg_wi(l));
LOG(("@I6 DoMLI(%ld)", l));
1988-06-22 16:57:09 +00:00
spoilFRA();
npush(mli(spop(l), t, l), l);
}
2019-03-17 14:42:00 +00:00
/** DVI w: Division (*) */
void DoDVI(register size l)
1988-06-22 16:57:09 +00:00
{
register long t = spop(arg_wi(l));
LOG(("@I6 DoDVI(%ld)", l));
1988-06-22 16:57:09 +00:00
spoilFRA();
npush(dvi(spop(l), t, l), l);
1988-06-22 16:57:09 +00:00
}
2019-03-17 14:42:00 +00:00
/** RMI w: Remainder (*) */
void DoRMI(register size l)
1988-06-22 16:57:09 +00:00
{
register long t = spop(arg_wi(l));
LOG(("@I6 DoRMI(%ld)", l));
1988-06-22 16:57:09 +00:00
spoilFRA();
npush(rmi(spop(l), t), l);
}
2019-03-17 14:42:00 +00:00
/** NGI w: Negate (two's complement) (*) */
void DoNGI(register size l)
1988-06-22 16:57:09 +00:00
{
LOG(("@I6 DoNGI(%ld)", l));
1988-06-22 16:57:09 +00:00
spoilFRA();
l = arg_wi(l);
npush(ngi(spop(l), l), l);
}
2019-03-17 14:42:00 +00:00
/** SLI w: Shift left (*) */
void DoSLI(register size l)
1988-06-22 16:57:09 +00:00
{
1989-11-22 13:38:37 +00:00
register long t = swpop();
1988-06-22 16:57:09 +00:00
LOG(("@I6 DoSLI(%ld)", l));
1988-06-22 16:57:09 +00:00
spoilFRA();
l = arg_wi(l);
npush(sli(spop(l), t, l), l);
}
2019-03-17 14:42:00 +00:00
/** SRI w: Shift right (*) */
void DoSRI(register size l)
1988-06-22 16:57:09 +00:00
{
1989-11-22 13:38:37 +00:00
register long t = swpop();
1988-06-22 16:57:09 +00:00
LOG(("@I6 DoSRI(%ld)", l));
1988-06-22 16:57:09 +00:00
spoilFRA();
l = arg_wi(l);
npush(sri(spop(l), t, l), l);
}
#define i_maxs(n) ((n == 2) ? I_MAXS2 : I_MAXS4)
#define i_mins(n) ((n == 2) ? I_MINS2 : I_MINS4)
2019-03-17 14:42:00 +00:00
/** Returns "w1" + "w2". */
PRIVATE long adi(long w1, long w2, size nbytes)
1988-06-22 16:57:09 +00:00
{
if (must_test && !(IgnMask&BIT(EIOVFL))) {
if (w1 > 0 && w2 > 0) {
if (i_maxs(nbytes) - w1 < w2)
trap(EIOVFL);
}
else if (w1 < 0 && w2 < 0) {
if (i_mins(nbytes) - w1 > w2)
trap(EIOVFL);
}
}
return (w1 + w2);
}
2019-03-17 14:42:00 +00:00
/** Returns "w1" - "w2" */
PRIVATE long sbi(long w1, long w2, size nbytes)
1988-06-22 16:57:09 +00:00
{
if (must_test && !(IgnMask&BIT(EIOVFL))) {
if (w2 < 0 && w1 > 0) {
if (i_maxs(nbytes) + w2 < w1)
trap(EIOVFL);
}
else if (w2 > 0 && w1 < 0) {
if (i_mins(nbytes) + w2 > w1) {
trap(EIOVFL);
}
}
}
return (w1 - w2);
}
#define labs(w) ((w < 0) ? (-w) : w)
2019-03-17 14:42:00 +00:00
/** Returns "w1" * "w2" */
PRIVATE long mli(long w1, long w2, size nbytes)
1988-06-22 16:57:09 +00:00
{
if (w1 == 0 || w2 == 0)
return (0L);
if (must_test && !(IgnMask&BIT(EIOVFL))) {
if ((w1 > 0 && w2 > 0) || (w2 < 0 && w1 < 0)) {
if ( w1 == i_mins(nbytes) || w2 == i_mins(nbytes)
|| (i_maxs(nbytes) / labs(w1)) < labs(w2)
) {
trap(EIOVFL);
}
}
else if (w1 > 0) {
if (i_mins(nbytes) / w1 > w2)
trap(EIOVFL);
}
else if (i_mins(nbytes) / w2 > w1) {
trap(EIOVFL);
}
}
return (w1 * w2);
}
PRIVATE long dvi(long w1, long w2, size nbytes)
1988-06-22 16:57:09 +00:00
{
if (w2 == 0) {
if (!(IgnMask&BIT(EIDIVZ))) {
trap(EIDIVZ);
}
else return (0L);
}
/* Check for division overflow. */
if ((w1 == i_mins(nbytes)) && (w2 == -1))
{
if (must_test && !(IgnMask&BIT(EIOVFL)))
{
trap(EIOVFL);
} else return i_mins(nbytes);
}
1988-06-22 16:57:09 +00:00
return (w1 / w2);
}
2019-03-17 14:42:00 +00:00
PRIVATE long rmi(long w1, long w2)
1988-06-22 16:57:09 +00:00
{
if (w2 == 0) {
if (!(IgnMask&BIT(EIDIVZ))) {
trap(EIDIVZ);
}
else return (0L);
}
return (w1 % w2);
}
2019-03-17 14:42:00 +00:00
PRIVATE long ngi(long w1, size nbytes)
1988-06-22 16:57:09 +00:00
{
if (must_test && !(IgnMask&BIT(EIOVFL))) {
if (w1 == i_mins(nbytes)) {
trap(EIOVFL);
}
}
return (-w1);
}
2019-03-17 14:42:00 +00:00
/** "w1" << "w2" */
PRIVATE long sli(long w1, long w2, size nbytes)
1988-06-22 16:57:09 +00:00
{
if (must_test) {
#ifdef LOGGING
/* check shift distance */
if (w2 < 0) {
warning(WSHNEG);
w2 = 0;
}
if (w2 >= nbytes*8) {
warning(WSHLARGE);
w2 = nbytes*8 - 1;
}
#endif /* LOGGING */
1988-06-22 16:57:09 +00:00
if (!(IgnMask&BIT(EIOVFL))) {
/* check overflow */
/* If the value is positive, then check, this is taken
* from rule INT32-C of SEI website.
*/
if ((w1 >= 0) && (w1 > (i_maxs(nbytes) >> w2)))
{
trap(EIOVFL);
}
if ((w1 < 0) && (w1 < (i_mins(nbytes) >> w2)))
{
1988-06-22 16:57:09 +00:00
trap(EIOVFL);
}
1988-06-22 16:57:09 +00:00
}
}
/* calculate result */
return (w1 << w2);
}
/*ARGSUSED*/
2019-03-17 14:42:00 +00:00
PRIVATE long sri(long w1, long w2, size nbytes) /* w1 >> w2 */
1988-06-22 16:57:09 +00:00
{
#ifdef LOGGING
if (must_test) {
/* check shift distance */
if (w2 < 0) {
warning(WSHNEG);
w2 = 0;
}
if (w2 >= nbytes*8) {
warning(WSHLARGE);
w2 = nbytes*8 - 1;
}
}
#endif /* LOGGING */
1988-06-22 16:57:09 +00:00
/* calculate result */
return (w1 >> w2);
}