Initial revision
This commit is contained in:
40
util/ego/lv/Makefile
Normal file
40
util/ego/lv/Makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
EMH=../../../h
|
||||
EML=../../../lib
|
||||
CFLAGS=
|
||||
SHARE=../share
|
||||
LV=.
|
||||
OBJECTS=lv.o
|
||||
SHOBJECTS=$(SHARE)/get.o $(SHARE)/aux.o $(SHARE)/put.o $(SHARE)/map.o $(SHARE)/alloc.o $(SHARE)/global.o $(SHARE)/debug.o $(SHARE)/lset.o $(SHARE)/cset.o $(SHARE)/parser.o $(SHARE)/files.o $(SHARE)/locals.o $(SHARE)/init_glob.o $(SHARE)/go.o
|
||||
SRC=lv.h lv.c
|
||||
.c.o:
|
||||
cc $(CFLAGS) -c $<
|
||||
all: $(OBJECTS)
|
||||
lv: \
|
||||
$(OBJECTS) $(SHOBJECTS)
|
||||
cc -o lv -i $(OBJECTS) $(SHOBJECTS) $(EML)/em_data.a
|
||||
opr:
|
||||
pr $(SRC) | opr
|
||||
dumpflop:
|
||||
tar -uf /mnt/ego/lv/lv.tarf $(SRC)
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
lv.o: ../../../h/em_mnem.h
|
||||
lv.o: ../../../h/em_pseu.h
|
||||
lv.o: ../../../h/em_spec.h
|
||||
lv.o: ../share/alloc.h
|
||||
lv.o: ../share/aux.h
|
||||
lv.o: ../share/cset.h
|
||||
lv.o: ../share/debug.h
|
||||
lv.o: ../share/def.h
|
||||
lv.o: ../share/files.h
|
||||
lv.o: ../share/get.h
|
||||
lv.o: ../share/global.h
|
||||
lv.o: ../share/go.h
|
||||
lv.o: ../share/init_glob.h
|
||||
lv.o: ../share/locals.h
|
||||
lv.o: ../share/lset.h
|
||||
lv.o: ../share/map.h
|
||||
lv.o: ../share/parser.h
|
||||
lv.o: ../share/put.h
|
||||
lv.o: ../share/types.h
|
||||
lv.o: lv.h
|
||||
584
util/ego/lv/lv.c
Normal file
584
util/ego/lv/lv.c
Normal file
@@ -0,0 +1,584 @@
|
||||
|
||||
/* L I V E V A R I A B L E S A N A L Y S I S */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "lv.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/cset.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/get.h"
|
||||
#include "../share/put.h"
|
||||
#include "../share/aux.h"
|
||||
#include "../share/init_glob.h"
|
||||
#include "../share/locals.h"
|
||||
#include "../share/go.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../share/parser.h"
|
||||
|
||||
/* TEMPORARY: should be put in ../../../h/em_mes.h: */
|
||||
#define ms_liv 9
|
||||
#define ms_ded 10
|
||||
|
||||
short nrglobals;
|
||||
short nrvars;
|
||||
|
||||
STATIC int Slv;
|
||||
STATIC bool mesgflag = FALSE; /* Suppress generation of live/dead info */
|
||||
|
||||
|
||||
STATIC clean_up()
|
||||
{
|
||||
local_p *p;
|
||||
|
||||
for (p = &locals[1]; p <= &locals[nrlocals]; p++) {
|
||||
oldlocal(*p);
|
||||
}
|
||||
oldmap(locals,nrlocals);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool is_dir_use(l)
|
||||
line_p l;
|
||||
{
|
||||
/* See if l is a direct use of some variable
|
||||
* (i.e. not through a pointer). A LIL is a
|
||||
* direct use of some pointer variable
|
||||
* (and an indirect use of some other variable).
|
||||
* A SIL is also a direct use.
|
||||
* A LOI, however, is not an direct use of a variable.
|
||||
* An an increment/decrement instruction is regarded
|
||||
* as a use here, and not as a definition, as the
|
||||
* variable is first used and than defined.
|
||||
*/
|
||||
|
||||
switch(INSTR(l)) {
|
||||
case op_dee:
|
||||
case op_del:
|
||||
case op_ine:
|
||||
case op_inl:
|
||||
case op_lde:
|
||||
case op_ldl:
|
||||
case op_lil:
|
||||
case op_loe:
|
||||
case op_lol:
|
||||
case op_sil:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool is_indir_use(l)
|
||||
line_p l;
|
||||
{
|
||||
/* See if instruction l uses some variable(s) indirectly,
|
||||
* i.e. through a pointer or via a procedure call.
|
||||
*/
|
||||
|
||||
switch(INSTR(l)) {
|
||||
case op_blm:
|
||||
case op_bls:
|
||||
case op_cai:
|
||||
case op_cal:
|
||||
case op_lar:
|
||||
case op_ldf:
|
||||
case op_lil:
|
||||
case op_lof:
|
||||
case op_loi:
|
||||
case op_los:
|
||||
case op_mon:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC bool is_def(l)
|
||||
line_p l;
|
||||
{
|
||||
/* See if l does a direct definition */
|
||||
|
||||
switch(INSTR(l)) {
|
||||
case op_sde:
|
||||
case op_sdl:
|
||||
case op_ste:
|
||||
case op_stl:
|
||||
case op_zre:
|
||||
case op_zrl:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
STATIC def_use(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Compute DEF(b) and USE(b), for every basic block b
|
||||
* of procedure p. DEF(b) contains the variables that
|
||||
* are certain to be defined (assigned) in b
|
||||
* before being used. USE(b) contains the variables
|
||||
* that may be used in b, before being defined.
|
||||
* (Note that uncertainty arises in the presence of
|
||||
* pointers and procedure calls).
|
||||
* We compute these sets, by scanning the text of
|
||||
* the basic block from beginning till end.
|
||||
*/
|
||||
|
||||
register bblock_p b;
|
||||
register line_p l;
|
||||
short v;
|
||||
bool found;
|
||||
cset all_ind_uses;
|
||||
|
||||
all_ind_uses = Cempty_set(nrvars);
|
||||
for (v = 1; v < nrlocals; v++) {
|
||||
if (!IS_REGVAR(locals[v])) {
|
||||
Cadd(LOC_TO_VARNR(v),&all_ind_uses);
|
||||
}
|
||||
}
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
USE(b) = Cempty_set(nrvars);
|
||||
DEF(b) = Cempty_set(nrvars);
|
||||
for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
|
||||
if (is_def(l)) {
|
||||
/* An direct definition (i.e. not
|
||||
* through a pointer).
|
||||
*/
|
||||
var_nr(l,&v,&found);
|
||||
if (found && !Cis_elem(v,USE(b))) {
|
||||
/* We do maintain live-dead info
|
||||
* for this variable, and it was
|
||||
* not used earlier in b.
|
||||
*/
|
||||
Cadd(v, &DEF(b));
|
||||
}
|
||||
} else {
|
||||
if (is_dir_use(l)) {
|
||||
var_nr(l,&v,&found);
|
||||
if (found && !Cis_elem(v,DEF(b))) {
|
||||
Cadd(v, &USE(b));
|
||||
}
|
||||
}
|
||||
if (is_indir_use(l)) {
|
||||
/* Add variable that may be used
|
||||
* by l to USE(b).
|
||||
*/
|
||||
Cjoin(all_ind_uses,&USE(b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Cdeleteset(all_ind_uses);
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC unite_ins(bbset,setp)
|
||||
lset bbset;
|
||||
cset *setp;
|
||||
{
|
||||
/* Take the union of L_IN(b), for all b in bbset,
|
||||
* and put the result in setp.
|
||||
*/
|
||||
|
||||
Lindex i;
|
||||
|
||||
Cclear_set(setp);
|
||||
for (i = Lfirst(bbset); i != (Lindex) 0; i = Lnext(i,bbset)) {
|
||||
Cjoin(L_IN((bblock_p) Lelem(i)), setp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC solve_lv(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Solve the data flow equations for Live Variables,
|
||||
* for procedure p. These equations are:
|
||||
* (1) IN[b] = OUT[b] - DEF[b] + USE[b]
|
||||
* (2) OUT(b) = IN(s1) + ... + IN(sn) ;
|
||||
* where SUCC(b) = {s1, ... , sn}
|
||||
*/
|
||||
|
||||
register bblock_p b;
|
||||
cset newout = Cempty_set(nrvars);
|
||||
bool change = TRUE;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
L_IN(b) = Cempty_set(nrvars);
|
||||
Ccopy_set(USE(b), &L_IN(b));
|
||||
L_OUT(b) = Cempty_set(nrvars);
|
||||
}
|
||||
while (change) {
|
||||
change = FALSE;
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
unite_ins(b->b_succ,&newout);
|
||||
if (!Cequal(newout,L_OUT(b))) {
|
||||
change = TRUE;
|
||||
Ccopy_set(newout, &L_OUT(b));
|
||||
Ccopy_set(newout, &L_IN(b));
|
||||
Csubtract(DEF(b), &L_IN(b));
|
||||
Cjoin(USE(b), &L_IN(b));
|
||||
}
|
||||
}
|
||||
}
|
||||
Cdeleteset(newout);
|
||||
}
|
||||
|
||||
|
||||
STATIC live_variables_analysis(p)
|
||||
proc_p p;
|
||||
{
|
||||
make_localtab(p);
|
||||
nrvars = nrglobals + nrlocals;
|
||||
def_use(p);
|
||||
solve_lv(p);
|
||||
}
|
||||
|
||||
|
||||
STATIC init_live_dead(b)
|
||||
bblock_p b;
|
||||
{
|
||||
/* For every register variable, see if it is
|
||||
* live or dead at the end of b.
|
||||
*/
|
||||
|
||||
register short v;
|
||||
local_p loc;
|
||||
|
||||
for (v = 1; v <= nrlocals; v++) {
|
||||
loc = locals[v];
|
||||
if (IS_REGVAR(loc) && Cis_elem(LOC_TO_VARNR(v),L_OUT(b))) {
|
||||
LIVE(loc);
|
||||
} else {
|
||||
DEAD(loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC line_p make_mesg(mesg,loc)
|
||||
short mesg;
|
||||
local_p loc;
|
||||
{
|
||||
/* Create a line for a message stating that
|
||||
* local variable loc is live/dead. This message
|
||||
* looks like: "mes ms_liv,off,size" or
|
||||
* "mes ms_ded,off,size".
|
||||
*/
|
||||
|
||||
line_p l = newline(OPLIST);
|
||||
register arg_p ap;
|
||||
|
||||
l->l_instr = ps_mes;
|
||||
ap = ARG(l) = newarg(ARGOFF);
|
||||
ap->a_a.a_offset = mesg;
|
||||
ap = ap->a_next = newarg(ARGOFF);
|
||||
ap->a_a.a_offset = loc->lc_off;
|
||||
ap = ap->a_next = newarg(ARGOFF);
|
||||
ap->a_a.a_offset = loc->lc_size;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC block_entry(b,prev)
|
||||
bblock_p b,prev;
|
||||
{
|
||||
short v,vn;
|
||||
local_p loc;
|
||||
bool was_live, is_live;
|
||||
|
||||
/* Generate a live/dead message for every register variable that
|
||||
* was live at the end of prev, but dead at the beginning of b,
|
||||
* or v.v. If prev = 0 (i.e. begin of procedure), parameters were
|
||||
* live, normal local variables were dead.
|
||||
*/
|
||||
|
||||
for (v = 1; v <= nrlocals; v++) {
|
||||
loc = locals[v];
|
||||
vn = LOC_TO_VARNR(v);
|
||||
if (prev == (bblock_p) 0) {
|
||||
was_live = loc->lc_off >= 0;
|
||||
} else {
|
||||
was_live = Cis_elem(vn,L_OUT(prev));
|
||||
}
|
||||
is_live = Cis_elem(vn,L_IN(b));
|
||||
if (was_live != is_live) {
|
||||
app_block(make_mesg((is_live?ms_liv:ms_ded),loc),b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC app_block(l,b)
|
||||
line_p l;
|
||||
bblock_p b;
|
||||
{
|
||||
line_p x = b->b_start;
|
||||
|
||||
if (x != (line_p) 0 && INSTR(x) == ps_pro) {
|
||||
/* start of procedure; append after pro pseudo ! */
|
||||
if ((l->l_next = x->l_next) != (line_p) 0) {
|
||||
PREV(l->l_next) = l;
|
||||
}
|
||||
x->l_next = l;
|
||||
PREV(l) = x;
|
||||
} else {
|
||||
if ((l->l_next = x) != (line_p) 0) {
|
||||
PREV(l->l_next) = l;
|
||||
}
|
||||
b->b_start = l;
|
||||
PREV(l) = (line_p) 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC definition(l,useless_out,v_out,mesgflag)
|
||||
line_p l;
|
||||
bool *useless_out;
|
||||
short *v_out;
|
||||
bool mesgflag;
|
||||
{
|
||||
/* Process a definition. If the defined (register-) variable
|
||||
* is live after 'l', then create a live-message and put
|
||||
* it after 'l'.
|
||||
*/
|
||||
|
||||
short v;
|
||||
bool found;
|
||||
local_p loc;
|
||||
|
||||
*useless_out = FALSE;
|
||||
var_nr(l,&v,&found);
|
||||
if (found && IS_LOCAL(v)) {
|
||||
*v_out = v;
|
||||
loc = locals[TO_LOCAL(v)];
|
||||
if (IS_REGVAR(loc)) {
|
||||
if (IS_LIVE(loc)) {
|
||||
if (!mesgflag) {
|
||||
appnd_line(make_mesg(ms_liv,loc), l);
|
||||
}
|
||||
DEAD(loc);
|
||||
} else {
|
||||
*useless_out = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STATIC use(l,mesgflag)
|
||||
line_p l;
|
||||
bool mesgflag;
|
||||
{
|
||||
/* Process a use. If the defined (register-) variable
|
||||
* is dead after 'l', then create a dead-message and put
|
||||
* it after 'l'.
|
||||
*/
|
||||
|
||||
short v;
|
||||
bool found;
|
||||
local_p loc;
|
||||
|
||||
var_nr(l,&v,&found);
|
||||
if (found && IS_LOCAL(v)) {
|
||||
loc = locals[TO_LOCAL(v)];
|
||||
if (IS_REGVAR(loc) && IS_DEAD(loc)) {
|
||||
if (!mesgflag) {
|
||||
appnd_line(make_mesg(ms_ded,loc), l);
|
||||
}
|
||||
LIVE(loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC nothing() { } /* No action to be undertaken at level 0 of parser */
|
||||
|
||||
STATIC rem_code(l1,l2,b)
|
||||
line_p l1,l2;
|
||||
bblock_p b;
|
||||
{
|
||||
line_p l,x,y;
|
||||
|
||||
x = PREV(l1);
|
||||
y = l2->l_next;
|
||||
for (l = l1; l != l2; l = l->l_next) {
|
||||
oldline(l);
|
||||
}
|
||||
if (x == (line_p) 0) {
|
||||
b->b_start = y;
|
||||
} else {
|
||||
x->l_next = y;
|
||||
}
|
||||
if (y != (line_p) 0) {
|
||||
PREV(y) = x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define SIZE(v) ((offset) locals[TO_LOCAL(v)]->lc_size)
|
||||
|
||||
|
||||
|
||||
|
||||
lv_mesg(p,mesgflag)
|
||||
proc_p p;
|
||||
bool mesgflag;
|
||||
{
|
||||
/* Create live/dead messages for every possible register
|
||||
* variable of p. A dead-message is put after a "use" of
|
||||
* such a variable, if the variable becomes dead just
|
||||
* after the use (i.e. this was its last use).
|
||||
* A live message is put after a "definition" of such
|
||||
* a variable, if the variable becomes live just
|
||||
* after the definition (which will usually be the case).
|
||||
* We traverse every basic block b of p from the last
|
||||
* instruction of b backwards to the beginning of b.
|
||||
* Initially, all variables that are dead at the end
|
||||
* of b are marked dead. All others are marked live.
|
||||
* If we come accross a definition of a variable X that
|
||||
* was marked live, we put a live-message after the
|
||||
* definition and mark X dead.
|
||||
* If we come accross a use of a variable X that
|
||||
* was marked dead, we put a dead-message after the
|
||||
* use and mark X live.
|
||||
* So at any point, the mark of X tells whether X is
|
||||
* live or dead immediately before (!) that point.
|
||||
* We also generate a message at the start of a basic block
|
||||
* for every variable that was live at the end of the (textually)
|
||||
* previous block, but dead at the entry of this block, or v.v.
|
||||
* On the fly, useless assignments are removed.
|
||||
*/
|
||||
|
||||
register bblock_p b;
|
||||
register line_p l;
|
||||
line_p lnp, prev;
|
||||
bblock_p prevb = (bblock_p) 0;
|
||||
short v;
|
||||
bool useless;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
block_entry(b,prevb); /* generate message at head of block */
|
||||
prevb = b;
|
||||
if (!mesgflag) {
|
||||
init_live_dead(b);
|
||||
}
|
||||
for (l = last_instr(b); l != (line_p) 0; l = prev) {
|
||||
/* traverse backwards! */
|
||||
prev = PREV(l);
|
||||
if (is_def(l)) {
|
||||
definition(l,&useless,&v,mesgflag);
|
||||
if (useless && /* assignment to dead var. */
|
||||
parse(prev,SIZE(v),&lnp,0,nothing)) {
|
||||
/* The code "VAR := expression" can
|
||||
* be removed. 'l' is the "STL VAR",
|
||||
* lnp is the beginning of the EM code
|
||||
* for the expression.
|
||||
*/
|
||||
prev = PREV(lnp);
|
||||
rem_code(lnp,l,b);
|
||||
OUTVERBOSE("useless assignment ,proc %d,local %d", curproc->p_id,
|
||||
(int) locals[TO_LOCAL(v)]->lc_off);
|
||||
Slv++;
|
||||
}
|
||||
} else {
|
||||
if (is_dir_use(l)) {
|
||||
use(l,mesgflag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC lv_extend(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Allocate extended data structures for Use Definition analysis */
|
||||
|
||||
register bblock_p b;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
b->b_extend = newlvbx();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC lv_cleanup(p)
|
||||
proc_p p;
|
||||
{
|
||||
/* Deallocate extended data structures for Use Definition analysis */
|
||||
|
||||
register bblock_p b;
|
||||
|
||||
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
||||
Cdeleteset(USE(b));
|
||||
Cdeleteset(DEF(b));
|
||||
Cdeleteset(L_IN(b));
|
||||
Cdeleteset(L_OUT(b));
|
||||
oldlvbx(b->b_extend);
|
||||
}
|
||||
}
|
||||
|
||||
lv_flags(p)
|
||||
char *p;
|
||||
{
|
||||
switch(*p) {
|
||||
case 'N':
|
||||
mesgflag = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lv_optimize(p)
|
||||
proc_p p;
|
||||
{
|
||||
locals = (local_p *) 0;
|
||||
lv_extend(p);
|
||||
live_variables_analysis(p);
|
||||
lv_mesg(p,mesgflag);
|
||||
/* generate live-dead messages for regvars */
|
||||
lv_cleanup(p);
|
||||
clean_up();
|
||||
}
|
||||
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
go(argc,argv,init_globals,lv_optimize,no_action,lv_flags);
|
||||
report("useless assignments deleted",Slv);
|
||||
exit(0);
|
||||
}
|
||||
42
util/ego/lv/lv.h
Normal file
42
util/ego/lv/lv.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* L I V E V A R I A B L E S A N A L Y S I S
|
||||
*
|
||||
* L V . H
|
||||
*/
|
||||
|
||||
|
||||
#define USE(b) (b)->b_extend->bx_lv.bx_use
|
||||
#define DEF(b) (b)->b_extend->bx_lv.bx_def
|
||||
#define L_IN(b) (b)->b_extend->bx_lv.bx_lin
|
||||
#define L_OUT(b) (b)->b_extend->bx_lv.bx_lout
|
||||
|
||||
extern short nrglobals; /* number of global variables for which
|
||||
* ud-info is maintained.
|
||||
*/
|
||||
extern short nrvars; /* total number of variables (global + local)
|
||||
* for which ud-info is maintained.
|
||||
*/
|
||||
|
||||
/* Every global variable for which ud-info is maintained has
|
||||
* a 'global variable number' (o_globnr). Every useful local
|
||||
* has a 'local variable number', which is its index in the
|
||||
* 'locals' table. All these variables also have a
|
||||
* 'variable number'. Conversions exist between these numbers.
|
||||
*/
|
||||
|
||||
#define TO_GLOBAL(v) (v)
|
||||
#define TO_LOCAL(v) (v - nrglobals)
|
||||
#define GLOB_TO_VARNR(v) (v)
|
||||
#define LOC_TO_VARNR(v) (v + nrglobals)
|
||||
#define IS_GLOBAL(v) (v <= nrglobals)
|
||||
#define IS_LOCAL(v) (v > nrglobals)
|
||||
|
||||
#define REGVAR(lc) lc->lc_flags |= LCF_REG
|
||||
#define IS_REGVAR(lc) (lc->lc_flags & LCF_REG)
|
||||
#define BADLC(lc) lc->lc_flags |= LCF_BAD
|
||||
#define IS_BADLC(lc) (lc->lc_flags & LCF_BAD)
|
||||
#define LIVE(lc) lc->lc_flags |= LCF_LIVE
|
||||
#define DEAD(lc) lc->lc_flags &= ~LCF_LIVE
|
||||
#define IS_LIVE(lc) (lc->lc_flags & LCF_LIVE)
|
||||
#define IS_DEAD(lc) (!(lc->lc_flags & LCF_LIVE))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user