Skip to content

Commit

Permalink
Move load-time removal of 'if' conditions
Browse files Browse the repository at this point in the history
To where they make sense.  Which now also lets us do load-time
optimizations for:

	if (1) {

	}
	else {
		# no need to compile this
	}

and

	if (0) {
		# ignored
	}
	elsif (..) {
		# compiled
	}

Which didn't work before
  • Loading branch information
alandekok committed Mar 22, 2014
1 parent 1eff459 commit f147456
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 65 deletions.
115 changes: 86 additions & 29 deletions src/main/modcall.c
Expand Up @@ -1887,8 +1887,6 @@ static modcallable *do_compile_modsingle(modcallable *parent,

#ifdef WITH_UNLANG
} else if (strcmp(modrefname, "if") == 0) {
modgroup *g;

if (!cf_section_name2(cs)) {
cf_log_err(ci, "'if' without condition.");
return NULL;
Expand All @@ -1901,15 +1899,9 @@ static modcallable *do_compile_modsingle(modcallable *parent,
if (!csingle) return NULL;
*modname = name2;

g = mod_callabletogroup(csingle);
g->cond = cf_data_find(g->cs, "if");
rad_assert(g->cond != NULL);

return csingle;

} else if (strcmp(modrefname, "elsif") == 0) {
modgroup *g;

if (parent &&
((parent->type == MOD_LOAD_BALANCE) ||
(parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
Expand All @@ -1923,17 +1915,9 @@ static modcallable *do_compile_modsingle(modcallable *parent,
}

*modname = name2;
csingle= do_compile_modgroup(parent, component, cs,
GROUPTYPE_SIMPLE,
grouptype, MOD_ELSIF);
if (!csingle) return NULL;
*modname = name2;

g = mod_callabletogroup(csingle);
g->cond = cf_data_find(g->cs, "if");
rad_assert(g->cond != NULL);

return csingle;
return do_compile_modgroup(parent, component, cs,
GROUPTYPE_SIMPLE,
grouptype, MOD_ELSIF);

} else if (strcmp(modrefname, "else") == 0) {
if (parent &&
Expand All @@ -1956,19 +1940,13 @@ static modcallable *do_compile_modsingle(modcallable *parent,
} else if (strcmp(modrefname, "update") == 0) {
*modname = name2;

csingle = do_compile_modupdate(parent, component, cs,
name2);
if (!csingle) return NULL;

return csingle;
return do_compile_modupdate(parent, component, cs,
name2);

} else if (strcmp(modrefname, "switch") == 0) {
*modname = name2;

csingle = do_compile_modswitch(parent, component, cs);
if (!csingle) return NULL;

return csingle;
return do_compile_modswitch(parent, component, cs);

} else if (strcmp(modrefname, "case") == 0) {
int i;
Expand Down Expand Up @@ -2341,11 +2319,90 @@ static modcallable *do_compile_modgroup(modcallable *parent,
c->name = cf_section_name1(cs);
if (strcmp(c->name, "group") == 0) {
c->name = "";
} else {
} else if (c->type == MOD_GROUP) {
c->type = MOD_POLICY;
}
}

#ifdef WITH_UNLANG
/*
* Do load-time optimizations
*/
if ((c->type == MOD_IF) || (c->type == MOD_ELSIF) || (c->type == MOD_ELSE)) {
modgroup *f, *p;

rad_assert(parent != NULL);

if (c->type == MOD_IF) {
g->cond = cf_data_find(g->cs, "if");
rad_assert(g->cond != NULL);

check_if:
if (g->cond->type == COND_TYPE_FALSE) {
INFO(" # Skipping contents of '%s' as it is always 'false' -- %s:%d",
group_name[g->mc.type],
cf_section_filename(g->cs), cf_section_lineno(g->cs));
goto set_codes;
}

} else if (c->type == MOD_ELSIF) {

g->cond = cf_data_find(g->cs, "if");
rad_assert(g->cond != NULL);

rad_assert(parent != NULL);
p = mod_callabletogroup(parent);

rad_assert(p->tail != NULL);

f = mod_callabletogroup(p->tail);
rad_assert((f->mc.type == MOD_IF) ||
(f->mc.type == MOD_ELSIF));

/*
* If we took the previous condition, we
* don't need to take this one.
*
* We reset our condition to 'true', so
* that subsequent sections can check
* that they don't need to be executed.
*/
if (f->cond->type == COND_TYPE_TRUE) {
skip_true:
INFO(" # Skipping contents of '%s' as previous '%s' is always 'true' -- %s:%d",
group_name[g->mc.type],
group_name[f->mc.type],
cf_section_filename(g->cs), cf_section_lineno(g->cs));
g->cond = f->cond;
goto set_codes;
}
goto check_if;

} else {
rad_assert(c->type == MOD_ELSE);

rad_assert(parent != NULL);
p = mod_callabletogroup(parent);

rad_assert(p->tail != NULL);

f = mod_callabletogroup(p->tail);
rad_assert((f->mc.type == MOD_IF) ||
(f->mc.type == MOD_ELSIF));

/*
* If we took the previous condition, we
* don't need to take this one.
*/
if (f->cond->type == COND_TYPE_TRUE) goto skip_true;
}

/*
* Else we need to compile this section
*/
}
#endif

/*
* Loop over the children of this group.
*/
Expand Down
36 changes: 0 additions & 36 deletions src/main/modules.c
Expand Up @@ -927,42 +927,6 @@ static int load_component_section(CONF_SECTION *cs,

cp = NULL;

/*
* Skip commented-out sections.
*
* We skip an "if" ONLY when there's no
* "else" after it, as the run-time
* interpretor needs the results of the
* previous "if".
*/
if (strcmp(name1, "if") == 0) {
fr_cond_t const *c;
CONF_ITEM *next_ci;

next_ci = cf_item_find_next(scs, modref);
if (next_ci && cf_item_is_section(next_ci)) {
char const *next_name;
CONF_SECTION *next_cs;

next_cs = cf_itemtosection(next_ci);
next_name = cf_section_name1(next_cs);
if ((strcmp(next_name, "else") == 0) ||
(strcmp(next_name, "elsif") == 0)) {
c = NULL;
} else {
c = cf_data_find(scs, "if");
}
} else {
c = cf_data_find(scs, "if");
}

if (c && c->type == COND_TYPE_FALSE) {
DEBUG(" # Skipping contents of '%s' at %s:%d as it statically evaluates to 'false'",
name1, cf_section_filename(scs), cf_section_lineno(scs));
continue;
}
}

} else if (cf_item_is_pair(modref)) {
cp = cf_itemtopair(modref);

Expand Down

0 comments on commit f147456

Please sign in to comment.