/*
Concurrent Clean Compiler: sa.c
===============================
This file contains the strictness analyser. It can handle tuples
as well as list strictness. The file is divided in the following
parts:
General support, including a local storage allocator
Support for storage of strictness information
Operations on expressions
Converions for the internal representation of the syntax tree
The abstract reducer
Main (external) functions
Debugging support
Author: Eric Nocker
At: Department of Computer Science
University of Nijmegen
Version: 0.9
Date: Januari, 1995
*/
#undef _DB_
/*
#define CHECK_STACK_OVERFLOW
#define _DB_STACK_
*/
#define DIVIDE_FUEL
#define SHOW_STRICT_EXPORTED_TUPLE_ELEMENTS
#define MORE_ANNOTS 1
#include "compiledefines.h"
#include "types.t"
#include "system.h"
#include "settings.h"
#include "sizes.h"
#include "syntaxtr.t"
#include "comsupport.h"
#include "checker.h"
#include "sa.t"
#include "sa.h"
#ifdef _DB_TEST_
# include "saprint.h"
#endif
#include "typeconv.h"
#include "statesgen.h"
#ifdef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
#include "codegen_types.h"
#endif
#define for_l(v,l,n) for(v=(l);v!=NULL;v=v->n)
#define NR_BLOCKS 200
#define NR_BLOCKS_FOR_ANALYSIS 100
#define BLOCK_SIZE (unsigned long) (16 * KBYTE)
unsigned long StrictMemUse = NR_BLOCKS * BLOCK_SIZE;
#ifdef CHECK_STACK_OVERFLOW
char *min_stack;
int stack_source = 0;
#endif
#if MORE_ANNOTS
# define MaxNrAnnots 100
#else
# define MaxNrAnnots 10 /* the maximum nr of strict rhs annots */
#endif
typedef int MyBool;
#define MyFalse 0
#define MyTrue 1
#define MyMightBeTrue 2
#define AreRelated 3
#define False MyFalse
#define True MyTrue
#define MightBeTrue MyMightBeTrue
Bool DoStrictExportChecks = False;
Bool DoStrictRelated = False;
#define Bool MyBool
static Bool StrictWarning = False; /* general warnings */
static Bool StrictAllWarning = True; /* warnings per function */
static Bool StrictChecks = False; /* warns for strange strictness */
static Bool StrictExportChecks = False; /* do export checks */
static unsigned StrictFuel = 60; /* 20; */ /* amount of reductions to do */
static unsigned min_d;
static unsigned max_memuse; /* the maximum memory use */
static char *CurrentName; /* current function name */
#ifdef _DB_
static Bool DBPrinting = False;
Exp infp, botmemp, topmemp;
#endif
#ifdef _DB_
Fun
#else
static Fun
#endif
* conssym, /* the cons id */
* nilsym, /* the nil id */
* apsym, /* the apply id */
* if_sym, /* the if id */
* true_sym, /* the true id */
* false_sym, /* the false id */
* selectsym[MaxNodeArity], /* the select ids */
* tuplesym[MaxNodeArity], /* the tuple ids */
* strict_sym[MaxNrAnnots], /* the strict ids */
* fail_sym, /* the fail id */
* inffunct_sym, /* the E2 id */
* botmemfunct_sym; /* the E3 id */
#if STRICT_LISTS
# ifndef _DB_
static
# endif
Fun *lazy_cons_sym0,*strict_cons_sym0,*tail_strict_cons_sym0,*strict_tail_strict_cons_sym0;
#endif
static ExpRepr top;
static ExpRepr bottom;
static ExpRepr inf;
static ExpRepr botmem;
static ExpRepr topmem;
/*
General Support
Containing:
- Debugging options
The following debugging options are available:
_DB_ general option, should always be set for the others
_DB_RED_ set on if reductions should be traced
_DB_EQ_ set on if comparison on expressions should be traced
output of the tracing is sent to the file "uit".
- Warnings Generation
- Storage allocator
In principle the storage allocator is quite simple: it supports a
fast allocation by allocating some large blocks if necessary. With
the functions 'Freeze..' and 'UnFreeze..' a basic part of the
storage (used for the function table and syntax tree) can be frozen.
Unfreezing releases all the other memory. The function 'MemUse' can
be used for obtaining the current memory usage.
*/
#ifdef _DB_
File outfile;
# define Assume ProcAssume
# define Assume2 ProcAssume
static void ProcAssume (Bool cond, char *err, char *proc)
{
Bool stop = False;
if (! cond)
{ if (! stop)
FPrintF (StdError, "FATAL ERROR: %s in %s\n", err, proc);
else
DoFatalError ("%s in %s\n", err, proc);
}
}
#else
# ifdef _DB_TEST_
# define Assume(A,B,C)
# define Assume2 ProcAssume
static void ProcAssume (Bool cond, char *err, char *proc)
{
Bool stop = False;
if (! cond)
{ if (! stop)
FPrintF (StdError, "FATAL ERROR: %s in %s\n", err, proc);
else
DoFatalError ("%s in %s\n", err, proc);
}
}
# else
# define Assume2(A,B,C)
# define Assume(A,B,C)
# endif
#endif
/*
Warnings
Warnings can be given during or after the analysis. If after, some
warnings that would be given during the analysis should be collected
into one warning. This is indicated by 'depth_warning' and
'mem_warning'.
*/
static void error_in_function (char *m)
{
ErrorInCompiler ("sa.c",m,"");
}
static Bool depth_warning; /* set True if a depth warning is given */
static Bool mem_warning; /* set True if a memory warning is given */
static Bool time_warning; /* set True if a time warning is given */
static Bool export_warning; /* set True if an export warning is given */
static Bool max_depth_reached; /* set True if max depth reached, no more
such warnings should be given */
static Bool max_time_reached; /* set True if max time reached, no more
such warnings should be given */
static Bool initialising = True; /* set True when building function table
this results in other warnings */
static Bool instantiating = False; /* set True when copying an expression */
static void GiveStrictWarning (char *f, char *msg)
{
#if 1
CurrentLine=0;
if (f)
StaticMessage (False,"%s","%s",f,msg);
else
StaticMessage (False,"","%s",msg);
#else
if (f)
FPrintF (StdError, "Warning [%s%s,%s]: %s\n", CurrentModule, CurrentExt, f, msg);
else
FPrintF (StdError, "Warning [%s%s]: %s\n", CurrentModule, CurrentExt, msg);
#endif
}
/*******************************************************************************
* The Storage Allocator for the strictness analysis *
******************************************************************************/
static char *SA_store [NR_BLOCKS]; /* the memory blocks */
static unsigned n_allocated_blocks = 0; /* the nr of allocated blocks */
static unsigned usedblocks = 0; /* the nr of blocks in use */
static char *high = Null; /* current end position in block */
static char *free_pos = Null; /* current free position in block */
static unsigned fblocks = 0; /* the freezed nr of blocks */
static char *ffree = Null; /* the freezed free position */
static void NewBlock (void)
{
if (usedblocks < n_allocated_blocks)
++usedblocks;
else if (n_allocated_blocks<NR_BLOCKS && (fblocks==0 || n_allocated_blocks<fblocks+NR_BLOCKS_FOR_ANALYSIS) && BLOCK_SIZE*(n_allocated_blocks+1)<StrictMemUse){
if (! (free_pos = (char *) Alloc (BLOCK_SIZE, SizeOf (char))))
return;
SA_store[n_allocated_blocks] = free_pos;
n_allocated_blocks++;
usedblocks++;
} else {
free_pos = NULL;
return;
}
free_pos = SA_store[usedblocks - 1];
high = free_pos + BLOCK_SIZE;
}
static jmp_buf SAEnv, SAEnv2, SAEnv3;
#define SAllocType(t) ((t*)SAlloc(sizeof(t)))
#define SAllocArrayType(n,t) ((t*)SAlloc((n)*sizeof(t)))
static char *SAlloc (unsigned n)
{
/* be sure to return an even address */
n = ReSize (n);
if (free_pos!=NULL && free_pos + n < high){
char *m;
m=free_pos;
free_pos = m+n;
return m;
} else
NewBlock ();
if (free_pos!=NULL && free_pos + n < high){
free_pos += n;
return (free_pos - n);
} else {
if (initialising)
longjmp (SAEnv, 1);
if (StrictAllWarning)
GiveStrictWarning (CurrentName, "out of memory (result approximated)");
else
mem_warning = True;
if (instantiating)
longjmp (SAEnv3, 1);
else
longjmp (SAEnv2, 1);
return NULL;
}
}
static void FreezeAlloc (void)
{
ffree = free_pos;
fblocks = usedblocks;
}
static void FreeUnFreezedBlocks (void)
{
usedblocks = fblocks;
free_pos = ffree;
high = SA_store[fblocks-1] + BLOCK_SIZE;
}
void free_unused_sa_blocks (void)
{
int i;
for (i=usedblocks; i<n_allocated_blocks; ++i){
if (SA_store[i]!=NULL){
Free ((void *) SA_store[i]);
SA_store[i]=NULL;
}
}
n_allocated_blocks = usedblocks;
}
static unsigned MemUse (void)
{
long l;
if (n_allocated_blocks==0)
return 0;
if (! free_pos)
l = (long) (usedblocks-1) * BLOCK_SIZE;
else
l = (long) (usedblocks-1) * BLOCK_SIZE + ((long) free_pos - (long) SA_store[usedblocks-1]);
return (unsigned) ((l-1) / KBYTE) + 1;
}
static void FreeBlocks (void)
{
unsigned i;
for (i = 0; i < n_allocated_blocks; i++){
if (SA_store[i]!=NULL){
Free ((void *) SA_store[i]);
SA_store[i]=NULL;
}
}
n_allocated_blocks = usedblocks = fblocks = 0;
free_pos = ffree = Null;
}
#define NewExpArgs(n) SAllocArrayType(n,Exp)
static Exp NewExp (ExpKind kind, unsigned sym, Bool hnf, unsigned arity)
{
Exp e;
e = SAllocType (ExpRepr);
e->e_kind = kind;
e->e_sym = sym;
e->e_hnf = hnf;
e->e_spechnf= hnf;
e->e_hasind = False;
e->e_red = False;
e->e_mark = False;
e->e_mark2 = False;
e->e_imark = False;
e->e_fwd = Null;
e->e_deps = Null;
if (arity == 0)
e->e_args = NULL;
else
e->e_args = NewExpArgs (arity);
#ifdef _DB_
e->e_mmark = False;
e->e_dmark = False;
e->e_shared = False;
e->e_add = 0;
#endif
return e;
}
static Exp NewValueExp (Fun *fun, Bool hnf, unsigned arity)
{
Exp e;
e = SAllocType (ExpRepr);
e->e_kind = Value;
e->e_fun = fun;
e->e_hnf = hnf;
e->e_spechnf= hnf;
e->e_hasind = False;
e->e_red = False;
e->e_mark = False;
e->e_mark2 = False;
e->e_imark = False;
e->e_fwd = Null;
e->e_deps = Null;
if (arity == 0)
e->e_args = NULL;
else
e->e_args = NewExpArgs (arity);
#ifdef _DB_
e->e_mmark = False;
e->e_dmark = False;
e->e_shared = False;
e->e_add = 0;
#endif
return e;
}
#define NewTop() (NewExp (Top, 0, True, 0))
static void InitExp (Exp e, ExpKind kind, unsigned sym, Bool hnf)
{
e->e_kind = kind;
e->e_sym = sym;
e->e_hnf = hnf;
e->e_spechnf= hnf;
e->e_hasind = False;
e->e_red = False;
e->e_mark = False;
e->e_mark2 = False;
e->e_imark = False;
e->e_fwd = Null;
e->e_deps = Null;
#ifdef _DB_
e->e_mmark = False;
e->e_dmark = False;
e->e_shared = False;
e->e_add = 0;
#endif
}
static void InitValueExp (Exp e,Fun *fun,Bool hnf)
{
e->e_kind = Value;
e->e_fun = fun;
e->e_hnf = hnf;
e->e_spechnf= hnf;
e->e_hasind = False;
e->e_red = False;
e->e_mark = False;
e->e_mark2 = False;
e->e_imark = False;
e->e_fwd = Null;
e->e_deps = Null;
#ifdef _DB_
e->e_mmark = False;
e->e_dmark = False;
e->e_shared = False;
e->e_add = 0;
#endif
}
static unsigned start_fuel;
static void SetStartFuel (void)
{
start_fuel = StrictFuel;
}
static Bool OutOfFuel (void)
{
if (start_fuel == 0)
return True;
--start_fuel;
return False;
}
/* Operations on StrictInfos and contexts */
static StrictKind MaxStrict (StrictKind s1, StrictKind s2)
{
if (s1 < s2)
return s2;
else
return s1;
}
static Context SimpleContext (Context context, StrictKind kind, Bool spec)
{
if (! context)
context = SAllocType (ContextRepr);
context->context_arity = 1;
context->context_speculative = spec;
context->context_kind = kind;
context->context_args = NULL;
return context;
}
static Context NewSimpleContext (StrictKind kind, Bool spec)
{
Context context;
context = SAllocType (ContextRepr);
context->context_arity = 1;
context->context_speculative = spec;
context->context_kind = kind;
context->context_args = NULL;
return context;
}
static Context StrictInfoToContext (StrictInfo *s, Context curcontext, Bool resultinfo)
{
Context context;
if (! resultinfo && curcontext->context_kind == NotStrict)
return curcontext;
if (IsTupleInfo (s)){
StrictKind info_kind = GetTupleStrictKind (s);
if (info_kind == NotStrict){
if (resultinfo)
return curcontext;
context = SAllocType (ContextRepr);
context->context_arity = 1;
context->context_speculative = curcontext->context_speculative;
context->context_kind = NotStrict;
context->context_args = (Context *) Null;
}
else {
unsigned i, n;
Bool has_strict_arg = False;
Context subcontext;
n = s->strict_arity;
context = SAllocType (ContextRepr);
context->context_arity = s->strict_arity;
context->context_speculative = curcontext->context_speculative;
context->context_kind = HnfStrict;
context->context_args = SAllocArrayType (n,Context);
for (i = 0; i < n; i++)
{ if (! resultinfo)
subcontext = curcontext;
else if (curcontext->context_arity > 1)
subcontext = curcontext->context_args[i];
else
subcontext = NewSimpleContext (NotStrict, curcontext->context_speculative);
context->context_args[i] = StrictInfoToContext (& GetTupleInfo (s, i), subcontext, resultinfo);
if (context->context_args[i]->context_kind != NotStrict)
has_strict_arg = True;
}
if (! has_strict_arg)
context->context_arity = 1;
}
}
else {
StrictKind info_kind = GetStrictKind (s, ContextToIndex (curcontext->context_kind));
if (resultinfo){
if (info_kind <= curcontext->context_kind)
return curcontext;
context = SAllocType (ContextRepr);
context->context_arity = 1;
context->context_speculative = curcontext->context_speculative;
context->context_kind = info_kind;
context->context_args = NULL;
} else {
if (info_kind == curcontext->context_kind && curcontext->context_arity == 1)
return curcontext;
context = SAllocType (ContextRepr);
context->context_arity = 1;
context->context_speculative = curcontext->context_speculative;
context->context_kind = info_kind;
context->context_args = NULL;
}
}
return context;
}
static Context CopyContext (Context curcontext)
{
Context context;
if (! curcontext || curcontext->context_kind == NotStrict)
return NULL;
context = SAllocType (ContextRepr);
context->context_arity = curcontext->context_arity;
context->context_speculative = False;
context->context_kind = curcontext->context_kind;
if (context->context_arity > 1){
unsigned i, n;
n = context->context_arity;
context->context_args = SAllocArrayType (n,Context);
for (i = 0; i < n; i++)
context->context_args[i] = CopyContext (curcontext->context_args[i]);
} else
context->context_args = NULL;
return context;
}
/* Operations on expressions */
static void InitValues (void)
{
static ExpRepr botmem1;
static ExpRepr botmem2;
static Exp infargs[2];
static Exp botmem1args[2];
static Exp botmem2args[2];
static Exp botmemargs[2];
static ExpRepr topmem1;
static ExpRepr topmem2;
static Exp topmem1args[2];
static Exp topmemargs[2];
#ifdef _DB_
infp = & inf;
botmemp = & botmem;
topmemp = & topmem;
#endif
InitValueExp (&inf, conssym, True);
inf.e_args = infargs;
inf.e_args[0] = & top;
inf.e_args[1] = & inf;
InitValueExp (&topmem1, nilsym, True);
InitValueExp (&topmem2, conssym, True);
InitExp (&topmem, Lub, 2, True);
topmem.e_kind = Top;
topmem.e_args = topmemargs;
topmem.e_args[0] = & topmem1;
topmem.e_args[1] = & topmem2;
topmem2.e_args = topmem1args;
topmem2.e_args[0] = & top;
topmem2.e_args[1] = & topmem;
InitValueExp (&botmem1, conssym, True);
InitValueExp (&botmem2, conssym, True);
InitExp (&botmem, Lub, 2, True);
botmem.e_args = botmemargs;
botmem.e_args[0] = & botmem1;
botmem.e_args[1] = & botmem2;
botmem1.e_args = botmem1args;
botmem1.e_args[0] = & top;
botmem1.e_args[1] = & botmem;
botmem2.e_args = botmem2args;
botmem2.e_args[0] = & bottom;
botmem2.e_args[1] = & topmem;
}
static void RemoveMark (Exp e)
{
unsigned n,i;
if (! e->e_mark)
return;
e->e_mark = False;
switch (e->e_kind){
case Top:
case Bottom:
case FunValue:
return;
case Ind:
RemoveMark (e->e_args[0]);
return;
case Argument:
return;
case Value:
n = e->e_fun->fun_arity;
break;
case Dep:
case Lub:
n = e->e_sym;
break;
default:
Assume (False, "unknown case", "RemoveMark");
return;
}
for (i = 0; i < n; i++)
RemoveMark (e->e_args[i]);
}
static Exp InstantiateExp2 (Exp e)
{
unsigned arity, i;
Exp new_e;
if (e->e_mark)
return e->e_fwd;
e->e_mark = True;
switch (e->e_kind){
case Top:
new_e = NewTop();
e->e_fwd = new_e;
break;
case Dep:
{
unsigned j;
Exp arg_e;
arity = e->e_sym;
new_e = NewExp (Dep, e->e_sym, e->e_hnf, arity);
e->e_fwd = new_e;
for (i = 0, j = 0; i < arity; i++){
arg_e = InstantiateExp2 (e->e_args[i]);
if (arg_e->e_kind == Bottom){
e->e_fwd = & bottom;
new_e = & bottom;
return new_e;
} else if (arg_e->e_kind == Top) /* || arg_e->e_hnf) */
/* simply skip it */
;
else {
new_e->e_args[j] = arg_e;
j++;
}
}
if (j == 0){
new_e = NewTop();
e->e_fwd = new_e;
} else
new_e->e_sym = j;
break;
}
case Bottom:
e->e_fwd = & bottom;
new_e = & bottom;
break;
case FunValue:
e->e_mark = False;
e->e_fwd = e;
new_e = e;
break;
case Ind:
new_e = NewExp (Ind, 0, False, 1);
e->e_fwd = new_e;
new_e->e_args[0] = e->e_args[0];
break;
case Argument:
#ifndef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
Assume2 (e->e_args[0] != Null, "argument not bound", "InstantiateExp");
#endif
e->e_fwd = new_e = e->e_args[0];
#ifndef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
e->e_args[0] = NULL;
#endif
break;
case Value:
arity = e->e_fun->fun_arity;
new_e = NewValueExp (e->e_fun, e->e_hnf, arity);
e->e_fwd = new_e;
for (i = 0; i < arity; i++)
new_e->e_args[i] = InstantiateExp2 (e->e_args[i]);
break;
case Lub:
arity = e->e_sym;
new_e = NewExp (Lub, e->e_sym, True, arity);
e->e_fwd = new_e;
for (i = 0; i < arity; i++)
new_e->e_args[i] = InstantiateExp2 (e->e_args[i]);
break;
default:
Assume (False, "unknown case", "InstantiateExp");
return ⊤
}
return new_e;
}
static Exp InstantiateExp (Exp e)
{
Exp new_e;
instantiating = True;
if (setjmp (SAEnv3) != 0){
RemoveMark (e);
instantiating = False;
longjmp (SAEnv2, 1);
}
new_e = InstantiateExp2 (e);
RemoveMark (e);
instantiating = False;
return new_e;
}
/*
During (Ext)LtExp2 a the addresses in Val/Dep expressions are determined for
which an AreRelated relation exists
the Bool CheckAreRelated should be (un)set before(after) LtExp is called
*/
static Bool CheckAreRelated = False;
static Exp *s_exp1, *s_exp2, *q_exp;
/* JVG */
#define MAX_LT_EXP2_CALLS 100000
static long lt_exp2_max_n_calls;
/* */
static Bool LtExp2 (Exp e1, Exp e2)
{
unsigned n, i;
#ifdef CHECK_STACK_OVERFLOW
char x;
if (&x < min_stack)
{ printf ("Stack overflow in LtExp\n");
#ifdef _DB_
FPrintF (outfile, "Stack overflow in LtExp\n");
#endif
return False;
}
#endif
if (e1 == e2)
return True;
if (e1->e_mark || e2->e_mark)
return MightBeTrue;
if (e2->e_kind == Top)
return True;
/* JVG */
if (++lt_exp2_max_n_calls >= MAX_LT_EXP2_CALLS)
return MightBeTrue;
/* */
switch (e1->e_kind){
case Bottom:
return True;
case Top:
return False;
case FunValue:
if (e2->e_kind == FunValue && e1->e_fun==e2->e_fun)
return True;
else
break;
case Ind:
e1->e_mark = True;
if (LtExp2 (e1->e_args[0], e2)){
e1->e_mark = False;
return True;
}
e1->e_mark = False;
break;
case Value:
case Dep:
{
int s_index;
s_index = -1;
if (e1->e_kind==Value){
if (e1->e_kind!=e2->e_kind || e1->e_fun!=e2->e_fun)
break;
n = e1->e_fun->fun_arity;
} else {
if (e1->e_kind!=e2->e_kind || e1->e_sym!=e2->e_sym)
break;
n = e1->e_sym;
}
e1->e_mark = True;
e2->e_mark = True;
for (i = 0; i < n; i++){
Bool b;
b = LtExp2 (e1->e_args[i], e2->e_args[i]);
switch (b){
case True:
continue;
case MightBeTrue:
e1->e_mark = False;
e2->e_mark = False;
return MightBeTrue;
case False:
case AreRelated:
if (CheckAreRelated && s_index < 0){
s_index = i;
continue;
} else {
e1->e_mark = False;
e2->e_mark = False;
return False;
}
}
}
e1->e_mark = False;
e2->e_mark = False;
if (s_index >= 0){
s_exp1 = & e1->e_args[s_index];
s_exp2 = & e2->e_args[s_index];
return AreRelated;
} else
return True;
}
case Lub:
e1->e_mark = True;
n = e1->e_sym;
for (i = 0; i < n; i++){
Bool b;
b = LtExp2 (e1->e_args[i], e2);
if (b != True){
e1->e_mark = False;
return b;
}
}
e1->e_mark = False;
return True;
default:
Assume (False, "illegal case", "LtExp");
return False;
}
/* check if e2 is a lub or Ind */
if (e2->e_kind == Lub){
Bool result;
result = False;
e2->e_mark = True;
n = e2->e_sym;
for (i = 0; i < n; i++){
Bool b;
b = LtExp2 (e1, e2->e_args[i]);
if (b == True){
e2->e_mark = False;
return b;
} else if (b == MightBeTrue)
result = MightBeTrue;
}
e2->e_mark = False;
return result;
} else if (e2->e_kind == Ind){
e2->e_mark = True;
if (LtExp2 (e1, e2->e_args[0])){
e2->e_mark = False;
return True;
}
e2->e_mark = False;
}
return False;
}
#ifdef _DB_
#undef Bool
Bool IsInAPath (Exp e1, Exp e2, APath p)
#define Bool MyBool
#else
static Bool IsInAPath (Exp e1, Exp e2, APath p)
#endif
{
for ( ; p; p = p->ap_next){
if (e1 == p->ap_e1 && e2 == p->ap_e2)
return True;
}
return False;
}
#ifdef _DB_
APath AddToAPath (Exp e1, Exp e2, APath p)
#else
static APath AddToAPath (Exp e1, Exp e2, APath p)
#endif
{
APath new;
new = SAllocType (APathRepr);
new->ap_e1 = e1;
new->ap_e2 = e2;
new->ap_next = p;
return new;
}
static Bool EqExp2 (Exp e1, Exp e2)
{
unsigned n, i;
if (e1 == e2)
return True;
if (e1->e_mark)
return MightBeTrue;
switch (e1->e_kind)
{
case Bottom:
if (e2->e_kind == Bottom)
return True;
else
return False;
case Top:
if (e2->e_kind == Top)
return True;
else
return False;
case FunValue:
if (e2->e_kind == FunValue && e1->e_fun==e2->e_fun)
return True;
else
return False;
case Argument:
return False;
case Ind:
return (e2->e_kind == Ind && e1->e_args[0] == e2->e_args[0]);
case Value:
case Dep:
if (e1->e_kind!=e2->e_kind)
return False;
if (e1->e_kind == Value){
if (e1->e_fun != e2->e_fun)
return False;
n = e1->e_fun->fun_arity;
} else {
if (e1->e_sym != e2->e_sym)
return False;
n = e1->e_sym;
}
e1->e_mark = True;
for (i = 0; i < n; i++)
{ Bool b = EqExp2 (e1->e_args[i], e2->e_args[i]);
if (b != True)
{ e1->e_mark = False;
return b;
}
}
e1->e_mark = False;
return True;
case Lub:
if (e2->e_kind != Lub || e1->e_sym != e2->e_sym)
return False;
e1->e_mark = True;
n = e1->e_sym;
for (i = 0; i < n; i++)
{ Bool b = EqExp2 (e1->e_args[i], e2->e_args[i]);
/* JVG added: */
if (b!=True)
/**/
{ e1->e_mark = False;
return b;
}
}
e1->e_mark = False;
return True;
default:
Assume (False, "illegal case", "EqExp");
return False;
}
} /* EqExp2 */
static Bool ExtEqExp2 (Exp e1, Exp e2, APath p)
{
unsigned n, i;
APath newp;
if (e1 == e2)
return True;
if (IsInAPath (e1, e2, p))
return True;
if (e1->e_mark && e2->e_mark)
return False;
newp = AddToAPath (e1, e2, p);
switch (e1->e_kind){
case Bottom:
if (e2->e_kind == Bottom)
return True;
else
return False;
case Top:
if (e2->e_kind == Top)
return True;
else
return False;
case FunValue:
if (e2->e_kind == FunValue && e1->e_fun==e2->e_fun)
return True;
else
return False;
case Argument:
return False;
case Ind:
return (e2->e_kind == Ind && e1->e_args[0] == e2->e_args[0]);
case Value:
case Dep:
if (e1->e_kind != e2->e_kind)
return False;
if (e1->e_kind == Value){
if (e1->e_fun != e2->e_fun)
return False;
n = e1->e_fun->fun_arity;
} else {
if (e1->e_sym != e2->e_sym)
return False;
n = e1->e_sym;
}
e1->e_mark = True;
e2->e_mark = True;
for (i = 0; i < n; i++)
{ if (! ExtEqExp2 (e1->e_args[i], e2->e_args[i], newp))
{ e1->e_mark = False;
e2->e_mark = False;
return False;
}
}
e1->e_mark = False;
e2->e_mark = False;
return True;
case Lub:
if (e2->e_kind != Lub || e1->e_sym != e2->e_sym)
return False;
e1->e_mark = True;
e2->e_mark = True;
n = e1->e_sym;
for (i = 0; i < n; i++)
{ if (! ExtEqExp2 (e1->e_args[i], e2->e_args[i], newp))
{ e1->e_mark = False;
e2->e_mark = False;
return False;
}
}
e1->e_mark = False;
e2->e_mark = False;
return True;
default:
Assume (False, "unknown case", "ExtEqExp2");
return False;
}
} /* ExtEqExp2 */
#ifdef _DB_
#undef Bool
static Bool EqExp (Exp e1, Exp e2)
#define Bool MyBool
#else
static Bool EqExp (Exp e1, Exp e2)
#endif /* _DB_ */
{
Bool b;
b = EqExp2 (e1, e2);
if (b == MightBeTrue && StrictDoExtEq){
b = ExtEqExp2 (e1, e2, (APath) Null);
Assume (! ContainsMark (e1), "e1 is marked", "EqExp (Ext)");
Assume (! ContainsMark (e2), "e2 is marked", "EqExp (Ext)");
}
else
{ Assume (! ContainsMark (e1), "e1 is marked", "EqExp");
}
if (b == True)
return True;
else
return False;
}
static Bool ExtLtExp2 (Exp e1, Exp e2, APath p)
{
if (e1 == e2)
return True;
if (e1->e_kind == Bottom || e2->e_kind == Top)
return True;
if (e1->e_kind == Top || e2->e_kind == Bottom)
return False;
if (IsInAPath (e1, e2, p))
return True;
switch (e1->e_kind){
case FunValue:
if (e2->e_kind == FunValue && e1->e_fun == e2->e_fun)
return True;
else
break;
case Ind:
{
APath newp;
newp = AddToAPath (e1, e2, p);
if (ExtLtExp2 (e1->e_args[0], e2, newp))
return True;
else
break;
}
case Value:
case Dep:
{
unsigned n, i;
int s_index;
APath newp;
if (e1->e_kind != e2->e_kind)
break;
if (e1->e_kind==Value){
if (e1->e_fun != e2->e_fun)
break;
n=e1->e_fun->fun_arity;
} else {
if (e1->e_sym != e2->e_sym)
break;
n=e1->e_sym;
}
s_index = -1;
newp = AddToAPath (e1, e2, p);
for (i = 0; i < n; i++){
Bool b = ExtLtExp2 (e1->e_args[i], e2->e_args[i], newp);
switch (b){
case True:
continue;
case False:
case AreRelated:
if (CheckAreRelated && s_index < 0){
s_index = i;
continue;
}
return False;
}
}
if (s_index >= 0){
s_exp1 = & e1->e_args[s_index];
s_exp2 = & e2->e_args[s_index];
return AreRelated;
} else
return True;
return True;
}
case Lub:
{
unsigned n, i;
APath newp;
n = e1->e_sym;
newp = AddToAPath (e1, e2, p);
for (i = 0; i < n; i++){
Bool b = ExtLtExp2 (e1->e_args[i], e2, newp);
if (b != True)
return False;
}
return True;
}
default:
Assume (False, "illegal case", "LtExp");
return False;
}
/* check if e2 is a lub */
if (e2->e_kind == Lub){
unsigned n, i;
APath newp;
n = e2->e_sym;
newp = AddToAPath (e1, e2, p);
for (i = 0; i < n; i++){
if (ExtLtExp2 (e1, e2->e_args[i], newp) == True)
return True;
}
} else if (e2->e_kind == Ind){
if (ExtLtExp2 (e1, e2->e_args[0], p))
return True;
}
return False;
}
static Bool LtExp (Exp e1, Exp e2)
{
Bool b;
#ifdef _DB_EQ_
if (DBPrinting)
{ FPrintF (outfile, "Less then e1: ");
DumpExp (outfile, e1);
FPrintF (outfile, "\n e2: ");
DumpExp (outfile, e2);
FPutC ('\n', outfile);
}
#endif
/* JVG */
lt_exp2_max_n_calls=0;
/* */
b = LtExp2 (e1, e2);
#ifdef _DB_EQ_
if (DBPrinting){
if (b == True)
FPrintF (outfile, "Result: True\n\n");
else if (b == MightBeTrue)
FPrintF (outfile, "Result: MightBeTrue\n\n");
else
FPrintF (outfile, "Result: False\n\n");
}
#endif
if (b == MightBeTrue && StrictDoExtEq){
b = ExtLtExp2 (e1, e2, (APath) Null);
#ifdef _DB_EQ_
if (DBPrinting){
if (b == True)
FPrintF (outfile, "Result2: True\n\n");
else if (b == MightBeTrue)
FPrintF (outfile, "Result2: MightBeTrue\n\n");
else
FPrintF (outfile, "Result2: False\n\n");
}
#endif
}
return b;
}
static Bool IsContainedIn (Exp e1, ExpP ep2)
{
Exp e2;
e2 = *ep2;
if (e2->e_mark2)
return False;
if (EqExp (e1, e2)){
q_exp = ep2;
return True;
}
switch (e2->e_kind){
case Value:
{ unsigned n, i;
e2->e_mark2 = True;
n = e2->e_fun->fun_arity;
for (i = 0; i < n; i++){
if (IsContainedIn (e1, & e2->e_args[i])){
e2->e_mark2 = False;
return True;
}
}
e2->e_mark2 = False;
return False;
}
case Lub:
{ unsigned n, i;
e2->e_mark2 = True;
n = e2->e_sym;
for (i = 0; i < n; i++){
if (! IsContainedIn (e1, & e2->e_args[i])){
e2->e_mark2 = False;
return False;
}
}
e2->e_mark2 = False;
return True;
}
default:
return False;
}
}
static int SortLtExp (Exp e1,Exp e2)
{
ExpKind kind1, kind2;
kind1 = e1->e_kind;
kind2 = e2->e_kind;
if (kind1 == kind2){
if (kind1 == Value){
if (e1->e_hnf)
return -1;
else if (e2->e_hnf)
return -1;
else
return (e1->e_fun < e2->e_fun);
} else
return False;
} else
return (kind1 < kind2);
}
#define LESS(a,b) (SortLtExp ((a),(b)))
static void Sort (Exp *defs, unsigned high)
{
unsigned low,father, son;
Exp val;
low = high / 2;
while (high > 1){
val = defs[father = low];
for (;;){
son = 2 * father + 1;
if (son >= high)
{ defs[father] = val;
break;
};
if (son == high - 1){
if (LESS (val, defs[son])){
defs[father] = defs[son];
defs[son] = val;
} else {
defs[father] = val;
};
break;
};
if (LESS (defs[son], defs[son + 1]))
son++;
if (!LESS (val, defs[son])){
defs[father] = val;
break;
};
defs[father] = defs[son];
father = son;
};
if (low > 0){
low--;
} else {
val = defs[0];
defs[0] = defs[--high];
defs[high] = val;
}
}
}
static Bool ContainsExpOfKind (Exp e, ExpKind kind)
{
unsigned i;
Bool result = False;
for (i = 0; i < e->e_sym; i++)
{ if (e->e_args[i]->e_kind == kind)
result = True;
else if (kind == Dep && e->e_args[i]->e_kind == Bottom)
{ e->e_kind = Bottom;
e->e_hnf = True;
e->e_deps = Null;
return False;
}
else if (kind == Lub && e->e_args[i]->e_kind == Top)
{ e->e_kind = Top;
e->e_hnf = True;
return False;
}
}
return result;
}
static Bool IsInArgs (Exp *args, unsigned n, Exp e)
{
unsigned i;
for (i = 0; i < n; i++)
if (args[i] == e)
return True;
return False;
}
static void RemoveExpOfKind (Exp e, ExpKind kind)
{ unsigned i, j, k, n, new_n, new_done;
Exp *new_args;
/* count the new number of 'kind' args (the current args + the new ones) */
n = e->e_sym;
new_n = 0;
for (i = 0; i < n; i++)
{ if (e->e_args[i]->e_kind == kind)
new_n += e->e_args[i]->e_sym;
else
new_n += 1;
}
new_args = NewExpArgs (new_n);
for (i = 0, j = 0; i < n; i++)
{ if (e->e_args[i]->e_kind == kind)
{ int kind_n = e->e_args[i]->e_sym;
for (k = 0; k < kind_n; k++)
{ if (! IsInArgs (e->e_args, j, e->e_args[i]->e_args[k]))
{ new_args[j] = e->e_args[i]->e_args[k];
j++;
}
}
}
else
if (! IsInArgs (e->e_args, j, e->e_args[i]))
{ new_args[j] = e->e_args[i];
j++;
}
}
/* put new arguments in original expression */
e->e_args = new_args;
e->e_sym = j;
new_done = n;
/* remove remaining subkind expressions */
if (ContainsExpOfKind (e, kind))
RemoveExpOfKind (e, kind);
}
#define IsTupleExp(A) ((A)->e_kind==Value && ((A)->e_fun>=tuplesym[0] && (A)->e_fun<=tuplesym[MaxNodeArity-1]))
/* JVG: added 16-8-2000 */
static void remove_deps_from_tuple_arguments (Exp e)
{
if (e->e_deps==NULL)
return;
if (IsTupleExp(e)){
int n,arity;
arity=e->e_fun->fun_arity;
for (n=0; n<arity; ++n){
remove_deps_from_tuple_arguments (e->e_args[n]);
e->e_args[n]->e_deps=NULL;
}
}
}
/**/
static void UpdateExp (Exp src, Exp dst);
static void RemoveCycles (ExpP ep, ExpKind kind)
{ unsigned i, n;
Exp e = *ep;
if (e->e_mark)
{ *ep = & bottom;
e->e_mark = False;
return;
}
e->e_mark = True;
n = e->e_sym;
for (i = 0; i < n; i++)
{ if (e->e_args[i]->e_kind == kind)
RemoveCycles (& e->e_args[i], kind);
}
e->e_mark = False;
} /* RemoveCycles */
static void SortExpOfKind (Exp e, ExpKind kind)
{ unsigned n, j, i;
Bool remove;
Exp e2 = e; /* temp pointer: the pointer can be changed by RemoveCycles */
Assume2 (e->e_kind == kind, "No exp of right kind", "SortExpOfKind");
RemoveCycles (& e2, kind);
if (ContainsExpOfKind (e, kind))
RemoveExpOfKind (e, kind);
if (e->e_kind != kind)
return;
n = e->e_sym;
Sort (e->e_args, e->e_sym);
if (kind == Dep)
{ for (i = n; i > 0; i--)
if (e->e_args[i-1]->e_kind != Top)
break;
n = i;
}
for (i = 0; i+1 < n; ){
if (LtExp (e->e_args[i], e->e_args[i+1]) == True){
remove = True;
#if 1
/* JVG: added 16-8-2000 */
if (kind==Lub)
remove_deps_from_tuple_arguments (e->e_args[i]);
#endif
e->e_args[i] = e->e_args[i+1];
} else if (LtExp (e->e_args[i+1], e->e_args[i]) == True){
#if 1
/* JVG: added 16-8-2000 */
if (kind==Lub)
remove_deps_from_tuple_arguments (e->e_args[i+1]);
#endif
remove = True;
} else
remove = False;
if (remove){
for (j = i+1; j+1 < n; j++)
e->e_args[j] = e->e_args[j+1];
n--;
} else
i++;
}
e->e_sym = n;
if (n > 20)
{
#ifdef _DB_
FPrintF (StdOut, "SortLub %d:", n);
DumpExp (StdOut, e);
FPutC ('\n', StdOut);
#endif /* _DB_ */
e->e_kind = Top;
return;
}
if (n == 1 && kind == Lub)
UpdateExp (e->e_args[0], e);
else if (n == 0 && kind == Dep)
e->e_kind = Top;
}
static void CopyDeps (Dependency fromdep,Dependency *newdeps)
{
Dependency new;
for (;fromdep; fromdep = fromdep->dep_next){
new = SAllocType (DependencyRepr);
new->dep_exp = fromdep->dep_exp;
new->dep_next = *newdeps;
*newdeps = new;
}
}
static Dependency AddDeps (Dependency fromdep, Dependency taildeps)
{ Dependency new;
for (;fromdep; fromdep = fromdep->dep_next)
{
new = SAllocType (DependencyRepr);
new->dep_exp = fromdep->dep_exp;
new->dep_next = taildeps;
taildeps = new;
}
return taildeps;
} /* AddDeps */
static Dependency CombineDependencies (Dependency deps1, Dependency deps2)
{
Dependency new;
new = NULL;
if (! deps1 || ! deps2)
return NULL;
CopyDeps (deps1,&new);
CopyDeps (deps2,&new);
/*
for (; deps1; deps1 = deps1->dep_next)
{ Dependency dep;
Exp e;
e = deps1->dep_exp;
for (dep = deps2; dep; dep = dep->dep_next)
{ if (e == dep->dep_exp)
{ Dependency new2;
new2 = SAllocType (DependencyRepr);
new2->dep_exp = e;
new2->dep_next = new;
new = new2;
}
}
}
*/
return new;
}
static Exp TakeLub (Exp e1, Exp e2)
{
Exp new_e;
unsigned n, i, j;
Dependency newdeps;
if (! e1 && ! e2)
return & bottom;
if (! e1 || e1->e_kind == Bottom)
return e2;
if (! e2 || e2->e_kind == Bottom)
return e1;
newdeps = CombineDependencies (e1->e_deps, e2->e_deps);
/* create a new Lub expression and copy all the elements */
if (e1->e_kind == Lub && e2->e_kind == Lub)
{ new_e = NewExp (Lub, 0, True, e1->e_sym + e2->e_sym);
j = 0;
for (i = 0; i < e1->e_sym; i++)
{ if (e1->e_args[i]->e_kind == Bottom)
continue;
else if (e1->e_args[i]->e_kind == Top)
return NewTop();
else
{ new_e->e_args[j] = e1->e_args[i];
j++;
}
}
for (i = 0; i < e2->e_sym; i++)
{ if (e2->e_args[i]->e_kind == Bottom)
continue;
else if (e2->e_args[i]->e_kind == Top)
return NewTop();
else
{ new_e->e_args[j] = e2->e_args[i];
j++;
}
}
new_e->e_sym = j;
}
else if (e1->e_kind == Lub)
{ n = e1->e_sym;
new_e = NewExp (Lub, 0, True, n + 1);
j = 0;
for (i = 0; i < n; i++)
{ if (e1->e_args[i]->e_kind == Bottom)
continue;
else if (e1->e_args[i]->e_kind == Top)
return NewTop();
else
{ new_e->e_args[j] = e1->e_args[i];
j++;
}
}
new_e->e_args[j] = e2;
new_e->e_sym = j + 1;
}
else if (e2->e_kind == Lub)
{ n = e2->e_sym;
new_e = NewExp (Lub, 0, True, 1 + n);
j = 0;
for (i = 0; i < n; i++)
{ if (e2->e_args[i]->e_kind == Bottom)
continue;
else if (e2->e_args[i]->e_kind == Top)
return NewTop();
else
{ new_e->e_args[j] = e2->e_args[i];
j++;
}
}
new_e->e_args[j] = e1;
new_e->e_sym = j + 1;
}
else
{ new_e = NewExp (Lub, 2, True, 2);
new_e->e_args[0] = e1;
new_e->e_args[1] = e2;
}
SortExpOfKind (new_e, Lub);
new_e->e_deps = newdeps;
return new_e;
}
static void UpdateExp (Exp src, Exp dst)
{ unsigned arity, i;
if (src == dst)
return;
dst->e_kind = src->e_kind;
dst->e_hnf = src->e_hnf;
dst->e_spechnf = src->e_spechnf;
dst->e_red = False;
switch (src->e_kind)
{
case Top:
dst->e_sym = src->e_sym;
arity = 0;
break;
case FunValue:
dst->e_fun = src->e_fun;
arity = 0;
break;
case Bottom:
dst->e_sym = src->e_sym;
dst->e_args = Null;
dst->e_deps = Null;
return;
case Ind:
#ifdef _DB_
FPrintF (outfile, "Update with indirection %u %u\n", src->e_add,dst->e_add);
#endif
dst->e_sym = src->e_sym;
arity = 1;
break;
case Value:
dst->e_fun = src->e_fun;
arity = src->e_fun->fun_arity;
break;
case Lub:
case Dep:
dst->e_sym = src->e_sym;
arity = src->e_sym;
break;
default:
Assume (False, "unknown case", "UpdateExp");
dst->e_sym = src->e_sym;
arity = 0;
break;
}
dst->e_args = NewExpArgs (arity);
for (i = 0; i < arity; i++)
dst->e_args[i] = src->e_args[i];
/* add dependencies of source to destination */
dst->e_deps = AddDeps (dst->e_deps, src->e_deps);
if (dst->e_kind == Lub)
SortExpOfKind (dst, Lub);
}
/*******************************************************************************
* The function table, initialisation *
******************************************************************************/
static Bool has_fail; /* the current alternative contains a Fail */
#define IsTupleExp(A) ((A)->e_kind==Value && ((A)->e_fun>=tuplesym[0] && (A)->e_fun<=tuplesym[MaxNodeArity-1]))
#define TypeArgsOfRecord(R) ((R)->sdef_type->type_constructors->cl_constructor->type_node_arguments)
static Bool HasStrictAnnot (Annotation annot)
{
if (! StrictDoAnnots)
return False;
return annot==StrictAnnot;
}
static Bool HasProcessAnnot (Annotation annot)
{
return False;
/* parallel annotations are only used in parallel compilation */
if (! DoParallel || ! annot)
return False;
switch (annot){
case ContinueAnnot:
case ParallelAnnot:
case ParallelAtAnnot:
case LazyParallelAnnot:
case InterleavedAnnot:
case LazyInterleavedAnnot:
case DeferAnnot:
case WaitAnnot:
case ContInterleavedAnnot:
case ParallelNFAnnot:
case InterleavedNFAnnot:
return True;
default:
return False;
}
}
static Exp ConvertNode (Node node, NodeId node_id);
static void ConvertToApplyNode (Exp e, Node node, unsigned arity)
{
if (arity==0){
e->e_fun = node->node_symbol->symb_def->sdef_sa_fun;
e->e_kind = FunValue;
e->e_hnf = True;
} else {
Exp left, right;
Args args;
unsigned i;
args = node->node_arguments;
left = NewValueExp (NULL,False,0);
ConvertToApplyNode (left, node, arity-1);
for (i = 1; i < arity; i++, args = args->arg_next)
;
right = ConvertNode (args->arg_node, NULL);
e->e_fun = apsym;
e->e_kind = Value;
e->e_hnf = True;
e->e_args = NewExpArgs (2);
e->e_args[0] = left;
e->e_args[1] = right;
}
}
static Exp ConvertNodeId (NodeId nid)
{
Exp e;
if (nid->nid_exp)
return nid->nid_exp;
if (nid->nid_refcount>=0){
if (nid->nid_node_def)
return ConvertNode (nid->nid_node_def->def_node, nid);
else {
DoFatalError ("ConvertNode (SA): no node or nid");
return & top;
}
} else {
#ifndef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
if (nid->nid_node)
return ConvertNode (nid->nid_node, nid);
#endif
e = NewExp (Argument, 0, False, 1);
e->e_args[0] = NULL;
nid->nid_exp_ = e;
return e;
}
}
static Exp ConvertNodeDefs (Node root, NodeDefs defs, StrictNodeIdP strictids)
{
Exp e, rootexp;
int i, nr_strict;
NodeDefs node_def;
StrictNodeIdP ids;
/* convert node defs */
for_l (node_def,defs,def_next)
if (node_def->def_node!=NULL)
ConvertNode (node_def->def_node,node_def->def_id);
/* convert root node */
rootexp = ConvertNode (root,NULL);
/* convert strict node defs */
nr_strict = 0;
for_l (ids,strictids,snid_next)
nr_strict++;
if (nr_strict==0)
return rootexp;
e = NewValueExp (strict_sym [nr_strict - 1], False, nr_strict + 1);
for (i=0,ids=strictids; i< nr_strict; i++,ids=ids->snid_next)
e->e_args[i] = ConvertNode (ids->snid_node_id->nid_node,ids->snid_node_id);
e->e_args[i] = rootexp;
return e;
}
static unsigned CountStrictArgs (TypeArgs args)
{
TypeNode node;
unsigned n = 0;
if (! args)
return 0;
for (; args; args = args->type_arg_next){
node = args->type_arg_node;
if (node->type_node_annotation!=StrictAnnot)
continue;
n += 1;
if (!node->type_node_is_var && node->type_node_symbol->symb_kind==tuple_type)
n += CountStrictArgs (node->type_node_arguments);
}
return n;
}
static void ConvertStrictSelections (Exp exp, TypeNode node, Exp *e_args, unsigned *i)
{
if (!node->type_node_is_var && node->type_node_symbol->symb_kind==tuple_type){
TypeArgs typeargs;
unsigned j;
Exp selexp;
e_args[*i] = exp;
(*i) ++;
for (j = 0, typeargs = node->type_node_arguments; typeargs; typeargs = typeargs->type_arg_next, j++){
node = typeargs->type_arg_node;
if (node->type_node_annotation!=StrictAnnot)
continue;
selexp = NewValueExp (selectsym[j], False, 1);
selexp->e_args[0] = exp;
ConvertStrictSelections (selexp, node, e_args, i);
}
} else {
if (exp->e_kind == Top || exp->e_hnf)
return;
e_args[*i] = exp;
(*i) ++;
}
}
static void InitNode (Node node);
static void InitNodeDefs (NodeDefs defs)
{
for ( ; defs; defs=defs->def_next){
if (defs->def_id)
defs->def_id->nid_exp_ = NULL;
InitNode (defs->def_node);
}
}
static void InitNode (Node node)
{
if (! node)
return;
if (node->node_kind==NodeIdNode)
node->node_node_id->nid_exp_ = NULL;
else {
Args args;
if (node->node_kind==IfNode){
InitNodeDefs (node->node_then_node_defs);
InitNodeDefs (node->node_else_node_defs);
}
#ifdef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
else if (node->node_kind==SwitchNode){
for_l (args,node->node_arguments,arg_next){
NodeP node_p;
node_p=args->arg_node;
if (node_p->node_kind==CaseNode){
NodeP case_alt_node_p;
case_alt_node_p=node_p->node_arguments->arg_node;
if (case_alt_node_p->node_kind==PushNode){
NodeIdListElementP node_id_list;
for_l (node_id_list,case_alt_node_p->node_node_ids,nidl_next)
node_id_list->nidl_node_id->nid_exp=NULL;
case_alt_node_p=case_alt_node_p->node_arguments->arg_next->arg_node;
}
InitNode (case_alt_node_p);
InitNodeDefs (node_p->node_node_defs);
} else if (node_p->node_kind==DefaultNode){
InitNode (node_p->node_arguments->arg_node);
InitNodeDefs (node_p->node_node_defs);
} else
error_in_function ("InitNode");
}
return;
} else if (node->node_kind==GuardNode){
InitNode (node->node_arguments->arg_node);
InitNode (node->node_arguments->arg_next->arg_node);
InitNodeDefs (node->node_node_defs);
return;
}
#endif
for_l (args,node->node_arguments,arg_next)
InitNode (args->arg_node);
}
}
static void InitAlternative (RuleAltS *alt)
{
NodeDefs nds;
InitNode (alt->alt_lhs_root);
#ifndef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
for_l (nds,alt->alt_lhs_defs,def_next){
if (nds->def_id)
nds->def_id->nid_exp_ = NULL;
InitNode (nds->def_node);
}
#endif
if (alt->alt_kind==Contractum){
InitNode (alt->alt_rhs_root);
InitNodeDefs (alt->alt_rhs_defs);
}
}
/* 'StrictUpdates' defines whether a record update is strict */
#define StrictUpdates
static Exp ConvertNode (Node node, NodeId nid)
{
Exp e;
unsigned arity, i;
Args arg;
if (nid==NULL){
if (node->node_kind==NodeIdNode)
return ConvertNodeId (node->node_node_id);
} else {
if (nid->nid_exp)
return nid->nid_exp;
if (node->node_kind==NodeIdNode){
if (node->node_node_id==nid)
return ConvertNodeId (nid);
else
return ConvertNodeId (nid->nid_node->node_node_id);
}
}
if (HasProcessAnnot (node->node_annotation))
return & top;
e = NewValueExp (NULL,False,0);
if (nid)
nid->nid_exp_ = e;
switch (node->node_kind){
case NormalNode:
{ arity = node->node_arity;
switch (node->node_symbol->symb_kind){
case tuple_symb:
e->e_fun = tuplesym[arity];
break;
case bool_denot:
if (node->node_symbol -> symb_bool)
e->e_fun = true_sym;
else
e->e_fun = false_sym;
e->e_hnf = True;
break;
case cons_symb:
#if STRICT_LISTS
if (node->node_symbol->symb_head_strictness>1){
e->e_fun = (node->node_symbol->symb_tail_strictness ? strict_tail_strict_cons_sym0 : strict_cons_sym0)+arity;
break;
} else if (node->node_symbol->symb_tail_strictness){
e->e_fun = tail_strict_cons_sym0+arity;
break;
}
e->e_hnf = True;
e->e_fun = lazy_cons_sym0+arity;
#else
e->e_hnf = True;
e->e_fun = conssym;
#endif
break;
case nil_symb:
e->e_hnf = True;
e->e_fun = nilsym;
break;
case apply_symb:
e->e_fun = apsym;
break;
case select_symb:
e->e_fun = selectsym[arity - 1];
arity = 1;
break;
case fail_symb:
has_fail = True;
e->e_fun = fail_sym;
return e;
case if_symb:
e->e_fun = if_sym;
if (arity != 3)
{ e->e_kind = FunValue;
e->e_hnf = True;;
}
break;
case definition:
{
SymbDef sdef;
sdef = node->node_symbol->symb_def;
if (sdef->sdef_kind == INSTANCE)
DoFatalError ("Strictness analysis (ConvertNode): instance encounterred");
if (sdef->sdef_kind==DEFRULE || sdef->sdef_kind==SYSRULE){
TypeAlts rule;
TypeArgs typeargs;
unsigned int i;
Exp exp;
#if SA_RECOGNIZES_ABORT_AND_UNDEF
if (sdef->sdef_module==StdMiscId->ident_name){
if ((sdef->sdef_ident==abort_id && node->node_arity==1) || sdef->sdef_ident==undef_id){
e->e_kind = Bottom;
e->e_sym = 0;
e->e_hnf = True;
e->e_spechnf= True;
return e;
}
}
#endif
rule = sdef->sdef_rule_type->rule_type_rule;
typeargs = rule->type_alt_lhs->type_node_arguments;
/* count the number of strict args in the type */
arity = CountStrictArgs (typeargs);
if (arity == 0){
e->e_kind = Top;
return e;
}
e->e_kind = Dep;
e->e_args = NewExpArgs (arity);
i = 0;
for (arg = node->node_arguments; arg; arg = arg->arg_next, typeargs = typeargs->type_arg_next){
if (typeargs->type_arg_node->type_node_annotation!=StrictAnnot)
continue;
exp = ConvertNode (arg->arg_node, NULL);
ConvertStrictSelections (exp, typeargs->type_arg_node, e->e_args, &i);
}
if (i == 0)
e->e_kind = Top;
else
e->e_sym = i;
return e;
} else {
e->e_fun = sdef->sdef_sa_fun;
if (sdef->sdef_kind==RECORDTYPE ? arity==sdef->sdef_cons_arity : arity==sdef->sdef_arity)
e->e_kind = Value;
else {
ConvertToApplyNode (e, node, arity);
return e;
}
}
break;
}
default:
e = & top;
if (nid)
nid->nid_exp_ = e;
return e;
}
e->e_args = NewExpArgs (arity);
for (i = 0,arg=node->node_arguments; arg!=NULL; arg=arg->arg_next,++i)
e->e_args[i] = ConvertNode (arg->arg_node, NULL);
break;
}
case IfNode:
{ arity = 3;
e->e_fun = if_sym;
e->e_args = NewExpArgs (arity);
/* conditional part */
arg = node->node_arguments;
e->e_args[0] = ConvertNode (arg->arg_node, Null);
/* then and else part */
arg = arg->arg_next;
e->e_args[1] = ConvertNodeDefs (arg->arg_node, node->node_then_node_defs,node->node_then_strict_node_ids);
arg = arg->arg_next;
e->e_args[2] = ConvertNodeDefs (arg->arg_node, node->node_else_node_defs,node->node_else_strict_node_ids);
break;
}
case SelectorNode:
{
int field_nr;
field_nr = node->node_symbol->symb_def->sdef_sel_field_number;
arg = node->node_arguments;
if (node->node_arity>=SELECTOR_U){
if (node->node_arity>=SELECTOR_L){
Exp tuple,record,result,tuple_result,selection;
tuple=ConvertNode (arg->arg_node,NULL);
record=NewValueExp (selectsym[0],False,1);
record->e_args[0]=tuple;
result=NewValueExp (selectsym[1],False,1);
result->e_args[0]=tuple;
selection=NewValueExp (selectsym [field_nr],False,1);
selection->e_args[0]=record;
tuple_result=NewValueExp (tuplesym[2],True,2);
tuple_result->e_args[0]=selection;
tuple_result->e_args[1]=result;
e->e_fun = strict_sym[1];
e->e_args = NewExpArgs (3);
e->e_args[0] = record;
e->e_args[1] = result;
e->e_args[2] = tuple_result;
} else {
Exp record,tuple_result,selection;
record=ConvertNode (arg->arg_node,NULL);
selection=NewValueExp (selectsym [field_nr],False,1);
selection->e_args[0]=record;
tuple_result=NewValueExp (tuplesym[2],True,2);
tuple_result->e_args[0]=selection;
tuple_result->e_args[1]=record;
e->e_fun = strict_sym[0];
e->e_args = NewExpArgs (2);
e->e_args[0] = record;
e->e_args[1] = tuple_result;
}
break;
}
e->e_fun = selectsym [field_nr];
e->e_args = NewExpArgs (1);
e->e_args[0] = ConvertNode (arg->arg_node, Null);
break;
}
case UpdateNode:
{ int field_nr, arity;
Exp oldrecordexp, selexp, newrecordexp;
/* make a new exp node if a strict update is required */
#ifndef StrictUpdates
newrecordexp = e;
#else
newrecordexp = NewValueExp (NULL,False,0);
#endif
/* convert the old record */
arg = node->node_arguments;
oldrecordexp = ConvertNode (arg->arg_node, Null);
/* build a record expression for the new record node */
newrecordexp->e_fun = node->node_symbol->symb_def->sdef_sa_fun;
newrecordexp->e_kind = Value;
arity = node->node_symbol->symb_def->sdef_cons_arity;
/* initialise the arguments of the new record exp */
newrecordexp->e_args = NewExpArgs (arity);
for (i = 0; i < arity; i++)
newrecordexp->e_args[i] = NULL;
/* now fill in the updates of the new record */
for_l (arg,node->node_arguments->arg_next,arg_next){
field_nr = arg->arg_node->node_symbol->symb_def->sdef_sel_field_number;
newrecordexp->e_args[field_nr] = ConvertNode (arg->arg_node->node_arguments->arg_node, Null);
}
/* finally, create selections for the parts which are not updated */
for (i = 0; i < arity; i++)
{ if (newrecordexp->e_args[i])
continue;
selexp = NewValueExp (selectsym [i], False, 1);
selexp->e_args[0] = oldrecordexp;
newrecordexp->e_args[i] = selexp;
}
/* fill the strictness cell if necessary */
#ifdef StrictUpdates
e->e_args = NewExpArgs (2);
e->e_fun = strict_sym[0];
e->e_args[0] = oldrecordexp;
e->e_args[1] = newrecordexp;
#endif
break;
}
case MatchNode:
{
Exp exp;
Symbol symbol;
exp = ConvertNode (node->node_arguments->arg_node, Null);
symbol=node->node_symbol;
if (symbol->symb_kind==definition && symbol->symb_def->sdef_kind==CONSTRUCTOR &&
symbol->symb_def->sdef_arity==1)
{
Exp selexp;
selexp = NewValueExp (selectsym[0], False, 1);
selexp->e_args[0] = exp;
exp = selexp;
}
if (nid)
nid->nid_exp_ = exp;
return exp;
}
default:
DoFatalError ("ConvertNode (SA): unknown node kind");
return & top;
}
return e;
}
#ifdef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
static void convert_pattern_to_apply_node (Exp e,SymbolP symbol,NodeIdListElementP node_id_list,unsigned arity)
{
if (arity==0){
e->e_fun = symbol->symb_def->sdef_sa_fun;
e->e_kind = FunValue;
e->e_hnf = True;
} else {
Exp left,right;
unsigned i;
NodeIdListElementP node_id_list_elem;
left = NewValueExp (NULL,False,0);
convert_pattern_to_apply_node (left,symbol,node_id_list,arity-1);
node_id_list_elem=node_id_list;
i=1;
while (i<arity){
node_id_list_elem=node_id_list_elem->nidl_next;
++i;
}
right = ConvertNodeId (node_id_list_elem->nidl_node_id);
e->e_fun = apsym;
e->e_kind = Value;
e->e_hnf = True;
e->e_args = NewExpArgs (2);
e->e_args[0] = left;
e->e_args[1] = right;
}
}
static Exp convert_pattern (SymbolP symbol_p,int arity,NodeIdListElementP node_id_list)
{
NodeIdListElementP node_id_list_elem;
Exp e;
e = NewValueExp (NULL,False,0);
switch (symbol_p->symb_kind){
case tuple_symb:
e->e_fun = tuplesym[arity];
break;
case bool_denot:
if (symbol_p -> symb_bool)
e->e_fun = true_sym;
else
e->e_fun = false_sym;
e->e_hnf = True;
break;
case cons_symb:
#if STRICT_LISTS
if (symbol_p->symb_head_strictness>1){
e->e_fun = (symbol_p->symb_tail_strictness ? strict_tail_strict_cons_sym0 : strict_cons_sym0)+arity;
break;
} else if (symbol_p->symb_tail_strictness){
e->e_fun = tail_strict_cons_sym0+arity;
break;
}
e->e_hnf = True;
e->e_fun = lazy_cons_sym0+arity;
#else
e->e_hnf = True;
e->e_fun = conssym;
#endif
break;
case nil_symb:
e->e_hnf = True;
e->e_fun = nilsym;
break;
case definition:
{
SymbDef sdef;
sdef = symbol_p->symb_def;
if (sdef->sdef_kind == INSTANCE)
DoFatalError ("Strictness analysis (convert_pattern): instance encounterred");
if (sdef->sdef_kind==DEFRULE || sdef->sdef_kind==SYSRULE){
TypeAlts rule;
TypeArgs typeargs;
unsigned int i;
Exp exp;
rule = sdef->sdef_rule_type->rule_type_rule;
typeargs = rule->type_alt_lhs->type_node_arguments;
/* count the number of strict args in the type */
arity = CountStrictArgs (typeargs);
if (arity == 0){
e->e_kind = Top;
return e;
}
e->e_kind = Dep;
e->e_args = NewExpArgs (arity);
i = 0;
for (node_id_list_elem=node_id_list; node_id_list_elem!=NULL; node_id_list_elem=node_id_list_elem->nidl_next,typeargs=typeargs->type_arg_next){
if (typeargs->type_arg_node->type_node_annotation==StrictAnnot){
exp = ConvertNodeId (node_id_list_elem->nidl_node_id);
ConvertStrictSelections (exp,typeargs->type_arg_node,e->e_args,&i);
}
}
if (i == 0)
e->e_kind = Top;
else
e->e_sym = i;
return e;
} else {
e->e_fun = sdef->sdef_sa_fun;
if (sdef->sdef_kind==RECORDTYPE ? arity==sdef->sdef_cons_arity : arity==sdef->sdef_arity)
e->e_kind = Value;
else {
convert_pattern_to_apply_node (e,symbol_p,node_id_list,arity);
return e;
}
}
break;
}
default:
e = & top;
return e;
}
e->e_args = NewExpArgs (arity);
{
unsigned int i;
for (i=0,node_id_list_elem=node_id_list; node_id_list_elem!=NULL; node_id_list_elem=node_id_list_elem->nidl_next,++i)
e->e_args[i] = ConvertNodeId (node_id_list_elem->nidl_node_id);
}
return e;
}
static void convert_root_node (NodeP rhs_root_p,NodeDefs node_defs,StrictNodeIdP strict_node_ids,Alts fun_alt_p);
static void convert_switch_node (NodeP switch_node_p,Alts fun_alt_p)
{
ArgP arg_p;
Alts *last_next_switch_alt_p;
fun_alt_p->fun_rhs = ConvertNodeId (switch_node_p->node_node_id);
fun_alt_p->fun_is_guard=0;
last_next_switch_alt_p=&fun_alt_p->fun_switch_alts;
for_l (arg_p,switch_node_p->node_arguments,arg_next){
Alts case_alt_p;
Bool old_has_fail;
NodeP case_alt_node_p,node_p;
case_alt_p=SAllocType (AltsRepr);
*last_next_switch_alt_p=case_alt_p;
last_next_switch_alt_p=&case_alt_p->fun_next;
node_p=arg_p->arg_node;
if (node_p->node_kind==CaseNode){
case_alt_node_p=node_p->node_arguments->arg_node;
if (case_alt_node_p->node_kind==PushNode){
case_alt_p->fun_lhs=convert_pattern (node_p->node_symbol,node_p->node_arity,case_alt_node_p->node_node_ids);
case_alt_node_p=case_alt_node_p->node_arguments->arg_next->arg_node;
} else {
case_alt_p->fun_lhs=convert_pattern (node_p->node_symbol,0,NULL);
}
} else if (node_p->node_kind==DefaultNode){
case_alt_node_p=node_p->node_arguments->arg_node;
case_alt_p->fun_lhs=NULL;
} else
error_in_function ("convert_switch_node");
old_has_fail=has_fail;
has_fail=False;
convert_root_node (case_alt_node_p,node_p->node_node_defs,node_p->node_strict_node_ids,case_alt_p);
case_alt_p->fun_has_fail=has_fail;
if (old_has_fail)
has_fail=True;
}
*last_next_switch_alt_p=NULL;
}
static void convert_guard_node (NodeP guard_node_p,NodeDefs node_defs,StrictNodeIdP strict_node_ids,Alts fun_alt_p)
{
Alts fail_alt_p;
fail_alt_p=SAllocType (AltsRepr);
fun_alt_p->fun_is_guard=1;
fun_alt_p->fun_switch_alts=fail_alt_p;
fun_alt_p->fun_rhs=ConvertNodeDefs (guard_node_p->node_arguments->arg_node,node_defs,strict_node_ids);
convert_root_node (guard_node_p->node_arguments->arg_next->arg_node,guard_node_p->node_node_defs,guard_node_p->node_guard_strict_node_ids,fail_alt_p);
}
static void convert_root_node (NodeP rhs_root_p,NodeDefs node_defs,StrictNodeIdP strict_node_ids,Alts fun_alt_p)
{
if (rhs_root_p->node_kind==SwitchNode){
NodeDefP node_def;
for_l (node_def,node_defs,def_next)
if (node_def->def_node!=NULL)
ConvertNode (node_def->def_node,node_def->def_id);
if (strict_node_ids!=NULL)
error_in_function ("convert_root_node");
convert_switch_node (rhs_root_p,fun_alt_p);
} else if (rhs_root_p->node_kind==GuardNode){
convert_guard_node (rhs_root_p,node_defs,strict_node_ids,fun_alt_p);
} else {
fun_alt_p->fun_rhs = ConvertNodeDefs (rhs_root_p,node_defs,strict_node_ids);
fun_alt_p->fun_switch_alts=NULL;
}
}
#endif
static void ConvertAlternatives (Alts *funalts,RuleAlts rulealts)
{
Alts fun_alt_p;
if (! rulealts){
*funalts = NULL;
return;
}
fun_alt_p=SAllocType (AltsRepr);
*funalts = fun_alt_p;
InitAlternative (rulealts);
#ifndef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
fun_alt_p->fun_lhs = ConvertNodeDefs (rulealts->alt_lhs_root,rulealts->alt_lhs_defs,NULL);
#else
fun_alt_p->fun_lhs = ConvertNodeDefs (rulealts->alt_lhs_root,NULL,NULL);
#endif
has_fail = False;
if (rulealts->alt_kind==Contractum){
#ifdef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
convert_root_node (rulealts->alt_rhs_root,rulealts->alt_rhs_defs,rulealts->alt_strict_node_ids,fun_alt_p);
#else
fun_alt_p->fun_rhs = ConvertNodeDefs (rulealts->alt_rhs_root, rulealts->alt_rhs_defs, rulealts->alt_strict_node_ids);
#endif
} else {
/* code block */
fun_alt_p->fun_rhs = ⊤
#ifdef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
fun_alt_p->fun_switch_alts=NULL;
#endif
}
fun_alt_p->fun_has_fail = has_fail;
/* convert the following alternatives */
ConvertAlternatives (&fun_alt_p->fun_next, rulealts->alt_next);
}
static StrictInfo *InitNewStrictInfos (unsigned arity, StrictKind s)
{
unsigned i;
StrictInfo *strict_infos;
strict_infos = SAllocArrayType (arity,StrictInfo);
for (i = 0; i < arity; i++){
strict_infos[i].strict_arity = 1;
InitStrictInfo (&strict_infos[i],s);
}
return strict_infos;
}
static void InitStrictResult (StrictInfo *s)
{
s->strict_arity = 1;
InitStrictInfo (s, HnfStrict);
}
static void ConvertStateToStrictInfo (TypeNode node, StrictInfo *s, Bool adopt_annots)
{
if (node->type_node_is_var || node->type_node_symbol->symb_kind!=tuple_type){
/*
#ifdef _DB_
if (node->type_node_is_var)
printf ("ConvertStateToStrictInfo Var\n");
else {
if (node->type_node_symbol->symb_kind==definition)
printf ("ConvertStateToStrictInfo Definition %s\n",node->type_node_symbol->symb_def->sdef_ident->ident_name);
else
printf ("ConvertStateToStrictInfo NoTuple %d\n",node->type_node_symbol->symb_kind);
}
#endif
*/
s->strict_arity = 1;
if (adopt_annots && node->type_node_annotation==StrictAnnot)
InitStrictInfo (s, HnfStrict);
else
InitStrictInfo (s, NotStrict);
} else {
unsigned arity = node->type_node_arity;
unsigned i;
TypeArgs args = node->type_node_arguments;
s->strict_arity = arity;
/*
#ifdef _DB_
printf ("ConvertStateToStrictInfo Tuple %d\n",arity);
#endif
*/
if (adopt_annots && node->type_node_annotation==StrictAnnot)
GetTupleStrictKind (s) = HnfStrict;
else
GetTupleStrictKind (s) = NotStrict;
GetTupleInfos (s) = SAllocArrayType (arity,StrictInfo);
for (i = 0; i < arity; i++, args = args->type_arg_next)
ConvertStateToStrictInfo (args->type_arg_node, & GetTupleInfo (s, i),
adopt_annots);
}
}
static void ConvertTypeArgsToStrictInfos (TypeArgs args, unsigned arity, StrictInfo **strict_args, Bool adopt_annots)
{
unsigned i;
*strict_args = SAllocArrayType (arity,StrictInfo);
for (i = 0; i < arity; i++, args = args->type_arg_next){
/*
#ifdef _DB_
printf ("ConvertTypeArgsToStrictInfos %d\n",i);
#endif
*/
ConvertStateToStrictInfo (args->type_arg_node, & (*strict_args)[i], adopt_annots);
}
}
static void ConvertStateInfoToStrictInfos (TypeAlts rule_type_alts, unsigned arity, StrictInfo **strict_args,
StrictInfo *result, Bool adopt_annots)
{
TypeArgs args;
TypeNode node;
if (! rule_type_alts){
*strict_args = InitNewStrictInfos (arity, NotStrict);
InitStrictResult (result);
return;
}
/* do the arguments */
args = rule_type_alts->type_alt_lhs->type_node_arguments;
ConvertTypeArgsToStrictInfos (args, arity, strict_args, adopt_annots);
/* do the result */
node = rule_type_alts->type_alt_rhs;
if (node->type_node_is_var)
InitStrictResult (result);
else
ConvertStateToStrictInfo (node, result, True);
/* the result is of course always strict */
if (IsTupleInfo (result))
GetTupleStrictKind (result) = HnfStrict;
else
InitStrictInfo (result, HnfStrict);
}
#if CLEAN2
/*
Encoding for strictness information:
The strictness information that is found by the strictness
analyser is encoded in a bit string. There are two encodings
compact (but fragile):
0 a (s)* trailing zeros are removed
robust (but long):
1 a (w s t)*
a any strictness added
()* repeated for each argument position, recursively
for strict (after sa) tuples
w argument was strict
s argument strictness added
t argument is tuple
Example:
f :: ! a ( a, [a]) -> a // before sa
f :: ! a ! ( ! a, [a]) -> a // after sa
compact 0 1 0 1 1 0 => 01011 (trailing zeros removed)
robust 1 1 100 011 010 000 => 11100011010000
The bit string is represented by a bit count and an array of
ints (each 32 bits), where the least significant bit of an int
is the first bit in the bit string.
*/
#define StrictPositionsRobustEncoding 1
#define kMaxStrictPositions 1024
#if StrictPositionsRobustEncoding
# define kBitsPerStrictPosition 3
#else
# define kBitsPerStrictPosition 1
# endif
#define kMaxStrictBits (2+kMaxStrictPositions*kBitsPerStrictPosition)
#define kBitsPerInt (sizeof (int)*8)
#define ceilingdiv(a, b) (((a)+(b)-1)/(b)) /* ceiling (a/b) */
#define bits2ints(n) ceilingdiv(n, kBitsPerInt)
static int strict_positions_last_one;
static StrictPositionsP strict_positions;
static void StrictPositionsClear (void)
{
int i, sizeInts;
if (strict_positions == NULL)
{
int sizeBytes;
sizeInts = bits2ints(kMaxStrictBits);
sizeBytes = sizeof (StrictPositionsS) + (sizeInts-1) * sizeof (int);
strict_positions = CompAlloc (sizeBytes);
for (i = 0; i < sizeInts; i++)
strict_positions->sp_bits[i] = 0;
strict_positions->sp_size = 0;
}
sizeInts = bits2ints (strict_positions->sp_size);
for (i = 0; i < sizeInts; i++)
strict_positions->sp_bits[i] = 0;
strict_positions->sp_size = 0;
strict_positions_last_one = 0;
}
static void StrictPositionsAddBit (Bool bit)
{
int size;
StrictPositionsP positions;
positions = strict_positions;
size = positions->sp_size;
if (bit)
{
Assume (size < kMaxStrictPositions, "too many strict positions", "AddStrictPositions");
positions->sp_bits [size/kBitsPerInt] |= 1 << (size % kBitsPerInt);
strict_positions_last_one = size+1;
}
positions->sp_size = size+1;
}
static StrictPositionsP StrictPositionsCopy (void)
{
StrictPositionsP positions;
int sizeBits;
#if StrictPositionsRobustEncoding
sizeBits = strict_positions->sp_size;
#else
sizeBits = strict_positions_last_one;
#endif
Assume (sizeBits < kMaxStrictPositions, "too many strict positions", "StrictPositionsToInts");
if (sizeBits == 0)
{
static StrictPositionsS no_strict_postions = {0, {0}};
positions = &no_strict_postions;
}
else
{
int sizeInts, sizeBytes;
sizeInts = bits2ints(sizeBits);
sizeBytes = sizeof (StrictPositionsS) + (sizeInts-1) * sizeof (int);
positions = CompAlloc (sizeBytes);
memcpy (positions, strict_positions, sizeBytes);
}
return positions;
}
#define StrictPositionsStrictAdded(is_strict) StrictPositionsAddBit (is_strict)
#if StrictPositionsRobustEncoding
# define StrictPositionsWasStrict(is_strict_annotated) StrictPositionsAddBit (is_strict_annotated)
# define StrictPositionsType(is_tuple) StrictPositionsAddBit (is_tuple)
#else
# define StrictPositionsWasStrict(is_strict_annotated)
# define StrictPositionsType(is_tuple)
#endif
#endif /* CLEAN2 */
static void UpdateStateInfoWithStrictInfo (TypeNode node, StrictInfo *s,Bool *strict_added_p,Bool *warning)
{
Bool is_strict_annotated, is_strict, is_tuple, strict_added;
is_strict_annotated = node->type_node_annotation==StrictAnnot;
is_tuple = IsTupleInfo (s);
is_strict = (is_tuple ? GetTupleStrictKind (s) : GetStrictKind (s, 0)) != NotStrict;
strict_added = !is_strict_annotated && is_strict;
#if CLEAN2
StrictPositionsWasStrict (is_strict_annotated);
StrictPositionsStrictAdded (strict_added);
StrictPositionsType (is_tuple);
#endif
if (strict_added) {
node->type_node_annotation=StrictAnnot;
*strict_added_p = True;
}
if (is_strict_annotated && !is_strict && StrictChecks)
*warning = True;
if (is_tuple && (is_strict || is_strict_annotated)){
unsigned arity = s->strict_arity;
unsigned i;
TypeArgs args = node->type_node_arguments;
for (i = 0; i < arity; i++, args = args->type_arg_next) {
#ifndef SHOW_STRICT_EXPORTED_TUPLE_ELEMENTS
Bool local_strict_added;
local_strict_added = False;
strict_added_p = &local_strict_added;
#endif
UpdateStateInfoWithStrictInfo (args->type_arg_node,&GetTupleInfo (s,i),strict_added_p,warning);
}
}
}
static void UpdateStateInfosWithStrictInfos (TypeAlts rule, unsigned arity, StrictInfo *strict_args,
StrictInfo *result, Bool *strict_added, Bool *warning)
{ unsigned i;
TypeArgs args;
if (! rule)
return;
/* do the arguments */
args = rule->type_alt_lhs->type_node_arguments;
#if CLEAN2
StrictPositionsClear ();
StrictPositionsAddBit (StrictPositionsRobustEncoding);
StrictPositionsAddBit (False);
#endif
for (i = 0; i < arity; i++, args = args->type_arg_next) {
UpdateStateInfoWithStrictInfo (args->type_arg_node,&strict_args[i], strict_added, warning);
}
#if CLEAN2
if (*strict_added)
{
Assume (strict_positions->sp_size > 2, "not enough bits", "UpdateStateInfosWithStrictInfos");
Assume (strict_positions_last_one > 2, "not enough bits", "UpdateStateInfosWithStrictInfos");
strict_positions->sp_bits [0] |= 1 << 1;
}
rule->type_alt_strict_positions = StrictPositionsCopy ();
#endif
/* the result has no sense at the moment */
}
Bool IsListArg (Fun *f, unsigned n)
{
TypeArgs args;
TypeAlts typerule;
unsigned i;
if (f->fun_kind == Function)
typerule = f->fun_symbol->sdef_rule->rule_type;
else
/* ?? */
return False;
args = typerule->type_alt_lhs->type_node_arguments;
for (i = 0; i < n; i++)
args = args->type_arg_next;
return (! args->type_arg_node->type_node_is_var && args->type_arg_node->type_node_symbol->symb_kind==list_type);
}
static Bool HasListResult (Fun *f)
{
TypeAlts typerule;
if (f->fun_kind == Function)
typerule = f->fun_symbol->sdef_rule->rule_type;
else
return False;
return (!typerule->type_alt_rhs->type_node_is_var && typerule->type_alt_rhs->type_node_symbol->symb_kind==list_type);
}
static void BuildInfFunction (Fun *f)
{
Alts alt, alt2;
Exp lhs, rhs, arg_cons, arg_x, arg_y, nil_exp;
/* the following function is built:
E2 (Cons x y) = E2 y
E2 Nil = Nil
*/
f->fun_symbol = Null;
f->fun_arity = 1;
f->fun_kind = Function;
f->fun_strictargs = InitNewStrictInfos (1, HnfStrict);
f->fun_single = False;
InitStrictResult (& f->fun_strictresult);
f->fun_alts = alt = SAllocType (AltsRepr);
alt2 = SAllocType (AltsRepr);
alt->fun_has_fail = False;
alt->fun_next = alt2;
alt2->fun_has_fail = False;
alt2->fun_next = Null;
nil_exp = NewValueExp (nilsym, True, 0);
arg_x = NewExp (Argument, 0, False, 1);
arg_y = NewExp (Argument, 0, False, 1);
arg_cons = NewValueExp (conssym, True, 2);
arg_cons->e_args[0] = arg_x;
arg_cons->e_args[1] = arg_y;
lhs = NewValueExp (inffunct_sym, False, 1);
lhs->e_args[0] = arg_cons;
rhs = NewValueExp (inffunct_sym, False, 1);
rhs->e_args[0] = arg_y;
alt->fun_lhs = lhs;
alt->fun_rhs = rhs;
lhs = NewValueExp (inffunct_sym, False, 1);
lhs->e_args[0] = nil_exp;
rhs = nil_exp;
alt2->fun_lhs = lhs;
alt2->fun_rhs = rhs;
}
static void BuildBotmemFunction (Fun *f)
{
Alts alt, alt2;
Exp lhs, rhs, arg_cons, arg_x, arg_y, strict_rhs, nil_exp;
/* the following function is built:
E3 (Cons x y) = Strict x (E3 y)
E3 Nil = Nil
*/
f->fun_symbol = Null;
f->fun_arity = 1;
f->fun_kind = Function;
f->fun_strictargs = InitNewStrictInfos (1, HnfStrict);
f->fun_single = False;
InitStrictResult (& f->fun_strictresult);
f->fun_alts = alt = SAllocType (AltsRepr);
alt2 = SAllocType (AltsRepr);
alt->fun_has_fail = False;
alt->fun_next = alt2;
alt2->fun_has_fail = False;
alt2->fun_next = Null;
nil_exp = NewValueExp (nilsym, True, 0);
arg_x = NewExp (Argument, 0, False, 1);
arg_y = NewExp (Argument, 0, False, 1);
arg_cons = NewValueExp (conssym, True, 2);
arg_cons->e_args[0] = arg_x;
arg_cons->e_args[1] = arg_y;
lhs = NewValueExp (botmemfunct_sym, False, 1);
lhs->e_args[0] = arg_cons;
rhs = NewValueExp (botmemfunct_sym, False, 1);
rhs->e_args[0] = arg_y;
strict_rhs = NewValueExp (strict_sym[0], False, 2);
strict_rhs->e_args[0]= arg_x;
strict_rhs->e_args[1]= rhs;
alt->fun_lhs = lhs;
alt->fun_rhs = strict_rhs;
lhs = NewValueExp (botmemfunct_sym, False, 1);
lhs->e_args[0] = nil_exp;
rhs = nil_exp;
alt2->fun_lhs = lhs;
alt2->fun_rhs = rhs;
}
static void init_predefined_symbols (void)
{
unsigned i;
Fun *f,*funs;
unsigned nr_funs;
/* add entries for tuples (MaxTupleArity), selectors (MaxTupleArity),
strict functions (for strict annots), lists (2), conditional (4)
and the apply. Also for the two list functions if necessary.
*/
nr_funs = MaxNodeArity + MaxNodeArity + MaxNrAnnots + 2 + 4 + 1
#if STRICT_LISTS
/* +3 */
+11
#endif
;
if (StrictDoLists)
nr_funs += 2;
/* allocate enough space for the function table */
funs = (Fun *) SAlloc ((unsigned long) nr_funs * sizeof (Fun));
/* initialise the function table with tuples */
for (i = 0, f = funs; i < MaxNodeArity; i++, f++){
tuplesym[i] = f;
f->fun_symbol = Null; /* TupleDefs[i]; */
f->fun_arity = i;
f->fun_kind = Constructor;
f->fun_strictargs = Null;
f->fun_single = True;
InitStrictResult (& f->fun_strictresult);
}
/* initialise the function table with selectors and update functions */
for (i = 0; i < MaxNodeArity; i++,f++){
selectsym[i] = f;
f->fun_symbol = Null;
f->fun_arity = 1;
f->fun_kind = SelFunction;
f->fun_strictargs = InitNewStrictInfos (1, HnfStrict);
f->fun_single = False;
InitStrictResult (& f->fun_strictresult);
}
#if MORE_ANNOTS
{
StrictInfo *shared_strict_infos;
shared_strict_infos=InitNewStrictInfos (MaxNrAnnots+1,HnfStrict);
#endif
/* initialise the function table with strict functions */
for (i = 0; i < MaxNrAnnots; i++,f++){
strict_sym[i] = f;
f->fun_symbol = Null;
f->fun_arity = i+2;
f->fun_kind = StrictFunction;
#if MORE_ANNOTS
f->fun_strictargs = shared_strict_infos;
#else
f->fun_strictargs = InitNewStrictInfos (i+2, HnfStrict);
#endif
f->fun_single = False;
InitStrictResult (& f->fun_strictresult);
}
#if MORE_ANNOTS
}
#endif
/* initialise the function table with lists, conditional and apply */
nilsym = f;
f->fun_symbol = Null;
f->fun_arity = 0;
f->fun_kind = Constructor;
f->fun_strictargs = Null;
f->fun_single = False;
InitStrictResult (& f->fun_strictresult);
f++;
#if !STRICT_LISTS
conssym = f;
f->fun_symbol = Null;
f->fun_arity = 2;
f->fun_kind = Constructor;
f->fun_strictargs = Null;
f->fun_single = False;
InitStrictResult (& f->fun_strictresult);
f++;
#else
lazy_cons_sym0 = f;
for (i=0; i<=2; ++i){
f->fun_symbol = Null;
f->fun_arity = i;
f->fun_kind = Constructor;
f->fun_strictargs = Null;
f->fun_single = False;
InitStrictResult (& f->fun_strictresult);
f++;
}
strict_cons_sym0 = f;
for (i=0; i<=2; ++i){
f->fun_symbol = NULL;
f->fun_arity = i;
f->fun_kind = Constructor;
f->fun_strictargs = InitNewStrictInfos (2,NotStrict);;
f->fun_single = False;
InitStrictInfo (f->fun_strictargs,HnfStrict);
InitStrictResult (&f->fun_strictresult);
++f;
}
tail_strict_cons_sym0 = f;
for (i=0; i<=2; ++i){
f->fun_symbol = NULL;
f->fun_arity = i;
f->fun_kind = Constructor;
f->fun_strictargs = InitNewStrictInfos (2,NotStrict);;
f->fun_single = False;
InitStrictInfo (&f->fun_strictargs[1],HnfStrict);
InitStrictResult (&f->fun_strictresult);
++f;
}
strict_tail_strict_cons_sym0 = f;
for (i=0; i<=2; ++i){
f->fun_symbol = NULL;
f->fun_arity = i;
f->fun_kind = Constructor;
f->fun_strictargs = InitNewStrictInfos (2,NotStrict);;
f->fun_single = False;
InitStrictInfo (f->fun_strictargs,HnfStrict);
InitStrictInfo (&f->fun_strictargs[1],HnfStrict);
InitStrictResult (&f->fun_strictresult);
++f;
}
conssym = lazy_cons_sym0+2;
#endif
if_sym = f;
f->fun_symbol = Null;
f->fun_arity = 3;
f->fun_kind = IfFunction;
f->fun_strictargs = InitNewStrictInfos (3, NotStrict);
f->fun_single = False;
InitStrictInfo (f->fun_strictargs, HnfStrict);
InitStrictResult (& f->fun_strictresult);
f++;
true_sym = f;
f->fun_symbol = Null;
f->fun_arity = 0;
f->fun_kind = Constructor;
f->fun_strictargs = Null;
f->fun_single = False;
InitStrictResult (& f->fun_strictresult);
f++;
false_sym = f;
f->fun_symbol = Null;
f->fun_arity = 0;
f->fun_kind = Constructor;
f->fun_strictargs = Null;
f->fun_single = False;
InitStrictResult (& f->fun_strictresult);
f++;
fail_sym = f;
f->fun_symbol = Null;
f->fun_arity = 0;
f->fun_kind = FailFunction;
f->fun_strictargs = Null;
f->fun_single = False;
InitStrictResult (& f->fun_strictresult);
f++;
apsym = f;
f->fun_symbol = Null;
f->fun_arity = 2;
f->fun_kind = ApFunction;
f->fun_strictargs = InitNewStrictInfos (2, NotStrict);
f->fun_single = False;
InitStrictInfo (f->fun_strictargs, HnfStrict);
InitStrictResult (& f->fun_strictresult);
f++;
/* initialise the function table with the inf and botmem function function */
if (StrictDoLists){
inffunct_sym = f;
BuildInfFunction (f);
f++;
botmemfunct_sym = f;
BuildBotmemFunction (f);
f++;
}
}
static void convert_imp_rule_type (SymbDef sdef)
{
Fun *f;
unsigned arity;
TypeAlts rule_type;
f=SAllocType (Fun);
sdef->sdef_sa_fun = f;
arity = sdef->sdef_arity;
f->fun_kind = Function;
f->fun_symbol = sdef;
f->fun_arity = arity;
rule_type = sdef->sdef_rule->rule_type;
/*
#ifdef _DB_
printf ("ConvertStateInfoToStrictInfos %s\n",sdef->sdef_ident->ident_name);
#endif
*/
ConvertStateInfoToStrictInfos (rule_type,arity, &f->fun_strictargs, &f->fun_strictresult, !StrictChecks);
}
static void convert_imp_rule_alts (SymbDef sdef)
{
Fun *f;
f=sdef->sdef_sa_fun;
if (f->fun_kind==Function){
ImpRules rule;
rule = f->fun_symbol->sdef_rule;
ConvertAlternatives (&f->fun_alts,rule->rule_alts);
} else
f->fun_alts = NULL;
}
static void ConvertSyntaxTree (Symbol symbols)
{
unsigned arity;
Symbol sym;
Bool annot_warning;
SymbDef sdef;
Fun *f;
annot_warning = False;
init_predefined_symbols();
/* initialise the function table with constructors */
for_l (sym,symbols,symb_next)
if (sym->symb_kind==definition){
sdef = sym->symb_def;
if (sdef->sdef_kind==TYPE){
ConstructorList talts;
for_l (talts,sdef->sdef_type->type_constructors,cl_next){
SymbDef cdef;
f=SAllocType (Fun);
cdef = talts->cl_constructor->type_node_symbol->symb_def;
cdef->sdef_sa_fun = f;
f->fun_symbol = cdef;
arity = f->fun_arity = cdef->sdef_arity;
f->fun_single = False;
f->fun_kind = Constructor;
f->fun_single = cdef->sdef_type->type_nr_of_constructors == 1;
cdef->sdef_constructor=talts;
if (cdef->sdef_strict_constructor)
ConvertTypeArgsToStrictInfos (talts->cl_constructor->type_node_arguments,arity,&f->fun_strictargs, True);
else
f->fun_strictargs = NULL;
InitStrictResult (& f->fun_strictresult);
}
} else if (sdef->sdef_kind==RECORDTYPE){
f=SAllocType (Fun);
sdef->sdef_sa_fun = f;
f->fun_symbol = sdef;
arity = f->fun_arity = sdef->sdef_cons_arity;
f->fun_kind = Constructor;
f->fun_single = True;
if (sdef->sdef_strict_constructor)
ConvertTypeArgsToStrictInfos (TypeArgsOfRecord (sdef), arity,&f->fun_strictargs, True);
else
f->fun_strictargs = Null;
InitStrictResult (& f->fun_strictresult);
}
}
/* initialise the function table with symbols with a definition */
for_l (sdef,scc_dependency_list,sdef_next_scc)
if (sdef->sdef_kind==IMPRULE && sdef->sdef_over_arity==0)
convert_imp_rule_type (sdef);
/* convert the rules */
for_l (sdef,scc_dependency_list,sdef_next_scc)
if (sdef->sdef_kind==IMPRULE && sdef->sdef_over_arity==0)
convert_imp_rule_alts (sdef);
/* give a warning for annotated functions */
if (annot_warning && StrictAllWarning)
GiveStrictWarning ((char *) Null, "no strictness analysis for functions with code blocks");
}
static void update_function_strictness (SymbDef sdef)
{
Fun *f;
unsigned arity;
f=sdef->sdef_sa_fun;
arity = f->fun_arity;
if (f->fun_kind == Function){
TypeAlts rule;
Bool strict_added,warning;
rule = sdef->sdef_rule->rule_type;
#if 0
printf ("%s\n",sdef->sdef_ident->ident_name);
#endif
strict_added = False;
warning = False;
UpdateStateInfosWithStrictInfos (rule, arity, f->fun_strictargs, &f->fun_strictresult,&strict_added, &warning);
if (strict_added && sdef->sdef_exported){
if (DoListStrictTypes && ! DoListAllTypes)
PrintType (sdef, rule);
else
export_warning = True;
}
if (warning && (StrictAllWarning || StrictChecks))
GiveStrictWarning (sdef->sdef_ident->ident_name, "not all user annotations could be derived");
if (export_warning && (StrictAllWarning || StrictExportChecks))
GiveStrictWarning (sdef->sdef_ident->ident_name, "function not annotated as being strict in definition module");
}
}
static void UpdateSyntaxTree (void)
{
SymbDef sdef;
for_l (sdef,scc_dependency_list,sdef_next_scc)
if (sdef->sdef_kind==IMPRULE && sdef->sdef_over_arity==0)
update_function_strictness (sdef);
}
/*******************************************************************************
* The Abstract Reducer *
******************************************************************************/
static Bool ReduceInContext (ExpP ep, Path p, Context context);
static int rel_depth = 0;
static Bool CheckRelation (Exp e, Path p, Context context)
{
Exp exp_new, exp_cq, exp_dum;
Bool result;
unsigned old_fuel;
/*
FPrintF (outfile, "\n\nAreRelated?");
FPrintF (outfile, "\ne: ");
DumpExp (outfile, e);
FPrintF (outfile, "\np->e: ");
DumpExp (outfile, p->p_exp);
FPrintF (outfile, "\nexp1: ");
DumpExp (outfile, *s_exp1);
FPrintF (outfile, "\nexp2: ");
DumpExp (outfile, *s_exp2);
FPrintF (outfile, "\n");
*/
/* check if there is a common subexpression */
if (! IsContainedIn (*s_exp2, s_exp1))
return False;
/*
FPrintF (outfile, "Yes\nqexp: ");
DumpExp (outfile, *q_exp);
FPrintF (outfile, "\n\n");
*/
rel_depth++;
#ifdef _DB_EQ_
if (DBPrinting){
FPrintF (outfile, "Result: AreRelated (");
DumpExp (outfile, *s_exp1);
FPrintF (outfile, ", ");
DumpExp (outfile, *s_exp2);
FPrintF (outfile, ", ");
DumpExp (outfile, *q_exp);
FPrintF (outfile, ")\n\n");
}
#endif /* _DB_EQ_ */
/* we have the following situation (e is a growing expression)
e = C[C"[q]]
p->e = C[q]
with
s_exp1 = C"[q]
s_exp2 = q (inside p->e)
q_exp = q (inside C"[q])
we will reduce
C[x : <q, C"[x]>]
*/
/* fetch C"[q] from e (i.e. replace it by a copy) */
exp_cq = InstantiateExp (*s_exp1);
exp_dum = *s_exp1;
*s_exp1 = exp_cq;
exp_cq = exp_dum;
/* replace q by <expcq,q>, but only if q is not Bot */
if ((*q_exp)->e_kind == Bottom)
*q_exp = exp_cq;
else
{ exp_dum = NewExp (Lub, 2, True, 2);
exp_dum->e_args[0] = exp_cq;
exp_dum->e_args[1] = *q_exp;
*q_exp = exp_dum;
SortExpOfKind (exp_dum, Lub);
}
/* create an expression to be reduced: C[q] becomes C[exp_cq] */
exp_dum = InstantiateExp (p->p_exp);
exp_new = p->p_exp;
p->p_exp = exp_dum;
*s_exp2 = exp_cq;
/* instantiate ?? */
exp_new = InstantiateExp (exp_new);
#ifdef _DB_RED_
if (DBPrinting)
FPrintF (outfile, "Relation (%d) --> ", rel_depth);
#endif
old_fuel = start_fuel;
result = ReduceInContext (&exp_new, (Path) Null, CopyContext (context));
start_fuel = old_fuel;
#ifdef _DB_RED_
if (DBPrinting)
FPrintF (outfile, "\n<-- End relation (%d)\n", rel_depth);
#endif
rel_depth--;
return result;
}
static Bool IsInPath (Exp e, Path p, Exp *r, Context context)
{
for ( ; p; p = p->p_next){
Bool b;
CheckAreRelated = DoStrictRelated;
b = LtExp (e, p->p_exp);
CheckAreRelated = False;
if (b == True){
*r = p->p_root;
return True;
} else if (b == AreRelated){
if (CheckRelation (e, p, context)){
*r = p->p_root;
return True;
}
}
}
return False;
}
static Path AddToPath (Exp e, Path p)
{
Path new;
if (! StrictDoPaths)
return p;
if (e->e_kind != Value || e->e_fun->fun_kind != Function)
return p;
if (! StrictDoAllPaths && p && p->p_exp->e_kind == Value && p->p_exp->e_fun->fun_symbol &&
p->p_exp->e_fun->fun_symbol->sdef_ancestor != e->e_fun->fun_symbol->sdef_ancestor)
return p;
new = SAllocType (PathRepr);
new->p_exp = InstantiateExp (e);
new->p_root = e;
new->p_next = p;
return new;
}
/*
static Path AddToPath (Exp e, Path p)
{ Path new, p2;
if (! StrictDoPaths)
return p;
if (e->e_kind != Value || e->e_fun->fun_kind != Function)
return p;
if (! StrictDoAllPaths && p && p->p_exp->e_kind == Value && p->p_exp->e_fun->fun_symbol &&
p->p_exp->e_fun->fun_symbol->sdef_ancestor != e->e_fun->fun_symbol->sdef_ancestor)
return p;
new = SAllocType (PathRepr);
new->p_exp = InstantiateExp (e);
new->p_root = e;
new->p_next = Null;
if (! p)
return new;
for (p2 = p; p2->p_next; p2 = p2->p_next)
;
p2->p_next = new;
return p;
} AddToPath
*/
static MatchKind CombineWithPartialMatch (MatchKind m)
{
switch (m){
case InfiniteMatch:
case PartialInfiniteMatch:
return PartialInfiniteMatch;
case NoMatch:
return NoMatch;
case LubMatch:
return LubMatch;
case ReduceMatch:
return ReduceMatch;
default:
return PartialMatch;
}
}
static void BindArgsToTop (Exp *args, unsigned arity, Bool *no_patterns)
{
unsigned i;
for (i = 0; i < arity; i++){
switch (args[i]->e_kind){
case Argument:
args[i]->e_args[0] = NewTop();
continue;
case Value:
if (! args[i]->e_fun->fun_single)
*no_patterns = False;
BindArgsToTop (args[i]->e_args, args[i]->e_fun->fun_arity, no_patterns);
break;
case Lub:
Assume2 (False, "Lub in pattern", "BindArgsToExp");
default:
*no_patterns = False;
}
}
}
static Bool ReduceDepExpression (Exp e, Path p, Context context)
{
unsigned arity, i;
arity = e->e_sym;
for (i = 0; i < arity; i++){
if (ReduceInContext (& e->e_args[i], p, NewSimpleContext (HnfStrict, context->context_speculative)))
return True;
}
SortExpOfKind (e, Dep);
if (e->e_kind == Bottom)
return True;
/* collect all dependencies, and replace by Top */
arity = e->e_sym;
for (i = 0; i < arity; i++)
{ if (e->e_args[i]->e_kind != Bottom)
e->e_deps = AddDeps (e->e_args[i]->e_deps, e->e_deps);
}
e->e_kind = Top;
e->e_hnf = True;
return False;
}
static Exp ConvertExpWithContext (Exp e, Context context)
{
if (context->context_arity != 1)
return e;
switch (context->context_kind){
case SpineStrict:
{
Exp new;
new = NewValueExp (inffunct_sym, False, 1);
new->e_args[0] = e;
return new;
}
case TailStrict:
{
Exp new;
new = NewValueExp (botmemfunct_sym, False, 1);
new->e_args[0] = e;
return new;
}
default:
return e;
}
}
static Bool CheckStrictArgsOfFunction (Exp e, Path p, Context context)
{
unsigned arity, i;
Fun *f;
StrictInfo *strictargs;
Context newcontext;
Exp new, *args;
Dependency newdeps;
f = e->e_fun;
args = e->e_args;
newdeps = e->e_deps;
if (! (strictargs = f->fun_strictargs))
return False;
arity = f->fun_arity;
for (i = 0; i < arity; i++){
newcontext = StrictInfoToContext (& strictargs[i], context, False);
if (! IsStrictContext (newcontext))
continue;
new = ConvertExpWithContext (args[i], newcontext);
if (ReduceInContext (& new, p, newcontext))
return True;
CopyDeps (new->e_deps, & newdeps);
}
e->e_deps = newdeps;
return False;
}
static Exp TakeContextLub (ExpP ep1, ExpP ep2, Path p, Context context)
{
if (*ep1){
if (ReduceInContext (ep1, p, context))
*ep1 = & bottom;
} else
*ep1 = & bottom;
if (*ep2){
if (ReduceInContext (ep2, p, context))
*ep2 = & bottom;
} else
*ep2 = & bottom;
return TakeLub (*ep1, *ep2);
}
static MatchKind MatchArgs (Exp args_act[], Exp args_for[], unsigned n, Dependency *dep, ExpP *e_stopp);
static MatchKind MatchExp (ExpP ep_act,Exp e_for,Dependency *dep,Exp **e_stopp)
{
MatchKind m;
if (e_for->e_kind==Argument){
e_for->e_args[0] = *ep_act;
return TotalMatch;
} else if (!(*ep_act)->e_hnf){
*e_stopp = ep_act;
return ReduceMatch;
} else if ((*ep_act)->e_kind == Bottom)
return InfiniteMatch;
else if ((*ep_act)->e_kind == Lub){
*e_stopp = ep_act;
return LubMatch;
}
/* the formal argument is a pattern, the actual argument a reduce, non-Bottom, non-Lub
value, so start the pattern matching
*/
switch (e_for->e_kind){
case Top:
m = PartialMatch;
break;
case FunValue:
if ((*ep_act)->e_kind == FunValue){
if (e_for->e_fun == (*ep_act)->e_fun){
m = TotalMatch;
break;
} else
return NoMatch;
}
m = PartialMatch;
break;
case Value:
switch ((*ep_act)->e_kind){
case Top:
case Dep:
case Ind:
{
Bool no_patterns;
/* In case of a constructor with only one alternative we have a TotalMatch */
no_patterns = True;
BindArgsToTop (e_for->e_args, e_for->e_fun->fun_arity, &no_patterns);
if (no_patterns && e_for->e_fun->fun_single)
m = TotalMatch;
else
m = PartialMatch;
break;
}
case Value:
if ((*ep_act)->e_fun != e_for->e_fun)
return NoMatch;
m = MatchArgs ((*ep_act)->e_args, e_for->e_args, (*ep_act)->e_fun->fun_arity, dep, e_stopp);
if (m != PartialMatch && m != TotalMatch)
return m;
break;
default:
Assume (False, "illegal case", "MatchExp");
return NoMatch;
}
break;
default:
Assume (False, "illegal case", "MatchExp");
return NoMatch;
}
/* we have a partial or total match, test now for dependencies */
if ((*ep_act)->e_deps && (*ep_act)->e_kind != Bottom)
CopyDeps ((*ep_act)->e_deps, dep);
return m;
}
static MatchKind MatchArgs (Exp args_act[],Exp args_for[],unsigned n,Dependency *dep,ExpP *e_stopp)
{
MatchKind m;
if (n == 0)
return TotalMatch;
m = MatchExp (&args_act[0],args_for[0],dep,e_stopp);
switch (m){
case LubMatch:
case ReduceMatch:
case NoMatch:
case InfiniteMatch:
case PartialInfiniteMatch:
return m;
case PartialMatch:
return CombineWithPartialMatch (MatchArgs (&args_act[1], &args_for[1], n-1, dep, e_stopp));
case TotalMatch:
return MatchArgs (&args_act[1], &args_for[1], n-1, dep, e_stopp);
default:
Assume (False, "unknown case", "MatchArgs");
return NoMatch;
}
}
static MatchKind MatchAlternative (Exp *ep,Exp *args_act,Exp *args_for,Alts alt,unsigned n,Dependency rootdeps,Path p,Context context);
static MatchKind MatchAlternative (Exp *ep,Exp *args_act,Exp *args_for,Alts alt,unsigned n,Dependency rootdeps,Path p,Context context)
{
MatchKind m;
ExpP e_stopp;
Dependency newdeps;
newdeps = NULL;
*ep = NULL;
m = MatchArgs (args_act,args_for,n,&newdeps,&e_stopp);
switch (m){
case LubMatch:
{
Exp next_e,*lub_args,e_stop;
unsigned k, i;
MatchKind next_m;
next_e = NULL;
/* store the Lub expression (it can be changed by future reductions, but the argument vector cannot) */
e_stop = *e_stopp;
lub_args = e_stop->e_args;
k = e_stop->e_sym;
m = NoMatch;
/* replace the Lub expression with all its elements */
for (i = 0; i < k; i++){
*e_stopp = lub_args[i];
next_m = MatchAlternative (&next_e, args_act, args_for, alt, n, rootdeps, p, context);
switch (next_m){
case NoMatch:
if (m == TotalMatch)
m = PartialMatch;
continue;
case InfiniteMatch:
case PartialInfiniteMatch:
if (m == NoMatch)
m = PartialInfiniteMatch;
continue;
case PartialMatch:
m = PartialMatch;
*ep = TakeContextLub (ep, &next_e, p, context);
break;
case TotalMatch:
if (m == NoMatch && i == 0)
m = TotalMatch;
else if (m != TotalMatch)
m = PartialMatch;
*ep = TakeContextLub (ep, &next_e, p, context);
break;
}
}
/* restore the original expression */
*e_stopp = e_stop;
/* return the match result */
if (m == LubMatch)
m = NoMatch;
break;
}
case ReduceMatch:
ReduceInContext (e_stopp, p, NewSimpleContext (HnfStrict, False));
return MatchAlternative (ep, args_act, args_for, alt, n, rootdeps, p, context);
case InfiniteMatch:
case PartialInfiniteMatch:
case NoMatch:
break;
case PartialMatch:
case TotalMatch:
#ifdef _DB_
# ifdef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
if (alt->fun_switch_alts==NULL)
# endif
if (!ArgsBound (alt->fun_rhs)){
FPrintF (StdError, "WARNING!!!\n");
if (alt->fun_lhs==NULL)
FPutS ("NULL",StdError);
else
DumpExp (StdError, alt->fun_lhs);
FPutC ('\n', StdError);
DumpExp (StdError, alt->fun_rhs);
FPutC ('\n', StdError);
DumpExp (StdError, *args_act);
FPutC ('\n', StdError);
/* Assume (False, "Not all args bound", "MatchAlternative"); */
}
#endif
#ifdef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
if (alt->fun_switch_alts==NULL){
#endif
#ifdef _DB_
fprintf (outfile,"InstantiateExp: ");
DumpExp (outfile,alt->fun_rhs);
fprintf (outfile,"\n");
#endif
*ep = InstantiateExp (alt->fun_rhs);
if ((*ep)->e_kind!=Bottom){
CopyDeps (rootdeps,&newdeps);
(*ep)->e_deps = newdeps;
}
#if 1 /* JVG */
if (m==TotalMatch && alt->fun_has_fail && (*ep)->e_kind==Value && (*ep)->e_fun->fun_kind==IfFunction){
(*ep)->e_red = True;
if (CheckStrictArgsOfFunction (*ep,p,context)){
UpdateExp (&bottom,*ep);
(*ep)->e_red = False;
return InfiniteMatch;
}
(*ep)->e_red = False;
}
#endif
#ifdef TRANSFORM_PATTERNS_BEFORE_STRICTNESS_ANALYSIS
} else {
if (!alt->fun_is_guard){
Exp switch_arg_exp,new_e,next_e;
Alts switch_alt;
MatchKind next_m,m2;
switch_arg_exp=alt->fun_rhs;
if (switch_arg_exp->e_kind!=Argument)
error_in_function ("MatchAlternative");
switch_arg_exp=switch_arg_exp->e_args[0];
next_e=NULL;
new_e=NULL;
m2=NoMatch;
for_l (switch_alt,alt->fun_switch_alts,fun_next){
if (switch_alt->fun_lhs!=NULL){
next_m=MatchAlternative (&next_e,&switch_arg_exp,&switch_alt->fun_lhs,switch_alt,1,rootdeps,p,context);
# if 0 && defined(_DB_)
fprintf (outfile,"MatchAlternative\nactual arg = ");
DumpExp (outfile,switch_arg_exp);
fprintf (outfile,"\nformal arg = ");
DumpExp (outfile,switch_alt->fun_lhs);
fprintf (outfile,"\n");
# endif
} else
next_m=MatchAlternative (&next_e,&switch_arg_exp,&switch_alt->fun_lhs,switch_alt,0,rootdeps,p,context);
switch (next_m){
case NoMatch:
continue;
case PartialInfiniteMatch:
if (m2==NoMatch)
m2=PartialInfiniteMatch;
continue;
case InfiniteMatch:
if (m2==NoMatch)
m2=InfiniteMatch;
if (new_e==NULL)
new_e=⊥
break;
case PartialMatch:
m2=PartialMatch;
new_e=TakeContextLub (&new_e,&next_e,p,context);
if (new_e->e_kind==Top && new_e->e_deps==NULL)
break;
continue;
case TotalMatch:
new_e=TakeContextLub (&new_e,&next_e,p,context);
if (switch_alt->fun_has_fail){
m2=PartialMatch;
continue;
}
m2=TotalMatch;
break;
default:
error_in_function ("MatchAlternative");
}
break;
}
if (m==PartialMatch)
m=CombineWithPartialMatch (m2);
else
m=m2;
*ep=new_e;
} else {
Exp new_e,next_e,dummy_exp;
MatchKind next_m;
new_e = InstantiateExp (alt->fun_rhs);
if (new_e->e_kind!=Bottom){
CopyDeps (rootdeps,&newdeps);
new_e->e_deps = newdeps;
}
if (m==TotalMatch && new_e->e_kind==Value && new_e->e_fun->fun_kind==IfFunction){
new_e->e_red = True;
if (CheckStrictArgsOfFunction (new_e,p,context)){
UpdateExp (&bottom,new_e);
new_e->e_red = False;
*ep=new_e;
return InfiniteMatch;
}
new_e->e_red = False;
}
dummy_exp=NULL;
next_m=MatchAlternative (&next_e,&dummy_exp,&dummy_exp,alt->fun_switch_alts,0,rootdeps,p,context);
switch (next_m){
case NoMatch:
m=NoMatch;
break;
case PartialInfiniteMatch:
m=PartialInfiniteMatch;
break;
case InfiniteMatch:
if (new_e==NULL)
new_e=⊥
if (m==TotalMatch)
m=InfiniteMatch;
else
m=PartialInfiniteMatch;
break;
case PartialMatch:
new_e=TakeContextLub (&new_e,&next_e,p,context);
m=PartialMatch;
break;
case TotalMatch:
new_e=TakeContextLub (&new_e,&next_e,p,context);
break;
default:
error_in_function ("MatchAlternative");
}
*ep=new_e;
}
}
#endif
break;
default:
Assume (False, "illegal case", "MatchAlternative");
}
return m;
}
/*******************************************************************************
* Support for indirections *
******************************************************************************/
static Bool ContainsIndirection2 (Exp e)
{
unsigned i,arity;
if (e->e_mark)
return False;
if (e->e_deps)
return True;
switch (e->e_kind){
case Bottom:
case Top:
case FunValue:
return False;
case Ind:
return True;
case Value:
e->e_mark = True;
arity = e->e_fun->fun_arity;
break;
case Dep:
case Lub:
e->e_mark = True;
arity = e->e_sym;
break;
default:
Assume (False, "illegal case", "ContainsIndirection");
return False;
}
/* Only reached if kind is Value, Dep or Lub */
for (i = 0; i < arity; i++)
if (ContainsIndirection2 (e->e_args[i]))
return True;
return False;
}
static Bool ContainsIndirection (Exp e)
{
Bool res;
res = ContainsIndirection2 (e);
RemoveMark (e);
return res;
}
static Bool IsInEachAlt2 (Exp e, Exp root)
{
unsigned i;
if (e->e_mark)
return False;
if (e->e_deps){
Dependency deps;
for (deps = e->e_deps; deps; deps = deps->dep_next)
if (deps->dep_exp == root)
return True;
}
switch (e->e_kind){
case Bottom:
return True;
case Top:
case FunValue:
return False;
case Ind:
/* it is sufficient that there is an indirection.
let: t -> t' -> C[t,t']
and suppose we are solving indirections to t'.
Other indirections are to t, but since:
C[t,t'] -> C[t',t']
they can also be considered indirections to t'.
*/
return True;
case Dep:
case Value:
{
int arity;
if (e->e_hnf && e->e_kind != Dep)
return False;
if (e->e_kind==Value)
arity=e->e_fun->fun_arity;
else
arity=e->e_sym;
e->e_mark = True;
for (i = 0; i < arity; i++){
if (IsInEachAlt2 (e->e_args[i], root)){
e->e_mark = False;
return True;
}
}
e->e_mark = False;
return False;
}
case Lub:
e->e_mark = True;
for (i = 0; i < e->e_sym; i++)
{ if (! IsInEachAlt2 (e->e_args[i], root))
{ e->e_mark = False;
return False;
}
}
e->e_mark = False;
return True;
default:
Assume (False, "illegal case", "IsInEachAlt2");
return False;
}
}
static Bool IsInEachAlt (Exp e, Exp root)
{
Bool res;
res = IsInEachAlt2 (e, root);
return res;
}
static void ReplaceIndByBottom (Exp e, Exp root)
{
unsigned i, arity;
if (e->e_imark)
return;
if (e->e_deps){
Dependency deps;
for (deps = e->e_deps; deps; deps = deps->dep_next){
if (deps->dep_exp == root){
e->e_kind = Bottom;
e->e_hnf = True;
e->e_deps = Null;
return;
}
}
}
switch (e->e_kind){
case Bottom:
case Top:
case FunValue:
return;
case Ind:
e->e_kind = Bottom;
e->e_hnf = True;
e->e_deps = Null;
return;
case Value:
e->e_imark = True;
arity = e->e_fun->fun_arity;
break;
case Lub:
case Dep:
e->e_imark = True;
arity = e->e_sym;
break;
default:
Assume (False, "illegal case", "ReplaceIndByBottom");
return;
}
/* Only reached if kind is Value or Lub */
for (i = 0; i < arity; i++)
ReplaceIndByBottom (e->e_args[i], root);
} /* ReplaceIndByBottom */
static void ReplaceIndByPtr (Exp *e, Exp root)
{
unsigned i, arity;
if ((*e)->e_imark)
return;
/*
if ((*e)->e_deps)
{ Dependency deps;
for (deps = (*e)->e_deps; deps; deps = deps->dep_next)
{ if (deps->dep_exp == root)
{ *e = root;
return;
}
}
}
*/
switch ((*e)->e_kind){
case Bottom:
case Top:
case FunValue:
return;
case Ind:
if (root == (*e)->e_args[0])
*e = root;
return;
case Value:
(*e)->e_imark = True;
arity = (*e)->e_fun->fun_arity;
break;
case Lub:
case Dep:
(*e)->e_imark = True;
arity = (*e)->e_sym;
break;
default:
Assume (False, "illegal case", "ReplaceIndByPtr");
return;
}
/* Only reached if kind is Value or Lub */
for (i = 0; i < arity; i++)
ReplaceIndByPtr (& (*e)->e_args[i], root);
} /* ReplaceIndByPtr */
static void RemoveMarksAndLubs (Exp e)
{
unsigned arity, i;
if (! e->e_imark)
return;
e->e_imark = False;
switch (e->e_kind){
case Bottom:
case Top:
case Ind:
case FunValue:
Assume2 (False, "e is marked illegal", "RemoveMarksAndLubs");
return;
case Value:
arity = e->e_fun->fun_arity;
break;
case Lub:
case Dep:
arity = e->e_sym;
break;
default:
Assume (False, "illegal case", "RemoveMarksAndLubs");
return;
}
/* Only reached if kind is Value or Lub */
for (i = 0; i < arity; i++)
RemoveMarksAndLubs (e->e_args[i]);
if (e->e_kind == Lub)
SortExpOfKind (e, Lub);
} /* RemoveMarksAndLubs */
static void ResolveIndirections (ExpP rootp, Path p, Context context)
{
if (! (*rootp)->e_hasind)
return;
if (IsInEachAlt (*rootp, *rootp))
ReplaceIndByBottom (*rootp, *rootp);
else
ReplaceIndByPtr (rootp, *rootp);
RemoveMarksAndLubs (*rootp);
if ((*rootp)->e_kind == Value)
(*rootp)->e_hnf = False;
ReduceInContext (rootp, p, context);
}
/*******************************************************************************
* *
* Reduction functions for the various kinds of functions *
They are called by 'Reduce'. Note that right type of the expression
and reductions of strict arguments are checked by 'Reduce'
ReduceStrict
Strict !s1...!sn x -> x;
ReduceIf
If !Bool x x -> x;
ReduceAp
Ap !(x -> y) x -> y;
ReduceSelection
SelectN !(x1....xM) -> xN;
ReduceFunction
general function call
* *
******************************************************************************/
static Exp GetResultOfFunctionApplication (Exp e, Path p, Context context)
{
MatchKind m;
Exp new_e,next_e;
Alts alt;
Fun * f;
#ifdef _DB_RED_
unsigned i;
#endif
new_e = NULL;
next_e = NULL;
f = e->e_fun;
#ifdef _DB_RED_
for (alt = f->fun_alts, i = 1; alt!=NULL; alt = alt->fun_next, i++){
#else
for_l (alt,f->fun_alts,fun_next){
#endif
m = MatchAlternative (&next_e,e->e_args,alt->fun_lhs->e_args,alt,f->fun_arity,e->e_deps,p,context);
#ifdef _DB_RED_
if (DBPrinting){
DumpMatch (outfile, m);
FPrintF (outfile, " (%s, %d)\n", f->fun_symbol ? f->fun_symbol->sdef_ident->ident_name : "??", i);
}
#endif
switch (m){
case NoMatch:
case PartialInfiniteMatch:
continue;
case InfiniteMatch:
if (new_e)
return new_e;
else
return & bottom;
case PartialMatch:
new_e = TakeContextLub (&new_e, &next_e, p, context);
if (new_e->e_kind == Top && ! new_e->e_deps)
return new_e;
continue;
case TotalMatch:
new_e = TakeContextLub (&new_e, &next_e, p, context);
/* consider it as a partial match if the right hand side leads to a fail reduction */
if (alt->fun_has_fail)
continue;
return new_e;
default:
Assume (False, "unknown case", "GetResultOfFunctionApplication");
}
}
if (new_e)
return new_e;
else
return ⊥
}
static Exp ReduceFunction (Exp e, Path p, Context context)
{
Exp result;
StrictInfo *r;
Context newcontext;
r = &e->e_fun->fun_strictresult;
newcontext = StrictInfoToContext (r, context, True);
result = GetResultOfFunctionApplication (e, p, newcontext);
/* JVG */
if (ReduceInContext (&result, p, newcontext))
/*
if (ReduceInContext (&result, p, context))
*/
return & bottom;
return result;
}
static Exp ReduceStrictFunction (Exp e, Path p, Context context)
{
int arity;
arity = e->e_fun->fun_arity;
if (ReduceInContext (& e->e_args[arity-1], p, context))
return & bottom;
else
return e->e_args[arity-1];
}
static Exp ReduceIfFunction (Exp e, Path p, Context context)
{
Exp cond;
cond = e->e_args[0];
if (cond->e_kind == Value){
Exp e2;
if (cond->e_fun==true_sym)
e2 = e->e_args[1];
else if (cond->e_fun==false_sym)
e2 = e->e_args[2];
else
return TakeContextLub (& e->e_args[1], & e->e_args[2], p, context);
if (ReduceInContext (& e2, p, context))
return & bottom;
else
return e2;
} else
return TakeContextLub (& e->e_args[1], & e->e_args[2], p, context);
}
static Exp ReduceAp (Exp e, Path p, Context context)
{
Exp e2;
unsigned n;
/* walk through the left AP spine, note that this spine is in hnf !! */
for (e2 = e, n = 0; ; e2 = e2->e_args[0], n++){
if (e2->e_kind == Value && e2->e_fun->fun_kind == ApFunction)
continue;
else
break;
}
switch (e2->e_kind){
case Top:
case Dep:
case Ind:
if (IsSpeculativeContext (context))
return e;
else
return NewTop();
case Lub:
{ Exp new_e = Null, next_e;
unsigned arity;
/* if there is a lub, it should be the first element of the spine */
Assume2 (n == 1, "strange Lub in AP spine", "ReduceAp");
/* replace the top most AP by a Lub of reduced AP nodes */
arity = e2->e_sym;
for (n = 0; n < arity; n++){
next_e = NewValueExp (apsym, False, 2);
next_e->e_args[0] = e2->e_args[n];
next_e->e_args[1] = e->e_args[1];
new_e = TakeContextLub (& new_e, & next_e, p, context);
}
return new_e;
}
case Value:
case Bottom:
Assume2 (False, "first arg of AP not reduced, or type error", "ReduceAp");
return NewTop();
case FunValue:
{
unsigned arity;
Exp new;
arity = e2->e_fun->fun_arity;
if (arity != n){
e->e_hnf = True;
return e;
}
new = NewValueExp (e2->e_fun, False, arity);
for (e2 = e, n = arity; n > 0; e2 = e2->e_args[0], n--)
new->e_args[n-1] = e2->e_args[1];
if (ReduceInContext (& new, p, context))
return & bottom;
else
return new;
}
default:
Assume (False, "unknown case", "ReduceAp");
return NewTop();
}
}
static Exp GetSelection (Exp tuple_exp, unsigned n, Path p, Context context)
{
switch (tuple_exp->e_kind){
case Top:
case Dep:
case Ind:
return NewTop();
case Bottom:
return & bottom;
case Value:
{ ExpP argp;
/* JVG: added 14-8-2000 */
if (!tuple_exp->e_hnf)
return NewTop();
/* */
if (n >= tuple_exp->e_fun->fun_arity)
return & bottom;
argp = & tuple_exp->e_args [n];
if (ReduceInContext (argp, p, context))
return & bottom;
else
return *argp;
}
default:
Assume (False, "illegal case", "GetSelection");
return ⊤
}
}
static Exp ReduceSelector (Exp e, Path p, Context context)
{
Exp tuple_exp, new_e;
unsigned i, arity;
tuple_exp = e->e_args[0];
if (tuple_exp->e_kind == Lub){
/* try to take the selections of the elements of the lub */
arity = tuple_exp->e_sym;
new_e = NewExp (Lub, arity, True, arity);
for (i = 0; i < arity; i++)
new_e->e_args[i] = GetSelection (tuple_exp->e_args[i], e->e_fun - selectsym[0], p, context);
if (new_e->e_kind == Lub)
SortExpOfKind (new_e, Lub);
return new_e;
}
else
return GetSelection (tuple_exp, e->e_fun - selectsym[0], p, context);
}
/* The reduction engine */
static void ReduceArguments (Exp e)
{
unsigned i, arity;
arity = e->e_fun->fun_arity;
for (i = 0; i < arity; i++){
#if 0 && defined (_DB_)
printf ("Reduce argument %d\n",i);
#endif
(void) ReduceInContext (& e->e_args[i], (Path) Null, NewSimpleContext (HnfStrict, True));
#if 0 && defined (_DB_)
printf ("End reduce argument %d\n",i);
#endif
}
}
static Exp MakeIndirection (Exp e)
{
Exp new;
new = NewExp (Ind, 0, True, 1);
new->e_deps = SAllocType (DependencyRepr);
new->e_deps->dep_exp = e;
new->e_deps->dep_next = Null;
new->e_args[0] = e;
return new;
}
static void Reduce (ExpP ep, Path p, Context context)
{
Exp e2,e;
e = *ep;
if (e->e_kind==Dep){
if (ReduceDepExpression (e, p, context)){
UpdateExp (& bottom, e);
e->e_red = False;
}
return;
}
Assume (e->e_kind == Value, "illegal expression kind", "Reduce");
/* mark the node is being under reduction. The marking should be removed
before returning
*/
e->e_red = True;
#ifdef DIVIDE_FUEL
{
unsigned int saved_fuel1,saved_fuel2;
saved_fuel1=(start_fuel>>2);
saved_fuel2=(start_fuel>>1);
start_fuel-=saved_fuel1;
#endif
if (CheckStrictArgsOfFunction (e, p, context)){
#ifdef DIVIDE_FUEL
start_fuel+=saved_fuel1;
#endif
e = *ep;
UpdateExp (& bottom, e);
e->e_red = False;
return;
}
#ifdef DIVIDE_FUEL
start_fuel+=saved_fuel1;
#endif
if (e->e_fun->fun_kind==Function && StrictDoEager){
#ifdef DIVIDE_FUEL
if (start_fuel>saved_fuel2){
start_fuel-=saved_fuel2;
#endif
e = *ep;
/* JVG added 23-1-2003: */
if (e->e_kind==Value && e->e_fun->fun_kind==Function)
/* */
ReduceArguments (e);
#ifdef DIVIDE_FUEL
start_fuel+=saved_fuel2;
}
#endif
}
#ifdef DIVIDE_FUEL
}
#endif
/* NOTE: the arguments have to be reduced before the next switches
statement, because 'ep' itself might be reduced by the above call
*/
e = *ep;
if (e->e_kind != Value)
return;
switch (e->e_fun->fun_kind){
case Constructor:
e->e_red = False;
e->e_hnf = True;
return;
case Function:
e2 = ReduceFunction (e, p, context);
break;
case IfFunction:
e2 = ReduceIfFunction (e, p, context);
break;
case ApFunction:
e2 = ReduceAp (e, p, context);
break;
case SelFunction:
e2 = ReduceSelector (e, p, context);
break;
case StrictFunction:
e2 = ReduceStrictFunction (e, p, context);
break;
case FailFunction:
e2 = & bottom;
break;
default:
Assume (False, "illegal function kind", "Reduce");
return;
}
e->e_red = False;
UpdateExp (e2, e);
}
static Bool CheckEndOfReductions (ExpP ep, Path p, Context context, Bool *result)
{
Exp root, e;
e = *ep;
/* check the reduction context */
if (! IsStrictContext (context))
return True;
/* check for hnf and simple context */
if (e->e_hnf){
/* JVG ??? 2-10-1998 */
if (e->e_kind==Bottom){
*result = True;
return True;
}
/* */
if (context->context_arity == 1){
*result = e->e_kind == Bottom;
return True;
}
}
/* check if expression is already evaluated in speculative context */
if (IsSpeculativeContext (context) && e->e_spechnf)
return True;
/* check if current exp is already under reduction */
if (e->e_red){
*ep = MakeIndirection (e);
/* JVG changed 23-1-2003: */
e->e_hasind = True;
/*
(*ep)->e_hasind = True;
*/
#ifdef _DB_RED_
if (DBPrinting){
FPrintF (outfile, "Result is indirection: ");
DumpExp (outfile, *ep);
FPutC ('\n', outfile);
}
#endif
return True;
}
#ifdef _DB_RED_
if (DBPrinting){
FPrintF (outfile, "Reduce (%u ", start_fuel);
DumpContext (outfile, context);
FPutS ("): ", outfile);
DumpExp (outfile, *ep);
FPrintF (outfile, "\n Path: ");
DumpPath (outfile, p);
FPutC ('\n', outfile);
}
#endif
/* check current reduction fuel */
if (OutOfFuel()){
/* JVG added */
if (e->e_kind!=Bottom)
/* */
UpdateExp (& top, e);
if (! max_time_reached){
if (StrictAllWarning)
GiveStrictWarning (CurrentName,"out of fuel (result approximated)");
else
time_warning = True;
max_time_reached = True;
}
#ifdef _DB_RED_
if (DBPrinting)
FPrintF (outfile, "Result is approximated\n");
#endif
return True;
}
/* check if exp is in current path */
if (IsInPath (e, p, & root, context)){
*ep = MakeIndirection (root);
root->e_hasind = True;
#ifdef _DB_RED_
if (DBPrinting){
FPrintF (outfile, "Result is Indirection: ");
DumpExp (outfile, *ep);
FPutC ('\n', outfile);
}
#endif
return True;
}
return False;
}
static Bool ReduceInContext (ExpP ep, Path p, Context context)
{
Exp e;
Path newp;
Bool result = False;
#ifdef _DB_RED_
unsigned e_fuel = start_fuel;
#endif
#ifdef CHECK_STACK_OVERFLOW
char x;
if (&x < min_stack){
printf ("Stack overflow in ReduceInContext\n");
#ifdef _DB_
FPrintF (outfile, "Stack overflow in ReduceInContext\n");
#endif
/* JVG added */
if ((*ep)->e_kind!=Bottom)
/* */
UpdateExp (& top, *ep);
return False;
}
#endif
/* start with some checks which result in easy returns */
if (CheckEndOfReductions (ep, p, context, & result))
return result;
e = *ep;
newp = AddToPath (e, p);
if (! e->e_hnf){
e->e_hasind = False;
Reduce (ep, newp, context);
}
ResolveIndirections (ep, p, context);
e = *ep;
result = False;
if (e->e_kind == Bottom)
result = True;
else if (IsSpeculativeContext (context)){
e->e_spechnf = True;
result = (e->e_kind == Bottom);
} else {
/* JVG */
if (e->e_kind==Value && e->e_fun->fun_kind!=Constructor && ! e->e_hnf && ! ContainsIndirection (e))
/*
Bool cont_ind;
cont_ind = ContainsIndirection (e);
if (e->e_kind == Value && e->e_fun->fun_kind != Constructor && ! e->e_hnf && ! cont_ind)
*/
UpdateExp (& top, e);
}
#ifdef _DB_RED_
if (DBPrinting){
FPrintF (outfile, "Result (%d): ", e_fuel);
DumpExp (outfile, e);
FPutC ('\n', outfile);
FPutC ('\n', outfile);
}
#endif
if (result == True)
return True;
else if (context->context_arity == 1){
switch (context->context_kind){
case SpineStrict:
if (e->e_kind == Value && e->e_fun==conssym){
if (ReduceInContext (& e->e_args[1], p, context))
return True;
}
if (LtExp ((*ep), & inf) == True)
return True;
break;
case TailStrict:
if (e->e_kind == Value && e->e_fun==conssym){
if (ReduceInContext (& e->e_args[1], p, context))
return True;
if (ReduceInContext (& (*ep)->e_args[0], p, NewSimpleContext (HnfStrict, False)))
return True;
}
if (LtExp ((*ep), & botmem) == True)
return True;
break;
default:
return result;
}
} else {
unsigned i, arity = context->context_arity;
if (IsTupleExp (e)){
#if 1
/* JVG: added 15-8-2000 */
Dependency new_e_deps;
new_e_deps=e->e_deps;
for (i=0; i<arity; i++){
Context arg_context;
arg_context=context->context_args[i];
if (ReduceInContext (&e->e_args[i],p,arg_context)){
(*ep) = (*ep)->e_args[i] = ⊥
return True;
}
if (IsStrictContext (arg_context) && e->e_args[i]->e_kind!=Bottom){
Dependency from_dep;
for_l (from_dep,e->e_args[i]->e_deps,dep_next){
Dependency old_dep;
Exp from_dep_exp;
from_dep_exp=from_dep->dep_exp;
for_l (old_dep,new_e_deps,dep_next)
if (old_dep->dep_exp==from_dep_exp)
break;
if (old_dep==NULL){
Dependency new_dep;
new_dep = SAllocType (DependencyRepr);
new_dep->dep_exp = from_dep_exp;
new_dep->dep_next = new_e_deps;
new_e_deps = new_dep;
}
}
}
}
e->e_deps=new_e_deps;
#else
for (i=0; i<arity; i++){
if (ReduceInContext (& e->e_args[i], p, context->context_args[i])){
(*ep) = (*ep)->e_args[i] = ⊥
return True;
}
}
#endif
} else {
if (e->e_kind==Lub){
for (i=0; i<(*ep)->e_sym; i++){
if (!ReduceInContext (& (*ep)->e_args[i], p, context))
return False;
(*ep)->e_args[i] = & bottom;
}
return True;
} else
return False;
}
}
#ifdef _DB_RED_
if (DBPrinting){
FPrintF (outfile, "Result (%d): ", e_fuel);
DumpExp (outfile, *ep);
FPutC ('\n', outfile);
FPutC ('\n', outfile);
}
#endif
return result;
}
/* The initialisation functions */
static unsigned found_strict; /* the number of found strict args */
static Fun * cur_funct; /* the current function id */
static unsigned cur_argnr; /* the current argument number */
static Exp BuildTupleExp (StrictInfo *s, Exp bottomelem)
{ Exp e;
if (s->strict_arity < 0)
{ s->strict_arity = -s->strict_arity;
e = bottomelem;
}
else if (! IsTupleInfo (s))
e = NewTop();
else
{ unsigned arity, i;
arity = s->strict_arity;
e = NewValueExp (tuplesym[arity], True, arity);
for (i = 0; i < arity; i++)
e->e_args[i] = BuildTupleExp (& GetTupleInfo (s, i), bottomelem);
}
return e;
}
static Exp BuildApplicationWithBottom (StrictKind argkind, StrictKind context)
{
Exp e, bottom_elem;
unsigned i;
unsigned arity;
arity = cur_funct->fun_arity;
/* set the general values of the expression */
bottom_elem = & bottom;
e = NewValueExp (cur_funct, False, arity);
/* set all arguments to top */
for (i = 0; i < arity; i++)
e->e_args[i] = NewTop();
/* set the right argument to bottom, inf ... */
switch (argkind){
case NotStrict:
return e;
case HnfStrict:
bottom_elem = & bottom;
break;
case SpineStrict:
Assume2 (IsListArg (cur_funct,cur_argnr), "BuildAppWithBot" , "??");
if (IsListArg (cur_funct,cur_argnr))
bottom_elem = & inf;
else
bottom_elem = & bottom;
break;
case TailStrict:
Assume2 (IsListArg (cur_funct,cur_argnr), "BuildAppWithBot" , "??");
if (IsListArg (cur_funct,cur_argnr))
bottom_elem = & botmem;
else
bottom_elem = & bottom;
break;
}
e->e_args[cur_argnr] = BuildTupleExp (&cur_funct->fun_strictargs[cur_argnr], bottom_elem);
/* set the outermost function */
switch (context){
case NotStrict:
case HnfStrict:
return e;
case SpineStrict:
{ Exp e2;
e2 = NewValueExp (inffunct_sym, False, 1);
e2->e_args[0] = e;
return e2;
}
case TailStrict:
{ Exp e2;
e2 = NewValueExp (botmemfunct_sym, False, 1);
e2->e_args[0] = e;
return e2;
}
}
return e;
}
static void SetStrict (StrictInfo *s, StrictKind kind, unsigned k)
{
unsigned i;
if (s == &cur_funct->fun_strictargs[cur_argnr])
found_strict++;
if (IsTupleInfo (s))
GetTupleStrictKind (s) = kind;
else {
if (! IsListArg (cur_funct, cur_argnr) && kind != NotStrict)
kind = HnfStrict;
for (i = k; i < 3; i++)
GetStrictKind (s, i) = MaxStrict (GetStrictKind (s, i), kind);
}
}
static Bool CheckIfStrict (StrictKind arg_kind, StrictKind context)
{
Bool result;
Exp e;
unsigned m;
SetStartFuel();
if (setjmp (SAEnv2) == 0){
e = BuildApplicationWithBottom (arg_kind, context);
result = ReduceInContext (& e, (Path) Null, NewSimpleContext (context, False));
} else
result = False;
m = MemUse ();
if (m > max_memuse)
max_memuse = m;
FreeUnFreezedBlocks();
return (result || e->e_kind == Bottom);
}
static void FindStrictPropsOfStrictInfo (StrictInfo *s, StrictKind arg_kind, StrictKind context)
{
unsigned i,index;
if (! context)
return;
index = ContextToIndex (context);
if (IsTupleInfo (s)){
/* We allow no contexts for lists within a tuple at the moment */
if (context == SpineStrict || context == TailStrict)
return;
if (GetTupleStrictKind (s) == NotStrict){
s->strict_arity = - s->strict_arity;
if (CheckIfStrict (arg_kind, context))
SetStrict (s, HnfStrict, index);
}
/* Find strictness properties of arguments of tuple */
if (context != HnfStrict)
;
else if (GetTupleStrictKind (s) == HnfStrict){
for (i = 0; i < s->strict_arity; i++)
FindStrictPropsOfStrictInfo (& GetTupleInfo(s, i), arg_kind, context);
}
} else {
if (GetStrictKind (s, index) < arg_kind){
s->strict_arity = - s->strict_arity;
if (CheckIfStrict (arg_kind, context))
SetStrict (s, arg_kind, index);
}
}
if (s->strict_arity < 0)
s->strict_arity = - s->strict_arity;
}
static void DeriveStrictness (Fun *f, unsigned arg, StrictKind arg_kind, StrictKind context)
{
cur_funct = f;
cur_argnr = arg;
FindStrictPropsOfStrictInfo (&f->fun_strictargs[arg], arg_kind, context);
}
#define IsAnalysableFun(A) (! (A)->fun_symbol->sdef_no_sa &&\
(A)->fun_arity != 0 &&\
(A)->fun_kind == Function)
static void FindStrictPropertiesOfFunction (Fun *f)
{
unsigned arity,n;
/* ContextRepr context; */
n = 0;
arity = f->fun_arity;
if (! IsAnalysableFun (f))
return;
max_depth_reached = False;
max_time_reached = False;
CurrentName = f->fun_symbol->sdef_ident->ident_name;
#if 0
printf ("%s\n",CurrentName);
#endif
#ifdef _DB_
DBPrinting = 1; /* strcmp ("catenate", CurrentName) == 0; */
#endif
#ifdef _DB_STACK_
if (DBPrinting)
FPrintF (outfile, "--> %s\n", CurrentName);
#endif
/* Check if function might terminate, currently disabled since all args
have to be changed!! */
/* DeriveStrictness (f, 0, NotStrict, SimpleContext (&context, HnfStrict, False)); */
/* Check for normal strictness in argument */
for (n = 0; n < arity; n++)
DeriveStrictness (f, n, HnfStrict, HnfStrict);
/* Check for special kinds of strictness in the case of lists */
if (StrictDoLists){
Bool list_result;
list_result = HasListResult (f);
for (n = 0; n < arity; n++){
if (! IsListArg (f, n))
continue;
/* Hnf context */
DeriveStrictness (f, n, SpineStrict, HnfStrict);
DeriveStrictness (f, n, TailStrict, HnfStrict);
if (! list_result)
continue;
/* Spine context */
DeriveStrictness (f, n, SpineStrict, SpineStrict);
DeriveStrictness (f, n, TailStrict, SpineStrict);
/* Tail context */
DeriveStrictness (f, n, SpineStrict, TailStrict);
DeriveStrictness (f, n, TailStrict, TailStrict);
}
}
#ifdef _DB_TEST_
if (StrictDoVerbose)
{ FPrintF (StdOut, "(%4d)%15s ", (int) start_fuel, f->fun_symbol->sdef_ident->ident_name);
DumpStrictInfoOfFunction (StdOut, f);
FPutC ('\n', StdOut);
}
#endif
}
#ifdef _DB_TEST_
static void PrintFoundStrictArgs (File w)
{
unsigned perc,nr_args;
SymbDef sdef;
nr_args = 0;
for_l (sdef,scc_dependency_list,sdef_next_scc)
if (sdef->sdef_kind==IMPRULE && sdef->sdef_over_arity==0){
Fun *f;
f=sdef->sdef_sa_fun;
if (! StrictDoVerbose)
{ FPrintF (StdOut, "%15s ", f->fun_symbol->sdef_ident->ident_name);
DumpStrictInfoOfFunction (StdOut, f);
FPutC ('\n', StdOut);
}
nr_args += f->fun_arity;
}
if (nr_args == 0)
perc = 100;
else
perc = (100 * found_strict) / nr_args;
FPrintF (w, "\n%d strict arguments found (%d%%), %d Kbyte used\n", found_strict, perc, max_memuse);
}
#endif
int init_strictness_analysis (ImpMod imod)
{
StrictWarning = DoStrictWarning;
StrictAllWarning = DoStrictAllWarning;
StrictChecks = DoStrictCheck;
StrictExportChecks = DoStrictExportChecks;
Verbose ("Strictness analysis");
/* Initialise all */
#ifdef _DB_
cur_add = 1;
/* outfile = StdOut; */
outfile = fopen ("SADump","w");
/* StrictDoLists = True; */
DBPrinting = False;
#endif
#if CLEAN2
strict_positions = NULL;
#endif
max_memuse = 0;
found_strict = 0;
initialising = True;
FreeBlocks ();
/* to be inited before converting the syntaxtree */
InitExp (&top, Top, 0, True);
InitExp (&bottom, Bottom, 0, True);
if (setjmp (SAEnv) == 0){
ConvertSyntaxTree (imod->im_symbols);
/* other values are converted after syntaxconversion (because of cons symbol) */
InitValues ();
/*
dump the table (DB mode only)
DumpTable (StdOut);
return;
*/
FreezeAlloc ();
initialising = False;
return True;
} else {
FreeBlocks ();
if (StrictWarning)
GiveStrictWarning (NULL,"not enough memory for strictness analysis");
#ifdef _DB_
FClose (outfile);
#endif
return False;
}
}
void do_strictness_analysis (void)
{
#ifdef CHECK_STACK_OVERFLOW
char x;
min_stack = &x - 20*1024;
#endif
depth_warning = False;
time_warning = False;
export_warning = False;
mem_warning = False;
/* Do the analysis */
{
SymbDef sdef;
for_l (sdef,scc_dependency_list,sdef_next_scc)
if (sdef->sdef_kind==IMPRULE && sdef->sdef_over_arity==0)
FindStrictPropertiesOfFunction (sdef->sdef_sa_fun);
}
UpdateSyntaxTree();
#ifdef _DB_TEST_
PrintFoundStrictArgs (StdOut);
#endif
#ifdef _DB_
FClose (outfile);
#endif
#if 0
if (StrictWarning){
if (mem_warning || depth_warning || time_warning)
GiveStrictWarning (NULL, "derived strictness properties approximated");
} else
#endif
if (StrictAllWarning){
if (mem_warning)
GiveStrictWarning (NULL,"strictness analysis out of memory (result approximated)");
if (depth_warning)
GiveStrictWarning (NULL,"max depth reached in strictness analysis (result approximated)");
if (time_warning)
GiveStrictWarning (NULL,"max time needed in strictness analysis (result approximated)");
}
if (StrictWarning && export_warning)
GiveStrictWarning ((char *) Null, "not all derived strictness information is exported");
free_unused_sa_blocks();
}
void finish_strictness_analysis (void)
{
if (n_allocated_blocks!=0){
if (bottom.e_kind!=Bottom || bottom.e_hnf!=True || top.e_kind!=Top || top.e_hnf!=True)
ErrorInCompiler ("sa","","Bottom or top changed");
FreeBlocks();
}
}
void StrictnessAnalysis (ImpMod imod)
{
if (init_strictness_analysis (imod)){
do_strictness_analysis();
finish_strictness_analysis();
}
}
int StrictnessAnalysisConvertRules (ImpRuleS *rules)
{
if (initialising)
return 0;
initialising=True;
if (setjmp (SAEnv)==0){
ImpRuleS *rule;
for_l (rule,rules,rule_next)
convert_imp_rule_type (rule->rule_root->node_symbol->symb_def);
for_l (rule,rules,rule_next)
convert_imp_rule_alts (rule->rule_root->node_symbol->symb_def);
FreezeAlloc();
initialising = False;
return 1;
} else {
FreeUnFreezedBlocks();
if (StrictWarning)
GiveStrictWarning (NULL,"not enough memory for strictness analysis of all functions");
return 0;
}
}
void StrictnessAnalysisForRule (SymbDef sdef)
{
FindStrictPropertiesOfFunction (sdef->sdef_sa_fun);
update_function_strictness (sdef);
}