diff --git a/b2/Makefile b/b2/Makefile index 4323712..b02e684 100644 --- a/b2/Makefile +++ b/b2/Makefile @@ -79,11 +79,17 @@ y.tab.o: y.tab.c $(CC) -c $(CFLAGS) $*.c -o $*.o $(call MKDEP, $*) +relop.o: unreachable.inc + +unreachable.inc: genredmap.pl + $(GEN) ./$< 0 >$@ || { rm -f $@; exit 1; } + -include $(OBJS:.o=.d) clean: rm -f $(OBJS) $(OBJS:.o=.d) rm -f lex.yy.c y.tab.c y.tab.h y.output + rm -f redmap.inc spotless: clean rm -f boom diff --git a/b2/chr.c b/b2/chr.c index ecad525..c15f177 100644 --- a/b2/chr.c +++ b/b2/chr.c @@ -83,12 +83,12 @@ static int comp(const void *a, enum relop op, const void *b, const void *user) } -static void check_redundant(const struct field *f, +static void check_unreachable(const struct field *f, const struct condition *c1, const struct condition *c2) { - if (relop_implies(c1->relop, c2->relop, &c1->value, &c2->value, + if (relop_unreachable(c1->relop, c2->relop, &c1->value, &c2->value, comp, f->fmt)) - yywarn("redundant condition"); + yywarn("unreachable condition"); } @@ -107,10 +107,10 @@ void field_finalize(struct field *field) for (sel = field->sel; sel; sel = sel->next) for (cond = sel->cond; cond; cond = cond->next) { for (c2 = cond->next; c2; c2 = c2->next) - check_redundant(field, cond, c2); + check_unreachable(field, cond, c2); for (s2 = sel->next; s2; s2 = s2->next) for (c2 = s2->cond; c2; c2 = c2->next) - check_redundant(field, cond, c2); + check_unreachable(field, cond, c2); } } diff --git a/b2/genredmap.pl b/b2/genredmap.pl new file mode 100755 index 0000000..25e8da1 --- /dev/null +++ b/b2/genredmap.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl +# +# genredmap.pl - Redundacy detector map generator +# +# Copyright 2012 by Werner Almesberger +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# + +# +# This script finds the relational operators op = f(opa, opb), for which +# the following is true: +# +# forall A, B: (A op B) -> forall X: !(X opa A) -> !(X opa B) +# +# In other words: if, with X a variable and A and B constants, we have a +# cascade of the form +# +# if (X opa A) ...; +# else if (X opa B) ...; +# +# and A op B is true, then the second branch will never be taken. +# + +%op = ( + "lt" => sub { $_[0] < $_[1] }, + "le" => sub { $_[0] <= $_[1] }, + "eq" => sub { $_[0] == $_[1] }, + "ge" => sub { $_[0] >= $_[1] }, + "gt" => sub { $_[0] > $_[1] }, + +); + +@ops = ("lt", "le", "eq", "ge", "gt"); + +$always = 0; + +$a = 2; +@v = (0, 1, 2, 3, 4); + +for $opa (@ops) { +#next unless $opa eq "lt"; + for $opb (@ops) { +#next unless $opb eq "lt"; + $best = 0; + OP: for $op (@ops) { + $hit = 0; + for $b (@v) { +#print "($opa, $opb) $a $op $b\n"; + next unless $op{$op}->($a, $b); + for $x (@v) { +#print " A: $x $opa $a\n"; + next if $op{$opa}->($x, $a); +#print " B: $x $opb $b\n"; + next OP + if $op{$opb}->($x, $b) != $always; + $hit++; +#print " HIT ($hit)\n"; + } + } + if ($hit > $best) { + $best = $hit; + $best_op = $op; + } + } + print "\t[idx_$opa][idx_$opb] = rel_$best_op,\n" if $best; + } +} diff --git a/b2/relop.c b/b2/relop.c index ff9411b..a31e262 100644 --- a/b2/relop.c +++ b/b2/relop.c @@ -19,33 +19,16 @@ /* * Operator to use for * - * forall X: (A op B) == ((X opa A) -> (X opb B)) + * (A op B) -> forall X: !(X opa A) -> !(X opb B)) * - * For unlimited sets of values: - * - * opa -> < <= == >= > - * opb - * < >= >= 0 0 0 - * <= > >= 0 0 0 - * == > >= == <= < - * >= 0 0 0 <= < - * > 0 0 0 <= <= - * - * For limited sets of values, we could decide also in some edge cases, - * but let's save such sophistication for later. + * This is for unlimited sets of values. For limited sets of values, we could + * decide also in some edge cases, but let's save such sophistication for + * later. */ -static const enum relop implies_op[idx_n][idx_n] = { - [idx_lt][idx_lt] = rel_ge, - [idx_lt][idx_le] = rel_ge, - - [idx_le][idx_lt] = rel_gt, - [idx_le][idx_le] = rel_ge, - - [idx_eq][idx_lt] = rel_gt, - [idx_eq][idx_le] = rel_ge, - [idx_eq][idx_eq] = rel_eq, +static const enum relop unreachable_op[idx_n][idx_n] = { +#include "unreachable.inc" }; @@ -68,23 +51,13 @@ static int relop2index(enum relop op) } -static enum relop swap_op(enum relop op) -{ - return idx_n-1-relop2index(op); -} - - -int relop_implies(enum relop opa, enum relop opb, const void *a, const void *b, +int relop_unreachable(enum relop opa, enum relop opb, + const void *a, const void *b, int (*cmp)(const void *a, enum relop op, const void *b, const void *user), const void *user) { - if (opa <= opb) - return cmp(a, - implies_op[relop2index(opa)][relop2index(opb)], b, user); - else - return cmp(b, - swap_op(implies_op[relop2index(opb)][relop2index(opa)]), - a, user); + return cmp(a, + unreachable_op[relop2index(opa)][relop2index(opb)], b, user); } diff --git a/b2/relop.h b/b2/relop.h index adb2f50..82f1408 100644 --- a/b2/relop.h +++ b/b2/relop.h @@ -35,10 +35,11 @@ enum relop { /* - * relop_implies checks whether, for all X: (X opb A) -> (X opa B) + * relop_unreachable checks whether, for all X: !(X opb A) -> !(X opa B) */ -int relop_implies(enum relop opa, enum relop opb, const void *a, const void *b, +int relop_unreachable(enum relop opa, enum relop opb, + const void *a, const void *b, int (*cmp)(const void *a, enum relop op, const void *b, const void *user), const void *user); void dump_relop(FILE *file, enum relop op); diff --git a/b2/test/hierrul b/b2/test/hierrul index c15b59a..cb90932 100755 --- a/b2/test/hierrul +++ b/b2/test/hierrul @@ -69,7 +69,7 @@ p = { EOF expect < { mouse: { X=* } cat: { Y=* }