Files
mercury/runtime/wrapper.mod
1995-05-06 07:29:58 +00:00

474 lines
10 KiB
Modula-2

/*
** Copyright (C) 1995 University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
#include "imp.h"
#include "timing.h"
#include "getopt.h"
#include "io_rt.h"
#include "init.h"
/* global variables concerned with testing (i.e. not with the engine) */
/* command-line options */
/* size of data areas, in kilobytes */
uint heap_size = 40960;
uint detstack_size = 512;
uint nondstack_size = 128;
/* size of the redzones at the end of data areas, in kilobytes */
uint heap_zone_size = 16;
uint detstack_zone_size = 16;
uint nondstack_zone_size = 16;
/* primary cache size to optimize for */
uint pcache_size = 8192;
/* other options */
int r1val = -1;
int r2val = -1;
int r3val = -1;
bool check_space = FALSE;
static bool use_own_timer = FALSE;
static int repeats = 1;
static Code *which = NULL;
/* misc. */
int repcounter = 1;
char scratchbuf[256];
static int start_time;
static int finish_time;
const char * progname;
int mercury_argc; /* not counting progname or debug options */
char ** mercury_argv;
int mercury_exit_status = 0;
#ifdef USE_GCC_NONLOCAL_GOTOS
#define SAFETY_BUFFER_SIZE 1024 /* size of stack safety buffer */
#define MAGIC_MARKER_2 142 /* a random character */
#endif
extern int main(int argc, char **argv);
static void process_options(int argc, char **argv);
static void usage(void);
static void run_code(void);
#ifdef MEASURE_REGISTER_USAGE
static void print_register_usage_counts(void);
#endif
Declare_entry(do_interpreter);
int main(int argc, char **argv)
{
#ifndef SPEED
/*
** ensure stdio & stderr are unbuffered even if redirected
** using setvbuf() is more complicated than using setlinebuf(),
** but also more portable
*/
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
#endif
#ifdef CONSERVATIVE_GC
GC_quiet = TRUE;
/* call the init_gc() function defined in <foo>_init.c -
this is to work around a Solaris 2.X (X <= 4) linker bug */
init_gc();
#endif
/* initialize label table to be empty */
init_entries();
#if defined(USE_GCC_GLOBAL_REGISTERS) && !defined(USE_ASM_LABELS)
do_init_modules();
#endif
mercury_init_io();
/* process the command line options, save results in global vars */
process_options(argc, argv);
/* execute the selected entry point */
init_engine();
run_code();
return mercury_exit_status;
}
void do_init_modules(void)
{
static bool done = FALSE;
if (!done) {
init_modules();
done = TRUE;
}
}
static void process_options(int argc, char **argv)
{
int c;
int i;
int val;
List *ptr;
List *label_list;
progname = argv[0];
for (i = 0; i < MAXFLAG; i++)
debugflag[i] = FALSE;
if (default_entry != NULL)
{
which = default_entry;
}
while ((c = getopt(argc, argv, "hcltp:d:r:w:s:z:1:2:3:")) != EOF)
{
switch (c)
{
case 'h': usage();
case 'c': check_space = TRUE;
when 'l': label_list = get_all_labels();
for_list (ptr, label_list)
{
Label *label;
label = (Label *) ldata(ptr);
printf("%u %x %s\n",
(unsigned) label->e_addr,
(unsigned) label->e_addr,
label->e_name);
}
exit(0);
when 't': use_own_timer = TRUE;
calldebug = FALSE;
nondstackdebug = FALSE;
detstackdebug = FALSE;
heapdebug = FALSE;
gotodebug = FALSE;
sregdebug = FALSE;
finaldebug = FALSE;
when 'd': if (streq(optarg, "b"))
nondstackdebug = TRUE;
or (streq(optarg, "c"))
calldebug = TRUE;
or (streq(optarg, "d"))
detaildebug = TRUE;
or (streq(optarg, "g"))
gotodebug = TRUE;
or (streq(optarg, "G"))
#ifdef CONSERVATIVE_GC
GC_quiet = FALSE;
#else
fatal_error("-dG: GC not enabled");
#endif
or (streq(optarg, "s"))
detstackdebug = TRUE;
or (streq(optarg, "h"))
heapdebug = TRUE;
or (streq(optarg, "f"))
finaldebug = TRUE;
or (streq(optarg, "p"))
progdebug = TRUE;
or (streq(optarg, "m"))
memdebug = TRUE;
or (streq(optarg, "r"))
sregdebug = TRUE;
or (streq(optarg, "a"))
{
calldebug = TRUE;
nondstackdebug = TRUE;
detstackdebug = TRUE;
heapdebug = TRUE;
gotodebug = TRUE;
sregdebug = TRUE;
finaldebug = TRUE;
}
else
usage();
use_own_timer = FALSE;
when 'p': if (sscanf(optarg, "%d", &pcache_size) != 1)
usage();
if (pcache_size < 512)
pcache_size *= 1024;
when 'r': if (sscanf(optarg, "%d", &repeats) != 1)
usage();
when 'w': {
Label *which_label;
which_label = lookup_label_name(optarg);
if (which_label == NULL)
{
fprintf(stderr,
"predicate name %s unknown\n",
optarg);
exit(1);
}
which = which_label->e_addr;
}
when 's': if (sscanf(optarg+1, "%d", &val) != 1)
usage();
if (optarg[0] == 'h')
heap_size = val;
or (optarg[0] == 'd')
detstack_size = val;
or (optarg[0] == 'n')
nondstack_size = val;
else
usage();
when 'z': if (sscanf(optarg+1, "%d", &val) != 1)
usage();
if (optarg[0] == 'h')
heap_zone_size = val;
or (optarg[0] == 'd')
detstack_zone_size = val;
or (optarg[0] == 'n')
nondstack_zone_size = val;
else
usage();
when '1': if (sscanf(optarg, "%d", &r1val) != 1)
usage();
when '2': if (sscanf(optarg, "%d", &r2val) != 1)
usage();
when '3': if (sscanf(optarg, "%d", &r3val) != 1)
usage();
otherwise: usage();
}
}
mercury_argc = argc - optind;
mercury_argv = argv + optind;
if (which == NULL)
{
fprintf(stderr, "no entry point supplied on command line "
"or by default\n");
exit(1);
}
}
static void usage(void)
{
printf("Usage: %s [-hclt] [-d[abcdghs]] [-[sz][hdn]#] [-p#] [-r#] [-1#] [-2#] [-3#] -w name\n",
progname);
printf("-h \t\tprint this usage message\n");
printf("-c \t\tcheck cross-function stack usage\n");
printf("-l \t\tprint all labels\n");
printf("-t \t\tuse own timer\n");
printf("-dg \t\tdebug gotos\n");
printf("-dc \t\tdebug calls\n");
printf("-db \t\tdebug backtracking\n");
printf("-dh \t\tdebug heap\n");
printf("-ds \t\tdebug detstack\n");
printf("-df \t\tdebug final success/failure\n");
printf("-da \t\tdebug all\n");
printf("-dm \t\tdebug memory allocation\n");
printf("-dG \t\tdebug garbage collection\n");
printf("-dd \t\tdetailed debug\n");
printf("-sh<n> \t\tallocate n kb for the heap\n");
printf("-sd<n> \t\tallocate n kb for the det stack\n");
printf("-sn<n> \t\tallocate n kb for the nondet stack\n");
printf("-zh<n> \t\tallocate n kb for the heap redzone\n");
printf("-zd<n> \t\tallocate n kb for the det stack redzone\n");
printf("-zn<n> \t\tallocate n kb for the nondet stack redzone\n");
printf("-p<n> \t\tprimary cache size in (k)bytes\n");
printf("-r<n> \t\trepeat n times\n");
printf("-w<name> \tcall predicate with given name\n");
printf("-1<x> \t\tinitialize register r1 with value x\n");
printf("-2<x> \t\tinitialize register r2 with value x\n");
printf("-3<x> \t\tinitialize register r3 with value x\n");
exit(1);
}
void run_code(void)
{
#if !defined(SPEED) && defined(USE_GCC_NONLOCAL_GOTOS)
/*
** double-check to make sure that we're not corrupting
** the C stack with these non-local gotos, by filling
** a buffer with a known value and then later checking
** that it still contains only this value
*/
unsigned char safety_buffer[SAFETY_BUFFER_SIZE];
global_pointer_2 = safety_buffer; /* defeat optimization */
memset(safety_buffer, MAGIC_MARKER_2, SAFETY_BUFFER_SIZE);
#endif
#ifndef SPEED
heapmax = heapmin;
detstackmax = detstackmin;
nondstackmax = nondstackmin;
#endif
if (use_own_timer)
start_time = get_run_time();
for (repcounter = 0; repcounter < repeats; repcounter++)
{
debugmsg0("About to call engine\n");
call_engine(ENTRY(do_interpreter));
debugmsg0("Returning from call_engine\n");
}
if (use_own_timer)
finish_time = get_run_time();
#if defined(USE_GCC_NONLOCAL_GOTOS) && !defined(SPEED)
{
int i;
for (i = 0; i < SAFETY_BUFFER_SIZE; i++)
assert(safety_buffer[i] == MAGIC_MARKER_2);
}
#endif
if (detaildebug)
{
sprintf(scratchbuf,
"after final call");
debugregs(scratchbuf);
}
#ifndef SPEED
if (memdebug)
{
printf("\n");
printf("max heap used: %6d words\n", heapmax - heapmin);
printf("max detstack used: %6d words\n", detstackmax - detstackmin);
printf("max nondstack used: %6d words\n", nondstackmax - nondstackmin);
}
#endif
#ifdef MEASURE_REGISTER_USAGE
printf("\n");
print_register_usage_counts();
#endif
if (use_own_timer)
printf("%8.3fu ", ((double) (finish_time - start_time)) / 1000);
}
#ifdef MEASURE_REGISTER_USAGE
static void print_register_usage_counts(void)
{
int i;
printf("register usage counts:\n");
for (i = 0; i < MAX_RN; i++)
{
if (1 <= i && i <= ORD_RN)
{
printf("r%d", i);
}
else
{
switch (i)
{
case SI_RN:
printf("succip");
when HP_RN:
printf("hp");
when SP_RN:
printf("sp");
when CF_RN:
printf("curfr");
when MF_RN:
printf("maxfr");
otherwise:
printf("UNKNOWN%d", i);
}
}
printf("\t%lu\n", (unsigned long)num_uses[i]);
}
}
#endif
BEGIN_MODULE(interpreter_module)
BEGIN_CODE
do_interpreter:
push(hp);
push(succip);
push(maxfr);
mkframe("interpreter", 1, LABEL(global_fail));
call(which, LABEL(global_success), LABEL(do_interpreter));
global_success:
#ifndef SPEED
if (finaldebug)
{
save_transient_registers();
printregs("global succeeded");
if (detaildebug)
dumpnondstack();
}
#endif
redo();
global_fail:
#ifndef SPEED
if (finaldebug)
{
save_transient_registers();
printregs("global failed");
if (detaildebug)
dumpnondstack();
maxfr = (Word *) pop();
succip = (Code *) pop();
hp = (Word *) pop();
if (detaildebug)
{
save_transient_registers();
printregs("after popping...");
}
}
else
#endif
{
maxfr = (Word *) pop();
succip = (Code *) pop();
hp = (Word *) pop();
}
proceed();
#ifndef USE_GCC_NONLOCAL_GOTOS
return 0;
#endif
END_MODULE