diff options
Diffstat (limited to 'backendC/CleanCompilerSources/codegen2.c')
-rw-r--r-- | backendC/CleanCompilerSources/codegen2.c | 5441 |
1 files changed, 5441 insertions, 0 deletions
diff --git a/backendC/CleanCompilerSources/codegen2.c b/backendC/CleanCompilerSources/codegen2.c new file mode 100644 index 0000000..4dcfd77 --- /dev/null +++ b/backendC/CleanCompilerSources/codegen2.c @@ -0,0 +1,5441 @@ +/* + (Concurrent) Clean Compiler: Code Generator + + Authors: Sjaak Smetsers & John van Groningen + At: University of Nijmegen, department of computing science + Version: 1.2 +*/ + +#pragma segment codegen2 +#pragma options (!macsbug_names) + +#define FASTER_STRICT_IF /* also in statesgen.c */ +#define DO_LAZY_SELECTORS_FROM_BOXED_STRICT_RECORDS +#define FREE_STRICT_LHS_TUPLE_ELEMENTS 1 /* also in codegen1.c */ +#define SELECTORS_FIRST 1 /* also in codegen.c */ + +#include "system.h" +#include "syntaxtr.t" +#include "comsupport.h" + +#include "settings.h" +#include "sizes.h" +#include "checker.h" +#include "codegen_types.h" +#include "codegen.h" +#include "codegen1.h" +#include "codegen2.h" +#include "sa.h" +#include "statesgen.h" +#include "transform.h" +#include "instructions.h" +#include "typechecker.h" +#include "optimisations.h" +#include "buildtree.h" + +#define for_l(v,l,n) for(v=(l);v!=NULL;v=v->n) +#define for_li(v,i,l,n) for(v=(l),i=0;v!=NULL;v=v->n,++i) +#define for_ll(v1,v2,l1,l2,n1,n2) for(v1=(l1),v2=(l2);v1!=NULL;v1=v1->n1,v2=v2->n2) +#define for_la(v1,v2,l1,l2,n1) for(v1=(l1),v2=(l2);v1!=NULL;v1=v1->n1,++v2) + +static void error_in_function (char *m) +{ + ErrorInCompiler ("codegen2.c",m,""); +} + +char *Co_Wtype = "incorrect type"; +char *Co_Wspine = "non-terminating rule specified"; + +char else_symb[] = "else"; +char then_symb[] = "then"; +char notused_string[] = "notused"; + +SymbDef ApplyDef,IfDef; + +unsigned NewLabelNr; + +StateS StrictOnAState; +static StateS UnderEvalState,ProcIdState; + +StateS OnAState; + +Bool LazyTupleSelectors [MaxNodeArity-NrOfGlobalSelectors]; + +LabDef BasicDescriptors [NrOfObjects]; +int ObjectSizes [NrOfObjects]; + +static void InitBasicDescriptor (ObjectKind kind,char *name,int size) +{ + BasicDescriptors[kind].lab_mod = NULL; + BasicDescriptors[kind].lab_pref = no_pref; + BasicDescriptors[kind].lab_issymbol = False; + BasicDescriptors[kind].lab_name = name; + BasicDescriptors[kind].lab_post = 0; + ObjectSizes[kind] = size; +} + +Bool EqualState (StateS st1,StateS st2) +{ + if (IsSimpleState (st1) && IsSimpleState (st2)) + return st1.state_kind==st2.state_kind; + + switch (st1.state_type){ + case RecordState: + return st2.state_type==RecordState; + case TupleState: + if (st2.state_type==TupleState && st1.state_arity==st2.state_arity){ + int i; + + for (i=0; i<st1.state_arity; i++) + if (!EqualState (st1.state_tuple_arguments[i],st2.state_tuple_arguments[i])) + return False; + + return True; + } else + return False; + case ArrayState: + return st2.state_type==ArrayState; + default: + return False; + } +} + +/* int InitAStackTop,InitBStackTop; */ + +void NewEmptyNode (int *asp_p,int nrargs) +{ + GenCreate (nrargs); + *asp_p += SizeOfAStackElem; +} + +void save_node_id_state (NodeId node_id,SavedNidStateS **saved_nid_state_l) +{ + SavedNidStateP new_saved_state; + + new_saved_state=CompAllocType (SavedNidStateS); + + new_saved_state->save_state=node_id->nid_state; + new_saved_state->save_node_id=node_id; + + new_saved_state->save_next=*saved_nid_state_l; + *saved_nid_state_l=new_saved_state; +} + +void restore_saved_node_id_states (SavedNidStateP saved_node_id_states) +{ + while (saved_node_id_states){ + saved_node_id_states->save_node_id->nid_state_=saved_node_id_states->save_state; + saved_node_id_states=saved_node_id_states->save_next; + } +} + +static Bool CopyArgument (StateS demstate,StateS offstate,int aindex,int bindex,int *asp_p,int *bsp_p,int offasize,int offbsize,Bool newnode); + +static void GenProcIdCalculation (Node node,Annotation annot,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + if (annot==ParallelAtAnnot){ + Node procidnode; + + procidnode=get_p_at_node (node); + if (procidnode->node_kind!=NodeIdNode) + Build (procidnode,asp_p,bsp_p,code_gen_node_ids_p); + else { + int asize,bsize; + NodeId nid; + + nid=procidnode->node_node_id; + + DetermineSizeOfState (nid->nid_state,&asize,&bsize); + CopyArgument (ProcIdState,nid->nid_state,nid->nid_a_index,nid->nid_b_index,asp_p,bsp_p,asize,bsize,False); + } + } else { + GenNewP(); + ++*bsp_p; + } +} + +static void GenRedIdCalculation (Node redidnode,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + if (redidnode){ + if (redidnode->node_kind!=NodeIdNode) + Build (redidnode,asp_p,bsp_p,code_gen_node_ids_p); + else { + int asize,bsize; + NodeId nid; + + nid=redidnode->node_node_id; + + DetermineSizeOfState (nid->nid_state,&asize, &bsize); + CopyArgument (ProcIdState,nid->nid_state,nid->nid_a_index,nid->nid_b_index,asp_p,bsp_p,asize, bsize, False); + } + } else + GenPushReducerId (-1); +} + +static char *GetReducerCode (Annotation annot) +{ + switch (annot) + { case ParallelAnnot: + case ParallelAtAnnot: + return ext_hnf_reducer_code; + case ParallelNFAnnot: + return ext_nf_reducer_code; + default: + return ""; + } +} + +void UnpackRecord (int aindex,int *asp_p,int *bsp,Bool removeroot,int arity,States argstates) +{ + int asize,bsize; + + DetermineSizeOfStates (arity, argstates, & asize, & bsize); + + if (removeroot) + GenReplRArgs (asize, bsize); + else + GenPushRArgs (*asp_p - aindex, asize , bsize); + *asp_p += asize; + *bsp += bsize; +} + +static void UnpackArrayOnTopOfStack (void) +{ + GenPushArray (0); +#if UPDATE_POP + GenUpdatePopA (0,1); +#else + GenUpdateA (0,1); + GenPopA (1); +#endif +} + +void UnpackArray (int aindex, int *asp_p, Bool removeroot) +{ + if (removeroot){ + GenPushArray (0); +#if UPDATE_POP + GenUpdatePopA (0,1); +#else + GenUpdateA (0,1); + GenPopA (1); +#endif + } else + GenPushArray (*asp_p - aindex); + + *asp_p += SizeOfAStackElem; +} + +Coercions CoerceStateKind (StateKind dem_state_kind, StateKind off_state_kind) +{ + if (dem_state_kind==Undefined) + error_in_function ("CoerceStateKind"); + + switch (off_state_kind){ + case OnB: + if (dem_state_kind == OnB) + return BToB; + else + return BToA; + case OnA: + case SemiStrict: + case LazyRedirection: + if (dem_state_kind == OnA) + return AToA; + else + return Reduce; + case StrictOnA: + if (dem_state_kind == OnB) + return AToB; + else + return AToA; + case StrictRedirection: + if (dem_state_kind == OnB) + return AToB; + else if (dem_state_kind == StrictRedirection) + return AToA; + else + return AToRoot; + case Parallel: + if (dem_state_kind == OnA) + return AToA; + else + StaticMessage (False, "","parallel annotation in strict context ignored"); + return Reduce; + case UnderEval: + if (dem_state_kind == OnA) + return MayBecomeCyclicSpine; + else + return CyclicSpine; + default: + error_in_function ("CoerceStateKind"); + return AToA; + } +} + +Bool TypeErrorFound, CycleErrorFound; + +void GenReduceError (void) +{ + GenDAStackLayout (0); + GenJsr (&cycle_lab); + GenOAStackLayout (0); + + CycleErrorFound = True; +} + +Coercions CoerceSimpleStateArgument (StateS demstate,StateKind offkind,int aindex,int *asp_p,Bool leaveontop, Bool *ontop) +{ + Coercions c; + + /* Examine the argument states to see whether it has to be reduced */ + + if (IsSimpleState (demstate)) + c = CoerceStateKind (demstate.state_kind, offkind); + else + c = CoerceStateKind (StrictOnA, offkind); + + switch (c){ + case Reduce: + if (leaveontop){ + GenPushA (*asp_p - aindex); + GenJsrEval (0); + *asp_p += SizeOfAStackElem; + *ontop = True; + } else { + GenJsrEval (*asp_p - aindex); + *ontop = False; + } + break; + case MayBecomeCyclicSpine: + GenCreate (-1); + *asp_p += SizeOfAStackElem; + *ontop = True; + break; + case CyclicSpine: + GenReduceError (); + StaticMessage (False,CurrentAltLabel.lab_symbol->sdef_ident->ident_name,Co_Wspine); + *ontop = False; + break; + default: + *ontop = False; + break; + } + + return c; +} + +static StateKind AdjustStateKind (StateKind statekind, Coercions c) +{ + switch (c){ + case Reduce: + return StrictOnA; + case MayBecomeCyclicSpine: + return OnA; + default: + return statekind; + } +} + +static void CoerceArgumentsUsingStackFrames (int arity,States demstates,States offstates,int aindex,int bindex, + int *asp_p, int *bsp, int *anext, int *bnext, int asize, int bsize); + +void CoerceArgumentUsingStackFrames (StateS demstate, StateS offstate,int aindex,int bindex,int *asp_p,int *bsp, + int *anext,int *bnext,int asize,int bsize) +{ + if (IsSimpleState (demstate) && demstate.state_kind==Undefined) + return; + + if (IsSimpleState (offstate)){ + Coercions c; + Bool ontop; + StateKind offkind; + + ontop = False; + offkind = offstate.state_kind; + + c = CoerceSimpleStateArgument (demstate, offkind, aindex, asp_p, False, &ontop); + offkind = AdjustStateKind (offkind, c); + + Assume (! ontop,"codegen","CoerceArgumentUsingStackFrames"); + + if (IsSimpleState (demstate)){ + switch (CoerceStateKind (demstate.state_kind, offkind)){ + case AToA: + case AToRoot: + PutInAFrames (aindex, anext); + return; + case AToB: + PushBasicFromAOnB (demstate.state_object, *asp_p - aindex); + *bsp += ObjectSizes [demstate.state_object]; + PutInBFrames (*bsp, bnext, ObjectSizes [demstate.state_object]); + return; + case BToA: + ++*asp_p; + BuildBasicFromB (offstate.state_object,*bsp - bindex); + PutInAFrames (*asp_p, anext); + return; + case BToB: + PutInBFrames (bindex, bnext, ObjectSizes [demstate.state_object]); + return; + default: + ; + } + } else { + switch (demstate.state_type){ + case TupleState: + /* + A tuple is demanded whereas a node is offered. + Each argument is converted to its demanded state. Note that + the offered state of each argument after pushing it on + the stack is 'OnAState'. + */ + { + int i,arity,index; + States argstates; + + arity = demstate.state_arity; + argstates = demstate.state_tuple_arguments; + + GenPushArgs (*asp_p - aindex, arity, arity); + *asp_p += arity; + index = *asp_p; + + for (i=arity-1; i>=0; i--) + CoerceArgumentUsingStackFrames (argstates [i], OnAState,index-i, 0, asp_p, bsp, anext, bnext, 1, 0); + break; + } + case RecordState: + { + int asize,bsize,arity; + States argstates; + + arity = demstate.state_arity; + argstates = demstate.state_record_arguments; + + DetermineSizeOfStates (arity, argstates, &asize, &bsize); + GenPushRArgs (*asp_p - aindex, asize , bsize); + *asp_p += asize; + *bsp += bsize; + CoerceArgumentsUsingStackFrames (arity, argstates, argstates,*asp_p,*bsp, asp_p, bsp, anext, bnext, asize, bsize); + break; + } + case ArrayState: + GenPushArray (*asp_p-aindex); + *asp_p += 1; + PutInAFrames (*asp_p, anext); + break; + } + } + } else if (IsSimpleState (demstate)){ + switch (offstate.state_type){ + case TupleState: + BuildTuple (aindex, bindex, *asp_p, *bsp,offstate.state_arity, offstate.state_tuple_arguments, + asize,bsize,*asp_p,NormalFill,True); + *asp_p += SizeOfAStackElem; + break; + case RecordState: + BuildRecord (offstate.state_record_symbol,aindex, bindex, *asp_p, *bsp, + asize,bsize,*asp_p,NormalFill,True); + *asp_p += SizeOfAStackElem; + break; + case ArrayState: + GenBuildArray (*asp_p-aindex); + ++*asp_p; + break; + } + PutInAFrames (*asp_p, anext); + } else { + switch (offstate.state_type){ + case TupleState: + CoerceArgumentsUsingStackFrames + (demstate.state_arity, demstate.state_tuple_arguments, + offstate.state_tuple_arguments, aindex, bindex, asp_p, bsp, anext, bnext, + asize, bsize); + break; + case RecordState: + CoerceArgumentsUsingStackFrames + (demstate.state_arity,demstate.state_record_arguments, + offstate.state_record_arguments, aindex, bindex, asp_p, bsp, anext, bnext, + asize, bsize); + break; + case ArrayState: + PutInAFrames (aindex, anext); + break; + } + } +} + +static void CoerceArgumentsUsingStackFrames (int arity, StateS demstates[], StateS offstates[],int aindex, int bindex, + int *asp_p, int *bsp, int *anext, int *bnext,int asize, int bsize) +{ + int i; + + aindex -= asize; + bindex -= bsize; + + for (i=arity-1; i>=0; i--){ + int asize,bsize; + + DetermineSizeOfState (offstates[i],&asize, &bsize); + aindex += asize; + bindex += bsize; + + CoerceArgumentUsingStackFrames (demstates [i],offstates [i],aindex,bindex,asp_p,bsp,anext,bnext,asize,bsize); + } +} + +void AdjustTuple (int localasp,int localbsp,int *asp_p,int *bsp_p,int arity,StateS demstates[],StateS offstates[],int asize,int bsize) +{ + int a_ind,b_ind,dummy,oldamax,oldbmax,newamax,newbmax; + + a_ind=0; + b_ind=0; + dummy = 0, + + newamax = localasp + 1 + arity; + newbmax = localbsp + 1; + AddStateSizesAndMaxFrameSizes (arity, demstates, &newamax, &dummy, &newbmax); + + InitStackConversions (newamax, newbmax, &oldamax, &oldbmax); + + CoerceArgumentsUsingStackFrames (arity, demstates, offstates, localasp, localbsp, + &localasp, &localbsp, &a_ind, &b_ind, asize, bsize); + + GenAStackConversions (localasp,a_ind); + GenBStackConversions (localbsp,b_ind); + + ExitStackConversions (oldamax, oldbmax); + + *asp_p += a_ind-asize; + *bsp_p += b_ind-bsize; +} + +void UnpackTuple (int aindex,int *asp_p,int *bsp_p,Bool removeroot,int arity,StateS argstates[]) +{ + int aselmts,oldaframesize,locasp,asize,maxasize; + + aselmts = 0; + locasp = arity; + asize = 0; + maxasize = arity; + + if (removeroot) + GenReplArgs (arity, arity); + else + GenPushArgs (*asp_p- aindex, arity, arity); + + AddStateSizesAndMaxFrameSizes (arity, argstates, &maxasize, &asize,bsp_p); + + InitAStackConversions (maxasize+1, &oldaframesize); + + EvaluateAndMoveArguments (arity,argstates,&locasp,&aselmts); + + GenAStackConversions (locasp,aselmts); + + FreeAFrameSpace (oldaframesize); + *asp_p += aselmts; +} + +static void MoveArgumentsFromBToA (int arity,States argstates,int aindex,int bindex,int asp_p,int bsp,int asize,int bsize) +{ + int i; + + aindex -= asize; + bindex -= bsize; + + for (i=arity-1; i>=0; i--){ + DetermineSizeOfState (argstates[i],&asize, &bsize); + aindex += asize; + bindex += bsize; + + PackArgument (argstates[i], aindex, bindex, asp_p, bsp, asize, bsize); + + asp_p++; + } +} + +void BuildTuple (int aindex,int bindex,int asp_p,int bsp,int arity, + States argstates,int asize,int bsize,int rootindex,FillKind fkind,Bool newnode) +{ + MoveArgumentsFromBToA (arity, argstates, aindex, bindex, asp_p, bsp, asize, bsize); + if (newnode) + GenBuildh (&tuple_lab,arity); + else + GenFillh (&tuple_lab,arity,arity+asp_p-rootindex,fkind); +} + +void BuildRecord (SymbDef record_sdef,int aindex,int bindex,int asp,int bsp,int asize,int bsize,int rootindex,FillKind fkind,Bool newnode) +{ + LabDef record_lab; + + ConvertSymbolToRLabel (&record_lab,record_sdef); + + if (newnode) + GenBuildR (&record_lab,asize,bsize,asp-aindex,bsp-bindex,False); + else + GenFillR (&record_lab,asize,bsize,asp-rootindex,asp-aindex,bsp-bindex,fkind,False); +} + +void PackArgument (StateS argstate,int aindex,int bindex,int asp,int bsp,int offasize,int offbsize) +{ + if (IsSimpleState (argstate)){ + if (argstate.state_kind==OnB) + BuildBasicFromB (argstate.state_object,bsp - bindex); + else + GenPushA (asp - aindex); + } else { + switch (argstate.state_type){ + case TupleState: + BuildTuple (aindex, bindex, asp, bsp,argstate.state_arity, argstate.state_tuple_arguments, + offasize,offbsize,asp,NormalFill,True); + return; + case RecordState: + BuildRecord (argstate.state_record_symbol,aindex, bindex, asp, bsp, + offasize,offbsize,asp,NormalFill,True); + return; + case ArrayState: + GenBuildArray (asp - aindex); + return; + } + } +} + +void CoerceArgumentOnTopOfStack (int *asp_p,int *bsp_p,StateS argstate,StateS nodestate,int asize,int bsize) +{ + if (IsSimpleState (argstate) && argstate.state_kind==Undefined){ + GenPopA (asize); + *asp_p-=asize; + GenPopB (bsize); + *bsp_p-=bsize; + } else if (IsSimpleState (nodestate)){ + if (IsSimpleState (argstate)){ + Coercions c; + + c = CoerceStateKind (argstate.state_kind, nodestate.state_kind); + + if (c==Reduce){ + GenJsrEval (0); + c = CoerceStateKind (argstate.state_kind, StrictOnA); + } + switch (c){ + case AToB: + PushBasicFromAOnB (argstate.state_object, 0); + *bsp_p+=ObjectSizes [argstate.state_object]; + GenPopA (1); + *asp_p-=1; + return; + case BToA: + ++*asp_p; + BuildBasicFromB (nodestate.state_object,0); + GenPopB (bsize); + *bsp_p-=bsize; + return; + case AToA: + case AToRoot: + return; + case BToB: + return; + default: + ; + } + } else { + if (CoerceStateKind (StrictOnA, nodestate.state_kind)==Reduce) + GenJsrEval (0); + + switch (argstate.state_type){ + case TupleState: /* a tuple is demanded but not offered */ + *asp_p-=1; + UnpackTuple (*asp_p,asp_p,bsp_p,True,argstate.state_arity, argstate.state_tuple_arguments); + break; + case RecordState: + *asp_p-=1; + UnpackRecord (*asp_p,asp_p,bsp_p,True,argstate.state_arity,argstate.state_record_arguments); + break; + case ArrayState: + UnpackArrayOnTopOfStack(); + break; + } + } + } else if (IsSimpleState (argstate)){ + /* a tuple or record is offered but not demanded */ + + switch (nodestate.state_type){ + case TupleState: + BuildTuple (*asp_p,*bsp_p,*asp_p,*bsp_p,nodestate.state_arity,nodestate.state_tuple_arguments, + asize,bsize,*asp_p,NormalFill,True); + *asp_p+=1; + break; + case RecordState: + BuildRecord (nodestate.state_record_symbol,*asp_p,*bsp_p,*asp_p,*bsp_p, + asize,bsize,*asp_p,NormalFill,True); + *asp_p+=1; + break; + case ArrayState: + GenBuildArray (0); + ++*asp_p; + break; + } +#if UPDATE_POP + GenUpdatePopA (0,asize); +#else + GenUpdateA (0,asize); + GenPopA (asize); +#endif + *asp_p-=asize; + GenPopB (bsize); + *bsp_p-=bsize; + } else { + if (argstate.state_type==TupleState) + AdjustTuple (asize,bsize,asp_p,bsp_p,argstate.state_arity, + argstate.state_tuple_arguments, nodestate.state_tuple_arguments,asize, bsize); + } +} + +#define HasBeenReduced(c) ((c)==Reduce) + +static void CopyArguments (States demstates,States offstates,int arity,int aindex,int bindex,int *asp_p,int *bsp,int aszie,int bsize); + +static Bool CopyArgument (StateS demstate,StateS offstate,int aindex,int bindex,int *asp_p,int *bsp_p,int offasize,int offbsize,Bool newnode) +{ + if (IsSimpleState (demstate) && demstate.state_kind==Undefined) + return False; + + if (IsSimpleState (offstate)){ + Bool leftontop; + Coercions c; + StateKind offkind; + + offkind = offstate.state_kind; + + c = CoerceSimpleStateArgument (demstate, offkind, aindex, asp_p, True, &leftontop); + offkind = AdjustStateKind (offkind, c); + + if (IsSimpleState (demstate)){ + StateKind demkind; + + demkind = demstate.state_kind; + switch (CoerceStateKind (demkind, offkind)){ + case AToB: + PushBasicFromAOnB (demstate.state_object, *asp_p - aindex); + *bsp_p += ObjectSizes [demstate.state_object]; + if (leftontop){ + GenPopA (1); + *asp_p -= SizeOfAStackElem; + } + break; + case BToA: + if (newnode){ + ++*asp_p; + BuildBasicFromB (offstate.state_object,*bsp_p - bindex); + } else + FillBasicFromB (offstate.state_object,*bsp_p - bindex,0,NormalFill); + break; + case BToB: + PushBasicOnB (demstate.state_object, *bsp_p - bindex); + *bsp_p += ObjectSizes [demstate.state_object]; + break; + case AToA: + case AToRoot: + if (leftontop){ + if (!newnode) + GenFillFromA (0, 1, NormalFill); + } else { + if (newnode){ + GenPushA (*asp_p - aindex); + *asp_p += SizeOfAStackElem; + } else + GenFillFromA (*asp_p - aindex, 0, NormalFill); + } + break; + default: + break; + } + } else { + if (leftontop) + *asp_p -= SizeOfAStackElem; + switch (demstate.state_type){ + case TupleState: + UnpackTuple (aindex, asp_p,bsp_p,leftontop, demstate.state_arity,demstate.state_tuple_arguments); + break; + case RecordState: + UnpackRecord (aindex, asp_p,bsp_p,leftontop, demstate.state_arity,demstate.state_record_arguments); + break; + case ArrayState: + UnpackArray (aindex, asp_p, leftontop); + break; + } + } + return HasBeenReduced (c); + } + else if (IsSimpleState (demstate)){ + switch (offstate.state_type){ + case TupleState: + BuildTuple (aindex, bindex, *asp_p, *bsp_p,offstate.state_arity, offstate.state_tuple_arguments, + offasize, offbsize, *asp_p, NormalFill,newnode); + if (newnode) + *asp_p += SizeOfAStackElem; + break; + case RecordState: + BuildRecord (offstate.state_record_symbol, aindex, bindex, *asp_p, *bsp_p, + offasize, offbsize, *asp_p, NormalFill, newnode); + if (newnode) + *asp_p += SizeOfAStackElem; + break; + case ArrayState: + if (newnode){ + GenBuildArray (*asp_p - aindex); + ++*asp_p; + } else + GenFillArray (*asp_p - aindex, 0, NormalFill); + break; + } + return False; /** to indicate that the offered object has not been changed **/ + } else { + switch (offstate.state_type){ + case TupleState: + CopyArguments (demstate.state_tuple_arguments, + offstate.state_tuple_arguments, demstate.state_arity, + aindex, bindex, asp_p, bsp_p, offasize, offbsize); + break; + case RecordState: + CopyArguments (demstate.state_record_arguments, + offstate.state_record_arguments, demstate.state_arity, + aindex, bindex, asp_p, bsp_p, offasize, offbsize); + break; + case ArrayState: + GenPushA (*asp_p - aindex); + *asp_p += SizeOfAStackElem; + break; + } + return False; + } +} + +static void CopyArguments (States demstates,States offstates,int arity,int aindex,int bindex,int *asp_p,int *bsp_p,int asize,int bsize) +{ + int i; + + aindex-= asize; + bindex -= bsize; + + for (i=arity-1; i>=0; i--){ + DetermineSizeOfState (offstates[i],&asize, &bsize); + aindex += asize; + bindex += bsize; + CopyArgument (demstates[i],offstates[i],aindex,bindex,asp_p,bsp_p,asize,bsize,True); + } +} + +static void CreateParallelCode (NodeDefs nds,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + switch (nds->def_node->node_annotation){ + case ParallelAnnot: + case ParallelAtAnnot: + case ParallelNFAnnot: + if (nds->def_id->nid_mark & ON_A_CYCLE_MASK){ + /* the channel has already been created */ + GenSendGraph (GetReducerCode (nds->def_node->node_annotation), 0,*asp_p-nds->def_id->nid_a_index); + GenPopA (1); + *asp_p -= SizeOfAStackElem; + } else { + GenProcIdCalculation (nds->def_node,nds->def_node->node_annotation,asp_p,bsp_p,code_gen_node_ids_p); + GenCreateChannel (channel_code); + --*bsp_p; + GenSendGraph (GetReducerCode (nds->def_node->node_annotation), 1, 0); + GenUpdateA (0, 1); + GenPopA (1); + } + break; + case InterleavedAnnot: + GenNewInterleavedReducer (*asp_p-nds->def_id->nid_a_index, hnf_reducer_code); + break; + case ContinueAnnot: + if (get_p_at_node (nds->def_node)){ + GenRedIdCalculation (get_p_at_node (nds->def_node),asp_p,bsp_p,code_gen_node_ids_p); + SetContinueOnReducer (*asp_p-nds->def_id->nid_a_index); + } else + SetContinue (*asp_p-nds->def_id->nid_a_index); + break; + case ContInterleavedAnnot: + GenNewContInterleavedReducer (*asp_p-nds->def_id->nid_a_index); + break; + case WaitAnnot: + GenSetRedId (*asp_p-nds->def_id->nid_a_index); + break; + case InterleavedNFAnnot: + GenNewInterleavedReducer (*asp_p-nds->def_id->nid_a_index, nf_reducer_code); + break; + } +} + +void ChangeEvalStatusKindToStrictOnA (NodeId node_id,SavedNidStateS **saved_nid_state_l) +{ + if (!IsSimpleState (node_id->nid_state)) + error_in_function ("ChangeEvalStatusKindToStrictOnA"); + + if (saved_nid_state_l) + save_node_id_state (node_id,saved_nid_state_l); + + node_id->nid_state__.state_kind = StrictOnA; +} + +static void ChangeEvalStatusKind (NodeId noid, StateKind state) +{ + if (noid){ + if (!IsSimpleState (noid->nid_state)) + error_in_function ("ChangeEvalStatusKind"); + noid->nid_state__.state_kind = state; + } +} + +static void ReduceSemiStrictNodes (const NodeDefs nds,int asp) +{ + NodeDefs nd; + int has_parallel_state; + + has_parallel_state=0; + + for_l (nd,nds,def_next){ + if (IsSimpleState (nd->def_id->nid_state)){ + switch (nd->def_id->nid_state.state_kind){ + case SemiStrict: + if (nd->def_node->node_state.state_mark & STATE_PARALLEL_MASK){ + has_parallel_state=1; + continue; + } + + ChangeEvalStatusKind (nd->def_id, StrictOnA); + /* evaluate strict annotated */ + GenJsrEval (asp - nd->def_id->nid_a_index); + break; + case Parallel: + StaticMessage (False, "","parallel annotation ignored(?)"); + break; + } + } + } + + if (has_parallel_state) + for_l (nd,nds,def_next){ + if (IsSimpleState (nd->def_id->nid_state)){ + if (nd->def_id->nid_state.state_kind==SemiStrict){ + ChangeEvalStatusKind (nd->def_id, StrictOnA); + /* evaluate strict annotated */ + GenJsrEval (asp - nd->def_id->nid_a_index); + } + } + } +} + +void BuildOrFillLazyFieldSelector (SymbDef selector_sdef,StateKind result_state_kind,int *asp_p,NodeId update_node_id) +{ + LabDef nsellab,dsellab; + char *record_name; + int fill_arity; + SymbDef record_sdef; + StateS *field_result_state_p; + + ConvertSymbolToDandNLabel (&dsellab,&nsellab,selector_sdef); + + record_sdef=selector_sdef->sdef_type->type_lhs->ft_symbol->symb_def; + record_name=record_sdef->sdef_ident->ident_name; + + field_result_state_p=&record_sdef->sdef_record_state.state_record_arguments [selector_sdef->sdef_sel_field_number]; + fill_arity= IsSimpleState (*field_result_state_p) ? (field_result_state_p->state_kind!=OnB ? -4 : -3) : 1; + + /* we use a negative arity to indicate lazy selectors */ + if (update_node_id==NULL) + GenBuildFieldSelector (&dsellab,&nsellab,record_name,fill_arity); + else { + GenFillFieldSelector (&dsellab,&nsellab,record_name,fill_arity,*asp_p-update_node_id->nid_a_index,result_state_kind==SemiStrict ? PartialFill : NormalFill); + *asp_p-=1; + } +} + +void ReplaceRecordOnTopOfStackByField (int *asp_p,int *bsp_p,int apos,int bpos,int asize,int bsize,int rec_a_size,int rec_b_size) +{ + int i; + + rec_a_size -= asize; + rec_b_size -= bsize; + + for (i = asize - 1; i >= 0; i--) +#if UPDATE_POP + if (i==0) + GenUpdatePopA (apos,rec_a_size); + else +#endif + GenUpdateA (apos + i, rec_a_size + i); + + for (i = bsize - 1; i >= 0; i--) +#if UPDATE_POP + if (i==0) + GenUpdatePopB (bpos,rec_b_size); + else +#endif + GenUpdateB (bpos + i, rec_b_size + i); + +#if UPDATE_POP + if (asize==0) +#endif + GenPopA (rec_a_size); + *asp_p-=rec_a_size; + +#if UPDATE_POP + if (bsize==0) +#endif + GenPopB (rec_b_size); + + *bsp_p-=rec_b_size; +} + +#define ResultIsNotInRootNormalForm(state) (IsLazyState (state) ||\ + IsSimpleState (state) && (state).state_kind == LazyRedirection) + +void add_node_id_to_list (struct node_id *node_id,NodeIdListElementS **node_ids_l) +{ + NodeIdListElementP free_node_id; + + free_node_id=CompAllocType (NodeIdListElementS); + free_node_id->nidl_node_id=node_id; + + free_node_id->nidl_next=*node_ids_l; + *node_ids_l=free_node_id; +} + +#if 0 +# include "dbprint.h" +#endif + +#if FREE_STRICT_LHS_TUPLE_ELEMENTS +static void add_node_id_or_tuple_node_ids_to_list (NodeIdP node_id,NodeIdListElementS **free_node_ids_l) +{ + if (! (node_id->nid_node!=NULL && !IsSimpleState (node_id->nid_state))) + add_node_id_to_list (node_id,free_node_ids_l); + else { + ArgP arg_p; + + for_l (arg_p,node_id->nid_node->node_arguments,arg_next){ + NodeP arg_node_p; + + arg_node_p=arg_p->arg_node; + if (arg_node_p->node_kind==NodeIdNode){ + NodeIdP node_id_p; + + node_id_p=arg_node_p->node_node_id; + if (node_id_p->nid_refcount==-1) + add_node_id_or_tuple_node_ids_to_list (node_id_p,free_node_ids_l); + } + } + } +} +#endif + +void decrement_reference_count_of_node_id (struct node_id *node_id,NodeIdListElementS **free_node_ids_l) +{ + int ref_count; + +#if 0 + printf ("decrement_reference_count_of_node_id "); + DPrintNodeId (node_id,StdOut); + printf ("\n"); +#endif + + ref_count=node_id->nid_refcount; + + if (ref_count>0){ + if (--ref_count==0) + add_node_id_to_list (node_id,free_node_ids_l); + + node_id->nid_refcount=ref_count; + } else if (ref_count<-1){ + ++ref_count; + node_id->nid_refcount=ref_count; + + if (ref_count==-1){ +#if FREE_STRICT_LHS_TUPLE_ELEMENTS + if (unused_node_id_(node_id)) + add_node_id_or_tuple_node_ids_to_list (node_id,free_node_ids_l); +#else + if (! (node_id->nid_node!=NULL && !IsSimpleState (node_id->nid_state)) && unused_node_id_(node_id)){ +# if 0 + printf ("add to free_node_ids list "); + DPrintNodeId (node_id,StdOut); + printf ("\n"); +# endif + add_node_id_to_list (node_id,free_node_ids_l); + } +#endif + } + } +} + +void DetermineFieldSizeAndPositionAndRecordSize + (int fieldnr,int *asize_p,int *bsize_p,int *apos_p,int *bpos_p,int *rec_asize_p,int *rec_bsize_p,StateS *record_state_p) +{ + int i; + + DetermineFieldSizeAndPosition (fieldnr,asize_p,bsize_p,apos_p,bpos_p,record_state_p->state_record_arguments); + + *rec_asize_p = *asize_p + *apos_p; + *rec_bsize_p = *bsize_p + *bpos_p; + + for (i=fieldnr+1; i<record_state_p->state_arity; ++i) + AddSizeOfState (record_state_p->state_record_arguments[i],rec_asize_p,rec_bsize_p); +} + +int get_a_index_of_unpacked_lhs_node (ArgS *arg) +{ + while (arg!=NULL){ + int a_size,b_size; + + DetermineSizeOfState (arg->arg_state,&a_size,&b_size); + + if (a_size==0) + arg=arg->arg_next; + else { + Node arg_node; + + arg_node=arg->arg_node; + + if (arg_node->node_kind==NodeIdNode){ + NodeId node_id; + node_id=arg->arg_node->node_node_id; + + if (a_size!=0){ + if (node_id->nid_refcount<0 && node_id->nid_state.state_type!=SimpleState && node_id->nid_node!=NULL) + arg=node_id->nid_node->node_arguments; + else + return node_id->nid_a_index; + } + } else + arg=arg_node->node_arguments; + } + } + + return 0; +} + +int get_b_index_of_unpacked_lhs_node (ArgS *arg) +{ + while (arg!=NULL){ + int a_size,b_size; + + DetermineSizeOfState (arg->arg_state,&a_size,&b_size); + + if (b_size==0) + arg=arg->arg_next; + else { + Node arg_node; + + arg_node=arg->arg_node; + + if (arg_node->node_kind==NodeIdNode){ + NodeId node_id; + + node_id=arg->arg_node->node_node_id; + + if (node_id->nid_refcount<0 && node_id->nid_state.state_type!=SimpleState && node_id->nid_node!=NULL) + arg=node_id->nid_node->node_arguments; + else + return node_id->nid_b_index; + } else + arg=arg_node->node_arguments; + } + } + + return 0; +} + +Bool CopyNodeIdArgument (StateS demstate,NodeId node_id,int *asp_p,int *bsp_p) +{ + int a_size,b_size,a_index,b_index; + + DetermineSizeOfState (node_id->nid_state,&a_size,&b_size); + + a_index=node_id->nid_a_index; + b_index=node_id->nid_b_index; + + if (node_id->nid_refcount<0 && node_id->nid_state.state_type!=SimpleState && node_id->nid_node!=NULL){ + ArgS *args; + + args=node_id->nid_node->node_arguments; + + if (a_size!=0) + a_index=get_a_index_of_unpacked_lhs_node (args); + if (b_size!=0) + b_index=get_b_index_of_unpacked_lhs_node (args); + } + + return CopyArgument (demstate,node_id->nid_state,a_index,b_index,asp_p,bsp_p,a_size,b_size,True); +} + +static void FillOrReduceFieldSelection (Node node,SymbDef seldef,int *asp_p,int *bsp_p,NodeId update_node_id,CodeGenNodeIdsP code_gen_node_ids_p) +{ + Node arg_node; + Args arg; + int fieldnr; + + arg = node->node_arguments; + fieldnr = seldef->sdef_sel_field_number; + + arg_node=arg->arg_node; + + if (node->node_arity>=SELECTOR_U){ + if (IsLazyState (node->node_state)){ + SymbDef new_select_sdef; + LabDef name,codelab; + + BuildArg (arg,asp_p,bsp_p,code_gen_node_ids_p); + + new_select_sdef=create_select_function (node->node_symbol,node->node_arity); + + ConvertSymbolToDandNLabel (&name,&codelab,new_select_sdef); + + if (update_node_id==NULL) + GenBuild (&name,1,&codelab); + else { + GenFill (&name,1,&codelab,*asp_p-update_node_id->nid_a_index,node->node_state.state_kind==SemiStrict ? PartialFill : NormalFill); + --*asp_p; + } + } else { + if (arg_node->node_kind!=NodeIdNode){ + int asize,bsize,aindex,bindex; + StateP record_state_p; + + BuildArg (arg,asp_p,bsp_p,code_gen_node_ids_p); + + record_state_p=&seldef->sdef_type->type_lhs->ft_symbol->symb_def->sdef_record_state; + + DetermineFieldSizeAndPosition (fieldnr,&asize,&bsize,&aindex,&bindex,record_state_p->state_record_arguments); + + if (node->node_arity<SELECTOR_L){ + int n; + + for (n=0; n<asize; ++n) + GenPushA (aindex+asize-1); + *asp_p+=asize; + + for (n=0; n<bsize; ++n) + GenPushB (bindex+bsize-1); + *bsp_p+=bsize; + } else { + int record_a_size,record_b_size; + + DetermineSizeOfState (*record_state_p,&record_a_size,&record_b_size); + ReplaceRecordOnTopOfStackByField (asp_p,bsp_p,aindex,bindex,asize,bsize,record_a_size,record_b_size); + } + } else { + int a_size,b_size,apos,bpos,record_a_size,record_b_size,n; + StateS tuple_state,tuple_state_arguments[2],*record_state_p; + NodeId arg_node_id; + + arg_node_id=arg_node->node_node_id; + + record_state_p=&seldef->sdef_type->type_lhs->ft_symbol->symb_def->sdef_record_state; + + DetermineFieldSizeAndPositionAndRecordSize (fieldnr,&a_size,&b_size,&apos,&bpos,&record_a_size,&record_b_size,record_state_p); + + CopyNodeIdArgument (*record_state_p,arg_node_id,asp_p,bsp_p); + + for (n=0; n<a_size; ++n) + GenPushA (apos+a_size-1); + *asp_p+=a_size; + + for (n=0; n<b_size; ++n) + GenPushB (bpos+b_size-1); + *bsp_p+=b_size; + + tuple_state.state_type=TupleState; + tuple_state.state_arity=2; + tuple_state.state_tuple_arguments=tuple_state_arguments; + + tuple_state_arguments[0]=record_state_p->state_record_arguments[fieldnr]; + tuple_state_arguments[1]=*record_state_p; + + CoerceArgumentOnTopOfStack (asp_p,bsp_p,tuple_state,node->node_state,record_a_size+a_size,record_b_size+b_size); + + decrement_reference_count_of_node_id (arg_node_id,&code_gen_node_ids_p->free_node_ids); + } + } + return; + } + + if (arg_node->node_kind!=NodeIdNode){ + if (IsLazyState (node->node_state)){ + BuildArg (arg,asp_p,bsp_p,code_gen_node_ids_p); + +#ifdef DO_LAZY_SELECTORS_FROM_BOXED_STRICT_RECORDS + if (!ResultIsNotInRootNormalForm (arg_node->node_state) && update_node_id==NULL){ + int asize,bsize,apos,bpos,tot_asize,tot_bsize; + StateP record_state_p,field_state_p; + + record_state_p=&seldef->sdef_type->type_lhs->ft_symbol->symb_def->sdef_record_state; + + if (record_state_p->state_type!=RecordState) + error_in_function ("FillOrReduceFieldSelection"); + + DetermineFieldSizeAndPositionAndRecordSize (fieldnr,&asize,&bsize,&apos,&bpos,&tot_asize,&tot_bsize,record_state_p); + + GenPushRArgB (0,tot_asize,tot_bsize,bpos+1,bsize); + GenReplRArgA (tot_asize,tot_bsize,apos+1,asize); + + *asp_p -= 1-asize; + *bsp_p += bsize; + + field_state_p=&record_state_p->state_record_arguments [fieldnr]; + CoerceArgumentOnTopOfStack (asp_p,bsp_p,node->node_state,*field_state_p,asize,bsize); + + if (node->node_state.state_kind==OnA && !ResultIsNotInRootNormalForm (*field_state_p)) + node->node_state.state_kind=StrictOnA; + } else +#endif + + BuildOrFillLazyFieldSelector (seldef,node->node_state.state_kind,asp_p,update_node_id); + } else { + int asize,bsize,apos,bpos,tot_asize,tot_bsize; + + Build (arg_node,asp_p,bsp_p,code_gen_node_ids_p); + + DetermineFieldSizeAndPositionAndRecordSize (fieldnr,&asize,&bsize,&apos,&bpos,&tot_asize,&tot_bsize,&arg->arg_state); + CoerceArgumentOnTopOfStack (asp_p,bsp_p,arg->arg_state,arg_node->node_state,tot_asize,tot_bsize); + + ReplaceRecordOnTopOfStackByField (asp_p,bsp_p,apos,bpos,asize,bsize,tot_asize,tot_bsize); + CoerceArgumentOnTopOfStack (asp_p,bsp_p,node->node_state,arg->arg_state.state_record_arguments[fieldnr],asize,bsize); + } + } else { + StateS recstate; + NodeId arg_node_id; + + arg_node_id=arg_node->node_node_id; + + recstate=arg_node_id->nid_state; + + if (recstate.state_type==RecordState){ + int a_size,b_size,apos,bpos,record_a_index,record_b_index; + StateP field_state_p; + + DetermineFieldSizeAndPosition (fieldnr,&a_size,&b_size,&apos,&bpos,recstate.state_record_arguments); + + if (arg_node_id->nid_refcount<0 && arg_node_id->nid_node!=NULL){ + ArgS *args; + + args=arg_node_id->nid_node->node_arguments; + record_a_index=get_a_index_of_unpacked_lhs_node (args); + record_b_index=get_b_index_of_unpacked_lhs_node (args); + } else { + record_a_index=arg_node_id->nid_a_index; + record_b_index=arg_node_id->nid_b_index; + } + + field_state_p=&recstate.state_record_arguments[fieldnr]; + + if (update_node_id==NULL){ + CopyArgument (node->node_state,*field_state_p,record_a_index-apos,record_b_index-bpos,asp_p,bsp_p,a_size,b_size,True); + } else { + int locasp; + + locasp = *asp_p; + + GenPushA (*asp_p-update_node_id->nid_a_index); + *asp_p+=1; + + CopyArgument (node->node_state,*field_state_p,record_a_index-apos,record_b_index-bpos,asp_p,bsp_p,a_size,b_size,False); + + GenPopA (*asp_p-locasp); + *asp_p=locasp; + } + +#ifdef DO_LAZY_SELECTORS_FROM_BOXED_STRICT_RECORDS + if (node->node_state.state_type==SimpleState && node->node_state.state_kind==OnA && !ResultIsNotInRootNormalForm (*field_state_p)) + node->node_state.state_kind=StrictOnA; +#endif + decrement_reference_count_of_node_id (arg_node_id,&code_gen_node_ids_p->free_node_ids); + } else if (IsLazyState (node->node_state)){ +#ifdef DO_LAZY_SELECTORS_FROM_BOXED_STRICT_RECORDS + if ((recstate.state_kind==StrictOnA || recstate.state_kind==StrictRedirection) && update_node_id==NULL){ + int asize,bsize,apos,bpos,tot_asize,tot_bsize,recindex; + StateP record_state_p,field_state_p; + + recindex = arg_node_id->nid_a_index; + record_state_p=&seldef->sdef_type->type_lhs->ft_symbol->symb_def->sdef_record_state; + + if (record_state_p->state_type!=RecordState) + error_in_function ("FillOrReduceFieldSelection"); + + DetermineFieldSizeAndPositionAndRecordSize (fieldnr,&asize,&bsize,&apos,&bpos,&tot_asize,&tot_bsize,record_state_p); + + GenPushRArgB (*asp_p-recindex,tot_asize,tot_bsize,bpos+1,bsize); + GenPushRArgA (*asp_p-recindex,tot_asize,tot_bsize,apos+1,asize); + + *asp_p+=asize; + *bsp_p+=bsize; + + field_state_p=&record_state_p->state_record_arguments [fieldnr]; + CoerceArgumentOnTopOfStack (asp_p,bsp_p,node->node_state,*field_state_p,asize,bsize); + + if (node->node_state.state_kind==OnA && !ResultIsNotInRootNormalForm (*field_state_p)) + node->node_state.state_kind=StrictOnA; + + decrement_reference_count_of_node_id (arg_node_id,&code_gen_node_ids_p->free_node_ids); + } else +#endif + { + BuildArg (arg,asp_p,bsp_p,code_gen_node_ids_p); + + BuildOrFillLazyFieldSelector (seldef,node->node_state.state_kind,asp_p,update_node_id); + } + } else { + int a_size,b_size,apos, bpos, tot_asize, tot_bsize,recindex; + + /* the selector is strict but the record is not */ + + recindex = arg_node_id->nid_a_index; + + DetermineFieldSizeAndPositionAndRecordSize (fieldnr,&a_size,&b_size,&apos, &bpos,&tot_asize,&tot_bsize,&arg->arg_state); + + if (ResultIsNotInRootNormalForm (recstate)){ + GenJsrEval (*asp_p-recindex); + ChangeEvalStatusKindToStrictOnA (arg_node_id,code_gen_node_ids_p->saved_nid_state_l); + + recstate.state_kind = StrictOnA; + } + + GenPushRArgB (*asp_p-recindex, tot_asize, tot_bsize, bpos+1,b_size); + GenPushRArgA (*asp_p-recindex, tot_asize, tot_bsize, apos+1,a_size); + + *asp_p+=a_size; + *bsp_p+=b_size; + + recstate = arg->arg_state.state_record_arguments [fieldnr]; + CoerceArgumentOnTopOfStack (asp_p,bsp_p, node->node_state, recstate,a_size,b_size); + + decrement_reference_count_of_node_id (arg_node_id,&code_gen_node_ids_p->free_node_ids); + } + } +} + +void FillSelectSymbol (StateKind result_state_kind,int arity,int argnr,Args arg,int *asp_p,int *bsp_p, + NodeId update_node_id,CodeGenNodeIdsP code_gen_node_ids_p) +{ + LabDef sellab, nsellab; + + BuildLazyTupleSelectorLabel (&nsellab,arity,argnr); + + BuildArg (arg,asp_p,bsp_p,code_gen_node_ids_p); + + sellab = nsellab; + sellab.lab_pref = d_pref; + + /* we use a negative arity to indicate lazy selectors */ + if (update_node_id==NULL) + GenBuild (&sellab,-1,&nsellab); + else { + GenFill (&sellab,-1,&nsellab,*asp_p-update_node_id->nid_a_index,result_state_kind==SemiStrict ? PartialFill : NormalFill); + *asp_p-=1; + } +} + +#if defined (THUNK_LIFT_SELECTORS) +void FillSelectAndRemoveSymbol (StateKind result_state_kind,int arity,int argnr,Args arg,int *asp_p,int *bsp_p, + NodeId update_node_id,CodeGenNodeIdsP code_gen_node_ids_p) +{ + LabDef sellab, nsellab; + + BuildLazyTupleSelectorAndRemoveLabel (&nsellab,arity,argnr); + + BuildArg (arg,asp_p,bsp_p,code_gen_node_ids_p); + + sellab = nsellab; + sellab.lab_pref = d_pref; + + /* we use a negative arity to indicate lazy selectors */ + if (update_node_id==NULL) + GenBuild (&sellab,-1,&nsellab); + else { + GenFill (&sellab,-1,&nsellab,*asp_p-update_node_id->nid_a_index,result_state_kind==SemiStrict ? PartialFill : NormalFill); + *asp_p-=1; + } +} +#endif + +#if OPTIMIZE_LAZY_TUPLE_RECURSION +extern int lazy_tuple_recursion; +extern void update_tuple_element_node (StateP state_p,int tuple_element_a_index,int *asp_p,int *bsp_p); +#endif + +static void FillOrReduceSelectSymbol (Node node,int *asp_p,int *bsp_p,NodeId update_node_id,CodeGenNodeIdsP code_gen_node_ids_p) +{ + Args arg; + int argnr; + + arg = node->node_arguments; + argnr = node->node_arity; + + if (arg->arg_node->node_kind!=NodeIdNode){ + if (IsLazyState (node->node_state)) + FillSelectSymbol (node->node_state.state_kind,node->node_symbol->symb_arity,argnr,arg,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + else { + Node argnode; + int asize,bsize; + + argnode = arg->arg_node; + + DetermineSizeOfState (argnode->node_state, &asize, &bsize); + Build (argnode,asp_p,bsp_p,code_gen_node_ids_p); + CoerceArgumentOnTopOfStack (asp_p,bsp_p,arg->arg_state,argnode->node_state, asize, bsize); + } + } else { + StateS tupstate; + NodeId arg_node_id; + + /* the tuple is shared */ + + arg_node_id=arg->arg_node->node_node_id; +#if OPTIMIZE_LAZY_TUPLE_RECURSION + if ((arg_node_id->nid_mark2 & NID_CALL_VIA_LAZY_SELECTIONS_ONLY) && update_node_id==NULL){ + int select_node_index; + + select_node_index=arg_node_id->nid_a_index-argnr; + + GenPushA (*asp_p-select_node_index); + ++*asp_p; + + return; + } +#endif + + tupstate = arg_node_id->nid_state; + + if (IsSimpleState (tupstate)){ + if (IsLazyState (node->node_state)){ + /* added 10-8-1999 */ + if (!IsLazyStateKind (tupstate.state_kind)){ + GenPushArg (*asp_p-arg_node_id->nid_a_index,node->node_symbol->symb_arity,argnr); + *asp_p+=1; + + decrement_reference_count_of_node_id (arg_node_id,&code_gen_node_ids_p->free_node_ids); + } else + /* */ +#if defined (THUNK_LIFT_SELECTORS) + if (arg_node_id->nid_refcount>0 && (arg_node_id->nid_node_def->def_mark & NODE_DEF_SELECT_AND_REMOVE_MASK)!=0) + FillSelectAndRemoveSymbol (node->node_state.state_kind,node->node_symbol->symb_arity,argnr,arg,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + else +#endif + FillSelectSymbol (node->node_state.state_kind,node->node_symbol->symb_arity,argnr,arg,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + } else { + int arity,tupindex; + StateS selectstate; + + /* the selector is strict but the tuple is not */ + + arity = arg->arg_state.state_arity; + tupindex = arg_node_id->nid_a_index; + selectstate = arg->arg_state.state_tuple_arguments[argnr-1]; + + if (ResultIsNotInRootNormalForm (tupstate)){ + GenJsrEval (*asp_p-tupindex); + ChangeEvalStatusKindToStrictOnA (arg_node_id,code_gen_node_ids_p->saved_nid_state_l); + tupstate.state_kind = StrictOnA; + } + +#if defined (THUNK_LIFT_SELECTORS) + if (node->node_number!=0){ + char bits[MaxNodeArity+2]; + int n; + + GenPushArgsU (*asp_p-tupindex,arity,argnr); + if (argnr>1) + GenPopA (argnr-1); + + *asp_p+=1; + + for (n=0; n<=arity; ++n) + bits[n]='0'; + bits[arity+1]='\0'; + + bits[argnr]='1'; + + GenBuildh (&nil_lab,0); + + if (arity<=2) + GenFill1 (&tuple_lab,arity,*asp_p+1-tupindex,bits); + else + GenFill2 (&tuple_lab,arity,*asp_p+1-tupindex,bits); + } else { + GenPushArg (*asp_p-tupindex,arity,argnr); + *asp_p+=1; + } +#else + + GenPushArg (*asp_p-tupindex,arity,argnr); + *asp_p+=1; +#endif + if (!ResultIsNotInRootNormalForm (selectstate)) + GenJsrEval (0); + + CoerceArgumentOnTopOfStack (asp_p,bsp_p,selectstate,tupstate,1,0); + +#if OPTIMIZE_LAZY_TUPLE_RECURSION + if (update_node_id!=NULL) + update_tuple_element_node (&selectstate,update_node_id->nid_a_index,asp_p,bsp_p); +#endif + decrement_reference_count_of_node_id (arg_node_id,&code_gen_node_ids_p->free_node_ids); + } + } else { + int a_size,b_size,i,argasize,argbsize,a_index,b_index; + StateS selectstate; + + a_size=0; + b_size=0; + + for (i=0; i<argnr-1; i++) + AddSizeOfState (tupstate.state_tuple_arguments[i],&a_size,&b_size); + + if (IsSimpleState (arg->arg_state)) + selectstate = arg->arg_state; + else + selectstate = arg->arg_state.state_tuple_arguments[i]; + + DetermineSizeOfState (tupstate.state_tuple_arguments[i],&argasize, &argbsize); + + a_index=arg_node_id->nid_a_index; + b_index=arg_node_id->nid_b_index; + + if (arg_node_id->nid_refcount<0 && arg_node_id->nid_node!=NULL){ + ArgP args; + + args=arg_node_id->nid_node->node_arguments; + a_index=get_a_index_of_unpacked_lhs_node (args); + b_index=get_b_index_of_unpacked_lhs_node (args); + } + + if (update_node_id==NULL) + CopyArgument (selectstate,tupstate.state_tuple_arguments[i], + a_index - a_size,b_index - b_size,asp_p,bsp_p, argasize, argbsize, True); + else { + int locasp; + + locasp = *asp_p; + + GenPushA (*asp_p-update_node_id->nid_a_index); + ++*asp_p; + + CopyArgument (selectstate,tupstate.state_tuple_arguments[i], + a_index - a_size,b_index - b_size,asp_p,bsp_p, argasize, argbsize, False); + + GenPopA (*asp_p-locasp); + *asp_p=locasp; + } + + decrement_reference_count_of_node_id (arg_node_id,&code_gen_node_ids_p->free_node_ids); + } + } +} + +void DetermineArrayElemDescr (StateS elemstate,Label lab) +{ + if (elemstate.state_type==SimpleState) + *lab = BasicDescriptors [elemstate.state_object]; + else if (elemstate.state_type==RecordState){ + ConvertSymbolToRLabel (lab,elemstate.state_record_symbol); + } else + *lab = BasicDescriptors [UnknownObj]; +} + +#define UNUSED_NODE_ID_INDEX 30000 + +#if 0 +#include "dbprint.h" +#endif + +void cleanup_stack + (int *asp_p,int *bsp_p,int a_size,int b_size,NodeIdListElementS **a_node_ids_l,NodeIdListElementS **b_node_ids_l, + NodeIdListElementS **free_node_ids_l,MovedNodeIdP *moved_node_ids_l,int compact_stack_ok) +{ + NodeIdListElementP p_node_ids; + int asp,bsp; + int n_a_elements_popped; + + if (DoDebug){ + PrintComment (); + FPrintF (OutFile,compact_stack_ok ? "Remove unused stack elements" : "Remove unused stack elements without moving"); + } + + asp=*asp_p; + bsp=*bsp_p; + + n_a_elements_popped=0; + +#if 0 + printf ("cleanup_stack a_node_ids "); + for_l (p_node_ids,*a_node_ids_l,nidl_next){ + DPrintNodeId (p_node_ids->nidl_node_id,StdOut); + printf (" "); + } + printf ("\n"); +#endif + +#if 0 + printf ("cleanup_stack b_node_ids "); + for_l (p_node_ids,*b_node_ids_l,nidl_next){ + DPrintNodeId (p_node_ids->nidl_node_id,StdOut); + printf (" "); + } + printf ("\n"); +#endif + + p_node_ids=*a_node_ids_l; + while (p_node_ids!=NULL && p_node_ids->nidl_node_id->nid_a_index==UNUSED_NODE_ID_INDEX){ +#if 0 + printf ("cleanup_stack00 "); + printf ("%s ",CurrentAltLabel.lab_symbol->sdef_ident->ident_name); + DPrintNodeId (p_node_ids->nidl_node_id,StdOut); + printf ("\n"); +#endif + p_node_ids=p_node_ids->nidl_next; + } + + if (p_node_ids!=NULL && p_node_ids->nidl_node_id->nid_a_index==asp && (unused_node_id (p_node_ids->nidl_node_id))){ + int n_a_elements,n_b_elements; + + n_a_elements=0; + n_b_elements=0; + + do { +#if 0 + printf ("cleanup_stack01 "); + printf ("%s ",CurrentAltLabel.lab_symbol->sdef_ident->ident_name); + DPrintNodeId (p_node_ids->nidl_node_id,StdOut); + printf ("\n"); +#endif + + AddSizeOfState (p_node_ids->nidl_node_id->nid_state,&n_a_elements,&n_b_elements); + /* free p_node_ids */ + + p_node_ids=p_node_ids->nidl_next; + while (p_node_ids!=NULL && p_node_ids->nidl_node_id->nid_a_index==UNUSED_NODE_ID_INDEX){ +#if 0 + printf ("cleanup_stack02 "); + printf ("%s ",CurrentAltLabel.lab_symbol->sdef_ident->ident_name); + DPrintNodeId (p_node_ids->nidl_node_id,StdOut); + printf ("\n"); +#endif + p_node_ids=p_node_ids->nidl_next; + } + + } while (p_node_ids!=NULL && p_node_ids->nidl_node_id->nid_a_index==asp-n_a_elements && (unused_node_id (p_node_ids->nidl_node_id))); + + *a_node_ids_l=p_node_ids; + + n_a_elements_popped=n_a_elements; + } + + p_node_ids=*b_node_ids_l; + if (p_node_ids!=NULL && (unused_node_id (p_node_ids->nidl_node_id)) && p_node_ids->nidl_node_id->nid_b_index==bsp){ + int n_a_elements,n_b_elements; + + n_a_elements=0; + n_b_elements=0; + + do { + AddSizeOfState (p_node_ids->nidl_node_id->nid_state,&n_a_elements,&n_b_elements); + /* free p_node_ids */ + p_node_ids=p_node_ids->nidl_next; + } while (p_node_ids!=NULL && (unused_node_id (p_node_ids->nidl_node_id)) && p_node_ids->nidl_node_id->nid_b_index==bsp-n_b_elements); + + *b_node_ids_l=p_node_ids; + + if (n_b_elements!=0){ + int i; + + for (i=b_size-1; i>=0; --i) +#if UPDATE_POP + if (i==0) + GenUpdatePopB (0,n_b_elements); + else +#endif + GenUpdateB (i,i+n_b_elements); + +#if UPDATE_POP + if (b_size==0) +#endif + GenPopB (n_b_elements); + + *bsp_p-=n_b_elements; + } + } + + if (compact_stack_ok){ + NodeIdListElementP free_node_id,keep_node_ids; + int node_id_a_size,node_id_b_size; + int free_size,used_size,move_free_size,move_used_size; + + node_id_a_size=0; + node_id_b_size=0; + + asp=*asp_p-n_a_elements_popped; + + for_l (free_node_id,*free_node_ids_l,nidl_next){ + struct node_id *node_id; + + node_id=free_node_id->nidl_node_id; + + if (node_id->nid_a_index < asp) + AddSizeOfState (node_id->nid_state,&node_id_a_size,&node_id_b_size); + } + + free_size=0; + used_size=0; + + move_free_size=0; + move_used_size=0; + keep_node_ids=NULL; + + + p_node_ids=*a_node_ids_l; + + while (p_node_ids!=NULL && p_node_ids->nidl_node_id->nid_a_index==UNUSED_NODE_ID_INDEX){ +#if 0 + printf ("cleanup_stack03 "); + printf ("%s ",CurrentAltLabel.lab_symbol->sdef_ident->ident_name); + DPrintNodeId (p_node_ids->nidl_node_id,StdOut); + printf ("\n"); +#endif + p_node_ids=p_node_ids->nidl_next; + } + +#if 0 + printf ("cleanup_stack1 "); + printf ("%s\n",CurrentAltLabel.lab_symbol->sdef_ident->ident_name); + + if (p_node_ids!=NULL && p_node_ids->nidl_node_id->nid_a_index!=asp){ + printf ("asp=%d nid_a_index=%d ",asp,p_node_ids->nidl_node_id->nid_a_index); + DPrintNodeId (p_node_ids->nidl_node_id,StdOut); + printf ("\n"); + } +#endif + + while (p_node_ids!=NULL && p_node_ids->nidl_node_id->nid_a_index==asp){ + int element_a_size,element_b_size; + struct node_id *node_id; + + node_id=p_node_ids->nidl_node_id; + DetermineSizeOfState (node_id->nid_state,&element_a_size,&element_b_size); + +#if 0 + DPrintNodeId (node_id,StdOut); + printf ("\n"); +#endif + + if (unused_node_id (node_id)){ + free_size+=element_a_size; + } else { + if (free_size+used_size > node_id_a_size+node_id_a_size) + break; + + used_size+=element_a_size; + } + + asp-=element_a_size; + + p_node_ids=p_node_ids->nidl_next; + while (p_node_ids!=NULL && p_node_ids->nidl_node_id->nid_a_index==UNUSED_NODE_ID_INDEX){ +#if 0 + printf ("cleanup_stack11 "); + printf ("%s ",CurrentAltLabel.lab_symbol->sdef_ident->ident_name); + DPrintNodeId (p_node_ids->nidl_node_id,StdOut); + printf ("\n"); +#endif + p_node_ids=p_node_ids->nidl_next; + } + + if (free_size>=used_size){ + move_free_size=free_size; + move_used_size=used_size; + keep_node_ids=p_node_ids; + } + } + + if (move_free_size!=0){ + NodeIdListElementP reversed_node_ids; + int move_a_offset; + int source_asp,dest_asp; + + move_a_offset=move_free_size; + + source_asp=*asp_p-n_a_elements_popped-(move_free_size+move_used_size); + dest_asp=source_asp; + + reversed_node_ids=NULL; + p_node_ids=*a_node_ids_l; + + while (p_node_ids!=keep_node_ids){ + NodeIdListElementP next_p_node_ids; + + next_p_node_ids=p_node_ids->nidl_next; + p_node_ids->nidl_next=reversed_node_ids; + reversed_node_ids=p_node_ids; + p_node_ids=next_p_node_ids; + } + + while (reversed_node_ids!=NULL){ + NodeIdListElementP next_reversed_node_ids; + int element_a_size,element_b_size; + MovedNodeIdP new_moved_node_id; + struct node_id *node_id; + + node_id=reversed_node_ids->nidl_node_id; + + if (node_id->nid_a_index!=UNUSED_NODE_ID_INDEX){ + DetermineSizeOfState (node_id->nid_state,&element_a_size,&element_b_size); + + new_moved_node_id=CompAllocType (MovedNodeIdS); + new_moved_node_id->mnid_node_id=node_id; + new_moved_node_id->mnid_a_stack_offset=node_id->nid_a_index; + + new_moved_node_id->mnid_next=*moved_node_ids_l; + *moved_node_ids_l=new_moved_node_id; + +#if 0 + printf ("cleanup_stack2 "); + DPrintNodeId (node_id,StdOut); + printf ("\n"); +#endif + + if (unused_node_id (node_id)){ + source_asp+=element_a_size; + + node_id->nid_a_index_=UNUSED_NODE_ID_INDEX; + } else { + int n; + + for (n=element_a_size; n!=0; --n){ + ++source_asp; + ++dest_asp; + GenUpdateA (*asp_p+a_size-source_asp,*asp_p+a_size-dest_asp); + } + + node_id->nid_a_index_=dest_asp; + } + } + + next_reversed_node_ids=reversed_node_ids->nidl_next; + reversed_node_ids->nidl_next=p_node_ids; + p_node_ids=reversed_node_ids; + reversed_node_ids=next_reversed_node_ids; + } + + *a_node_ids_l=p_node_ids; +/* *a_node_ids_l=keep_node_ids; */ + + n_a_elements_popped+=move_a_offset; + } + } + + if (n_a_elements_popped!=0){ + int i; + + for (i=a_size-1; i>=0; --i) +#if UPDATE_POP + if (i==0) + GenUpdatePopA (0,n_a_elements_popped); + else +#endif + GenUpdateA (i,i+n_a_elements_popped); + +#if UPDATE_POP + if (a_size==0) +#endif + GenPopA (n_a_elements_popped); + + *asp_p-=n_a_elements_popped; + } + + { + NodeIdListElementP free_node_id; + int nil_on_stack; + + nil_on_stack=0; + asp=*asp_p; + + for_l (free_node_id,*free_node_ids_l,nidl_next){ + struct node_id *node_id; + + node_id=free_node_id->nidl_node_id; + +#if 0 + printf ("cleanup_stack3 "); + DPrintNodeId (node_id,StdOut); + printf ("\n"); +#endif + + if (node_id->nid_a_index < asp){ + int node_id_a_size,node_id_b_size,a_index; + + DetermineSizeOfState (node_id->nid_state,&node_id_a_size,&node_id_b_size); + + if (node_id_a_size>0){ + a_index=asp+a_size-node_id->nid_a_index; + + NodeIdComment (node_id); + + while (node_id_a_size>0){ + if (!nil_on_stack){ + GenBuildh (&nil_lab,0); + nil_on_stack=1; + } + + GenUpdateA (0,1+a_index); + + ++a_index; + --node_id_a_size; + } + } + } + } + *free_node_ids_l=free_node_id; + + if (nil_on_stack) + GenPopA (1); + } +} + +static void SubSizeOfState (StateS state,int *a_offset_p,int *b_offset_p); + +static void SubSizeOfStates (int arity,States states,int *a_offset_p,int *b_offset_p) +{ + for (; arity; arity--) + SubSizeOfState (states [arity-1],a_offset_p,b_offset_p); +} + +static void SubSizeOfState (StateS state,int *a_offset_p,int *b_offset_p) +{ + if (IsSimpleState (state)){ + if (state.state_kind==OnB) + *b_offset_p -= ObjectSizes [state.state_object]; + else if (state.state_kind != Undefined) + *a_offset_p -= 1; + } else { + switch (state.state_type){ + case RecordState: + SubSizeOfStates (state.state_arity,state.state_record_arguments,a_offset_p,b_offset_p); + break; + case TupleState: + SubSizeOfStates (state.state_arity,state.state_tuple_arguments,a_offset_p,b_offset_p); + break; + case ArrayState: + *a_offset_p -= 1; + break; + } + } +} + +static void SubSizeOfArguments (ArgS *args,int *a_offset_p,int *b_offset_p) +{ + ArgS *arg; + + for_l (arg,args,arg_next) + SubSizeOfState (arg->arg_state,a_offset_p,b_offset_p); +} + +void DetermineSizeOfArguments (ArgS *args,int *a_offset_p,int *b_offset_p) +{ + ArgS *arg; + + *a_offset_p=0; + *b_offset_p=0; + + for_l (arg,args,arg_next) + AddSizeOfState (arg->arg_state,a_offset_p,b_offset_p); +} + +static void BuildLazyArgs (Args args,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p); +static Bool BuildNonParArgs (Args args,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p); +static void BuildParArgs (ArgS* args,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p); +static void ReorderParallelAndNonParallelArgsWithResultNode (Args args,int *asize_p,int *bsize_p); + +#define BETWEEN(l,h,v) ((unsigned)((v)-(l)) <= (unsigned)((h)-(l))) + +static int ChangeArgumentNodeStatesIfStricter (Args offered_args,States demanded_states) +{ + StateP demanded_state_p; + ArgP arg_p; + + for_la (arg_p,demanded_state_p,offered_args,demanded_states,arg_next){ + Node arg_node; + int node_kind; + + arg_node=arg_p->arg_node; + + node_kind=arg_node->node_kind; + if (node_kind!=NodeIdNode){ + if (node_kind==NormalNode && (BETWEEN (int_denot,real_denot,arg_node->node_symbol->symb_kind) || arg_node->node_symbol->symb_kind==string_denot)) + ; + else + if (!FirstStateIsStricter (arg_node->node_state,*demanded_state_p)) + return 1; + } else + if (!FirstStateIsStricter (arg_node->node_node_id->nid_state,*demanded_state_p)) + return 1; + } + + for_la (arg_p,demanded_state_p,offered_args,demanded_states,arg_next){ + Node arg_node; + + arg_node=arg_p->arg_node; + if (arg_node->node_kind==NormalNode && + (BETWEEN (int_denot,real_denot,arg_node->node_symbol->symb_kind) || arg_node->node_symbol->symb_kind==string_denot) + ){ + arg_node->node_state=*demanded_state_p; + } + + arg_p->arg_state=*demanded_state_p; + } + + return 0; +} + +void BuildArgsWithNewResultNode (Args args,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p,int *a_size_p,int *b_size_p) +{ + BuildNonParArgs (args,asp_p,bsp_p,code_gen_node_ids_p); + NewEmptyNode (asp_p,-1); + BuildParArgs (args,asp_p,bsp_p,code_gen_node_ids_p); + ReorderParallelAndNonParallelArgsWithResultNode (args,a_size_p,b_size_p); +} + +void BuildArgsWithResultNodeOnStack (Args args,NodeIdP free_unique_node_id,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p,int *a_size_p,int *b_size_p) +{ + BuildNonParArgs (args,asp_p,bsp_p,code_gen_node_ids_p); + GenPushA (*asp_p-free_unique_node_id->nid_a_index); + *asp_p+=1; + decrement_reference_count_of_node_id (free_unique_node_id,&code_gen_node_ids_p->free_node_ids); + BuildParArgs (args,asp_p,bsp_p,code_gen_node_ids_p); + ReorderParallelAndNonParallelArgsWithResultNode (args,a_size_p,b_size_p); +} + +#if OPTIMIZE_LAZY_TUPLE_RECURSION +extern LabDef d_indirection_lab,n_indirection_lab; +#endif + +static void FillSymbol (Node node,SymbDef sdef,int *asp_p,int *bsp_p,NodeId update_node_id,CodeGenNodeIdsP code_gen_node_ids_p) +{ + LabDef name; + int symbarity; + + symbarity = sdef->sdef_kind==RECORDTYPE ? sdef->sdef_cons_arity : sdef->sdef_arity; + + if (symbarity==node->node_arity){ + switch (sdef->sdef_kind){ + case IMPRULE: + case DEFRULE: + case SYSRULE: + if (IsLazyState (node->node_state)){ + LabDef codelab; + + ConvertSymbolToDandNLabel (&name,&codelab,sdef); + + if (sdef->sdef_kind==IMPRULE && (sdef->sdef_rule->rule_mark & RULE_UNBOXED_LAZY_CALL)){ + int a_size,b_size; + +#ifndef OPTIMIZE_LAZY_TUPLE_RECURSION + if (update_node_id!=NULL) + error_in_function ("FillSymbol"); +#endif + + DetermineSizeOfArguments (node->node_arguments,&a_size,&b_size); + + if (b_size!=0) + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + else + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + +#if OPTIMIZE_LAZY_TUPLE_RECURSION + if (update_node_id!=NULL){ + if (a_size+b_size<=2){ + if (b_size!=0){ + GenFillU (&name,a_size,b_size,&codelab,*asp_p-update_node_id->nid_a_index); + *bsp_p -= b_size; + } else + GenFill (&name,a_size,&codelab,*asp_p-update_node_id->nid_a_index,NormalFill); + *asp_p-=a_size; + + GenPushA (*asp_p-update_node_id->nid_a_index); + *asp_p+=1; + } else { + if (b_size!=0) + GenBuildU (&name,a_size,b_size,&codelab); + else + GenBuild (&name,a_size,&codelab); + *asp_p += 1-a_size; + *bsp_p -= b_size; + + GenFill (&d_indirection_lab,-2,&n_indirection_lab,*asp_p-update_node_id->nid_a_index,NormalFill); + --*asp_p; + } + } else +#endif + { + *asp_p += 1-a_size; + *bsp_p -= b_size; + + if (b_size!=0) + GenBuildU (&name,a_size,b_size,&codelab); + else + GenBuild (&name,a_size,&codelab); + } + return; + } + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + if (update_node_id==NULL){ + *asp_p += 1-symbarity; + GenBuild (&name,symbarity,&codelab); + } else { +#if OPTIMIZE_LAZY_TUPLE_RECURSION + if ((update_node_id->nid_mark & ON_A_CYCLE_MASK)!=0 || symbarity<=2){ + GenFill (&name,symbarity,&codelab,*asp_p-update_node_id->nid_a_index,PartialFill); + *asp_p-=symbarity; + } else { + GenBuild (&name,symbarity,&codelab); + *asp_p+=1-symbarity; + GenFill (&d_indirection_lab,-2,&n_indirection_lab,*asp_p-update_node_id->nid_a_index,NormalFill); + --*asp_p; + } +#else + GenFill (&name,symbarity,&codelab,*asp_p-update_node_id->nid_a_index,node->node_state.state_kind==SemiStrict ? PartialFill : NormalFill); + *asp_p -= symbarity; +#endif + } + } else { + int newnode,a_size,b_size; + + ConvertSymbolToLabel (&name,sdef); + + newnode=False; + + if (update_node_id==NULL && ExpectsResultNode (node->node_state)){ + BuildArgsWithNewResultNode (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p,&a_size,&b_size); + + *asp_p-=a_size; + *bsp_p-=b_size; + + if (! (sdef->sdef_kind==SYSRULE + && sdef->sdef_ident->ident_instructions!=NULL + && *sdef->sdef_ident->ident_instructions!='\0' + && *sdef->sdef_ident->ident_instructions!='.')) + { + cleanup_stack (asp_p,bsp_p,a_size,b_size,&code_gen_node_ids_p->a_node_ids,&code_gen_node_ids_p->b_node_ids, + &code_gen_node_ids_p->free_node_ids,code_gen_node_ids_p->moved_node_ids_l, + code_gen_node_ids_p->doesnt_fail); + } + CallFunction (&name,sdef,True,node); + + AddSizeOfState (node->node_state,asp_p,bsp_p); + + return; + } + + DetermineSizeOfArguments (node->node_arguments,&a_size,&b_size); + + if (update_node_id!=NULL && update_node_id->nid_a_index!=*asp_p){ + GenPushA (*asp_p-update_node_id->nid_a_index); + *asp_p += SizeOfAStackElem; + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + *asp_p-=a_size+1; /* changed 20-7-1999, was a_size */ + *bsp_p-=b_size; + + if (! (sdef->sdef_kind==SYSRULE + && sdef->sdef_ident->ident_instructions!=NULL + && *sdef->sdef_ident->ident_instructions!='\0' + && *sdef->sdef_ident->ident_instructions!='.')) + { + cleanup_stack (asp_p,bsp_p,a_size+1,b_size,&code_gen_node_ids_p->a_node_ids,&code_gen_node_ids_p->b_node_ids, + &code_gen_node_ids_p->free_node_ids,code_gen_node_ids_p->moved_node_ids_l, + code_gen_node_ids_p->doesnt_fail); + } + + CallFunction (&name,sdef,True,node); + + AddSizeOfState (node->node_state,asp_p,bsp_p); + + GenPopA (1); + *asp_p-=1; + } else { + if (newnode) + ++a_size; + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + *asp_p-=a_size; + *bsp_p-=b_size; + + if (! (sdef->sdef_kind==SYSRULE + && sdef->sdef_ident->ident_instructions!=NULL + && *sdef->sdef_ident->ident_instructions!='\0' + && *sdef->sdef_ident->ident_instructions!='.')) + { + cleanup_stack (asp_p,bsp_p,a_size,b_size,&code_gen_node_ids_p->a_node_ids,&code_gen_node_ids_p->b_node_ids, + &code_gen_node_ids_p->free_node_ids,code_gen_node_ids_p->moved_node_ids_l, + code_gen_node_ids_p->doesnt_fail); + } + + CallFunction (&name,sdef,True,node); + + AddSizeOfState (node->node_state,asp_p,bsp_p); + } + } + return; + case CONSTRUCTOR: + if (sdef->sdef_strict_constructor){ + int lazy_fill; + + ConvertSymbolToLabel (&name,sdef); + + lazy_fill=IsLazyState (node->node_state); + + if (lazy_fill) + lazy_fill=ChangeArgumentNodeStatesIfStricter (node->node_arguments,sdef->sdef_constructor->cl_state_p); + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + if (lazy_fill){ + LabDef reclab, contlab; + + ConvertSymbolToConstructorDandNLabel (&reclab,&contlab,sdef); + + if (update_node_id==NULL){ + *asp_p+=1-symbarity; + GenBuild (&reclab,symbarity,&contlab); + } else { +#if OPTIMIZE_LAZY_TUPLE_RECURSION + if ((update_node_id->nid_mark & ON_A_CYCLE_MASK)!=0 || symbarity<=2){ + GenFill (&reclab,symbarity,&contlab,*asp_p-update_node_id->nid_a_index,ReleaseAndFill); + *asp_p-=symbarity; + } else { + GenBuild (&reclab,symbarity,&contlab); + *asp_p+=1-symbarity; + GenFill (&d_indirection_lab,-2,&n_indirection_lab,*asp_p-update_node_id->nid_a_index,NormalFill); + --*asp_p; + } +#else + GenFill (&reclab,symbarity,&contlab,*asp_p-update_node_id->nid_a_index, + node->node_state.state_kind==SemiStrict ? ReleaseAndFill : NormalFill); + *asp_p-=symbarity; +#endif + } + } else { + int asize,bsize; + LabDef record_label; + + DetermineSizeOfArguments (node->node_arguments,&asize,&bsize); + + ConvertSymbolToKLabel (&record_label,sdef); + + *asp_p-=asize; + *bsp_p-=bsize; + + if (update_node_id==NULL){ + GenBuildR (&record_label,asize,bsize,0,0,True); + *asp_p+=1; + } else { + GenFillR (&record_label,asize,bsize,*asp_p+asize-update_node_id->nid_a_index,0,0,node->node_state.state_kind==SemiStrict ? ReleaseAndFill : NormalFill,True); + } + } + } else { + ConvertSymbolToConstructorDLabel (&name,sdef); + + BuildLazyArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + if (update_node_id==NULL){ + *asp_p+=1-node->node_arity; + GenBuildh (&name,node->node_arity); + } else { + GenFillh (&name,node->node_arity,*asp_p-update_node_id->nid_a_index, + node->node_state.state_kind==SemiStrict ? ReleaseAndFill : NormalFill); + *asp_p-=node->node_arity; + } + } + return; + case RECORDTYPE: + ConvertSymbolToLabel (&name,sdef); + + if (IsSimpleState (node->node_state)){ + LabDef record_label; + int lazy_fill; + + lazy_fill=sdef->sdef_strict_constructor && IsLazyState (node->node_state); + + if (lazy_fill) + lazy_fill=ChangeArgumentNodeStatesIfStricter (node->node_arguments,sdef->sdef_record_state.state_record_arguments); + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + if (lazy_fill){ + LabDef contlab; + + ConvertSymbolToRecordDandNLabel (&record_label,&contlab,sdef); + + if (update_node_id==NULL){ + *asp_p+=1-symbarity; + GenBuild (&record_label,symbarity,&contlab); + } else { +#if OPTIMIZE_LAZY_TUPLE_RECURSION + if ((update_node_id->nid_mark & ON_A_CYCLE_MASK)!=0 || symbarity<=2){ + GenFill (&record_label,symbarity,&contlab,*asp_p-update_node_id->nid_a_index,ReleaseAndFill); + *asp_p-=symbarity; + } else { + GenBuild (&record_label,symbarity,&contlab); + *asp_p+=1-symbarity; + GenFill (&d_indirection_lab,-2,&n_indirection_lab,*asp_p-update_node_id->nid_a_index,NormalFill); + --*asp_p; + } +#else + GenFill (&record_label,symbarity,&contlab,*asp_p-update_node_id->nid_a_index, + node->node_state.state_kind==SemiStrict ? ReleaseAndFill : NormalFill); + *asp_p-=symbarity; +#endif + } + } else { + int asize,bsize; + + ConvertSymbolToRLabel (&record_label,sdef); + + DetermineSizeOfArguments (node->node_arguments,&asize,&bsize); + + *asp_p-=asize; + *bsp_p-=bsize; + + if (update_node_id==NULL){ + *asp_p+=1; + GenBuildR (&record_label,asize,bsize,0,0,True); + } else { + GenFillR (&record_label,asize,bsize,*asp_p+asize-update_node_id->nid_a_index,0,0,node->node_state.state_kind==SemiStrict ? ReleaseAndFill : NormalFill,True); + } + } + } else + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + return; + default: + if (update_node_id==NULL) + NewEmptyNode (asp_p,-1); + return; + } + } else { + if (sdef->sdef_kind==CONSTRUCTOR) + ConvertSymbolToConstructorDLabel (&name,sdef); + else + ConvertSymbolToDLabel (&name,sdef); + + /* Symbol has too few arguments */ + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + if (update_node_id==NULL){ + *asp_p+=1-node->node_arity; + GenBuildh (&name,node->node_arity); + } else { + GenFillh (&name,node->node_arity,*asp_p-update_node_id->nid_a_index,NormalFill); + *asp_p-=node->node_arity; + } + } +} + +void GenTypeError (void) +{ + GenDAStackLayout (0); + GenJsr (&type_error_lab); + GenOAStackLayout (0); + + TypeErrorFound = True; +} + +static void decrement_reference_count_of_node_ids_in_graph (Node node,NodeIdListElementS **free_node_ids_l) +{ + if (node->node_kind!=NodeIdNode){ + struct arg *arg; + + for_l (arg,node->node_arguments,arg_next) + decrement_reference_count_of_node_ids_in_graph (arg->arg_node,free_node_ids_l); + } else + decrement_reference_count_of_node_id (node->node_node_id,free_node_ids_l); +} + +static void increment_reference_count_of_node_ids_in_graph (Node node) +{ + if (node->node_kind!=NodeIdNode){ + struct arg *arg; + + for_l (arg,node->node_arguments,arg_next) + increment_reference_count_of_node_ids_in_graph (arg->arg_node); + } else { + struct node_id *node_id; + int ref_count; + + node_id=node->node_node_id; + ref_count=node_id->nid_refcount; + + if (ref_count>=0) + node_id->nid_refcount=ref_count+1; + else + node_id->nid_refcount=ref_count-1; + } +} + +#ifdef FASTER_STRICT_IF + +static void build_strict_then_or_else (Node then_or_else_node,Node else_node,int *asp_p,int *bsp_p, + CodeGenNodeIdsP code_gen_node_ids_p,StateS result_state) +{ + if (then_or_else_node->node_kind!=NodeIdNode){ + SavedNidStateP saved_node_id_states; + struct code_gen_node_ids code_gen_node_ids; + MovedNodeIdP moved_node_ids; + int a_size,b_size; + + saved_node_id_states=NULL; + moved_node_ids=NULL; + + code_gen_node_ids.free_node_ids=code_gen_node_ids_p->free_node_ids; + code_gen_node_ids.saved_nid_state_l=&saved_node_id_states; + code_gen_node_ids.doesnt_fail=False; + code_gen_node_ids.moved_node_ids_l=&moved_node_ids; + code_gen_node_ids.a_node_ids=code_gen_node_ids_p->a_node_ids; + code_gen_node_ids.b_node_ids=code_gen_node_ids_p->b_node_ids; + + if (else_node!=NULL) + decrement_reference_count_of_node_ids_in_graph (else_node,&code_gen_node_ids.free_node_ids); + + Build (then_or_else_node,asp_p,bsp_p,&code_gen_node_ids); + + if (else_node!=NULL) + increment_reference_count_of_node_ids_in_graph (else_node); + + restore_saved_node_id_states (saved_node_id_states); + + DetermineSizeOfState (then_or_else_node->node_state,&a_size,&b_size); + CoerceArgumentOnTopOfStack (asp_p,bsp_p,result_state,then_or_else_node->node_state,a_size,b_size); + } else { + NodeId nid; + int a_size,b_size; + + nid=then_or_else_node->node_node_id; + DetermineSizeOfState (nid->nid_state,&a_size,&b_size); + CopyArgument (result_state,nid->nid_state,nid->nid_a_index,nid->nid_b_index,asp_p,bsp_p,a_size,b_size,True); + } +} + +static void fill_strict_if_node (Node node,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + StateS condition_result_state; + LabDef else_label,endif_label; + Args arguments,then_arg,else_arg; + int else_asp,else_bsp; + + arguments = node->node_arguments; + + SetUnaryState (&condition_result_state,OnB,BoolObj); + EvaluateCondition (arguments->arg_node,asp_p,bsp_p,code_gen_node_ids_p,condition_result_state); + + MakeLabel (&else_label,"else",NewLabelNr,no_pref); + MakeLabel (&endif_label,"endif",NewLabelNr++,no_pref); + + GenJmpFalse (&else_label); + + then_arg=arguments->arg_next; + else_arg=then_arg->arg_next; + + else_asp=*asp_p; + else_bsp=*bsp_p; + + build_strict_then_or_else (then_arg->arg_node,else_arg->arg_node,asp_p,bsp_p,code_gen_node_ids_p,node->node_state); + + GenJmp (&endif_label); + + GenLabelDefinition (&else_label); + + build_strict_then_or_else (else_arg->arg_node,NULL,&else_asp,&else_bsp,code_gen_node_ids_p,node->node_state); + + if (else_asp!=*asp_p || else_bsp!=*bsp_p){ + int a_size,b_size; + + DetermineSizeOfState (node->node_state,&a_size,&b_size); + + if (else_asp>*asp_p){ + int difference,i; + + difference=else_asp - *asp_p; + for (i=a_size-1; i>=0; --i) +#if UPDATE_POP + if (i==0) + GenUpdatePopA (0,difference); + else +#endif + GenUpdateA (i,i+difference); + +#if UPDATE_POP + if (a_size==0) +#endif + GenPopA (difference); + } else if (else_asp<*asp_p){ + int difference,i; + + difference=*asp_p - else_asp; + + if (difference>a_size){ + int n; + + GenBuildh (&nil_lab,0); + + n=(difference-a_size)-1; + + for (i=0; i<n; ++i) + GenPushA (i); + + for (i=a_size-1; i>=0; --i) + GenPushA (difference-1); + + if (a_size>0){ + GenBuildh (&nil_lab,0); + + for (i=0; i<a_size; ++i) + GenUpdateA (0,difference+i); + + GenPopA (1); + } + } else { + for (i=difference-1; i>=0; --i) + GenPushA (difference-1); + + if (difference<a_size){ + GenBuildh (&nil_lab,0); + + for (i=difference; i<a_size; ++i){ + GenUpdateA (i+difference+1,i+1); + GenUpdateA (0,i+difference+1); + } + GenPopA (1); + } + } + } + + if (else_bsp>*bsp_p){ + int difference,i; + + difference=else_bsp - *bsp_p; + for (i=b_size-1; i>=0; --i) +#if UPDATE_POP + if (i==0) + GenUpdatePopB (0,difference); + else +#endif + GenUpdateB (i,i+difference); +#if UPDATE_POP + if (b_size==0) +#endif + GenPopB (difference); + } else if (else_bsp<*bsp_p){ + int difference,i; + SymbValue sv; + + sv.val_int="0"; + + difference=*bsp_p - else_bsp; + + if (difference>b_size){ + int n; + + PushBasic (IntObj,sv); + + n=(difference-b_size)-1; + + for (i=0; i<n; ++i) + GenPushB (i); + + for (i=b_size-1; i>=0; --i) + GenPushB (difference-1); + + if (b_size>0){ + PushBasic (IntObj,sv); + + for (i=0; i<b_size; ++i) + GenUpdateB (0,difference+i); + + GenPopB (1); + } + } else { + for (i=difference-1; i>=0; --i) + GenPushB (difference-1); + + if (difference<b_size){ + PushBasic (IntObj,sv); + + for (i=difference; i<b_size; ++i){ + GenUpdateB (i+difference+1,i+1); + GenUpdateB (0,i+difference+1); + } + GenPopB (1); + } + } + } + } + + { + int result_a_size,result_b_size; + + DetermineSizeOfState (node->node_state,&result_a_size,&result_b_size); + + if (code_gen_node_ids_p->a_node_ids!=NULL){ + int asp_without_result; + NodeIdListElementP a_node_ids,a_node_id_p; + + asp_without_result=*asp_p-result_a_size; + a_node_ids=code_gen_node_ids_p->a_node_ids; + + /* JVG: changed 28-10-1999 */ + a_node_id_p=a_node_ids; + while (a_node_id_p!=NULL && a_node_id_p->nidl_node_id->nid_a_index>asp_without_result) + if (a_node_id_p->nidl_node_id->nid_a_index!=UNUSED_NODE_ID_INDEX){ + a_node_id_p=a_node_id_p->nidl_next; + a_node_ids=a_node_id_p; + } else + a_node_id_p=a_node_id_p->nidl_next; + /* + while (a_node_ids!=NULL && + a_node_ids->nidl_node_id->nid_a_index>asp_without_result && a_node_ids->nidl_node_id->nid_a_index!=UNUSED_NODE_ID_INDEX) + { + a_node_ids=a_node_ids->nidl_next; + } + */ + code_gen_node_ids_p->a_node_ids=a_node_ids; + } + + if (code_gen_node_ids_p->b_node_ids!=NULL){ + int bsp_without_result; + NodeIdListElementP b_node_ids,b_node_id_p; + + bsp_without_result=*bsp_p-result_b_size; + b_node_ids=code_gen_node_ids_p->b_node_ids; + + /* JVG: changed 28-10-1999 */ + b_node_id_p=b_node_ids; + while (b_node_id_p!=NULL && b_node_id_p->nidl_node_id->nid_b_index>bsp_without_result) + if (b_node_id_p->nidl_node_id->nid_b_index!=UNUSED_NODE_ID_INDEX){ + b_node_id_p=b_node_id_p->nidl_next; + b_node_ids=b_node_id_p; + } else + b_node_id_p=b_node_id_p->nidl_next; + /* + while (b_node_ids!=NULL && + b_node_ids->nidl_node_id->nid_b_index>bsp_without_result && b_node_ids->nidl_node_id->nid_b_index!=UNUSED_NODE_ID_INDEX) + { + b_node_ids=b_node_ids->nidl_next; + } + */ + code_gen_node_ids_p->b_node_ids=b_node_ids; + } + } + + GenLabelDefinition (&endif_label); +} +#endif + +static void FillNormalNode (Node node,int *asp_p,int *bsp_p,NodeId update_node_id,CodeGenNodeIdsP code_gen_node_ids_p) +{ + Symbol symb; + + symb = node->node_symbol; + + switch (symb->symb_kind){ + case definition: + FillSymbol (node,symb->symb_def,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + return; + case select_symb: + FillOrReduceSelectSymbol (node,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + return; + case apply_symb: + FillSymbol (node,ApplyDef,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + return; + case if_symb: +#ifdef FASTER_STRICT_IF + if (node->node_arity==3 && !IsLazyState (node->node_state) && update_node_id==NULL) + fill_strict_if_node (node,asp_p,bsp_p,code_gen_node_ids_p); + else +#endif + FillSymbol (node,IfDef,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + return; + case tuple_symb: + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + if (IsSimpleState (node->node_state)){ + if (update_node_id==NULL){ + *asp_p+=1-node->node_arity; + GenBuildh (&tuple_lab,node->node_arity); + } else { + GenFillh (&tuple_lab,node->node_arity,*asp_p-update_node_id->nid_a_index, + node->node_state.state_kind == SemiStrict ? ReleaseAndFill : NormalFill); + *asp_p-=node->node_arity; + } + } + return; + case cons_symb: + BuildLazyArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + if (update_node_id==NULL){ + *asp_p+=1-node->node_arity; + GenBuildh (&cons_lab,node->node_arity); + } else { + GenFillh (&cons_lab, node->node_arity,*asp_p-update_node_id->nid_a_index, + node->node_state.state_kind == SemiStrict ? ReleaseAndFill : NormalFill); + *asp_p-=node->node_arity; + } + return; + case nil_symb: + if (update_node_id==NULL){ + *asp_p+=1; + GenBuildh (&nil_lab,node->node_arity); + } else + GenFillh (&nil_lab,node->node_arity,*asp_p-update_node_id->nid_a_index, + node->node_state.state_kind == SemiStrict ? ReleaseAndFill : NormalFill); + return; + case string_denot: + GenBuildString (symb->symb_val); + *asp_p+=1; + if (IsSimpleState (node->node_state)){ + if (update_node_id==NULL){ + GenBuildh (&BasicDescriptors[ArrayObj],1); + } else { + GenFillh (&BasicDescriptors[ArrayObj],1,*asp_p-update_node_id->nid_a_index,ReleaseAndFill); + *asp_p-=1; + } + } + return; + default: + if (symb->symb_kind<Nr_Of_Basic_Types){ + if (update_node_id==NULL){ + *asp_p+=1; + GenBuildh (&BasicDescriptors[symb->symb_kind],0); + } else + GenFillh (&BasicDescriptors[symb->symb_kind],0,*asp_p-update_node_id->nid_a_index, + node->node_state.state_kind == SemiStrict ? ReleaseAndFill : NormalFill); + } else { + ObjectKind denottype; + + denottype = (symb->symb_kind < Nr_Of_Predef_Types) + ? BasicSymbolStates [symb->symb_kind].state_object + : UnknownObj; + + if (node->node_state.state_object==denottype || + node->node_state.state_object==UnknownObj || denottype==UnknownObj +#if ABSTRACT_OBJECT + || node->node_state.state_object==AbstractObj || denottype==AbstractObj +#endif + ) + { + if (node->node_state.state_kind==OnB){ + *bsp_p += ObjectSizes [denottype]; + PushBasic (denottype, symb->symb_val); + } else { + if (update_node_id==NULL){ + *asp_p+=1; + BuildBasic (denottype,symb->symb_val); + } else { + FillBasic (denottype,symb->symb_val,*asp_p-update_node_id->nid_a_index, + node->node_state.state_kind == SemiStrict ? ReleaseAndFill : NormalFill); + } + } + } else { + StaticMessage (False,CurrentAltLabel.lab_symbol->sdef_ident->ident_name,Co_Wtype); + GenTypeError(); + } + } + } +} + +void RemoveSelectorsFromUpdateNode (ArgS *previous_arg,ArgS *arg) +{ + while (arg!=NULL){ + ArgS *field_arg; + + field_arg=arg->arg_node->node_arguments; + + previous_arg->arg_next=field_arg; + previous_arg=field_arg; + + arg=arg->arg_next; + } + previous_arg->arg_next=NULL; +} + +void UpdateNodeAndAddSelectorsToUpdateNode + (ArgS *record_arg,ArgS *first_field_arg,StateS *field_states,int record_a_size,int record_b_size,int *asp_p,int *bsp_p) +{ + ArgS *arg,*previous_arg; + int a_offset,b_offset,arg_a_offset,arg_b_offset,previous_field_number; + + a_offset=0; + b_offset=0; + arg_a_offset=record_a_size; + arg_b_offset=record_b_size; + + previous_field_number=0; + + previous_arg=record_arg; + for_l (arg,first_field_arg,arg_next){ + int field_number,arg_a_size,arg_b_size; + Node field_node; + + field_node=arg->arg_node; + field_node->node_arguments->arg_next=NULL; + + field_number=field_node->node_symbol->symb_def->sdef_sel_field_number; + + while (field_number!=previous_field_number){ + AddSizeOfState (field_states[previous_field_number],&a_offset,&b_offset); + ++previous_field_number; + } + + DetermineSizeOfState (field_states[field_number],&arg_a_size,&arg_b_size); + + while (arg_a_size){ + GenUpdateA (arg_a_offset,a_offset); + ++arg_a_offset; + ++a_offset; + --arg_a_size; + } + + while (arg_b_size){ + GenUpdateB (arg_b_offset,b_offset); + ++arg_b_offset; + ++b_offset; + --arg_b_size; + } + + ++previous_field_number; + + previous_arg->arg_next=arg; + previous_arg=arg; + } + previous_arg->arg_next=NULL; + + if (arg_a_offset!=record_a_size){ + a_offset=record_a_size; + while (a_offset>0){ + --a_offset; + --arg_a_offset; +#if UPDATE_POP + if (a_offset==0) + GenUpdatePopA (a_offset,arg_a_offset); + else +#endif + GenUpdateA (a_offset,arg_a_offset); + } +#if UPDATE_POP + if (record_a_size==0) +#endif + GenPopA (arg_a_offset); + + *asp_p -= arg_a_offset; + } + + if (arg_b_offset!=record_b_size){ + b_offset=record_b_size; + while (b_offset>0){ + --b_offset; + --arg_b_offset; +#if UPDATE_POP + if (b_offset==0) + GenUpdatePopB (b_offset,arg_b_offset); + else +#endif + GenUpdateB (b_offset,arg_b_offset); + } +#if UPDATE_POP + if (record_b_size==0) +#endif + GenPopB (arg_b_offset); + *bsp_p -= arg_b_offset; + } +} + +#ifdef DESTRUCTIVE_RECORD_UPDATES +void compute_bits_and_add_selectors_to_update_node + (ArgS *record_arg,ArgS *first_field_arg,StateS *field_states,int record_a_size,int record_b_size, + char bits[],int *n_a_fill_bits_p,int *n_b_fill_bits_p) +{ + ArgP arg,previous_arg; + int a_offset,b_offset,previous_field_number; + unsigned int a_bits,b_bits,n,arg_n,n_args; + int n_a_fill_bits,n_b_fill_bits; + + a_bits=0; + b_bits=0; + n_a_fill_bits=0; + n_b_fill_bits=0; + + a_offset=0; + b_offset=0; + + previous_field_number=0; + + previous_arg=record_arg; + for_l (arg,first_field_arg,arg_next){ + int field_number,arg_a_size,arg_b_size; + Node field_node; + + field_node=arg->arg_node; + field_node->node_arguments->arg_next=NULL; + + field_number=field_node->node_symbol->symb_def->sdef_sel_field_number; + + while (field_number!=previous_field_number){ + AddSizeOfState (field_states[previous_field_number],&a_offset,&b_offset); + ++previous_field_number; + } + + DetermineSizeOfState (field_states[field_number],&arg_a_size,&arg_b_size); + + a_bits |= (~((~0)<<arg_a_size))<<a_offset; + b_bits |= (~((~0)<<arg_b_size))<<b_offset; + + n_a_fill_bits+=arg_a_size; + n_b_fill_bits+=arg_b_size; + + a_offset+=arg_a_size; + b_offset+=arg_b_size; + + ++previous_field_number; + + previous_arg->arg_next=arg; + previous_arg=arg; + } + previous_arg->arg_next=NULL; + + bits[0]='0'; + + for (n=0; n<record_a_size; ++n){ + if (a_bits & (1<<n)) + bits[n+1]='1'; + else + bits[n+1]='0'; + } + + for (n=0; n<record_b_size; ++n){ + if (b_bits & (1<<n)) + bits[n+record_a_size+1]='1'; + else + bits[n+record_a_size+1]='0'; + } + + bits[record_a_size+record_b_size+1]='\0'; + + *n_a_fill_bits_p=n_a_fill_bits; + *n_b_fill_bits_p=n_b_fill_bits; +} +#endif + +static void FillUpdateNode (Node node,int *asp_p,int *bsp_p,NodeId update_node_id,CodeGenNodeIdsP code_gen_node_ids_p) +{ + ArgS *record_arg,*first_field_arg; + int record_a_size,record_b_size; + + record_arg=node->node_arguments; + first_field_arg=record_arg->arg_next; + + RemoveSelectorsFromUpdateNode (record_arg,first_field_arg); + + if (IsSimpleState (node->node_state)){ + int n_arguments; + LabDef name,codelab; + SymbDef new_update_sdef; + struct node *record_node; +#if DESTRUCTIVE_RECORD_UPDATES + int update_immediately; + StateP record_node_id_state_p; + + record_node=record_arg->arg_node; + + if (node->node_state.state_kind==StrictOnA){ + update_immediately=1; + record_node_id_state_p=&node->node_symbol->symb_def->sdef_record_state; + } else { + update_immediately=0; + + if (record_node->node_kind==NodeIdNode){ + record_node_id_state_p=&record_node->node_node_id->nid_state; + + if (record_node_id_state_p->state_type==RecordState){ + update_immediately=1; + + if (record_node_id_state_p->state_record_symbol->sdef_strict_constructor){ + StateS *record_states; + + record_states=record_node_id_state_p->state_record_arguments; + + if (!FieldArgumentNodeStatesAreStricter (record_arg->arg_next,first_field_arg,record_states)) + update_immediately=0; + else { + ArgP node_arg,field_arg; + + for_ll (node_arg,field_arg,record_arg->arg_next,first_field_arg,arg_next,arg_next){ + Node arg_node; + int field_number; + + field_number=field_arg->arg_node->node_symbol->symb_def->sdef_sel_field_number; + + arg_node=node_arg->arg_node; + if (arg_node->node_kind==NormalNode && + (BETWEEN (int_denot,real_denot,arg_node->node_symbol->symb_kind) || arg_node->node_symbol->symb_kind==string_denot)) + { + arg_node->node_state=record_states[field_number]; + } + + node_arg->arg_state=record_states[field_number]; + } + } + } + } + } + } + + if (update_immediately){ + if (node->node_state.state_kind==StrictOnA && record_node->node_kind==NodeIdNode){ + NodeIdP record_node_id; + + record_node_id=record_node->node_node_id; + + if ((record_node_id->nid_state.state_mark & STATE_UNIQUE_MASK)!=0 && + (record_node_id->nid_mark2 & NID_HAS_REFCOUNT_WITHOUT_UPDATES)!=0 && + record_node_id->nid_number== -1 && + record_node_id->nid_state.state_type==SimpleState && + record_node_id->nid_state.state_kind==StrictOnA && + update_node_id==NULL) + { + int n_a_fill_bits,n_b_fill_bits; + char bits[MaxNodeArity+2]; + LabDef record_lab; + + BuildArgs (record_arg->arg_next,asp_p,bsp_p,code_gen_node_ids_p); + + DetermineSizeOfState (*record_node_id_state_p,&record_a_size,&record_b_size); + + compute_bits_and_add_selectors_to_update_node (record_arg,first_field_arg, + record_node_id_state_p->state_record_arguments,record_a_size,record_b_size, + bits,&n_a_fill_bits,&n_b_fill_bits); + + ConvertSymbolToRLabel (&record_lab,record_node_id_state_p->state_record_symbol); + + if (record_a_size+record_b_size>2) + GenFill2R (&record_lab,record_a_size,record_b_size,*asp_p-record_node_id->nid_a_index,bits); + else + GenFill1R (&record_lab,record_a_size,record_b_size,*asp_p-record_node_id->nid_a_index,bits); + + *asp_p-=n_a_fill_bits; + *bsp_p-=n_b_fill_bits; + + GenPushA (*asp_p-record_node_id->nid_a_index); + *asp_p+=1; + + decrement_reference_count_of_node_id (record_node_id,&code_gen_node_ids_p->free_node_ids); + + return; + } + } + + record_arg->arg_state=*record_node_id_state_p; + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + DetermineSizeOfState (*record_node_id_state_p,&record_a_size,&record_b_size); + + UpdateNodeAndAddSelectorsToUpdateNode (record_arg,first_field_arg, + record_node_id_state_p->state_record_arguments,record_a_size,record_b_size,asp_p,bsp_p); + + if (update_node_id==NULL){ + BuildRecord (record_node_id_state_p->state_record_symbol,*asp_p,*bsp_p,*asp_p,*bsp_p,record_a_size,record_b_size, + 0,node->node_state.state_kind==SemiStrict ? PartialFill : NormalFill,True); + *asp_p+=1; + GenUpdateA (0,record_a_size); + } else + BuildRecord (record_node_id_state_p->state_record_symbol,*asp_p,*bsp_p,*asp_p,*bsp_p,record_a_size,record_b_size, + *asp_p-update_node_id->nid_a_index,node->node_state.state_kind==SemiStrict ? PartialFill : NormalFill,False); + + GenPopA (record_a_size); + *asp_p-=record_a_size; + GenPopB (record_b_size); + *bsp_p-=record_b_size; + + return; + } +#else + record_node=record_arg->arg_node; + if (record_node->node_kind==NodeIdNode){ + StateP record_node_id_state_p; + + record_node_id_state_p=&record_node->node_node_id->nid_state; + + if (record_node_id_state_p->state_type==SimpleState && record_node_id_state_p->state_kind==StrictOnA) + record_node_id_state_p=&node->node_symbol->symb_def->sdef_record_state; + + if (record_node_id_state_p->state_type==RecordState){ + int update_immediately; + + update_immediately=1; + + if (record_node_id_state_p->state_record_symbol->sdef_strict_constructor){ + StateP record_states; + + record_states=record_node_id_state_p->state_record_arguments; + + if (!FieldArgumentNodeStatesAreStricter (record_arg->arg_next,first_field_arg,record_states)) + update_immediately=0; + else { + ArgP node_arg,field_arg; + + for_ll (node_arg,field_arg,record_arg->arg_next,first_field_arg,arg_next,arg_next){ + Node arg_node; + int field_number; + + field_number=field_arg->arg_node->node_symbol->symb_def->sdef_sel_field_number; + + arg_node=node_arg->arg_node; + if (arg_node->node_kind==NormalNode && + (BETWEEN (int_denot,real_denot,arg_node->node_symbol->symb_kind) || arg_node->node_symbol->symb_kind==string_denot)) + { + arg_node->node_state=record_states[field_number]; + } + + node_arg->arg_state=record_states[field_number]; + } + } + } + + if (update_immediately){ + record_arg->arg_state=*record_node_id_state_p; + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + DetermineSizeOfState (*record_node_id_state_p,&record_a_size,&record_b_size); + + UpdateNodeAndAddSelectorsToUpdateNode (record_arg,first_field_arg, + record_node_id_state_p->state_record_arguments,record_a_size,record_b_size,asp_p,bsp_p); + + if (update_node_id==NULL){ + BuildRecord (record_node_id_state_p->state_record_symbol,*asp_p,*bsp_p,*asp_p,*bsp_p,record_a_size,record_b_size, + 0,node->node_state.state_kind==SemiStrict ? PartialFill : NormalFill,True); + *asp_p+=1; + GenUpdateA (0,record_a_size); + } else + BuildRecord (record_node_id_state_p->state_record_symbol,*asp_p,*bsp_p,*asp_p,*bsp_p,record_a_size,record_b_size, + *asp_p-update_node_id->nid_a_index,node->node_state.state_kind==SemiStrict ? PartialFill : NormalFill,False); + + GenPopA (record_a_size); + *asp_p-=record_a_size; + GenPopB (record_b_size); + *bsp_p-=record_b_size; + + return; + } + } + } +#endif + + n_arguments=node->node_arity; + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + new_update_sdef=CreateUpdateFunction (record_arg,first_field_arg,node); + + ConvertSymbolToDandNLabel (&name,&codelab,new_update_sdef); + + if (update_node_id==NULL){ + GenBuild (&name,n_arguments,&codelab); + *asp_p+=1-n_arguments; + } else { + GenFill (&name,n_arguments,&codelab,*asp_p-update_node_id->nid_a_index,node->node_state.state_kind==SemiStrict ? PartialFill : NormalFill); + *asp_p-=n_arguments; + } + } else { + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + DetermineSizeOfState (node->node_state,&record_a_size,&record_b_size); + + UpdateNodeAndAddSelectorsToUpdateNode (record_arg,first_field_arg, + node->node_state.state_record_arguments,record_a_size,record_b_size,asp_p,bsp_p); + } +} + +static LabDef selector_m_error_lab = {NULL,"",False,"selector_m_error",0}; + +void FillMatchNode (Node node,int *asp_p,int *bsp_p,NodeId update_node_id,CodeGenNodeIdsP code_gen_node_ids_p) +{ + int symbol_arity_eq_one; + Symbol symbol; + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + symbol=node->node_symbol; + + if (symbol->symb_kind==definition && symbol->symb_def->sdef_kind==CONSTRUCTOR && symbol->symb_def->sdef_arity==1) + symbol_arity_eq_one=1; + else + symbol_arity_eq_one=0; + + if (IsSimpleState (node->node_state) && !(symbol_arity_eq_one && !IsLazyState (node->node_state))){ + int n_arguments,strict_constructor; + LabDef name,codelab; + SymbDef new_match_sdef; + + strict_constructor=0; + + if (symbol->symb_kind==definition && symbol->symb_def->sdef_kind==CONSTRUCTOR){ + if (symbol->symb_def->sdef_strict_constructor) + strict_constructor=1; + else + if (symbol->symb_def->sdef_type->type_nr_of_constructors==1){ + if (symbol_arity_eq_one){ + LabDef sellab, nsellab; + + BuildLazyTupleSelectorLabel (&nsellab,1,1); + + sellab = nsellab; + sellab.lab_pref = d_pref; + + if (update_node_id==NULL){ + GenBuild (&sellab,-1,&nsellab); + } else { + GenFill (&sellab,-1,&nsellab,*asp_p-update_node_id->nid_a_index,node->node_state.state_kind==SemiStrict ? PartialFill : NormalFill); + *asp_p-=1; + } + } else + if (update_node_id!=NULL){ + GenFillFromA (0,*asp_p-update_node_id->nid_a_index,node->node_state.state_kind==SemiStrict ? PartialFill : NormalFill); + GenPopA (1); + *asp_p-=1; + } + + return; + } + } + + if (!symbol_arity_eq_one) + new_match_sdef=create_match_function (symbol,node->node_arity,strict_constructor); + else + new_match_sdef=create_select_and_match_function (symbol,strict_constructor); + + ConvertSymbolToDandNLabel (&name,&codelab,new_match_sdef); + + n_arguments=1; + + if (update_node_id==NULL){ + GenBuild (&name,n_arguments,&codelab); + } else { + GenFill (&name,n_arguments,&codelab,*asp_p-update_node_id->nid_a_index,node->node_state.state_kind==SemiStrict ? PartialFill : NormalFill); + *asp_p-=1; + } + } else { + struct state *demanded_state_array; + int demanded_state_arity; + int a_size,b_size; + struct arg *argument; + struct symbol *symbol; + int branch; + + argument = node->node_arguments; + + DetermineSizeOfState (argument->arg_state,&a_size,&b_size); + + if (CoerceStateKind (StrictOnA,argument->arg_state.state_kind)==Reduce) + GenJsrEval (0); + + symbol=node->node_symbol; + + branch=1; + + switch (symbol->symb_kind){ + case cons_symb: + GenEqDesc (&cons_lab,2,0); + break; + case definition: + { + SymbDef sdef; + + sdef=symbol->symb_def; + + if (sdef->sdef_kind==CONSTRUCTOR){ + if (sdef->sdef_type->type_nr_of_constructors==1){ + branch=0; + } else { + LabDef symbol_label; + + if (sdef->sdef_strict_constructor){ + ConvertSymbolToKLabel (&symbol_label,sdef); + GenEqDesc (&symbol_label,0,0); + } else { + ConvertSymbolToConstructorDLabel (&symbol_label,sdef); + GenEqDesc (&symbol_label,node->node_arity,0); + } + } + break; + } + } + default: + error_in_function ("FillMatchNode"); + } + + if (branch){ +#if 1 + GenExitFalse (&selector_m_error_lab); +#else + LabDef local_label; + + MakeLabel (&local_label,m_symb,NewLabelNr++,no_pref); + GenJmpTrue (&local_label); + + GenJmp (&selector_m_error_lab); + + GenLabelDefinition (&local_label); +#endif + } + + if (symbol_arity_eq_one){ + demanded_state_array=&node->node_state; + demanded_state_arity=1; + } else { + demanded_state_array=node->node_state.state_tuple_arguments; + demanded_state_arity=node->node_state.state_arity; + } + + if (symbol->symb_kind==definition && symbol->symb_def->sdef_kind==CONSTRUCTOR && symbol->symb_def->sdef_strict_constructor){ + StateP constructor_args_state_p; + int a_size,b_size,arity; + + arity=symbol->symb_def->sdef_arity; + + constructor_args_state_p=symbol->symb_def->sdef_constructor->cl_state_p; + DetermineSizeOfStates (arity,constructor_args_state_p,&a_size,&b_size); + + GenReplRArgs (a_size,b_size); + *asp_p -= 1-a_size; + *bsp_p += b_size; + + AdjustTuple (a_size,b_size,asp_p,bsp_p,arity,demanded_state_array,constructor_args_state_p,a_size,b_size); + } else { + *asp_p-=1; + UnpackTuple (*asp_p,asp_p,bsp_p,True,demanded_state_arity,demanded_state_array); + } + } +} + +#ifdef REUSE_UNIQUE_NODES +# if GENERATE_CODE_AGAIN +extern int call_code_generator_again; + +static void restore_removed_arguments (ArgP *arg_h,ArgP removed_args,unsigned int argument_overwrite_bits,int node_arity) +{ + int arg_n; + ArgP not_removed_args; + + not_removed_args=*arg_h; + + for (arg_n=0; arg_n<node_arity; ++arg_n){ + if (argument_overwrite_bits & (1<<arg_n)){ + *arg_h=not_removed_args; + arg_h=¬_removed_args->arg_next; + not_removed_args=not_removed_args->arg_next; + } else { + *arg_h=removed_args; + arg_h=&removed_args->arg_next; + removed_args=removed_args->arg_next; + } + } +} +# endif + +static +#if GENERATE_CODE_AGAIN + ArgP +#else + void +#endif + compute_bits_and_remove_unused_arguments (NodeP node,char bits[],unsigned int argument_overwrite_bits, + int *a_size_p,int *b_size_p,int *n_a_fill_bits_p,int *n_b_fill_bits_p) +{ + unsigned int a_bits,b_bits,a_size,b_size,n,arg_n; + int n_a_fill_bits,n_b_fill_bits,node_arity; + ArgS **arg_l; +#if GENERATE_CODE_AGAIN + ArgP removed_args,*removed_args_l; + + removed_args_l=&removed_args; +#endif + + arg_l=&node->node_arguments; + node_arity=node->node_arity; + + a_bits=0; + b_bits=0; + a_size=0; + b_size=0; + n_a_fill_bits=0; + n_b_fill_bits=0; + + for (arg_n=0; arg_n<node_arity; ++arg_n){ + ArgP arg_p; + int arg_a_size,arg_b_size; + + arg_p=*arg_l; + + DetermineSizeOfState (arg_p->arg_state,&arg_a_size,&arg_b_size); + + if (argument_overwrite_bits & (1<<arg_n)){ + a_bits |= (~((~0)<<arg_a_size))<<a_size; + b_bits |= (~((~0)<<arg_b_size))<<b_size; + + n_a_fill_bits+=arg_a_size; + n_b_fill_bits+=arg_b_size; + + arg_l=&arg_p->arg_next; + } else { + *arg_l=arg_p->arg_next; +#if GENERATE_CODE_AGAIN + *removed_args_l=arg_p; + removed_args_l=&arg_p->arg_next; +#endif + } + + a_size+=arg_a_size; + b_size+=arg_b_size; + } +#if GENERATE_CODE_AGAIN + *removed_args_l=NULL; +#endif + + for (n=0; n<a_size; ++n) + bits[n+1]='0' + ((a_bits>>n) & 1); + + for (n=0; n<b_size; ++n) + bits[n+a_size+1]='0' + ((b_bits>>n) & 1); + + bits[a_size+b_size+1]='\0'; + + *a_size_p=a_size; + *b_size_p=b_size; + *n_a_fill_bits_p=n_a_fill_bits; + *n_b_fill_bits_p=n_b_fill_bits; + +#if GENERATE_CODE_AGAIN + return removed_args; +#endif +} + +static void FillUniqueNodeWithNode (NodeP update_node,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + unsigned int argument_overwrite_bits,n_args,node_arity,arg_n; + char bits[MaxNodeArity+2]; + NodeIdP free_unique_node_id; + NodeP node,push_node; + LabDef name,*label_p; + SymbolP symbol; + ArgS **arg_l; + + node=update_node->node_arguments->arg_node; + push_node=update_node->node_node; + free_unique_node_id=push_node->node_arguments->arg_node->node_node_id; + + symbol=node->node_symbol; + + switch (symbol->symb_kind){ + case definition: + { + SymbDef sdef; + + sdef=node->node_symbol->symb_def; + + node_arity=node->node_arity; + + switch (sdef->sdef_kind){ + case CONSTRUCTOR: + if (push_node->node_record_symbol==node->node_symbol && push_node->node_arity==node_arity) + bits[0]='0'; + else + bits[0]='1'; + + if (sdef->sdef_strict_constructor){ + int a_size,b_size,n_a_fill_bits,n_b_fill_bits; +#if GENERATE_CODE_AGAIN + ArgP removed_args= +#endif + compute_bits_and_remove_unused_arguments (node,bits,update_node->node_arguments->arg_occurrence, + &a_size,&b_size,&n_a_fill_bits,&n_b_fill_bits); + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + +#if GENERATE_CODE_AGAIN + if (call_code_generator_again) + restore_removed_arguments (&node->node_arguments,removed_args,update_node->node_arguments->arg_occurrence,node->node_arity); +#endif + + ConvertSymbolToKLabel (&name,sdef); + + if (a_size+b_size>2) + GenFill2R (&name,a_size,b_size,*asp_p-free_unique_node_id->nid_a_index,bits); + else + GenFill1R (&name,a_size,b_size,*asp_p-free_unique_node_id->nid_a_index,bits); + + *asp_p-=n_a_fill_bits; + *bsp_p-=n_b_fill_bits; + + GenPushA (*asp_p-free_unique_node_id->nid_a_index); + *asp_p+=1; + + decrement_reference_count_of_node_id (free_unique_node_id,&code_gen_node_ids_p->free_node_ids); + + return; + } else { + ConvertSymbolToConstructorDLabel (&name,sdef); + label_p=&name; + } + break; + case RECORDTYPE: + { + int a_size,b_size,n_a_fill_bits,n_b_fill_bits; +#if GENERATE_CODE_AGAIN + ArgP removed_args; +#endif + if (push_node->node_record_symbol==node->node_symbol && push_node->node_arity==node_arity) + bits[0]='0'; + else + bits[0]='1'; + +#if GENERATE_CODE_AGAIN + removed_args= +#endif + compute_bits_and_remove_unused_arguments (node,bits,update_node->node_arguments->arg_occurrence, + &a_size,&b_size,&n_a_fill_bits,&n_b_fill_bits); + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + +#if GENERATE_CODE_AGAIN + if (call_code_generator_again) + restore_removed_arguments (&node->node_arguments,removed_args,update_node->node_arguments->arg_occurrence,node->node_arity); +#endif + + ConvertSymbolToRLabel (&name,sdef); + + if (a_size+b_size>2) + GenFill2R (&name,a_size,b_size,*asp_p-free_unique_node_id->nid_a_index,bits); + else + GenFill1R (&name,a_size,b_size,*asp_p-free_unique_node_id->nid_a_index,bits); + + *asp_p-=n_a_fill_bits; + *bsp_p-=n_b_fill_bits; + + GenPushA (*asp_p-free_unique_node_id->nid_a_index); + *asp_p+=1; + + decrement_reference_count_of_node_id (free_unique_node_id,&code_gen_node_ids_p->free_node_ids); + + return; + } + case IMPRULE: + case DEFRULE: + case SYSRULE: + if (IsLazyState (node->node_state)){ + LabDef codelab; + + ConvertSymbolToDandNLabel (&name,&codelab,sdef); + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + if (sdef->sdef_kind==IMPRULE && (sdef->sdef_rule->rule_mark & RULE_UNBOXED_LAZY_CALL)){ + int a_size,b_size; + + DetermineSizeOfArguments (node->node_arguments,&a_size,&b_size); + + if (a_size+b_size>node->node_arity){ + *asp_p += 1-a_size; + *bsp_p -= b_size; + if (b_size!=0) + GenBuildU (&name,a_size,b_size,&codelab); + else + GenBuild (&name,a_size,&codelab); + } else { + if (b_size!=0){ + GenFillU (&name,a_size,b_size,&codelab,*asp_p-free_unique_node_id->nid_a_index); + *bsp_p -= b_size; + } else + GenFill (&name,a_size,&codelab,*asp_p-free_unique_node_id->nid_a_index,NormalFill); + *asp_p-=a_size; + + GenPushA (*asp_p-free_unique_node_id->nid_a_index); + *asp_p+=1; + } + } else { + GenFill (&name,node->node_arity,&codelab,*asp_p-free_unique_node_id->nid_a_index,NormalFill); + *asp_p-=node->node_arity; + + GenPushA (*asp_p-free_unique_node_id->nid_a_index); + *asp_p+=1; + } + decrement_reference_count_of_node_id (free_unique_node_id,&code_gen_node_ids_p->free_node_ids); + + return; + } else { + int a_size,b_size; + + ConvertSymbolToLabel (&name,sdef); + + BuildArgsWithResultNodeOnStack (node->node_arguments,free_unique_node_id,asp_p,bsp_p,code_gen_node_ids_p,&a_size,&b_size); + + *asp_p-=a_size; + *bsp_p-=b_size; + + if (! (sdef->sdef_kind==SYSRULE + && sdef->sdef_ident->ident_instructions!=NULL + && *sdef->sdef_ident->ident_instructions!='\0' + && *sdef->sdef_ident->ident_instructions!='.')) + { + cleanup_stack (asp_p,bsp_p,a_size,b_size,&code_gen_node_ids_p->a_node_ids,&code_gen_node_ids_p->b_node_ids, + &code_gen_node_ids_p->free_node_ids,code_gen_node_ids_p->moved_node_ids_l, + code_gen_node_ids_p->doesnt_fail); + } + + CallFunction (&name,sdef,True,node); + + AddSizeOfState (node->node_state,asp_p,bsp_p); + + return; + } + default: + error_in_function ("FillUniqueNodeWithNode"); + return; + } + break; + } + case cons_symb: + node_arity=2; + + if (push_node->node_record_symbol->symb_kind==cons_symb && push_node->node_arity==node_arity) + bits[0]='0'; + else + bits[0]='1'; + + label_p=&cons_lab; + break; + case tuple_symb: + node_arity=node->node_arity; + + if (push_node->node_record_symbol->symb_kind==tuple_symb && push_node->node_arity==node_arity) + bits[0]='0'; + else + bits[0]='1'; + + label_p=&tuple_lab; + break; + default: + error_in_function ("FillUniqueNodeWithNode"); + return; + } + + arg_l=&node->node_arguments; + + argument_overwrite_bits=update_node->node_arguments->arg_occurrence; + + n_args=0; + +#if GENERATE_CODE_AGAIN + { + ArgP removed_args,*removed_args_l; + + removed_args_l=&removed_args; +#endif + + for (arg_n=0; arg_n<node_arity; ++arg_n){ + ArgP arg_p; + + arg_p=*arg_l; + if (argument_overwrite_bits & (1<<arg_n)){ + bits[arg_n+1]='1'; + arg_l=&(arg_p->arg_next); + ++n_args; + } else { + bits[arg_n+1]='0'; + *arg_l=arg_p->arg_next; +#if GENERATE_CODE_AGAIN + *removed_args_l=arg_p; + removed_args_l=&arg_p->arg_next; +#endif + } + } + +#if GENERATE_CODE_AGAIN + *removed_args_l=NULL; +#endif + + bits[arg_n+1]='\0'; + + BuildLazyArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + +#if GENERATE_CODE_AGAIN + if (call_code_generator_again) + restore_removed_arguments (&node->node_arguments,removed_args,update_node->node_arguments->arg_occurrence,node_arity); + } +#endif + + if (node_arity<=2) + GenFill1 (label_p,node_arity,*asp_p-free_unique_node_id->nid_a_index,bits); + else + GenFill2 (label_p,node_arity,*asp_p-free_unique_node_id->nid_a_index,bits); + + *asp_p-=n_args; + + GenPushA (*asp_p-free_unique_node_id->nid_a_index); + *asp_p+=1; + + decrement_reference_count_of_node_id (free_unique_node_id,&code_gen_node_ids_p->free_node_ids); +} +#endif + +#if ! OPTIMIZE_LAZY_TUPLE_RECURSION +static +#endif +void FillNodeOnACycle (Node node,int *asp_p,int *bsp_p,NodeId update_node_id,CodeGenNodeIdsP code_gen_node_ids_p) +{ + switch (node->node_kind){ + case NormalNode: + FillNormalNode (node,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + break; + case SelectorNode: + FillOrReduceFieldSelection (node,node->node_symbol->symb_def,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + break; + case UpdateNode: + FillUpdateNode (node,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + break; + case MatchNode: + FillMatchNode (node,asp_p,bsp_p,update_node_id,code_gen_node_ids_p); + break; + default: + error_in_function ("FillNodeOnACycle"); + } +} + +void Build (Node node,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + switch (node->node_kind){ + case NormalNode: + FillNormalNode (node,asp_p,bsp_p,NULL,code_gen_node_ids_p); + break; + case SelectorNode: + FillOrReduceFieldSelection (node,node->node_symbol->symb_def,asp_p,bsp_p,NULL,code_gen_node_ids_p); + break; + case UpdateNode: + FillUpdateNode (node,asp_p,bsp_p,NULL,code_gen_node_ids_p); + break; + case MatchNode: + FillMatchNode (node,asp_p,bsp_p,NULL,code_gen_node_ids_p); + break; +#ifdef REUSE_UNIQUE_NODES + case FillUniqueNode: + FillUniqueNodeWithNode (node,asp_p,bsp_p,code_gen_node_ids_p); + break; +#endif + default: + error_in_function ("Build"); + } +} + +void build_and_cleanup (Node node,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + SymbDef sdef; + + sdef=NULL; + + if (node->node_kind==NormalNode){ + switch (node->node_symbol->symb_kind){ + case definition: + sdef=node->node_symbol->symb_def; + break; + case apply_symb: + sdef=ApplyDef; + break; +#ifndef FASTER_STRICT_IF + case if_symb: + sdef=IfDef; + break; +#endif + } + } + + if (sdef!=NULL){ + int sdef_kind; + + sdef_kind=sdef->sdef_kind; + + if ((sdef_kind==IMPRULE || sdef_kind==DEFRULE || sdef_kind==SYSRULE) && + sdef->sdef_arity==node->node_arity && !IsLazyState (node->node_state)) + { + LabDef name; + int a_size,b_size; + ArgP node_args; + + ConvertSymbolToLabel (&name,sdef); + + node_args=node->node_arguments; + DetermineSizeOfArguments (node_args,&a_size,&b_size); +#if 1 + if (ExpectsResultNode (node->node_state)) + BuildArgsWithNewResultNode (node_args,asp_p,bsp_p,code_gen_node_ids_p,&a_size,&b_size); + else +#else + if (ExpectsResultNode (node->node_state)){ + NewEmptyNode (asp_p,-1); + ++a_size; + } +#endif + BuildArgs (node_args,asp_p,bsp_p,code_gen_node_ids_p); + + *asp_p-=a_size; + *bsp_p-=b_size; + + cleanup_stack (asp_p,bsp_p,a_size,b_size,&code_gen_node_ids_p->a_node_ids,&code_gen_node_ids_p->b_node_ids, + &code_gen_node_ids_p->free_node_ids,code_gen_node_ids_p->moved_node_ids_l, + code_gen_node_ids_p->doesnt_fail); + + CallFunction (&name,sdef,True,node); + + AddSizeOfState (node->node_state,asp_p,bsp_p); + + return; + } + } + + Build (node,asp_p,bsp_p,code_gen_node_ids_p); +} + +void BuildArg (Args arg,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + NodeP node; + int asize,bsize; + + ArgComment (arg); + + node=arg->arg_node; + + if (node->node_kind!=NodeIdNode){ + Build (node,asp_p,bsp_p,code_gen_node_ids_p); + DetermineSizeOfState (node->node_state, &asize, &bsize); + CoerceArgumentOnTopOfStack (asp_p,bsp_p,arg->arg_state,node->node_state,asize,bsize); + } else { + NodeId arg_node_id; + + arg_node_id=node->node_node_id; + + if (CopyNodeIdArgument (arg->arg_state,arg_node_id,asp_p,bsp_p)) + ChangeEvalStatusKindToStrictOnA (arg_node_id,code_gen_node_ids_p->saved_nid_state_l); + + decrement_reference_count_of_node_id (arg_node_id,&code_gen_node_ids_p->free_node_ids); + } +} + +static Bool LazyStates (StateS states[],int n_states) +{ + int n; + + for (n=0; n<n_states; ++n) + if (!IsLazyState (states[n])) + return False; + + return True; +} + +static Bool PushArgumentLater (StateS demstate,StateS offstate) +{ + if (demstate.state_type==SimpleState && demstate.state_kind==Undefined) + return False; + + if (offstate.state_type==SimpleState){ + Coercions c; + StateKind offkind; + + offkind = offstate.state_kind; + + if (demstate.state_type==SimpleState){ + c = CoerceStateKind (demstate.state_kind, offkind); + + if (c==Reduce || c==MayBecomeCyclicSpine || c==CyclicSpine) + return False; + else + return True; + } else { + c = CoerceStateKind (StrictOnA, offkind); + + if (c==Reduce || c==MayBecomeCyclicSpine || c==CyclicSpine) + return False; + + switch (demstate.state_type){ + case TupleState: + return LazyStates (demstate.state_tuple_arguments,demstate.state_arity); + case RecordState: + return LazyStates (demstate.state_record_arguments,demstate.state_arity); + case ArrayState: + return True; + } + } + } else if (demstate.state_type==SimpleState){ + switch (offstate.state_type){ + case TupleState: + /* + BuildTuple (aindex,bindex,*asp_p,*bsp_p,offstate.state_arity,offstate.state_tuple_arguments, + offasize,offbsize,*asp_p,NormalFill,newnode); + */ + return False; + case RecordState: + /* + BuildRecord (offstate.state_record_symbol,aindex,bindex,*asp_p,*bsp_p,offasize,offbsize,*asp_p,NormalFill,newnode); + */ + return False; + case ArrayState: + return True; + } + } else { + if (offstate.state_type!=demstate.state_type) + return False; + + switch (offstate.state_type){ + case TupleState: + { + int n,n_states; + + n_states=demstate.state_arity; + + for (n=0; n<n_states; ++n) + if (!PushArgumentLater (demstate.state_tuple_arguments[n],offstate.state_tuple_arguments[n])) + return False; + } + return True; + case RecordState: + { + int n,n_states; + + n_states=demstate.state_arity; + + for (n=0; n<n_states; ++n) + if (!PushArgumentLater (demstate.state_record_arguments[n],offstate.state_record_arguments[n])) + return False; + } + return True; + case ArrayState: + return True; + } + } + return False; +} + +static Bool BuildNonParArgs (Args args,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + Bool parallel; + + if (args==NULL) + return False; + + parallel = BuildNonParArgs (args->arg_next,asp_p,bsp_p,code_gen_node_ids_p); + + if (args->arg_state.state_mark & STATE_PARALLEL_MASK) + return True; + + { + Node node; + int asize,bsize; + + node=args->arg_node; + + if (node->node_kind!=NodeIdNode){ + if (node->node_kind==NormalNode){ + switch (node->node_symbol->symb_kind){ + case int_denot: + case bool_denot: + case char_denot: + case real_denot: + case string_denot: + args->arg_state.state_mark |= STATE_PARALLEL_MASK; + return True; + } + } + + ArgComment (args); + + Build (node,asp_p,bsp_p,code_gen_node_ids_p); + DetermineSizeOfState (node->node_state, &asize, &bsize); + CoerceArgumentOnTopOfStack (asp_p,bsp_p,args->arg_state, node->node_state, asize, bsize); + } else { + NodeId arg_node_id; + + arg_node_id=node->node_node_id; + + if (PushArgumentLater (args->arg_state,arg_node_id->nid_state)){ + args->arg_state.state_mark |= STATE_PARALLEL_MASK; + return True; + } else { + ArgComment (args); + + if (CopyNodeIdArgument (args->arg_state,arg_node_id,asp_p,bsp_p)) + ChangeEvalStatusKindToStrictOnA (arg_node_id,code_gen_node_ids_p->saved_nid_state_l); + + decrement_reference_count_of_node_id (arg_node_id,&code_gen_node_ids_p->free_node_ids); + } + } + } + + return parallel; +} + +#if 0 + static void PutArgInFrames (int *anext,int *bnext,int asp,int bsp,StateS state,int asize,int bsize) + { + if (IsSimpleState (state)){ + if (state.state_kind == OnB) + PutInBFrames (bsp, bnext, bsize); + else if (state.state_kind != Undefined) + PutInAFrames (asp, anext); + } else { + int i, arity; + + arity = state.state_arity; + + switch (state.state_type){ + case TupleState: + { States argstates = state.state_tuple_arguments; + asp -= asize; + bsp -= bsize; + for (i=arity-1; i>=0; i--){ + DetermineSizeOfState (argstates [i],&asize, &bsize); + asp += asize; + bsp += bsize; + PutArgInFrames (anext, bnext, asp, bsp, argstates [i], asize, bsize); + } + break; + } + case RecordState: + { States argstates = state.state_record_arguments; + asp -= asize; + bsp -= bsize; + for (i=arity-1; i>=0; i--){ + DetermineSizeOfState (argstates [i],&asize, &bsize); + asp += asize; + bsp += bsize; + PutArgInFrames (anext, bnext, asp, bsp, argstates [i], asize, bsize); + } + break; + } + case ArrayState: + PutInAFrames (asp, anext); + break; + } + } + } +#endif + +static void PutParAndNormalArgsInFrames (Args args,int *npar_a_offset_p,int *npar_b_offset_p,int *par_a_offset_p,int *par_b_offset_p,int *aind_p,int *bind_p) +{ + if (args!=NULL){ + int asize,bsize; + + PutParAndNormalArgsInFrames (args->arg_next,npar_a_offset_p,npar_b_offset_p,par_a_offset_p,par_b_offset_p,aind_p,bind_p); + + DetermineSizeOfState (args->arg_state,&asize,&bsize); + + if (args->arg_state.state_mark & STATE_PARALLEL_MASK){ + if (bsize!=0){ + *par_b_offset_p+=bsize; + PutInBFrames (*par_b_offset_p,bind_p,bsize); + } + while (asize!=0){ + ++*par_a_offset_p; + PutInAFrames (*par_a_offset_p,aind_p); + --asize; + } + } else { + if (bsize!=0){ + *npar_b_offset_p+=bsize; + PutInBFrames (*npar_b_offset_p,bind_p,bsize); + } + while (asize!=0){ + ++*npar_a_offset_p; + PutInAFrames (*npar_a_offset_p,aind_p); + --asize; + } + } + } +} + +static void ReorderParallelAndNonParallelArgsWithResultNode (Args args,int *asize_p,int *bsize_p) +{ + int par_a_size,par_b_size; + int npar_a_size,npar_b_size; + int asize,bsize; + int oldamax,oldbmax; + int aind,bind; + ArgS *arg; + + par_a_size=1; + par_b_size=0; + npar_a_size=0; + npar_b_size=0; + + for_l (arg,args,arg_next) + if (arg->arg_state.state_mark & STATE_PARALLEL_MASK) + AddSizeOfState (arg->arg_state,&par_a_size,&par_b_size); + else + AddSizeOfState (arg->arg_state,&npar_a_size,&npar_b_size); + + asize = par_a_size+npar_a_size; + bsize = par_b_size+npar_b_size; + + *asize_p=asize; + *bsize_p=bsize; + + if ((par_a_size==0 || npar_a_size==0) && (par_b_size==0 || npar_b_size==0)) + return; + + InitStackConversions (asize+2,bsize+2,&oldamax,&oldbmax); + + aind = 0; + bind = 0; + { + int npar_a_offset,npar_b_offset,par_a_offset,par_b_offset; + + npar_a_offset=0; + npar_b_offset=0; + par_a_offset=npar_a_size; + par_b_offset=npar_b_size; + + par_a_offset+=1; + PutInAFrames (par_a_offset,&aind); + + PutParAndNormalArgsInFrames (args,&npar_a_offset,&npar_b_offset,&par_a_offset,&par_b_offset,&aind,&bind); + } + + GenAStackConversions (asize,aind); + GenBStackConversions (bsize,bind); + + ExitStackConversions (oldamax,oldbmax); +} + +static void ReorderParallelAndNonParallelArgs (Args args) +{ + int par_a_size,par_b_size; + int npar_a_size,npar_b_size; + int asize,bsize; + int oldamax,oldbmax; + int aind,bind; + ArgS *arg; + + par_a_size=0; + par_b_size=0; + npar_a_size=0; + npar_b_size=0; + + for_l (arg,args,arg_next) + if (arg->arg_state.state_mark & STATE_PARALLEL_MASK) + AddSizeOfState (arg->arg_state,&par_a_size,&par_b_size); + else + AddSizeOfState (arg->arg_state,&npar_a_size,&npar_b_size); + + if ((par_a_size==0 || npar_a_size==0) && (par_b_size==0 || npar_b_size==0)) + return; + + asize = par_a_size+npar_a_size; + bsize = par_b_size+npar_b_size; + + InitStackConversions (asize+2,bsize+2,&oldamax,&oldbmax); + + aind = 0; + bind = 0; + { + int npar_a_offset,npar_b_offset,par_a_offset,par_b_offset; + + npar_a_offset=0; + npar_b_offset=0; + par_a_offset=npar_a_size; + par_b_offset=npar_b_size; + PutParAndNormalArgsInFrames (args,&npar_a_offset,&npar_b_offset,&par_a_offset,&par_b_offset,&aind,&bind); + } + + GenAStackConversions (asize,aind); + GenBStackConversions (bsize,bind); + + ExitStackConversions (oldamax,oldbmax); +} + +static void BuildParArgs (ArgS* args,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + if (args==NULL) + return; + + BuildParArgs (args->arg_next,asp_p,bsp_p,code_gen_node_ids_p); + + if (args->arg_state.state_mark & STATE_PARALLEL_MASK){ +/* ParComment (args); */ + BuildArg (args,asp_p,bsp_p,code_gen_node_ids_p); + } +} + +void BuildArgs (Args args,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + if (BuildNonParArgs (args,asp_p,bsp_p,code_gen_node_ids_p)){ + BuildParArgs (args,asp_p,bsp_p,code_gen_node_ids_p); + ReorderParallelAndNonParallelArgs (args); + } +} + +static void BuildLazyArgs (Args args,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + if (args==NULL) + return; + + BuildLazyArgs (args->arg_next,asp_p,bsp_p,code_gen_node_ids_p); + + BuildArg (args,asp_p,bsp_p,code_gen_node_ids_p); +} + +static void CreateCyclicExternalReducers (NodeDefs nds,int node_id_number,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + for (; nds && nds->def_id->nid_number==node_id_number; nds=nds->def_next){ + if (nds->def_node && (nds->def_id->nid_mark & ON_A_CYCLE_MASK) && HasExternalAnnot (nds->def_node)){ + NewEmptyNode (asp_p,-1); + + /* fill cycle and start reducer */ + + FillNodeOnACycle (nds->def_node,asp_p,bsp_p,nds->def_id,code_gen_node_ids_p); + + CreateParallelCode (nds,asp_p,bsp_p,code_gen_node_ids_p); + + ChangeEvalStatusKind (nds->def_id,OnA); + } + } +} + +#if OPTIMIZE_LAZY_TUPLE_RECURSION +extern NodeP tuple_result_p; + +static void generate_code_for_lazy_tuple_recursive_call (NodeP node,NodeIdP node_id_p,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + unsigned long result_and_call_same_select_vector; + NodeIdP first_tuple_call_node_id_p; + int n,arity,tuple_arity; + LabDef name,codelab; + NodeP fill_nodes; + SymbDef sdef; + + fill_nodes=node; + while (node->node_kind==FillUniqueNode) + node=node->node_arguments->arg_node; + + result_and_call_same_select_vector=0; + first_tuple_call_node_id_p=NULL; + + if (lazy_tuple_recursion){ + ArgP tuple_element_p; + + for_li (tuple_element_p,n,tuple_result_p->node_arguments,arg_next){ + NodeP node_p; + + node_p=tuple_element_p->arg_node; + + if (node_p->node_symbol->symb_kind==select_symb + && node_p->node_arguments->arg_node->node_kind==NodeIdNode + && n+1==node_p->node_arity + && (node_p->node_arguments->arg_node->node_node_id->nid_mark2 & NID_CALL_VIA_LAZY_SELECTIONS_ONLY) + ){ + NodeIdP tuple_call_node_id_p; + + tuple_call_node_id_p=node_p->node_arguments->arg_node->node_node_id; + if (first_tuple_call_node_id_p==NULL) + first_tuple_call_node_id_p=tuple_call_node_id_p; + + if (tuple_call_node_id_p==node_id_p) + result_and_call_same_select_vector |= (1<<n); + } + } + } + + tuple_arity=node->node_symbol->symb_def->sdef_rule->rule_type->type_alt_rhs->type_node_arity; + if (lazy_tuple_recursion){ + for (n=tuple_arity-1; n>=0; --n){ + if (result_and_call_same_select_vector & (1<<n)) + GenPushA (*asp_p - (tuple_arity-n)); + else { + if (fill_nodes!=node){ + NodeIdP free_unique_node_id; + + free_unique_node_id=fill_nodes->node_node->node_arguments->arg_node->node_node_id; + GenPushA (*asp_p-free_unique_node_id->nid_a_index); + + decrement_reference_count_of_node_id (free_unique_node_id,&code_gen_node_ids_p->free_node_ids); + + fill_nodes=fill_nodes->node_arguments->arg_node; + } else + GenCreate (-1); + } + ++*asp_p; + } +#if ! SELECTORS_FIRST + { + int offset; + + offset=tuple_arity-1; + for (n=tuple_arity-1; n>=0; --n){ + if (result_and_call_same_select_vector & (1<<n)){ + --offset; + } else { + GenPushA (offset); + ++*asp_p; + } + } + } +#endif + } else { + for (n=tuple_arity-1; n>=0; --n){ + GenCreate (-1); + ++*asp_p; + } +#if ! SELECTORS_FIRST + for (n=tuple_arity-1; n>=0; --n){ + GenPushA (tuple_arity-1); + ++*asp_p; + } +#endif + } + + + arity=node->node_arity; + + if (node->node_kind!=NormalNode || node->node_symbol->symb_kind!=definition || node->node_symbol->symb_def->sdef_kind!=IMPRULE + || arity!=node->node_symbol->symb_def->sdef_arity || !IsLazyState (node->node_state)) + error_in_function ("generate_code_for_lazy_tuple_recursive_call"); + + sdef=node->node_symbol->symb_def; + + ConvertSymbolToDandNLabel (&name,&codelab,sdef); + + codelab.lab_post=2; + name.lab_post=2; + + BuildArgs (node->node_arguments,asp_p,bsp_p,code_gen_node_ids_p); + + if (!lazy_tuple_recursion || first_tuple_call_node_id_p!=node_id_p){ + if (node->node_symbol->symb_def->sdef_rule->rule_mark & RULE_UNBOXED_LAZY_CALL){ + int a_size,b_size; + + DetermineSizeOfArguments (node->node_arguments,&a_size,&b_size); + +# if SELECTORS_FIRST + for (n=tuple_arity-1; n>=0; --n){ + GenPushA (a_size+tuple_arity-1); + ++*asp_p; + } +# endif + + if (b_size!=0) + GenBuildU (&name,a_size+tuple_arity,b_size,&codelab); + else + GenBuild (&name,arity+tuple_arity,&codelab); + + *bsp_p -= b_size; + *asp_p += 1-(a_size+tuple_arity); + } else { +# if SELECTORS_FIRST + for (n=tuple_arity-1; n>=0; --n){ + GenPushA (arity+tuple_arity-1); + ++*asp_p; + } +# endif + GenBuild (&name,arity+tuple_arity,&codelab); + *asp_p += 1-(arity+tuple_arity); + } + } else { + char bits[MaxNodeArity+2],*bits_p; + int n,n_updated_tuple_elements; + + bits_p=bits; +# if SELECTORS_FIRST + *bits_p++='1'; +# else + *bits_p++='0'; +# endif + n_updated_tuple_elements=0; + +# if SELECTORS_FIRST + for (n=0; n<tuple_arity; ++n) + if (result_and_call_same_select_vector & (1<<n)){ + *bits_p++ = '0'; + } else { + *bits_p++ = '1'; + ++n_updated_tuple_elements; + } +# endif + + if (node->node_symbol->symb_def->sdef_rule->rule_mark & RULE_UNBOXED_LAZY_CALL){ + int a_size,b_size; + + DetermineSizeOfArguments (node->node_arguments,&a_size,&b_size); +# if SELECTORS_FIRST + { + int offset; + + offset=tuple_arity-1; + for (n=tuple_arity-1; n>=0; --n){ + if (result_and_call_same_select_vector & (1<<n)){ + --offset; + } else { + GenPushA (a_size+offset); + ++*asp_p; + } + } + } +# endif + + for (n=0; n<a_size; ++n) + *bits_p++ = '1'; + +# if !SELECTORS_FIRST + for (n=0; n<tuple_arity; ++n) + if (result_and_call_same_select_vector & (1<<n)){ + *bits_p++ = '0'; + } else { + *bits_p++ = '1'; + ++n_updated_tuple_elements; + } +# endif + + for (n=0; n<b_size; ++n) + *bits_p++ = '1'; + + *bits_p++='\0'; + + if (b_size!=0) + GenFillcpU (&name,a_size+tuple_arity,b_size,&codelab,*asp_p,bits); + else + GenFillcp (&name,a_size+tuple_arity,&codelab,*asp_p,bits); + + *asp_p -= a_size+n_updated_tuple_elements; + *bsp_p -= b_size; + } else { +# if SELECTORS_FIRST + { + int offset; + + offset=tuple_arity-1; + for (n=tuple_arity-1; n>=0; --n){ + if (result_and_call_same_select_vector & (1<<n)){ + --offset; + } else { + GenPushA (arity+offset); + ++*asp_p; + } + } + } +# endif + + for (n=0; n<arity; ++n) + *bits_p++ = '1'; + +# if !SELECTORS_FIRST + for (n=0; n<tuple_arity; ++n) + if (result_and_call_same_select_vector & (1<<n)){ + *bits_p++ = '0'; + } else { + *bits_p++ = '1'; + ++n_updated_tuple_elements; + } +# endif + *bits_p++='\0'; + + GenFillcp (&name,arity+tuple_arity,&codelab,*asp_p,bits); + *asp_p -= arity+n_updated_tuple_elements; + } + + GenPushA (*asp_p); + ++*asp_p; + } + + { + int offset; + + offset=1; + for (n=0; n<tuple_arity; ++n){ + if (!lazy_tuple_recursion || !(result_and_call_same_select_vector & (1<<n))){ + LabDef sellab,nsellab; + + MakeLabel (&nsellab,"_Sel",0,n_pref); + + sellab = nsellab; + sellab.lab_pref = d_pref; + + GenPushA (0); + GenFill (&sellab,1,&nsellab,offset+1,NormalFill); + } + ++offset; + } + } +} +#endif + +static int FillNodeDefs (NodeDefs nds,int node_id_number,int *asp_p,int *bsp_p,NodeDefs *rest,CodeGenNodeIdsP code_gen_node_ids_p) +{ + int hasCyclicExternalReducer; + + hasCyclicExternalReducer=0; + + for (; nds!=NULL && nds->def_id->nid_number==node_id_number; nds=nds->def_next){ + Node node; + + node=nds->def_node; + + if (node==NULL){ + NodeId node_id; + + node_id=nds->def_id; + + /* we have a strict annotated left hand side nodeid */ + StrictIdComment (node_id); + + /* evaluate strict arg */ + if (node_id->nid_state.state_type==SimpleState) + ReduceArgumentToHnf (node_id,node_id->nid_state,*asp_p-node_id->nid_a_index,code_gen_node_ids_p->saved_nid_state_l); + } else { + struct state *result_state_p; + + result_state_p=&node->node_state; + + if (nds->def_id->nid_mark & ON_A_CYCLE_MASK){ + if (HasExternalAnnot (node)){ + hasCyclicExternalReducer=1; + continue; + } + + /* fill cycle */ + + FillNodeOnACycle (node,asp_p,bsp_p,nds->def_id,code_gen_node_ids_p); + } else { + int a_size,b_size; + + NodeDefComment (nds, "shared or annotated"); + +#if OPTIMIZE_LAZY_TUPLE_RECURSION + if (nds->def_id->nid_mark2 & NID_CALL_VIA_LAZY_SELECTIONS_ONLY) + generate_code_for_lazy_tuple_recursive_call (node,nds->def_id,asp_p,bsp_p,code_gen_node_ids_p); + else +#endif + if (node->node_kind==TupleSelectorsNode){ + struct arg *arg; + struct node *tuple_node; + struct state *tuple_state_p; + + tuple_node=node->node_node; + + if (tuple_node->node_kind!=NodeIdNode){ + build_and_cleanup (tuple_node,asp_p,bsp_p,code_gen_node_ids_p); + tuple_state_p=&tuple_node->node_state; + } else { + NodeId node_id; + + node_id=tuple_node->node_node_id; + if (CopyNodeIdArgument (tuple_node->node_arguments->arg_state,node_id,asp_p,bsp_p)) + ChangeEvalStatusKindToStrictOnA (node_id,code_gen_node_ids_p->saved_nid_state_l); + + tuple_state_p=&tuple_node->node_arguments->arg_state; + + decrement_reference_count_of_node_id (node_id,&code_gen_node_ids_p->free_node_ids); + } + + arg=node->node_arguments; + if (arg->arg_node->node_kind==NodeIdNode){ + int a_offset,b_offset,i; + + DetermineSizeOfState (*tuple_state_p,&a_offset,&b_offset); + + if (tuple_state_p->state_type!=TupleState) + error_in_function ("FillNodeDefs"); + + for (i=tuple_state_p->state_arity-1; i>=0; --i){ + int a_size,b_size; + NodeId node_id; + + DetermineSizeOfState (tuple_state_p->state_tuple_arguments[i],&a_size,&b_size); + + a_offset-=a_size; + b_offset-=b_size; + + if (arg!=NULL && arg->arg_node->node_node_id->nid_number==i){ + node_id=arg->arg_node->node_node_id; + arg=arg->arg_next; + } else { + if (a_size==0 && b_size==0) + continue; + + node_id=NewNodeId (NULL); + add_node_id_to_list (node_id,&code_gen_node_ids_p->free_node_ids); + } + + node_id->nid_a_index_=*asp_p - a_offset; + node_id->nid_b_index_=*bsp_p - b_offset; + node_id->nid_state_ = tuple_state_p->state_tuple_arguments[i]; + + if (a_size!=0) + add_node_id_to_list (node_id,&code_gen_node_ids_p->a_node_ids); + if (b_size!=0) + add_node_id_to_list (node_id,&code_gen_node_ids_p->b_node_ids); + } + + if (arg!=NULL) + error_in_function ("FillNodeDefs"); + + continue; + } + } else if (node->node_kind==NodeIdNode){ + NodeId node_id; + + node_id=node->node_node_id; + + if ((node_id->nid_mark & NID_SHARED_SELECTION_NODE_ID)==0 && EqualState (node->node_arguments->arg_state,node->node_state)){ + int a_size,b_size; + + nds->def_id->nid_a_index_=node_id->nid_a_index; + nds->def_id->nid_b_index_=node_id->nid_b_index; + nds->def_id->nid_state_=node_id->nid_state; + + DetermineSizeOfState (node_id->nid_state,&a_size,&b_size); + + if (a_size!=0){ + NodeIdListElementP p_node_id; + + for_l (p_node_id,code_gen_node_ids_p->a_node_ids,nidl_next) + if (p_node_id->nidl_node_id==node_id){ + p_node_id->nidl_node_id=nds->def_id; + break; + } + } + + if (b_size!=0){ + NodeIdListElementP p_node_id; + + for_l (p_node_id,code_gen_node_ids_p->a_node_ids,nidl_next) + if (p_node_id->nidl_node_id==node_id){ + p_node_id->nidl_node_id=nds->def_id; + break; + } + } + + continue; + } else { + result_state_p=&node->node_arguments->arg_state; + +#ifdef DO_LAZY_SELECTORS_FROM_BOXED_STRICT_RECORDS + if (result_state_p->state_type==SimpleState && result_state_p->state_kind==OnA && !ResultIsNotInRootNormalForm (node_id->nid_state)) + result_state_p->state_kind=StrictOnA; +#endif + if (CopyNodeIdArgument (*result_state_p,node_id,asp_p,bsp_p)) + ChangeEvalStatusKindToStrictOnA (node_id,code_gen_node_ids_p->saved_nid_state_l); + + decrement_reference_count_of_node_id (node_id,&code_gen_node_ids_p->free_node_ids); + } + } else + build_and_cleanup (node,asp_p,bsp_p,code_gen_node_ids_p); + + /* IsLazyState (nds->def_node->node_state) ? build shared or annotated : build and reduce */ + + DetermineSizeOfState (*result_state_p,&a_size,&b_size); + + if (a_size!=0) + add_node_id_to_list (nds->def_id,&code_gen_node_ids_p->a_node_ids); + + if (b_size!=0) + add_node_id_to_list (nds->def_id,&code_gen_node_ids_p->b_node_ids); + + nds->def_id->nid_a_index_=*asp_p; + nds->def_id->nid_b_index_=*bsp_p; + } + + /* start reducer, and (if a node is filled) set eval status */ + if (IsSimpleState (*result_state_p) && result_state_p->state_kind==Parallel){ + if (!((nds->def_id->nid_mark & ON_A_CYCLE_MASK) && HasExternalAnnot (node))){ + CreateParallelCode (nds,asp_p,bsp_p,code_gen_node_ids_p); + /* start reducer */ + ChangeEvalStatusKind (nds->def_id, OnA); + } + } else + nds->def_id->nid_state_=*result_state_p; + } + } + + *rest = nds; + + return hasCyclicExternalReducer; +} + +Bool NodeOnACycleIsInRootNormalForm (Node node) +{ + Symbol symb; + + symb=node->node_symbol; + + switch (symb->symb_kind){ + case select_symb: + case apply_symb: + return False; + case if_symb: + return (node->node_arity!=3); + case definition: + { + SymbDef sdef; + + sdef=symb->symb_def; + + if (node->node_kind!=NormalNode) + return False; + + if (sdef->sdef_kind==RECORDTYPE) + if (!sdef->sdef_strict_constructor) + return True; + else + return False; + + if (sdef->sdef_arity==node->node_arity) + switch (sdef->sdef_kind){ + case CONSTRUCTOR: + if (sdef->sdef_strict_constructor) + return False; + case DEFRULE: + case SYSRULE: + case IMPRULE: + return False; + default: + return True; + } + + return True; + } + default: + return True; + } +} + +static void CreateCycleNodesAndChannels (NodeDefs nds,NodeDefs rootdef,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + for (; nds!=NULL; nds=nds->def_next){ + if (! nds->def_node || nds==rootdef){ + /* we have a strict annotated left hand side nodeid, or a root (with a node) */ + continue; + } else if (nds->def_id->nid_mark & ON_A_CYCLE_MASK){ + if (HasExternalAnnot (nds->def_node)){ + NodeDefComment (nds, "Cycle containing a channel"); + GenProcIdCalculation (nds->def_node,nds->def_node->node_annotation,asp_p,bsp_p,code_gen_node_ids_p); + GenCreateChannel (channel_code); + --*bsp_p; + nds->def_id->nid_state_=nds->def_node->node_state; + } else { + NodeDefComment (nds, "OnACycle"); + if (NodeOnACycleIsInRootNormalForm (nds->def_node)) + GenCreate (-1); + else + GenCreate (nds->def_node->node_arity); + nds->def_id->nid_state_=OnAState; + } + ++*asp_p; + nds->def_id->nid_a_index_=*asp_p; + } else + nds->def_id->nid_state_=UnderEvalState; + } +} + +void CodeSharedNodeDefs (NodeDefs nds, NodeDefs rootdef,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p) +{ + NodeDefs rest,new_rest; + + CreateCycleNodesAndChannels (nds, rootdef,asp_p,bsp_p,code_gen_node_ids_p); + + for (rest=nds; rest!=NULL; rest=new_rest){ + int hasCyclicExternalReducer; + + hasCyclicExternalReducer=FillNodeDefs (rest,rest->def_id->nid_number,asp_p,bsp_p,&new_rest,code_gen_node_ids_p); + + if (hasCyclicExternalReducer) + CreateCyclicExternalReducers (rest, rest->def_id->nid_number,asp_p,bsp_p,code_gen_node_ids_p); + } + + ReduceSemiStrictNodes (nds,*asp_p); +} + +#if 0 + static void BuildStackFrameEntry (Args arg,int *asp_p,int *bsp_p,int *a_ind,int *b_ind,CodeGenNodeIdsP code_gen_node_ids_p) + { + int asize, bsize; + Node pattern; + + pattern=arg->arg_node; + + if (pattern->node_kind!=NodeIdNode){ + Build (pattern,asp_p,bsp_p,code_gen_node_ids_p); + + DetermineSizeOfState (pattern->node_state, &asize, &bsize); + CoerceArgumentOnTopOfStack (asp_p,bsp_p,arg->arg_state,pattern->node_state,asize,bsize); + + DetermineSizeOfState (arg->arg_state,&asize,&bsize); + PutArgInFrames (a_ind,b_ind,*asp_p,*bsp_p,arg->arg_state,asize,bsize); + } else { + StateS offstate; + int aindex; + NodeId arg_node_id; + + arg_node_id=pattern->node_node_id; + offstate = arg_node_id->nid_state; + aindex = arg_node_id->nid_a_index; + + if (IsSimpleState (offstate)){ + Bool leftontop; + Coercions c; + + c = CoerceSimpleStateArgument (arg->arg_state,offstate.state_kind,aindex,asp_p,False, &leftontop); + offstate.state_kind = AdjustStateKind (offstate.state_kind, c); + + if (HasBeenReduced (c)) + ChangeEvalStatusKindToStrictOnA (arg_node_id,code_gen_node_ids_p->saved_nid_state_l); + + if (leftontop) + aindex = *asp_p; + } + + DetermineSizeOfState (offstate, &asize, &bsize); + + CoerceArgumentUsingStackFrames (arg->arg_state,offstate,aindex,arg_node_id->nid_b_index,asp_p,bsp_p,a_ind, b_ind, asize, bsize); + } + } + + static Bool BuildStackFrameEntries (Args args,int *asp_p,int *bsp_p,int *a_ind,int *b_ind,CodeGenNodeIdsP code_gen_node_ids_p) + { + int parallel; + + parallel = False; + + if (args){ + if (BuildStackFrameEntries (args->arg_next,asp_p,bsp_p, a_ind, b_ind,code_gen_node_ids_p)) + parallel = True; + if (args->arg_state.state_parallel) + parallel = True; + else + BuildStackFrameEntry (args,asp_p,bsp_p, a_ind, b_ind,code_gen_node_ids_p); + } + return parallel; + } + + static void BuildParallelStackFrameEntries (Args args,int *asp_p,int *bsp_p,int *a_ind,int *b_ind,CodeGenNodeIdsP code_gen_node_ids_p) + { + if (args){ + BuildParallelStackFrameEntries (args->arg_next,asp_p,bsp_p, a_ind, b_ind,code_gen_node_ids_p); + + if (args->arg_state.state_parallel){ + ParComment (args); + BuildStackFrameEntry (args, asp_p,bsp_p, a_ind, b_ind,code_gen_node_ids_p); + } + } + } + + static void CopyToNewFrame (int *demframe, int *newdemframe, int size, int *sp1, int *sp2) + { + int i, j, k; + + for (i = 0, j = *sp1, k = *sp2; i < size; i++, j--, k--) + newdemframe[k] = demframe[j]; + + *sp1 -= size; + *sp2 -= size; + } + + static void AdjustDemandedFrames (Args args) + { + int *newdemaframe, *newdembframe; + int asp, parasp, newasp, bsp, parbsp, newbsp, asize, bsize, parasize, parbsize; + Args arg; + + /* determine sizes of (non) parallel part */ + asize = bsize = parasize = parbsize = 0; + + for (arg = args; arg; arg = arg->arg_next){ + if (arg->arg_state.state_parallel) + AddSizeOfState (arg->arg_state, ¶size, &parbsize); + else + AddSizeOfState (arg->arg_state, &asize, &bsize); + } + + if (parasize == 0 && parbsize == 0) + return; + + /* allocate space for temporary stack frames */ + newdemaframe = AllocTempDemandedAFrame (CurrentAFrameSize); + newdembframe = AllocTempDemandedBFrame (CurrentBFrameSize); + + /* copy the arguments to the temporary frames */ + parasp = newasp = asize + parasize; + parbsp = newbsp = bsize + parbsize; + asp = asize; + bsp = bsize; + + for_l (arg,args,arg_next){ + int asize,bsize; + + DetermineSizeOfState (arg->arg_state, &asize, &bsize); + + if (arg->arg_state.state_parallel){ + CopyToNewFrame (DemandedAFrame, newdemaframe, asize, ¶sp, &newasp); + CopyToNewFrame (DemandedBFrame, newdembframe, bsize, &parbsp, &newbsp); + } else { + CopyToNewFrame (DemandedAFrame, newdemaframe, asize, &asp, &newasp); + CopyToNewFrame (DemandedBFrame, newdembframe, bsize, &bsp, &newbsp); + } + } + + /* copy the new frame */ + for (asp = 1; asp <= asize + parasize; asp++) + DemandedAFrame[asp] = newdemaframe[asp]; + for (bsp = 1; bsp <= bsize + parbsize; bsp++) + DemandedBFrame[bsp] = newdembframe[bsp]; + } + + static void BuildNewStackFrame (ArgS *args,int asp,int bsp,Bool result_node_necessary,CodeGenNodeIdsP code_gen_node_ids_p) + { + int a_ind, b_ind, oldamax, oldbmax, newamax, newbmax, dummy; + Args arg; + + a_ind = 0; + b_ind = 0; + dummy=0; + + newamax = asp + 2; + newbmax = bsp + 2; + + for_l (arg,args,arg_next) + AddStateSizeAndMaxFrameSize (arg->arg_state,& newamax, & dummy, & newbmax); + + InitStackConversions (newamax, newbmax, &oldamax, &oldbmax); + + if (result_node_necessary){ + NewEmptyNode (&asp, -1); + PutInAFrames (asp, &a_ind); + } + + TypeErrorFound = False; + CycleErrorFound = False; + + if (BuildStackFrameEntries (args, &asp, &bsp,&a_ind, &b_ind,code_gen_node_ids_p)){ + BuildParallelStackFrameEntries (args, &asp, &bsp,&a_ind, &b_ind,code_gen_node_ids_p); + AdjustDemandedFrames (args); + } + + if (! (TypeErrorFound || CycleErrorFound)){ + GenAStackConversions (asp,a_ind); + GenBStackConversions (bsp,b_ind); + } + + ExitStackConversions (oldamax, oldbmax); + } +#endif + +static void move_a_stack_pointer (int old_asp,int new_asp) +{ + if (old_asp<new_asp){ + int offset; + + offset=0; + GenBuildh (&nil_lab,0); + ++old_asp; + + while (old_asp<new_asp){ + GenPushA (offset); + ++offset; + ++old_asp; + } + } else + GenPopA (old_asp-new_asp); +} + +void UpdateStackPointers (int old_asp,int old_bsp,int new_asp,int new_bsp) +{ + move_a_stack_pointer (old_asp,new_asp); + + if (old_bsp<new_bsp){ + int offset; + SymbValue sv; + + offset=0; + sv.val_int="0"; + PushBasic (IntObj,sv); + ++old_bsp; + + while (old_bsp<new_bsp){ + GenPushB (offset); + ++offset; + ++old_bsp; + } + } else + GenPopB (old_bsp-new_bsp); +} + +static void AdjustStacksAndJumpToThenOrElseLabel + (Label truelab,Label falselab,Label next_label,int asp,int bsp,int bsize,int then_asp,int then_bsp,int else_asp,int else_bsp) +{ + if (then_asp==else_asp){ + move_a_stack_pointer (asp,then_asp); + then_asp = else_asp = asp; + } + if (then_bsp==else_bsp){ + if (bsp-bsize<then_bsp){ + int offset,n; + SymbValue sv; + + offset=0; + sv.val_int="0"; + PushBasic (IntObj,sv); + ++bsp; + + while (bsp-bsize<then_bsp){ + GenPushB (offset); + ++offset; + ++bsp; + } + ++offset; + + for (n=0; n<bsize; ++n) + GenUpdateB (n+offset,n); + } else { + UpdateBasic (bsize,bsize-1,bsp-then_bsp-bsize); + GenPopB (bsp-then_bsp-bsize); + } + then_bsp = else_bsp = bsp - bsize; + } + + if (asp==else_asp && bsp - else_bsp - bsize == 0){ +#if 1 + if (falselab==next_label && asp==then_asp && bsp-bsize==then_bsp){ + GenJmpTrue (truelab); + truelab->lab_mod=NULL; + } else +#endif + { + GenJmpFalse (falselab); + falselab->lab_mod=NULL; + + UpdateStackPointers (asp, bsp-bsize, then_asp, then_bsp); +#if 1 + if (truelab!=next_label) +#endif + { + GenJmp (truelab); + truelab->lab_mod=NULL; + } + } + } else if (asp==then_asp && bsp - then_bsp - bsize == 0){ +#if 1 + if (truelab==next_label && asp==else_asp && bsp-bsize==else_bsp){ + GenJmpTrue (falselab); + falselab->lab_mod=NULL; + } else +#endif + { + GenJmpTrue (truelab); + truelab->lab_mod=NULL; + + UpdateStackPointers (asp, bsp-bsize, else_asp, else_bsp); +#if 1 + if (falselab!=next_label) +#endif + { + GenJmp (falselab); + falselab->lab_mod=NULL; + } + } + } else { + LabDef loclab; + + MakeLabel (&loclab, m_symb, NewLabelNr++, no_pref); + GenJmpFalse (&loclab); + + UpdateStackPointers (asp, bsp-bsize, then_asp, then_bsp); + GenJmp (truelab); + truelab->lab_mod=NULL; + + GenLabelDefinition (&loclab); + UpdateStackPointers (asp, bsp-bsize, else_asp, else_bsp); + +#if 1 + if (falselab!=next_label) +#endif + { + GenJmp (falselab); + falselab->lab_mod=NULL; + } + } +} + +void EvaluateCondition (Node cond_node,int *asp_p,int *bsp_p,CodeGenNodeIdsP code_gen_node_ids_p,StateS resultstate) +{ + switch (cond_node->node_kind){ + case NodeIdNode: + { + NodeId nid; + int boolean_b_size; + + nid=cond_node->node_node_id; + CopyNodeIdArgument (resultstate,nid,asp_p,bsp_p); + + decrement_reference_count_of_node_id (nid,&code_gen_node_ids_p->free_node_ids); + + boolean_b_size = ObjectSizes [resultstate.state_object]; + *bsp_p-=boolean_b_size; + break; + } + case NormalNode: + case SelectorNode: + case MatchNode: + { + int asize,bsize,boolean_b_size; + + Build (cond_node,asp_p,bsp_p,code_gen_node_ids_p); + DetermineSizeOfState (cond_node->node_state,&asize,&bsize); + CoerceArgumentOnTopOfStack (asp_p,bsp_p,resultstate,cond_node->node_state,asize,bsize); + boolean_b_size = ObjectSizes [resultstate.state_object]; + *bsp_p-=boolean_b_size; + break; + } + case IfNode: + EvaluateCondition (cond_node->node_arguments->arg_node,asp_p,bsp_p,code_gen_node_ids_p,resultstate); + break; + default: + error_in_function ("EvaluateCondition"); + } +} + +static Bool IsBooleanValue (Node node, Bool *val) +{ + if (node->node_kind==NormalNode && node->node_symbol->symb_kind==bool_denot){ + *val = node->node_symbol->symb_bool; + return True; + } else + return False; +} + +void subtract_else_ref_counts (struct node_id_ref_count_list *else_node_id_ref_counts,NodeIdListElementS **free_node_ids_l) +{ + struct node_id_ref_count_list *else_node_id_ref_count; + + for_l (else_node_id_ref_count,else_node_id_ref_counts,nrcl_next){ + struct node_id *node_id; + int ref_count; + + node_id=else_node_id_ref_count->nrcl_node_id; + + ref_count=node_id->nid_refcount; + if (ref_count>=0){ + ref_count -= else_node_id_ref_count->nrcl_ref_count; + node_id->nid_refcount=ref_count; + + if (ref_count==0) + add_node_id_to_list (node_id,free_node_ids_l); + } else { + ref_count += else_node_id_ref_count->nrcl_ref_count; + node_id->nid_refcount=ref_count; + + if (ref_count==-1){ + if (! (node_id->nid_node!=NULL && !IsSimpleState (node_id->nid_state)) && unused_node_id_(node_id)) + add_node_id_to_list (node_id,free_node_ids_l); + } + } + } +} + +void add_else_ref_counts (struct node_id_ref_count_list *else_node_id_ref_counts) +{ + struct node_id_ref_count_list *else_node_id_ref_count; + + for_l (else_node_id_ref_count,else_node_id_ref_counts,nrcl_next){ + struct node_id *node_id; + + node_id=else_node_id_ref_count->nrcl_node_id; + if (node_id->nid_refcount>=0) + node_id->nid_refcount += else_node_id_ref_count->nrcl_ref_count; + else + node_id->nid_refcount -= else_node_id_ref_count->nrcl_ref_count; + } +} + +static void EvaluateThenOrElsePartOfCondition + (NodeDefs defs,Node node,int asp,int bsp,StateS resultstate, Label truelab, Label falselab,Label next_label, + int then_asp,int then_bsp,int else_asp,int else_bsp,NodeIdListElementP a_node_ids,NodeIdListElementP b_node_ids, + struct node_id_ref_count_list *else_node_id_ref_counts,NodeIdListElementP free_node_ids); + +void BranchOnCondition (Node condnode,int asp,int bsp,CodeGenNodeIdsP code_gen_node_ids_p, StateS resultstate, + Label truelab,Label falselab,Label next_label,int then_asp,int then_bsp,int else_asp,int else_bsp) +{ + switch (condnode->node_kind){ + case NodeIdNode: + case NormalNode: + case SelectorNode: + case MatchNode: + { + int boolean_b_size; + boolean_b_size = ObjectSizes [resultstate.state_object]; + AdjustStacksAndJumpToThenOrElseLabel (truelab,falselab,next_label,asp,bsp+boolean_b_size,boolean_b_size,then_asp,then_bsp,else_asp,else_bsp); + break; + } + case IfNode: + { + Bool bool; + Label thenlabel,elselabel; + LabDef thenlab,elselab; + int new_then_asp,new_then_bsp,new_else_asp,new_else_bsp; + Args condpart; + + new_then_asp = asp; + new_then_bsp = bsp, + new_else_asp = asp; + new_else_bsp = bsp; + condpart = condnode->node_arguments; + + if (IsBooleanValue (condpart->arg_next->arg_node,&bool)){ + if (bool){ + thenlabel = truelab; + new_then_asp = then_asp; + new_then_bsp = then_bsp; + } else { + thenlabel = falselab; + new_then_asp = else_asp; + new_then_bsp = else_bsp; + } + } else { + thenlabel = NULL; + MakeLabel (&thenlab, then_symb, NewLabelNr++, no_pref); + thenlab.lab_mod=notused_string; + } + + if (IsBooleanValue (condpart->arg_next->arg_next->arg_node,&bool)){ + if (bool){ + elselabel = truelab; + new_else_asp = then_asp; + new_else_bsp = then_bsp; + } else { + elselabel = falselab; + new_else_asp = else_asp; + new_else_bsp = else_bsp; + } + } else { + elselabel = NULL; + MakeLabel (&elselab, else_symb, NewLabelNr++, no_pref); + elselab.lab_mod=notused_string; + } + + BranchOnCondition (condpart->arg_node,asp,bsp,code_gen_node_ids_p,resultstate, + thenlabel ? thenlabel : &thenlab, elselabel ? elselabel : &elselab, + !thenlabel ? &thenlab : !elselabel ? &elselab : next_label, + new_then_asp, new_then_bsp, new_else_asp, new_else_bsp); + + if (!thenlabel){ + if (thenlab.lab_mod==NULL) + GenLabelDefinition (&thenlab); + + EvaluateThenOrElsePartOfCondition (condnode->node_then_node_defs, + condpart->arg_next->arg_node, asp,bsp,resultstate,truelab,falselab,!elselabel ? &elselab : next_label, + then_asp,then_bsp,else_asp,else_bsp,code_gen_node_ids_p->a_node_ids,code_gen_node_ids_p->b_node_ids, + condnode->node_else_node_id_ref_counts,code_gen_node_ids_p->free_node_ids); + } + + if (!elselabel){ + if (elselab.lab_mod==NULL) + GenLabelDefinition (&elselab); + + EvaluateThenOrElsePartOfCondition (condnode->node_else_node_defs, + condpart->arg_next->arg_next->arg_node,asp,bsp,resultstate,truelab,falselab,next_label, + then_asp,then_bsp,else_asp,else_bsp,code_gen_node_ids_p->a_node_ids,code_gen_node_ids_p->b_node_ids, + NULL,code_gen_node_ids_p->free_node_ids); + } + break; + } + default: + error_in_function ("BranchOnCondition"); + } +} + +static void EvaluateThenOrElsePartOfCondition + (NodeDefs defs,Node node,int asp,int bsp,StateS resultstate, Label truelab, Label falselab,Label next_label, + int then_asp,int then_bsp,int else_asp,int else_bsp,NodeIdListElementP a_node_ids,NodeIdListElementP b_node_ids, + struct node_id_ref_count_list *else_node_id_ref_counts,NodeIdListElementP free_node_ids) +{ + SavedNidStateP saved_node_id_states; + MovedNodeIdP moved_node_ids; + struct code_gen_node_ids code_gen_node_ids; + + saved_node_id_states=NULL; + moved_node_ids=NULL; + + if (else_node_id_ref_counts!=NULL) + subtract_else_ref_counts (else_node_id_ref_counts,&free_node_ids); + + code_gen_node_ids.free_node_ids=free_node_ids; + code_gen_node_ids.saved_nid_state_l=&saved_node_id_states; + code_gen_node_ids.doesnt_fail=False; + code_gen_node_ids.moved_node_ids_l=&moved_node_ids; + code_gen_node_ids.a_node_ids=a_node_ids; + code_gen_node_ids.b_node_ids=b_node_ids; + + CodeSharedNodeDefs (defs,NULL,&asp,&bsp,&code_gen_node_ids); + + EvaluateCondition (node,&asp,&bsp,&code_gen_node_ids,resultstate); + + BranchOnCondition (node,asp,bsp,&code_gen_node_ids,resultstate,truelab,falselab,next_label,then_asp,then_bsp,else_asp,else_bsp); + + restore_saved_node_id_states (saved_node_id_states); + + if (else_node_id_ref_counts!=NULL) + add_else_ref_counts (else_node_id_ref_counts); +} + +void InitCoding (void) +{ + int i; + + NewLabelNr = 1; + SetUnaryState (& StrictOnAState, StrictOnA, UnknownObj); + SetUnaryState (& OnAState, OnA, UnknownObj); + SetUnaryState (& UnderEvalState, UnderEval, UnknownObj); + SetUnaryState (& ProcIdState, OnB, ProcIdObj); + + ApplyDef=MakeNewSymbolDefinition ("system", ApplyId, 2, DEFRULE); + ApplyDef->sdef_number=0; + + IfDef=MakeNewSymbolDefinition ("system", IfId, 3, DEFRULE); + IfDef->sdef_number=0; + + InitBasicDescriptor (UnknownObj, "_", SizeOfAStackElem); +#if ABSTRACT_OBJECT + InitBasicDescriptor (AbstractObj, "_", SizeOfAStackElem); +#endif + InitBasicDescriptor (IntObj, "INT", SizeOfInt); + InitBasicDescriptor (BoolObj, "BOOL", SizeOfBool); + InitBasicDescriptor (CharObj, "CHAR", SizeOfChar); + InitBasicDescriptor (StringObj, "STRING", SizeOfAStackElem); + InitBasicDescriptor (RealObj, "REAL", SizeOfReal); + InitBasicDescriptor (FileObj, "FILE", SizeOfFile); + InitBasicDescriptor (ArrayObj, "ARRAY", SizeOfAStackElem); + InitBasicDescriptor (UnboxedArrayObj, "ARRAY", SizeOfAStackElem); + + InitBasicDescriptor (WorldObj, "WORLD", SizeOfAStackElem); + InitBasicDescriptor (ProcIdObj, "PROCID", SizeOfProcId); + InitBasicDescriptor (RedIdObj, "REDID", SizeOfInt); + + for (i=0; i<MaxNodeArity-NrOfGlobalSelectors; i++) + LazyTupleSelectors [i] = False; + + next_update_function_n=0; + next_match_function_n=0; +} |