2012-02-05 11:35:58 -05:00
|
|
|
/****************************************************************
|
|
|
|
* *
|
2012-03-24 14:06:46 -04:00
|
|
|
* Copyright 2001, 2012 Fidelity Information Services, Inc *
|
2012-02-05 11:35:58 -05:00
|
|
|
* *
|
|
|
|
* This source code contains the intellectual property *
|
|
|
|
* of its copyright holder(s), and is made available *
|
|
|
|
* under a license. If you do not know the terms of *
|
|
|
|
* the license, please stop and do not read further. *
|
|
|
|
* *
|
|
|
|
****************************************************************/
|
|
|
|
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "opcode.h"
|
2012-03-24 14:06:46 -04:00
|
|
|
#include "mdq.h"
|
2012-02-05 11:35:58 -05:00
|
|
|
#include "mmemory.h"
|
2012-06-14 08:55:06 -04:00
|
|
|
#include <emit_code.h>
|
2012-03-24 14:06:46 -04:00
|
|
|
#include "fullbool.h"
|
2012-02-05 11:35:58 -05:00
|
|
|
|
2012-03-24 14:06:46 -04:00
|
|
|
LITREF octabstruct oc_tab[];
|
|
|
|
|
|
|
|
void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean_t sense, oprtype *addr)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
boolean_t expr_fini;
|
|
|
|
oprtype *i, *p;
|
|
|
|
triple *ref0, *ref1, *t0, *t1;
|
|
|
|
DCL_THREADGBL_ACCESS;
|
2012-02-05 11:35:58 -05:00
|
|
|
|
2012-03-24 14:06:46 -04:00
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
|
|
assert(((1 & sense) == sense) && ((1 & jmp_to_next) == jmp_to_next) && ((1 & jmp_type_one) == jmp_type_one));
|
|
|
|
assert((TRIP_REF == t->operand[0].oprclass) && (TRIP_REF == t->operand[1].oprclass));
|
2012-02-05 11:35:58 -05:00
|
|
|
if (jmp_to_next)
|
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
p = (oprtype *)mcalloc(SIZEOF(oprtype));
|
2012-02-05 11:35:58 -05:00
|
|
|
*p = put_tjmp(t);
|
2012-03-24 14:06:46 -04:00
|
|
|
} else
|
2012-02-05 11:35:58 -05:00
|
|
|
p = addr;
|
2012-03-24 14:06:46 -04:00
|
|
|
if (GTM_BOOL == TREF(gtm_fullbool) || !TREF(saw_side_effect))
|
|
|
|
{ /* nice simple short circuit */
|
|
|
|
assert(NULL == TREF(boolchain_ptr));
|
|
|
|
bx_tail(t->operand[0].oprval.tref, jmp_type_one, p);
|
|
|
|
bx_tail(t->operand[1].oprval.tref, sense, addr);
|
|
|
|
} else
|
|
|
|
{ /* got a side effect and don't want them short circuited - this violates info hiding big-time
|
|
|
|
* This code relies on the original technique of setting up a jump ladder
|
|
|
|
* then it changes the jumps into stotemps and creates a new ladder using the saved evaluations
|
|
|
|
* for the relocated jumps to work with
|
|
|
|
* The most interesting part is getting the addresses for the new jump operands (targets)
|
|
|
|
* In theory we could turn this technique on and off around each side effect, but that's even more
|
|
|
|
* complicated, requiring additional instructions, and we don't predict the typical boolean expression
|
|
|
|
* has enough subexpressions to justify the extra trouble, although the potential pay-back would be to
|
|
|
|
* avoid unnecessary global references - again not expecting that many in a typical boolean expresion
|
|
|
|
*/
|
|
|
|
assert(TREF(shift_side_effects));
|
|
|
|
t0 = t->exorder.fl;
|
|
|
|
if (expr_fini = (NULL == TREF(boolchain_ptr))) /* NOTE assignment */
|
|
|
|
{
|
|
|
|
if (OC_BOOLFINI == t0->opcode)
|
|
|
|
{ /* ex_tail wraps bools that produce a value with OC_BOOLINIT and OC_BOOLFINI */
|
|
|
|
assert(OC_COMVAL == t0->exorder.fl->opcode);
|
|
|
|
assert(TRIP_REF == t0->operand[0].oprclass);
|
|
|
|
} else
|
|
|
|
assert(((OC_NOOP == t0->opcode) && (t0 == TREF(curtchain)))
|
|
|
|
|| (oc_tab[t0->opcode].octype & OCT_BOOL));
|
|
|
|
TREF(boolchain_ptr) = &(TREF(boolchain));
|
|
|
|
dqinit(TREF(boolchain_ptr), exorder);
|
|
|
|
}
|
|
|
|
for (i = t->operand; i < ARRAYTOP(t->operand); i++)
|
|
|
|
{
|
|
|
|
t1 = i->oprval.tref;
|
|
|
|
if (&(t->operand[0]) == i)
|
|
|
|
bx_tail(t1, jmp_type_one, p);
|
|
|
|
else
|
|
|
|
{ /* operand[1] */
|
|
|
|
bx_tail(t1, sense, addr);
|
|
|
|
if (!expr_fini)
|
|
|
|
break; /* only need to relocate last operand[1] */
|
|
|
|
}
|
|
|
|
if (OC_NOOP == t1->opcode)
|
|
|
|
{ /* the technique of sprinkling noops means fishing around for the actual instruction */
|
|
|
|
do
|
|
|
|
{
|
|
|
|
t1 = t1->exorder.bl;
|
|
|
|
} while (OC_NOOP == t1->opcode);
|
|
|
|
if (oc_tab[t1->opcode].octype & OCT_JUMP)
|
|
|
|
t1 = t1->exorder.bl;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (t1 = i->oprval.tref; OC_NOOP == t1->opcode; t1 = t1->exorder.fl)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(NULL != TREF(boolchain_ptr));
|
|
|
|
switch (t1->opcode)
|
|
|
|
{ /* time to subvert the original jump ladder entry */
|
|
|
|
case OC_COBOOL:
|
|
|
|
/* insert COBOOL and copy of following JMP in boolchain; overlay them with STOTEMP and NOOP */
|
|
|
|
assert(oc_tab[t1->exorder.fl->opcode].octype & OCT_JUMP);
|
|
|
|
ref0 = maketriple(OC_COBOOL); /* coerce later while pulling it out of temp */
|
|
|
|
ref0->operand[0] = put_tref(t1);
|
|
|
|
ref1 = (TREF(boolchain_ptr))->exorder.bl;
|
|
|
|
dqins(ref1, exorder, ref0);
|
|
|
|
t1->opcode = OC_STOTEMP; /* save the value instead of coercing now */
|
|
|
|
t1 = t1->exorder.fl;
|
|
|
|
ref0 = maketriple(t1->opcode); /* create new jump on result of coerce */
|
|
|
|
ref0->operand[0] = t1->operand[0];
|
|
|
|
t1->operand[0].oprclass = NOCLASS;
|
|
|
|
t1->opcode = OC_NOOP; /* wipe out original jump */
|
|
|
|
break;
|
|
|
|
case OC_CONTAIN:
|
|
|
|
case OC_EQU:
|
|
|
|
case OC_FOLLOW:
|
|
|
|
case OC_NUMCMP:
|
|
|
|
case OC_PATTERN:
|
|
|
|
case OC_SORTS_AFTER:
|
|
|
|
/* insert copies of orig OC and following JMP in boolchain & overly originals with STOTEMPs */
|
|
|
|
assert(oc_tab[t1->exorder.fl->opcode].octype & OCT_JUMP);
|
|
|
|
assert(TRIP_REF == t1->operand[0].oprclass);
|
|
|
|
assert(TRIP_REF == t1->operand[1].oprclass);
|
|
|
|
ref0 = maketriple(t1->opcode); /* copy operands with the stotemps as args */
|
|
|
|
ref0->operand[0] = put_tref(t1);
|
|
|
|
ref0->operand[1] = put_tref(t1->exorder.fl);
|
|
|
|
ref1 = (TREF(boolchain_ptr))->exorder.bl;
|
|
|
|
dqins(ref1, exorder, ref0);
|
|
|
|
t1->opcode = OC_STOTEMP; /* overlay the original op with 1st stotemp */
|
|
|
|
t1 = t1->exorder.fl;
|
|
|
|
ref0 = maketriple(t1->opcode); /* copy jmp */
|
|
|
|
ref0->operand[0] = t1->operand[0];
|
|
|
|
t1->operand[0] = t1->exorder.bl->operand[1];
|
|
|
|
t1->opcode = OC_STOTEMP; /* overlay jmp with 2nd stotemp */
|
|
|
|
break;
|
|
|
|
case OC_JMPTSET:
|
|
|
|
case OC_JMPTCLR:
|
|
|
|
/* move copy of jmp to boolchain and NOOP it */
|
|
|
|
ref0 = maketriple(t1->opcode);
|
|
|
|
ref0->operand[0] = t1->operand[0];
|
|
|
|
t1->operand[0].oprclass = NOCLASS;
|
|
|
|
t1->opcode = OC_NOOP; /* wipe out original jump */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
GTMASSERT;
|
|
|
|
}
|
|
|
|
if (jmp_to_next) /* mark target for later adjustment */
|
|
|
|
ref0->operand[1].oprval.tref = ref0->operand[0].oprval.tref;
|
|
|
|
ref1 = (TREF(boolchain_ptr))->exorder.bl;
|
|
|
|
dqins(ref1, exorder, ref0);
|
|
|
|
}
|
|
|
|
if (expr_fini)
|
|
|
|
{ /* time to deal with new jump ladder */
|
|
|
|
assert(NULL != TREF(boolchain_ptr));
|
|
|
|
t0 = t0->exorder.bl;
|
|
|
|
assert(oc_tab[t0->opcode].octype & OCT_BOOL);
|
|
|
|
assert(t0 == t);
|
|
|
|
dqadd(t0, TREF(boolchain_ptr), exorder); /* insert the new jump ladder */
|
|
|
|
ref0 = (TREF(boolchain_ptr))->exorder.bl->exorder.fl;
|
|
|
|
if (ref0 == TREF(curtchain))
|
|
|
|
{
|
|
|
|
newtriple(OC_NOOP);
|
|
|
|
ref0 = (TREF(curtchain))->exorder.bl;
|
|
|
|
}
|
|
|
|
assert(ref0);
|
|
|
|
t0 = t->exorder.fl;
|
|
|
|
if ((OC_JMPTSET != t0->opcode) && (OC_JMPTCLR != t0->opcode))
|
|
|
|
t0 = t0->exorder.fl;
|
|
|
|
for (; (t0 != TREF(curtchain)) && oc_tab[t0->opcode].octype & OCT_JUMP; t0 = t1)
|
|
|
|
{ /* check for jumps with targets */
|
|
|
|
assert(INDR_REF == t0->operand[0].oprclass);
|
|
|
|
t1 = t0->exorder.fl;
|
|
|
|
if (oc_tab[t1->opcode].octype & OCT_BOOL)
|
|
|
|
t1 = ref1 = t1->exorder.fl;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((OC_JMPTSET == t1->opcode) || (OC_JMPTCLR == t1->opcode))
|
|
|
|
ref1 = t1;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (t0->operand[1].oprval.tref == t0->operand[0].oprval.tref)
|
|
|
|
{ /* adjust relocated jump to "next" */
|
|
|
|
if (oc_tab[ref1->opcode].octype & OCT_JUMP)
|
|
|
|
ref1 = ref1->exorder.fl;
|
|
|
|
if ((ref1 == TREF(curtchain)
|
|
|
|
|| (t == t0->operand[0].oprval.tref->exorder.fl)))
|
|
|
|
ref1 = ref0;
|
|
|
|
assert((OC_NOOP == ref1->opcode) || (OC_BOOLFINI == ref1->opcode)
|
|
|
|
|| (OC_COMVAL == ref1->opcode) || (oc_tab[ref1->opcode].octype & OCT_BOOL));
|
|
|
|
t0->operand[0] = put_tjmp(ref1);
|
|
|
|
t0->operand[1].oprval.tref = NULL;
|
|
|
|
} else if (TJMP_REF == t0->operand[0].oprval.indr->oprclass)
|
|
|
|
t0->operand[0] = put_tjmp(ref0); /* adjust jump to "addr" */
|
|
|
|
}
|
|
|
|
TREF(boolchain_ptr) = NULL;
|
|
|
|
}
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
|
|
|
t->opcode = OC_NOOP;
|
2012-03-24 14:06:46 -04:00
|
|
|
t->operand[0].oprclass = t->operand[1].oprclass = NOCLASS;
|
2012-02-05 11:35:58 -05:00
|
|
|
return;
|
|
|
|
}
|