ack/lang/m2/comp/code.c

1228 lines
23 KiB
C
Raw Normal View History

/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*
* Author: Ceriel J.H. Jacobs
*/
1986-05-21 18:32:20 +00:00
/* C O D E G E N E R A T I O N R O U T I N E S */
1994-06-24 14:02:31 +00:00
/* $Id$ */
1986-05-21 18:32:20 +00:00
/* Code generation for expressions and coercions
*/
#include "parameters.h"
1986-05-21 18:32:20 +00:00
#include "debug.h"
#include <stdlib.h>
1986-05-21 18:32:20 +00:00
#include <assert.h>
#include "em_arith.h"
#include "em_label.h"
#include "em_code.h"
#include "em_abs.h"
#include "alloc.h"
1986-05-21 18:32:20 +00:00
#include "code.h"
1986-05-21 18:32:20 +00:00
#include "type.h"
#include "error.h"
#include "LLlex.h"
1986-05-21 18:32:20 +00:00
#include "def.h"
#include "scope.h"
#include "desig.h"
#include "chk_expr.h"
1986-05-21 18:32:20 +00:00
#include "node.h"
#include "Lpars.h"
#include "tmpvar.h"
1986-05-30 18:48:00 +00:00
#include "standards.h"
1986-06-20 14:36:49 +00:00
#include "walk.h"
1986-05-21 18:32:20 +00:00
extern int proclevel;
extern char options[];
extern struct desig null_desig;
1986-06-06 02:22:09 +00:00
int fp_used;
1986-05-21 18:32:20 +00:00
/* Forward declarations */
static void CodeParameters(struct paramlist *, register struct node *);
static void CodeStd(struct node *);
static void compare(int, label);
static void truthvalue(int);
static void CodeUoper(register struct node *);
static void CodeSet(register struct node *, int);
static void CodeEl(register struct node *, register struct type *, int);
static void CodeDAddress(struct node *, int);
static void DoHIGH(register struct def *);
void CodeConst(arith cst, int size)
1986-05-21 18:32:20 +00:00
{
1987-07-21 13:54:33 +00:00
if (size <= (int) word_size) {
1986-05-21 18:32:20 +00:00
C_loc(cst);
}
1987-07-21 13:54:33 +00:00
else if (size == (int) dword_size) {
1986-05-21 18:32:20 +00:00
C_ldc(cst);
}
else {
1986-10-06 20:36:30 +00:00
crash("(CodeConst)");
1986-05-21 18:32:20 +00:00
}
}
void CodeString(register struct node *nd)
1986-05-21 18:32:20 +00:00
{
1986-09-25 19:39:06 +00:00
if (nd->nd_type->tp_fund != T_STRING) {
1987-05-18 15:57:33 +00:00
/* Character constant */
1996-11-19 09:12:36 +00:00
CodeConst(nd->nd_INT, nd->nd_type->tp_size);
1987-07-21 13:54:33 +00:00
return;
1986-05-23 09:46:31 +00:00
}
1987-07-21 13:54:33 +00:00
C_df_dlb(++data_label);
C_rom_scon(nd->nd_STR, WA((arith)(nd->nd_SLE + 1)));
c_lae_dlb(data_label);
1986-06-04 09:01:48 +00:00
}
void CodeExpr(struct node *nd, struct desig *ds, label true_label, label false_label)
1986-05-21 18:32:20 +00:00
{
register struct type *tp = nd->nd_type;
1986-05-21 18:32:20 +00:00
DoLineno(nd);
1986-06-06 02:22:09 +00:00
if (tp->tp_fund == T_REAL) fp_used = 1;
1986-05-21 18:32:20 +00:00
switch(nd->nd_class) {
case Def:
if (nd->nd_def->df_kind & (D_PROCEDURE|D_PROCHEAD)) {
C_lpi(nd->nd_def->prc_name);
1986-05-30 18:48:00 +00:00
ds->dsg_kind = DSG_LOADED;
break;
}
1986-06-04 09:01:48 +00:00
/* Fall through */
case Link:
1986-06-10 13:18:52 +00:00
case Arrsel:
case Arrow:
1986-05-21 18:32:20 +00:00
CodeDesig(nd, ds);
break;
case Oper:
CodeOper(nd, true_label, false_label);
1987-05-18 15:57:33 +00:00
ds->dsg_kind = DSG_LOADED;
true_label = NO_LABEL;
1986-05-21 18:32:20 +00:00
break;
case Uoper:
CodeUoper(nd);
ds->dsg_kind = DSG_LOADED;
break;
case Value:
switch(nd->nd_symb) {
1987-05-18 15:57:33 +00:00
case REAL:
C_df_dlb(++data_label);
1991-03-06 10:52:34 +00:00
if (! nd->nd_RSTR) {
static char buf[FLT_STRLEN];
flt_flt2str(&nd->nd_RVAL, buf, FLT_STRLEN);
C_rom_fcon(buf, tp->tp_size);
}
1991-03-06 10:52:34 +00:00
else C_rom_fcon(nd->nd_RSTR, tp->tp_size);
c_lae_dlb(data_label);
1987-07-21 13:54:33 +00:00
C_loi(tp->tp_size);
1986-05-21 18:32:20 +00:00
break;
case STRING:
CodeString(nd);
break;
case INTEGER:
1987-07-21 13:54:33 +00:00
CodeConst(nd->nd_INT, (int) (tp->tp_size));
1986-05-21 18:32:20 +00:00
break;
default:
crash("Value error");
}
ds->dsg_kind = DSG_LOADED;
break;
case Call:
CodeCall(nd);
ds->dsg_kind = DSG_LOADED;
break;
1986-05-23 19:25:21 +00:00
case Set: {
1987-07-21 13:54:33 +00:00
register unsigned i = (unsigned) (tp->tp_size) / (int) word_size;
1987-05-18 15:57:33 +00:00
register arith *st = nd->nd_set + i;
int null_set = 1;
1986-05-23 19:25:21 +00:00
1986-05-28 18:36:51 +00:00
ds->dsg_kind = DSG_LOADED;
1987-07-21 13:54:33 +00:00
for (; i; i--) {
if (*--st != 0) null_set = 0;
}
if (! null_set) {
i = (unsigned) (tp->tp_size) / (int) word_size;
st = nd->nd_set + i;
for (; i; i--) {
C_loc(*--st);
}
1986-05-23 19:25:21 +00:00
}
FreeSet(nd->nd_set);
CodeSet(nd, null_set);
1986-05-23 19:25:21 +00:00
}
break;
1986-05-21 18:32:20 +00:00
default:
crash("(CodeExpr) bad node type");
}
1987-05-18 15:57:33 +00:00
if (true_label != NO_LABEL) {
1986-10-06 20:36:30 +00:00
/* Only for boolean expressions
*/
1987-06-23 17:12:25 +00:00
CodeValue(ds, tp);
1986-05-21 18:32:20 +00:00
C_zne(true_label);
1993-11-19 09:53:47 +00:00
c_bra(false_label);
1986-05-21 18:32:20 +00:00
}
}
void CodeCoercion(struct type *t1, struct type *t2)
1986-05-21 18:32:20 +00:00
{
int fund1, fund2;
int sz1 = t1->tp_size;
int sz2;
1986-05-28 18:36:51 +00:00
1986-06-26 09:39:36 +00:00
t1 = BaseType(t1);
t2 = BaseType(t2);
sz2 = t2->tp_size;
1987-06-23 17:12:25 +00:00
switch(fund1 = t1->tp_fund) {
case T_WORD:
fund1 = T_INTEGER;
break;
case T_CHAR:
case T_ENUMERATION:
case T_CARDINAL:
case T_INTORCARD:
if (sz1 < (int) word_size) sz1 = word_size;
/* fall through */
case T_EQUAL:
1987-06-23 17:12:25 +00:00
case T_POINTER:
fund1 = T_CARDINAL;
break;
}
switch(fund2 = t2->tp_fund) {
1987-06-23 17:12:25 +00:00
case T_WORD:
fund2 = T_INTEGER;
break;
case T_CHAR:
case T_ENUMERATION:
sz2 = word_size;
/* fall through */
case T_EQUAL:
1987-06-23 17:12:25 +00:00
case T_POINTER:
fund2 = T_CARDINAL;
break;
}
1986-05-28 18:36:51 +00:00
switch(fund1) {
case T_INTEGER:
if (sz1 < (int) word_size) {
c_loc(sz1);
c_loc((int) word_size);
1987-06-23 17:12:25 +00:00
C_cii();
sz1 = word_size;
1987-06-23 17:12:25 +00:00
}
c_loc(sz1);
c_loc(sz2);
switch(fund2) {
case T_REAL:
C_cif();
1986-05-28 18:36:51 +00:00
break;
case T_INTEGER:
C_cii();
break;
case T_CARDINAL:
C_ciu();
break;
default:
crash("Funny integer conversion");
1986-05-28 18:36:51 +00:00
}
break;
case T_CARDINAL:
1986-08-26 14:33:24 +00:00
case T_INTORCARD:
c_loc(sz1);
c_loc(sz2);
switch(fund2) {
case T_REAL:
C_cuf();
1986-05-28 18:36:51 +00:00
break;
case T_CARDINAL:
case T_INTORCARD:
C_cuu();
break;
case T_INTEGER:
C_cui();
break;
default:
crash("Funny cardinal conversion");
1986-05-28 18:36:51 +00:00
}
break;
case T_REAL:
switch(fund2) {
case T_REAL:
c_loc(sz1);
c_loc(sz2);
C_cff();
1986-05-28 18:36:51 +00:00
break;
case T_INTEGER:
c_loc(sz1);
c_loc(sz2);
1986-05-28 18:36:51 +00:00
C_cfi();
break;
case T_CARDINAL:
if (! options['R']) {
label lb = ++text_label;
arith asz1 = sz1;
C_dup(asz1);
C_zrf(asz1);
C_cmf(asz1);
C_zge(lb);
c_loc(ECONV);
C_trp();
def_ilb(lb);
}
c_loc(sz1);
c_loc(sz2);
1986-05-28 18:36:51 +00:00
C_cfu();
break;
default:
crash("Funny REAL conversion");
}
break;
}
1986-05-21 18:32:20 +00:00
}
void CodeCall(struct node *nd)
1986-05-21 18:32:20 +00:00
{
register struct node *left = nd->nd_LEFT;
struct type *result_tp;
1988-10-25 17:43:19 +00:00
int needs_fn;
1986-05-21 18:32:20 +00:00
if (left->nd_type == std_type) {
CodeStd(nd);
return;
}
assert(IsProc(left));
1986-05-21 18:32:20 +00:00
result_tp = ResultType(left->nd_type);
#ifdef BIG_RESULT_ON_STACK
if (result_tp && TooBigForReturnArea(result_tp)) {
C_asp(-WA(result_tp->tp_size));
}
#endif
if (nd->nd_RIGHT) {
CodeParameters(ParamList(left->nd_type), nd->nd_RIGHT);
1986-05-21 18:32:20 +00:00
}
1986-08-26 14:33:24 +00:00
switch(left->nd_class) {
case Def: {
register struct def *df = left->nd_def;
if (df->df_kind == D_CONST) {
/* a procedure address */
df = df->con_const.tk_data.tk_def;
}
if (df->df_kind & (D_PROCEDURE|D_PROCHEAD)) {
int level = df->df_scope->sc_level;
1986-08-26 14:33:24 +00:00
if (level > 0) {
1987-05-18 15:57:33 +00:00
C_lxl((arith) (proclevel - level));
1986-08-26 14:33:24 +00:00
}
needs_fn = df->df_scope->sc_defmodule;
C_cal(df->prc_name);
1986-08-26 14:33:24 +00:00
break;
}}
/* Fall through */
default:
1988-10-25 17:43:19 +00:00
needs_fn = 1;
1986-05-30 18:48:00 +00:00
CodePExpr(left);
1986-05-21 18:32:20 +00:00
C_cai();
}
1987-05-18 15:57:33 +00:00
C_asp(left->nd_type->prc_nbpar);
if (result_tp) {
arith sz = WA(result_tp->tp_size);
if (TooBigForReturnArea(result_tp)) {
#ifndef BIG_RESULT_ON_STACK
C_lfr(pointer_size);
C_loi(sz);
#endif
1986-06-20 14:36:49 +00:00
}
else C_lfr(sz);
1986-05-21 18:32:20 +00:00
}
1988-10-25 17:43:19 +00:00
DoFilename(needs_fn);
1988-03-23 17:44:25 +00:00
DoLineno(nd);
1986-05-21 18:32:20 +00:00
}
/* Generates code to setup the parameters of a procedure call. */
static void CodeParameters(struct paramlist *param, register struct node *arg)
1986-06-17 12:04:05 +00:00
{
register struct type *tp;
register struct type *arg_type;
1986-09-25 19:39:06 +00:00
1986-06-17 12:04:05 +00:00
assert(param != 0 && arg != 0);
1987-07-16 19:51:40 +00:00
if (param->par_next) {
CodeParameters(param->par_next, arg->nd_RIGHT);
1986-06-17 12:04:05 +00:00
}
tp = TypeOfParam(param);
arg = arg->nd_LEFT;
arg_type = arg->nd_type;
1986-06-17 12:04:05 +00:00
if (IsConformantArray(tp)) {
register struct type *elem = tp->arr_elem;
1986-11-26 16:40:45 +00:00
1986-06-17 12:04:05 +00:00
C_loc(tp->arr_elsize);
if (IsConformantArray(arg_type)) {
DoHIGH(arg->nd_def);
if (elem->tp_size != arg_type->arr_elem->tp_size) {
1986-06-17 12:04:05 +00:00
/* This can only happen if the formal type is
1986-11-26 16:40:45 +00:00
ARRAY OF (WORD|BYTE)
1986-06-17 12:04:05 +00:00
*/
C_loc(arg_type->arr_elem->tp_size);
C_mlu(word_size);
1986-11-26 16:40:45 +00:00
if (elem == word_type) {
c_loc((int) word_size - 1);
C_adu(word_size);
c_loc((int) word_size - 1);
C_and(word_size);
1986-11-26 16:40:45 +00:00
}
else {
assert(elem == byte_type);
}
1986-06-17 12:04:05 +00:00
}
}
else if (arg->nd_symb == STRING) {
1991-03-13 17:26:07 +00:00
c_loc((int) arg->nd_SLE - 1);
1986-06-17 12:04:05 +00:00
}
1986-11-26 16:40:45 +00:00
else if (elem == word_type) {
C_loc((arg_type->tp_size+word_size-1) / word_size - 1);
1986-06-17 12:04:05 +00:00
}
1986-11-26 16:40:45 +00:00
else if (elem == byte_type) {
C_loc(arg_type->tp_size - 1);
1986-11-26 16:40:45 +00:00
}
1986-06-17 12:04:05 +00:00
else {
C_loc(arg_type->arr_high - arg_type->arr_low);
1986-06-17 12:04:05 +00:00
}
c_loc(0);
}
1991-03-13 13:49:56 +00:00
if (IsConformantArray(tp) || IsVarParam(param)) {
if (arg->nd_symb == STRING) {
CodeString(arg);
1986-06-17 12:04:05 +00:00
}
else switch(arg->nd_class) {
1987-07-22 10:59:24 +00:00
case Arrsel:
case Arrow:
case Def:
CodeDAddress(arg, IsVarParam(param));
1987-07-22 10:59:24 +00:00
break;
default:{
1986-11-26 16:40:45 +00:00
arith tmp, TmpSpace();
arith sz = WA(arg->nd_type->tp_size);
1986-11-26 16:40:45 +00:00
CodePExpr(arg);
tmp = TmpSpace(sz, arg->nd_type->tp_align);
STL(tmp, sz);
1986-11-26 16:40:45 +00:00
C_lal(tmp);
1987-07-22 10:59:24 +00:00
}
break;
1986-11-26 16:40:45 +00:00
}
return;
1986-06-17 12:04:05 +00:00
}
if (arg_type->tp_fund == T_STRING) {
CodePString(arg, tp);
1986-11-26 16:40:45 +00:00
return;
1986-06-17 12:04:05 +00:00
}
CodePExpr(arg);
1986-06-17 12:04:05 +00:00
}
void CodePString(struct node *nd, struct type *tp)
1986-12-01 10:06:53 +00:00
{
arith szarg = WA(nd->nd_type->tp_size);
register arith zersz = WA(tp->tp_size) - szarg;
if (zersz) {
/* null padding required */
assert(zersz > 0);
C_zer(zersz);
}
CodeString(nd); /* push address of string */
C_loi(szarg);
}
static void subu(int sz)
1987-11-26 14:15:24 +00:00
{
if (! options['R']) {
1991-03-13 17:26:07 +00:00
C_cal(sz == (int) word_size ? "subuchk" : "subulchk");
1987-11-26 14:15:24 +00:00
}
1991-03-13 17:26:07 +00:00
C_sbu((arith) sz);
1987-11-26 14:15:24 +00:00
}
static void addu(int sz)
1987-11-26 14:15:24 +00:00
{
if (! options['R']) {
1991-03-13 17:26:07 +00:00
C_cal(sz == (int) word_size ? "adduchk" : "addulchk");
1987-11-26 14:15:24 +00:00
}
1991-03-13 17:26:07 +00:00
C_adu((arith)sz);
1987-11-26 14:15:24 +00:00
}
static int complex_lhs(register struct node *nd)
{
switch(nd->nd_class) {
case Value:
case Name:
case Set:
case Def:
return 0;
case Select:
return complex_lhs(nd->nd_NEXT);
default:
return 1;
}
}
/* Generate code for internal procedures */
static void CodeStd(struct node *nd)
1986-05-21 18:32:20 +00:00
{
register struct node *arg = nd->nd_RIGHT;
register struct node *left = 0;
register struct type *tp = 0;
int std = nd->nd_LEFT->nd_def->df_value.df_stdname;
1986-05-30 18:48:00 +00:00
if (arg) {
left = arg->nd_LEFT;
1986-06-26 09:39:36 +00:00
tp = BaseType(left->nd_type);
arg = arg->nd_RIGHT;
1986-05-30 18:48:00 +00:00
}
1986-10-06 20:36:30 +00:00
switch(std) {
case S_ORD:
case S_VAL:
CodePExpr(left);
break;
1986-05-30 18:48:00 +00:00
case S_ABS:
CodePExpr(left);
if (tp->tp_fund == T_INTEGER) {
CAL((int)(tp->tp_size) == (int)int_size ? "absi" : "absl", (int)(tp->tp_size));
1986-05-30 18:48:00 +00:00
}
else if (tp->tp_fund == T_REAL) {
CAL((int)(tp->tp_size) == (int)float_size ? "absf" : "absd", (int)(tp->tp_size));
1986-05-30 18:48:00 +00:00
}
C_lfr(tp->tp_size);
break;
case S_CAP:
CodePExpr(left);
C_cal("cap");
1986-05-30 18:48:00 +00:00
break;
case S_HIGH:
assert(IsConformantArray(tp));
1987-05-18 15:57:33 +00:00
DoHIGH(left->nd_def);
1986-05-30 18:48:00 +00:00
break;
case S_SIZE:
case S_TSIZE:
assert(IsConformantArray(tp));
1987-05-18 15:57:33 +00:00
DoHIGH(left->nd_def);
C_inc();
C_loc(tp->arr_elem->tp_size);
C_mlu(word_size);
break;
1986-05-30 18:48:00 +00:00
case S_ODD:
1986-08-26 14:33:24 +00:00
CodePExpr(left);
if ((int) tp->tp_size == (int) word_size) {
c_loc(1);
1986-05-30 18:48:00 +00:00
C_and(word_size);
}
else {
assert(tp->tp_size == dword_size);
C_ldc((arith) 1);
C_and(dword_size);
C_ior(word_size);
}
break;
case S_ADR:
CodeDAddress(left, 1);
1986-05-30 18:48:00 +00:00
break;
case S_DEC:
1986-10-06 20:36:30 +00:00
case S_INC: {
register arith size;
int compl = complex_lhs(left);
arith tmp = 0;
1986-10-06 20:36:30 +00:00
size = left->nd_type->tp_size;
1991-03-13 17:26:07 +00:00
if ((int) size < (int) word_size) size = word_size;
if (compl) {
tmp = NewPtr();
CodeDAddress(left, 1);
STL(tmp, pointer_size);
LOL(tmp, pointer_size);
C_loi(left->nd_type->tp_size);
}
else CodePExpr(left);
CodeCoercion(left->nd_type, tp);
1987-06-23 17:12:25 +00:00
if (arg) {
CodePExpr(arg->nd_LEFT);
CodeCoercion(arg->nd_LEFT->nd_type, tp);
1987-06-23 17:12:25 +00:00
}
else {
c_loc(1);
1987-06-23 17:12:25 +00:00
CodeCoercion(intorcard_type, tp);
}
1986-10-06 20:36:30 +00:00
if (std == S_DEC) {
if (tp->tp_fund == T_INTEGER) C_sbi(size);
1991-03-13 17:26:07 +00:00
else subu((int) size);
1986-05-30 18:48:00 +00:00
}
else {
1986-10-06 20:36:30 +00:00
if (tp->tp_fund == T_INTEGER) C_adi(size);
1991-03-13 17:26:07 +00:00
else addu((int) size);
1986-05-30 18:48:00 +00:00
}
1991-03-13 17:26:07 +00:00
if ((int) size == (int) word_size) {
RangeCheck(left->nd_type, tp->tp_fund == T_INTEGER ?
int_type : card_type);
}
if (compl) {
LOL(tmp, pointer_size);
C_sti(left->nd_type->tp_size);
FreePtr(tmp);
}
else CodeDStore(left);
1986-05-30 18:48:00 +00:00
break;
1986-10-06 20:36:30 +00:00
}
1986-05-30 18:48:00 +00:00
case S_HALT:
1988-03-23 17:44:25 +00:00
C_cal("halt");
1986-05-30 18:48:00 +00:00
break;
case S_INCL:
case S_EXCL: {
int compl = complex_lhs(left);
arith tmp = 0;
if (compl) {
tmp = NewPtr();
CodeDAddress(left, 1);
STL(tmp, pointer_size);
LOL(tmp, pointer_size);
C_loi(left->nd_type->tp_size);
}
else CodePExpr(left);
CodePExpr(arg->nd_LEFT);
1987-10-28 16:03:56 +00:00
C_loc(tp->set_low);
C_sbi(word_size);
1986-05-30 18:48:00 +00:00
C_set(tp->tp_size);
if (std == S_INCL) {
C_ior(tp->tp_size);
}
else {
C_com(tp->tp_size);
C_and(tp->tp_size);
}
if (compl) {
LOL(tmp, pointer_size);
C_sti(left->nd_type->tp_size);
FreePtr(tmp);
}
else CodeDStore(left);
1986-05-30 18:48:00 +00:00
break;
}
1986-05-30 18:48:00 +00:00
default:
crash("(CodeStd)");
}
1986-05-21 18:32:20 +00:00
}
static int needs_rangecheck(register struct type *tpl, struct type *tpr)
1986-05-28 18:36:51 +00:00
{
arith rlo, rhi;
1986-05-28 18:36:51 +00:00
if (bounded(tpl)) {
/* In this case we might need a range check.
If both types are restricted. check the bounds
to see wether we need a range check.
We don't need one if the range of values of the
right hand side is a subset of the range of values
of the left hand side.
*/
if (bounded(tpr)) {
getbounds(tpr, &rlo, &rhi);
if (in_range(rlo, tpl) && in_range(rhi, tpl)) {
1993-11-16 16:31:27 +00:00
return 0;
}
1986-05-28 18:36:51 +00:00
}
1993-11-16 16:31:27 +00:00
return 1;
}
return 0;
}
void RangeCheck(register struct type *tpl, struct type *tpr)
1993-11-16 16:31:27 +00:00
{
arith rlo, rhi;
if (options['R']) return;
if (needs_rangecheck(tpl, tpr)) {
genrck(tpl);
return;
1986-05-28 18:36:51 +00:00
}
tpr = BaseType(tpr);
1996-08-14 07:42:40 +00:00
if ((tpl->tp_fund == T_INTEGER && tpr->tp_fund == T_CARDINAL) ||
(tpr->tp_fund == T_INTEGER && tpl->tp_fund == T_CARDINAL)) {
label lb = ++text_label;
C_dup(tpr->tp_size);
C_zer(tpr->tp_size);
C_cmi(tpr->tp_size);
C_zge(lb);
c_loc(ECONV);
C_trp();
def_ilb(lb);
}
1986-05-21 18:32:20 +00:00
}
void Operands(register struct node *nd)
1986-05-21 18:32:20 +00:00
{
CodePExpr(nd->nd_LEFT);
CodePExpr(nd->nd_RIGHT);
DoLineno(nd);
1986-05-21 18:32:20 +00:00
}
void CodeOper(
register struct node *expr, /* the expression tree itself */
label true_label,
label false_label /* labels to jump to in logical expr's */
)
1986-05-21 18:32:20 +00:00
{
register struct node *leftop = expr->nd_LEFT;
register struct node *rightop = expr->nd_RIGHT;
int fund = expr->nd_type->tp_fund;
arith size = expr->nd_type->tp_size;
1986-05-21 18:32:20 +00:00
1986-08-26 14:33:24 +00:00
switch (expr->nd_symb) {
1986-05-21 18:32:20 +00:00
case '+':
Operands(expr);
switch (fund) {
1986-05-21 18:32:20 +00:00
case T_INTEGER:
C_adi(size);
1986-05-21 18:32:20 +00:00
break;
case T_REAL:
C_adf(size);
1986-05-21 18:32:20 +00:00
break;
1986-08-26 14:33:24 +00:00
case T_POINTER:
1986-09-25 19:39:06 +00:00
case T_EQUAL:
C_ads(rightop->nd_type->tp_size);
break;
1986-05-21 18:32:20 +00:00
case T_CARDINAL:
1986-08-26 14:33:24 +00:00
case T_INTORCARD:
addu((int) size);
1986-05-21 18:32:20 +00:00
break;
case T_SET:
C_ior(size);
1986-05-21 18:32:20 +00:00
break;
default:
crash("bad type +");
}
break;
case '-':
Operands(expr);
switch (fund) {
1986-05-21 18:32:20 +00:00
case T_INTEGER:
C_sbi(size);
1986-05-21 18:32:20 +00:00
break;
case T_REAL:
C_sbf(size);
1986-05-21 18:32:20 +00:00
break;
case T_POINTER:
case T_EQUAL:
if (rightop->nd_type == address_type) {
C_sbs(size);
break;
}
C_ngi(rightop->nd_type->tp_size);
C_ads(rightop->nd_type->tp_size);
break;
1986-08-26 14:33:24 +00:00
case T_INTORCARD:
case T_CARDINAL:
subu((int) size);
1986-05-21 18:32:20 +00:00
break;
case T_SET:
C_com(size);
C_and(size);
1986-05-21 18:32:20 +00:00
break;
default:
crash("bad type -");
}
break;
case '*':
Operands(expr);
switch (fund) {
1986-05-21 18:32:20 +00:00
case T_INTEGER:
C_mli(size);
1986-05-21 18:32:20 +00:00
break;
case T_POINTER:
1986-09-25 19:39:06 +00:00
case T_EQUAL:
1986-05-21 18:32:20 +00:00
case T_CARDINAL:
1986-08-26 14:33:24 +00:00
case T_INTORCARD:
if (! options['R']) {
C_cal((int)(size) <= (int)word_size ?
1991-03-06 10:52:34 +00:00
"muluchk" :
"mululchk");
1987-11-26 14:15:24 +00:00
}
C_mlu(size);
1986-05-21 18:32:20 +00:00
break;
case T_REAL:
C_mlf(size);
1986-05-21 18:32:20 +00:00
break;
case T_SET:
C_and(size);
1986-05-21 18:32:20 +00:00
break;
default:
crash("bad type *");
}
break;
case '/':
Operands(expr);
switch (fund) {
1986-05-21 18:32:20 +00:00
case T_REAL:
C_dvf(size);
1986-05-21 18:32:20 +00:00
break;
case T_SET:
C_xor(size);
1986-05-21 18:32:20 +00:00
break;
default:
crash("bad type /");
}
break;
case DIV:
Operands(expr);
switch(fund) {
1986-05-21 18:32:20 +00:00
case T_INTEGER:
C_cal((int)(size) == (int)word_size
1990-07-16 09:05:19 +00:00
? "dvi"
: "dvil");
C_asp(2*size);
C_lfr(size);
1986-05-21 18:32:20 +00:00
break;
case T_POINTER:
1986-09-25 19:39:06 +00:00
case T_EQUAL:
1986-05-21 18:32:20 +00:00
case T_CARDINAL:
1986-08-26 14:33:24 +00:00
case T_INTORCARD:
C_dvu(size);
1986-05-21 18:32:20 +00:00
break;
default:
crash("bad type DIV");
}
break;
case MOD:
Operands(expr);
switch(fund) {
1986-05-21 18:32:20 +00:00
case T_INTEGER:
C_cal((int)(size) == (int)word_size
1990-07-16 09:05:19 +00:00
? "rmi"
: "rmil");
C_asp(2*size);
C_lfr(size);
1986-05-21 18:32:20 +00:00
break;
case T_POINTER:
1986-09-25 19:39:06 +00:00
case T_EQUAL:
1986-05-21 18:32:20 +00:00
case T_CARDINAL:
1986-08-26 14:33:24 +00:00
case T_INTORCARD:
C_rmu(size);
1986-05-21 18:32:20 +00:00
break;
default:
crash("bad type MOD");
}
break;
case '<':
case LESSEQUAL:
case '>':
case GREATEREQUAL:
case '=':
case '#': {
struct type *tp;
Operands(expr);
1986-08-26 14:33:24 +00:00
tp = BaseType(leftop->nd_type);
1996-08-14 07:42:40 +00:00
if (tp->tp_fund == T_INTORCARD) tp = BaseType(rightop->nd_type);
size = tp->tp_size;
1986-05-21 18:32:20 +00:00
switch (tp->tp_fund) {
case T_INTEGER:
C_cmi(size);
1986-05-21 18:32:20 +00:00
break;
case T_POINTER:
1986-09-25 19:39:06 +00:00
case T_HIDDEN:
1986-12-01 10:06:53 +00:00
case T_EQUAL:
1988-02-01 10:17:51 +00:00
C_cmp();
break;
1986-05-21 18:32:20 +00:00
case T_CARDINAL:
1986-08-26 14:33:24 +00:00
case T_INTORCARD:
C_cmu(size);
1986-05-21 18:32:20 +00:00
break;
case T_ENUMERATION:
case T_CHAR:
C_cmu(word_size);
break;
case T_REAL:
C_cmf(size);
1986-05-21 18:32:20 +00:00
break;
case T_SET:
1986-08-26 14:33:24 +00:00
if (expr->nd_symb == GREATEREQUAL) {
1986-05-28 18:36:51 +00:00
/* A >= B is the same as A equals A + B
*/
C_dup(size << 1);
C_asp(size);
C_ior(size);
expr->nd_symb = '=';
1986-05-28 18:36:51 +00:00
}
1986-08-26 14:33:24 +00:00
else if (expr->nd_symb == LESSEQUAL) {
1986-05-28 18:36:51 +00:00
/* A <= B is the same as A - B = {}
*/
C_com(size);
C_and(size);
C_zer(size);
expr->nd_symb = '=';
1986-05-28 18:36:51 +00:00
}
C_cms(size);
1986-05-21 18:32:20 +00:00
break;
default:
crash("bad type COMPARE");
}
1987-05-18 15:57:33 +00:00
if (true_label != NO_LABEL) {
1986-08-26 14:33:24 +00:00
compare(expr->nd_symb, true_label);
1993-11-19 09:53:47 +00:00
c_bra(false_label);
1987-07-21 13:54:33 +00:00
break;
1986-05-21 18:32:20 +00:00
}
1987-07-21 13:54:33 +00:00
truthvalue(expr->nd_symb);
1986-05-21 18:32:20 +00:00
break;
}
1987-07-21 13:54:33 +00:00
1993-11-16 16:31:27 +00:00
case IN: {
1986-05-28 18:36:51 +00:00
/* In this case, evaluate right hand side first! The
INN instruction expects the bit number on top of the
stack
*/
1993-11-19 09:53:47 +00:00
label l_toolarge = NO_LABEL, l_cont = NO_LABEL;
struct type *ltp = leftop->nd_type;
1993-11-19 09:53:47 +00:00
if (leftop->nd_symb == COERCION) {
/* Could be coercion to word_type. */
ltp = leftop->nd_RIGHT->nd_type;
}
if (leftop->nd_class == Value) {
if (! in_range(leftop->nd_INT, ElementType(rightop->nd_type))) {
if (true_label != NO_LABEL) {
c_bra(false_label);
}
else c_loc(0);
break;
}
CodePExpr(rightop);
C_loc(leftop->nd_INT - rightop->nd_type->set_low);
1993-11-19 09:53:47 +00:00
}
else {
CodePExpr(rightop);
CodePExpr(leftop);
C_loc(rightop->nd_type->set_low);
C_sbu(word_size);
if (needs_rangecheck(ElementType(rightop->nd_type), ltp)) {
l_toolarge = ++text_label;
C_dup(word_size);
C_loc(rightop->nd_type->tp_size*8);
C_cmu(word_size);
C_zge(l_toolarge);
}
1993-11-16 16:31:27 +00:00
}
1986-05-28 18:36:51 +00:00
C_inn(rightop->nd_type->tp_size);
1987-05-18 15:57:33 +00:00
if (true_label != NO_LABEL) {
1986-06-10 13:18:52 +00:00
C_zne(true_label);
1993-11-19 09:53:47 +00:00
c_bra(false_label);
}
else {
l_cont = ++text_label;
c_bra(l_cont);
1986-06-10 13:18:52 +00:00
}
1993-11-16 16:31:27 +00:00
if (l_toolarge != NO_LABEL) {
1993-11-19 09:53:47 +00:00
def_ilb(l_toolarge);
1993-11-16 16:31:27 +00:00
C_asp(word_size+rightop->nd_type->tp_size);
if (true_label != NO_LABEL) {
1993-11-19 09:53:47 +00:00
c_bra(false_label);
1993-11-16 16:31:27 +00:00
}
1993-11-19 09:53:47 +00:00
else c_loc(0);
}
if (l_cont != NO_LABEL) {
def_ilb(l_cont);
1993-11-16 16:31:27 +00:00
}
1986-05-21 18:32:20 +00:00
break;
1993-11-16 16:31:27 +00:00
}
1986-10-06 20:36:30 +00:00
case OR:
case AND: {
1988-10-13 15:43:23 +00:00
label l_maybe = ++text_label, l_end = NO_LABEL;
struct desig Des;
Des = null_desig;
1986-08-26 14:33:24 +00:00
1987-05-18 15:57:33 +00:00
if (true_label == NO_LABEL) {
1986-11-26 16:40:45 +00:00
true_label = ++text_label;
false_label = ++text_label;
1986-08-26 14:33:24 +00:00
l_end = ++text_label;
}
1986-10-06 20:36:30 +00:00
if (expr->nd_symb == OR) {
CodeExpr(leftop, &Des, true_label, l_maybe);
1986-10-06 20:36:30 +00:00
}
else CodeExpr(leftop, &Des, l_maybe, false_label);
def_ilb(l_maybe);
Des = null_desig;
CodeExpr(rightop, &Des, true_label, false_label);
1988-10-13 15:43:23 +00:00
if (l_end != NO_LABEL) {
def_ilb(true_label);
c_loc(1);
1993-11-19 09:53:47 +00:00
c_bra(l_end);
def_ilb(false_label);
c_loc(0);
def_ilb(l_end);
1986-05-21 18:32:20 +00:00
}
break;
1986-08-26 14:33:24 +00:00
}
1986-05-21 18:32:20 +00:00
default:
crash("(CodeOper) Bad operator");
1986-05-21 18:32:20 +00:00
}
}
/* Serves as an auxiliary function of CodeOper */
static void compare(int relop, label lbl)
1986-05-21 18:32:20 +00:00
{
switch (relop) {
case '<':
C_zlt(lbl);
break;
case LESSEQUAL:
C_zle(lbl);
break;
case '>':
C_zgt(lbl);
break;
case GREATEREQUAL:
C_zge(lbl);
break;
case '=':
C_zeq(lbl);
break;
case '#':
C_zne(lbl);
break;
default:
crash("(compare)");
}
}
/* Serves as an auxiliary function of CodeOper */
static void truthvalue(int relop)
1986-05-21 18:32:20 +00:00
{
switch (relop) {
case '<':
C_tlt();
break;
case LESSEQUAL:
C_tle();
break;
case '>':
C_tgt();
break;
case GREATEREQUAL:
C_tge();
break;
case '=':
C_teq();
break;
case '#':
C_tne();
break;
default:
crash("(truthvalue)");
}
}
/* Generates code for an unary expression */
void CodeUoper(register struct node *nd)
1986-05-21 18:32:20 +00:00
{
register struct type *tp = nd->nd_type;
1986-05-21 18:32:20 +00:00
CodePExpr(nd->nd_RIGHT);
1986-05-21 18:32:20 +00:00
switch(nd->nd_symb) {
case NOT:
C_teq();
break;
case '-':
switch(tp->tp_fund) {
case T_INTEGER:
1986-08-26 14:33:24 +00:00
case T_INTORCARD:
1986-05-21 18:32:20 +00:00
C_ngi(tp->tp_size);
break;
case T_REAL:
C_ngf(tp->tp_size);
break;
default:
crash("Bad operand to unary -");
}
break;
case COERCION:
CodeCoercion(nd->nd_RIGHT->nd_type, tp);
RangeCheck(tp, nd->nd_RIGHT->nd_type);
break;
case CAST:
break;
1986-05-21 18:32:20 +00:00
default:
crash("Bad unary operator");
}
}
1986-05-23 19:25:21 +00:00
static void CodeSet(register struct node *nd, int null_set)
1986-05-23 19:25:21 +00:00
{
register struct type *tp = nd->nd_type;
1986-05-23 19:25:21 +00:00
nd = nd->nd_NEXT;
1986-05-23 19:25:21 +00:00
while (nd) {
assert(nd->nd_class == Link && nd->nd_symb == ',');
if (nd->nd_LEFT) {
CodeEl(nd->nd_LEFT, tp, null_set);
null_set = 0;
}
nd = nd->nd_RIGHT;
1986-05-23 19:25:21 +00:00
}
if (null_set) C_zer(tp->tp_size);
1986-05-23 19:25:21 +00:00
}
static void CodeEl(register struct node *nd, register struct type *tp, int null_set)
1986-05-23 19:25:21 +00:00
{
register struct type *eltype = ElementType(tp);
1986-05-23 19:25:21 +00:00
if (nd->nd_class == Link && nd->nd_symb == UPTO) {
if (null_set) C_zer(tp->tp_size);
1987-10-28 16:03:56 +00:00
C_loc(tp->set_low);
1986-06-06 02:22:09 +00:00
C_loc(tp->tp_size); /* push size */
1986-06-26 09:39:36 +00:00
if (eltype->tp_fund == T_SUBRANGE) {
C_loc(eltype->sub_ub);
1986-06-04 09:01:48 +00:00
}
1993-11-19 09:53:47 +00:00
else C_loc(eltype->enm_ncst - 1);
Operands(nd);
CAL("LtoUset", 5 * (int) word_size);
/* library routine to fill set */
1986-05-23 19:25:21 +00:00
}
else {
1986-05-30 18:48:00 +00:00
CodePExpr(nd);
1987-10-28 16:03:56 +00:00
C_loc(tp->set_low);
C_sbi(word_size);
1986-05-23 19:25:21 +00:00
C_set(tp->tp_size);
if (! null_set) C_ior(tp->tp_size);
1986-05-23 19:25:21 +00:00
}
}
1986-05-30 18:48:00 +00:00
void CodePExpr(register struct node *nd)
1986-05-30 18:48:00 +00:00
{
struct desig designator;
1986-05-30 18:48:00 +00:00
designator = null_desig;
CodeExpr(nd, &designator, NO_LABEL, NO_LABEL);
CodeValue(&designator, nd->nd_type);
1986-05-30 18:48:00 +00:00
}
static void CodeDAddress(struct node *nd, int chk_controlvar)
1986-05-30 18:48:00 +00:00
{
/* Generate code to push the address of the designator "nd"
on the stack.
*/
struct desig designator;
int chkptr;
1986-05-30 18:48:00 +00:00
designator = null_desig;
if (chk_controlvar) ChkForFOR(nd);
CodeDesig(nd, &designator);
chkptr = designator.dsg_kind==DSG_PLOADED ||
designator.dsg_kind==DSG_PFIXED;
CodeAddress(&designator);
/* Generate dummy use of pointer, to get possible error message
as soon as possible
*/
if (chkptr && ! options['R']) {
C_dup(pointer_size);
C_loi((arith) 1);
C_asp(word_size);
}
1986-05-30 18:48:00 +00:00
}
void CodeDStore(register struct node *nd)
1986-05-30 18:48:00 +00:00
{
1986-05-30 18:48:00 +00:00
struct desig designator;
1986-05-30 18:48:00 +00:00
designator = null_desig;
1987-08-10 13:01:54 +00:00
ChkForFOR(nd);
CodeDesig(nd, &designator);
CodeStore(&designator, nd->nd_type);
1986-05-30 18:48:00 +00:00
}
1986-06-04 09:01:48 +00:00
static void DoHIGH(register struct def *df)
1986-06-04 09:01:48 +00:00
{
1986-08-26 14:33:24 +00:00
/* Get the high index of a conformant array, indicated by "nd".
The high index is the second field in the descriptor of
the array, so it is easily found.
*/
1986-06-20 14:36:49 +00:00
register arith highoff;
1986-06-04 09:01:48 +00:00
assert(df->df_kind == D_VARIABLE);
1986-08-26 14:33:24 +00:00
assert(IsConformantArray(df->df_type));
1986-06-04 09:01:48 +00:00
1986-08-26 14:33:24 +00:00
highoff = df->var_off /* base address and descriptor */
+ word_size + pointer_size;
/* skip base and first field of
descriptor
*/
1986-06-04 09:01:48 +00:00
if (df->df_scope->sc_level < proclevel) {
1986-06-10 13:18:52 +00:00
C_lxa((arith) (proclevel - df->df_scope->sc_level));
1986-06-04 09:01:48 +00:00
C_lof(highoff);
}
else C_lol(highoff);
}
#ifdef SQUEEZE
void c_bra(label l)
1993-11-19 09:53:47 +00:00
{
C_bra((label) l);
}
void c_loc(int n)
{
C_loc((arith) n);
}
void c_lae_dlb(label l)
{
C_lae_dlb(l, (arith) 0);
}
void CAL(char *name, int ssp)
{
C_cal(name);
C_asp((arith) ssp);
}
#endif