Devicetree
 help / color / mirror / Atom feed
From: Jon Loeliger <jdl-CYoMK+44s/E@public.gmane.org>
To: devicetree-discuss-mnsaURCQ41sdnm+yROfE0A@public.gmane.org
Subject: [PATCH 6/9 V3] Add the main IR evaluation implementation
Date: Fri, 26 Sep 2008 15:25:45 -0500	[thread overview]
Message-ID: <1222460748-20127-7-git-send-email-jdl@jdl.com> (raw)
In-Reply-To: <1222460748-20127-6-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>

Signed-off-by: Jon Loeliger <jdl-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 ir_eval.c | 1504 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 1504 insertions(+), 0 deletions(-)
 create mode 100644 ir_eval.c

diff --git a/ir_eval.c b/ir_eval.c
new file mode 100644
index 0000000..bd667cb
--- /dev/null
+++ b/ir_eval.c
@@ -0,0 +1,1504 @@
+/*
+ * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *                                                                   USA
+ */
+
+#include <stdio.h>
+
+#include "dtc.h"
+#include "srcpos.h"
+#include "ir.h"
+#include "ir_scope.h"
+
+
+/*
+ * Returns:
+ *    0 on success, with *val filled in
+ *    -1 == bad characters in literal number
+ *    -2 == literal out of range
+ *    -3 == bad literal
+ */
+
+int
+ir_eval_literal_guessing(const char *s, int base, int bits,
+			 unsigned long long *val)
+{
+	char *e;
+
+	errno = 0;
+	*val = strtoull(s, &e, base);
+
+	if (*e)
+		return -1;
+	else if ((errno == ERANGE)
+		 || ((bits < 64) && (*val >= (1ULL << bits))))
+		return -2;
+	else if (errno != 0)
+		return -3;
+
+	return 0;
+}
+
+unsigned long long
+ir_eval_literal_str(const char *s, int base, int bits)
+{
+	unsigned long long val;
+	char *e;
+
+	errno = 0;
+	val = strtoull(s, &e, base);
+
+	if (*e)
+		die("bad characters in literal");
+	else if ((errno == ERANGE)
+		 || ((bits < 64) && (val >= (1ULL << bits))))
+		die("literal out of range");
+	else if (errno != 0)
+		die("bad literal");
+
+	return val;
+}
+
+
+struct ir *
+ir_eval_cvt_to_string(struct ir *ir)
+{
+	char buf[30];
+	unsigned long long lit1;
+	struct ir *ir_new;
+
+	ir_new = ir_alloc(IR_LIT_STR, ir->ir_srcpos);
+	if (ir_is_constant(ir)) {
+		lit1 = ir_eval_for_addr(ir);
+		snprintf(buf, 30, "%llu", lit1);
+		ir_new->ir_lit_str = strdup(buf);
+	} else {
+		ir_error(ir,
+			 "Can't convert %s to a string\n",
+			 ir_type_string(ir->ir_type));
+	}
+
+	return ir_new;
+}
+
+
+/*
+ * FIXME: This should be named ir_is_constant_number()
+ */
+int
+ir_is_constant(struct ir *ir)
+{
+	return ir &&
+		(ir->ir_type == IR_LITERAL
+		 || ir->ir_type == IR_LIT_BYTE
+		 || ir->ir_type == IR_LIT_CELL
+		 || ir->ir_type == IR_LIT_ADDR);
+}
+
+
+int
+ir_is_string(struct ir *ir)
+{
+	return ir && ir->ir_type == IR_LIT_STR;
+}
+
+
+char *
+ir_eval_for_label(struct ir *ir)
+{
+	char *str;
+
+	if (ir == NULL)
+		return NULL;
+
+	if (ir->ir_type == IR_LABEL
+	    || ir->ir_type == IR_REF_PATH
+	    || ir->ir_type == IR_REF_PHANDLE) {
+		str = strdup(ir->ir_label_name);
+	} else if (ir->ir_type == IR_LIT_STR) {
+		str = strdup(ir->ir_lit_str);
+	} else {
+		str = NULL;
+	}
+
+	return str;
+}
+
+
+char *
+ir_eval_for_name(struct ir *ir)
+{
+	struct ir *ir_val;
+	char *str;
+
+	if (ir == NULL)
+		return NULL;
+
+	ir_val = ir;
+
+	if (ir_val == NULL) {
+		ir_error(ir, "Expected a name\n");
+		return NULL;
+	}
+
+	if (ir_val->ir_type != IR_PROPNODENAME
+	    && ir_val->ir_type != IR_ID
+	    && ir_val->ir_type != IR_LIT_STR)
+		return NULL;
+
+	str = strdup(ir->ir_lit_str);
+
+	return str;
+}
+
+
+/*
+ * FIXME: This is misnamed.  Should be more like ir_eval_for_const()
+ */
+uint64_t
+ir_eval_for_addr(struct ir *ir)
+{
+	unsigned long long a = 0;
+
+	struct ir *ir_val;
+
+	ir_val = ir_eval(ir);
+	if (ir_val == NULL) {
+		ir_error(ir, "Expected a const expression\n");
+		return 0;
+	}
+
+	/*
+	 * FIXME: UH, ir_is_constant() check or something?
+	 */
+
+	a  = ir_val->ir_literal;
+	ir_free(ir_val);
+	debug("eval_for_addr() is 0x%08llx\n", a);
+
+	return a;
+}
+
+
+char *
+ir_eval_for_c_string(struct ir *ir)
+{
+	struct data dtmp;
+	char *p;
+
+	if (ir == NULL)
+		return NULL;
+
+
+	if (!ir_is_string(ir))
+		return NULL;
+
+	p = ir->ir_lit_str;
+	dtmp = data_copy_escape_string(p, strlen(p));
+
+	return strdup(dtmp.val);
+}
+
+
+void
+ir_eval_for_data(struct ir *ir, struct data *d)
+{
+	struct ir *ir_val;
+	struct ir *iri;
+	struct data dtmp;
+	char *lab;
+	cell_t c;
+	unsigned long long ulit64;
+
+	if (ir == NULL)
+		return;
+
+	ir_val = ir_eval(ir);
+
+	switch (ir_val->ir_type) {
+	case IR_LIST:
+		for (iri = ir_val->ir_first; iri != NULL; iri = iri->ir_next) {
+			ir_eval_for_data(iri, d);
+		}
+		break;
+
+	case IR_LIT_STR:
+		dtmp = data_copy_escape_string(ir_val->ir_lit_str,
+					       strlen(ir_val->ir_lit_str));
+		*d = data_merge(*d, dtmp);
+		break;
+
+	case IR_LIT_BYTE:
+		*d = data_append_byte(*d, ir_val->ir_literal);
+		break;
+
+	case IR_LIT_ADDR:
+		ulit64 = ir_val->ir_literal;
+		*d = data_append_addr(*d, ulit64);
+		break;
+
+	case IR_LIT_CELL:
+		c = (cell_t) ir_val->ir_literal;
+		*d = data_append_cell(*d, c);
+		break;
+
+	case IR_CELL:
+		ir_eval_for_data(ir_val->ir_expr1, d);
+		break;
+
+	case IR_LABEL:
+		lab = ir_eval_for_label(ir);
+		*d = data_add_marker(*d, LABEL, lab);
+		break;
+
+	case IR_REF_PATH:
+		lab = ir_eval_for_label(ir);
+		*d = data_add_marker(*d, REF_PATH, lab);
+		break;
+
+	case IR_REF_PHANDLE:
+		lab = ir_eval_for_label(ir);
+		*d = data_add_marker(*d, REF_PHANDLE, lab);
+		*d = data_append_cell(*d, -1);
+		break;
+
+	case IR_INCBIN:	{
+		struct search_path path = { srcpos_file->dir, NULL, NULL };
+		struct data dinc = empty_data;
+		char *file_name;
+		struct dtc_file *file;
+		unsigned long long start;
+		unsigned long long len;
+		struct ir *ir_pos;
+
+		/*
+		 * expr1 is file_name
+		 * expr2 is start, NULL implies start of file
+		 * expr3 is length, NULL implies whole file
+		 */
+		file_name = ir_eval_for_c_string(ir_val->ir_expr1);
+		file = dtc_open_file(file_name, &path);
+
+		ir_pos = ir_val->ir_expr2;
+		start = ir_eval_for_addr(ir_val->ir_expr2);
+		if (ir_val->ir_expr3)
+			len = ir_eval_for_addr(ir_val->ir_expr3);
+		else
+			len = -1;
+
+		if (start != 0) {
+			if (fseek(file->file, start, SEEK_SET) != 0) {
+				ir_error(ir_pos,
+					 "Couldn't seek to offset %llu in \"%s\": %s",
+					 (unsigned long long)start,
+					 file_name,
+					 strerror(errno));
+			}
+		}
+
+		dinc = data_copy_file(file->file, len);
+		*d = data_merge(*d, dinc);
+		dtc_close_file(file);
+		break;
+	}
+
+	default:
+		ir_error(ir,
+			 "Can't convert IR type %s to data\n",
+			 ir_type_string(ir_val->ir_type));
+		break;
+	}
+}
+
+
+struct ir_scope *
+ir_eval_func_body(struct ir *ir_func)
+{
+	char *func_name;
+	struct ir *ir_func_def;
+	struct ir *ir_parameters;
+	struct ir *ir_statements;
+	struct ir_symbol *irsym;
+	struct ir *ir_p;
+	struct ir *ir_f;
+	char *param_name;
+	struct ir_scope *irs_scope;
+	struct ir *ir_next;
+	struct ir *ir_pos;
+
+	if (ir_func == NULL)
+		return NULL;
+
+	if (ir_func->ir_type != IR_FUNC_CALL)
+		return NULL;
+
+	/*
+	 * Lookup the function definition.
+	 */
+	ir_pos = ir_func->ir_expr1;
+	func_name = ir_eval_for_name(ir_func->ir_expr1);
+	debug("ir_eval_func_body(): Looking up %s\n", func_name);
+
+	irsym = irs_lookup(func_name, IRS_ANY);
+	if (irsym == NULL || irsym->irsym_type != IRSYM_FUNCDEF) {
+		ir_error(ir_pos,
+			 "%s isn't a function definition\n",
+			 func_name);
+		return NULL;
+	}
+
+	ir_func_def = irsym->irsym_value;
+	ir_statements = ir_func_def->ir_statements;
+	ir_parameters = ir_func_def->ir_declarations;
+
+	debug("ir_eval_func_body(): Found definition for %s\n",
+	      irsym->irsym_name);
+
+	/*
+	 * Set up parameter binding via eval-and-copy-in.
+	 *
+	 * First pass evaluates each parameter expression and
+	 * builds a temporary list of each eval() parameter.
+	 * These evaluations need to be done before the function
+	 * scope is opened.
+	 *
+	 * Remember to dodge a possible parent IR_LIST node.
+	 */
+	debug("ir_eval_func_body(): Evaluating parameters\n");
+	ir_p = ir_eval(ir_func->ir_expr2);
+	if (ir_p != NULL && ir_p->ir_type == IR_LIST) {
+		ir_p = ir_p->ir_first;
+	}
+
+	/*
+	 * Open an evaluation scope and symbol table for
+	 * the function.
+	 */
+	irs_push_scope(IRS_FUNC_CALL);
+
+	/*
+	 * Second pass loops over each formal parameter
+	 * and each actual expression simultaneously.
+	 *
+	 * Again remember to dodge a possible parent IR_LIST node.
+	 */
+	ir_f = ir_parameters;
+	if (ir_f != NULL && ir_f->ir_type == IR_LIST) {
+		ir_f = ir_f->ir_first;
+	}
+
+	debug("ir_eval_func_body(): Binding parameter to formals\n");
+
+	ir_pos = ir_p;
+	while (ir_f != NULL && ir_p != NULL) {
+		param_name = ir_f->ir_lit_str;
+
+		debug("ir_eval_func_body(): Binding parameter %s\n",
+		      param_name);
+
+		irsym = irs_create_local(param_name, IRSYM_VAR);
+
+		irsym->irsym_value = ir_p;
+		ir_next = ir_p->ir_next;
+		ir_p->ir_next = ir_p->ir_prev = NULL;
+
+		ir_f = ir_f->ir_next;
+		ir_p = ir_next;
+		ir_pos = ir_p;
+	}
+
+	if (ir_f != NULL && ir_p == NULL) {
+		ir_error(ir_pos,
+			 "Not enough parameters to %s (%s)\n",
+			 func_name,
+			 srcpos_string(ir_func_def->ir_srcpos));
+	}
+
+	if (ir_f == NULL && ir_p != NULL) {
+		ir_error(ir_pos,
+			 "Too many parameters to %s (%s)\n",
+			 func_name,
+			 srcpos_string(ir_func_def->ir_srcpos));
+	}
+
+	/*
+	 * And "invoke" it.
+	 */
+	ir_emit_statement_list(ir_statements);
+
+	/*
+	 * FIXME:  Do parameter copy-out here?
+	 */
+	irs_scope = irs_pop_scope();
+
+	/*
+	 * FIXME: This is a bit dodgy perhaps.
+	 */
+	return irs_scope;
+}
+
+
+struct ir *
+ir_eval_func_call(struct ir *ir_func)
+{
+	struct ir_scope *irs_scope;
+
+	/*
+	 * Perform function body.
+	 * Returned scope has "side effects".
+	 *
+	 * This context really just wants the return value,
+	 * but we could debate using nodes and properties too?
+	 */
+	irs_scope = ir_eval_func_body(ir_func);
+
+	if (!irs_scope)
+		return NULL;
+
+	return irs_scope->irs_expr;
+}
+
+
+struct ir *
+ir_eval(struct ir *ir)
+{
+	struct ir *ir_new;
+	struct ir *iri;
+	struct ir *ir1;
+	struct ir *ir2;
+	struct ir_symbol *irsym;
+	unsigned long long lit1;
+	unsigned long long lit2;
+	char *str;
+	int len;
+
+	if (ir == NULL)
+		return NULL;
+
+	ir_new = NULL;
+
+	/*
+	 * Perform IR node-specific evaluations.
+	 */
+	switch (ir->ir_type) {
+	case IR_LIT_STR:
+	case IR_LIT_BYTE:
+	case IR_LIT_CELL:
+	case IR_LIT_ADDR:
+	case IR_PROPNODENAME:
+	case IR_REF_PATH:
+		/*
+		 * Values already present in the IR node.
+		 */
+		ir_new = ir_copy(ir);
+		break;
+
+	case IR_REF_PHANDLE:
+		/*
+		 * Promote a REF_PHANDLE of a LIT_STR to a
+		 * direct REF_PHANDLE.
+		 */
+		ir_new = ir_copy(ir);
+		if (ir->ir_label) {
+			iri = ir_eval(ir->ir_label);
+			if (ir_is_string(iri)) {
+				ir_new->ir_label_name = iri->ir_lit_str;
+			}
+		}
+		break;
+
+	case IR_LABEL:
+		ir_new = ir_copy(ir);
+		break;
+
+	case IR_CVT_PROPNODENAME:
+		iri = ir_eval(ir->ir_expr1);
+		str = ir_eval_for_name(iri);
+		if (str) {
+			ir_new = ir_alloc(IR_PROPNODENAME, ir->ir_srcpos);
+			ir_new->ir_lit_str = str;
+		}
+		break;
+
+	case IR_CVT_STRING:
+		iri = ir_eval(ir->ir_expr1);
+		ir_new = ir_eval_cvt_to_string(iri);
+		break;
+
+	case IR_ID:
+		irsym = irs_lookup(ir->ir_lit_str, IRS_ANY);
+		if (irsym != NULL) {
+			ir_new = ir_eval(irsym->irsym_value);
+		} else {
+			ir_error(ir,
+				 "Unknown value for \"%s\"\n",
+				 ir->ir_lit_str);
+		}
+		break;
+
+	case IR_LIST:
+		ir_new = ir_alloc(IR_LIST, ir->ir_srcpos);
+		for (iri = ir->ir_first; iri != NULL; iri = iri->ir_next) {
+			ir_list_append(ir_new, ir_eval(iri));
+		}
+		break;
+
+	case IR_SELECT:
+		/*
+		 * Pick the ? or the : side.
+		 */
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		if (lit1) {
+			ir_new = ir_eval(ir->ir_expr2);
+		} else {
+			ir_new = ir_eval(ir->ir_expr3);
+		}
+		break;
+
+	case IR_OR:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		if (!lit1) {
+			lit1 = ir_eval_for_addr(ir->ir_expr2);
+		}
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = (lit1 != 0);
+		break;
+
+	case IR_AND:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		if (lit1) {
+			lit1 = ir_eval_for_addr(ir->ir_expr2);
+		}
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = (lit1 != 0);
+
+		break;
+
+	case IR_BIT_OR:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 | lit2;
+		break;
+
+	case IR_BIT_XOR:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 ^ lit2;
+		break;
+
+	case IR_BIT_AND:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 & lit2;
+		break;
+
+	case IR_EQ:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 == lit2;
+		break;
+
+	case IR_LT:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 < lit2;
+		break;
+
+	case IR_LE:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 <= lit2;
+		break;
+
+	case IR_GT:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 > lit2;
+		break;
+
+	case IR_GE:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 >= lit2;
+		break;
+
+	case IR_NE:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 != lit2;
+		break;
+
+	case IR_LSHIFT:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 << lit2;
+		break;
+
+	case IR_RSHIFT:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 >> lit2;
+		break;
+
+	case IR_ADD:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 + lit2;
+		break;
+
+	case IR_MINUS:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 - lit2;
+		break;
+
+	case IR_MULT:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 * lit2;
+		break;
+
+	case IR_DIV:
+		/* FIXME: check for division by const 0 */
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		lit2 = ir_eval_for_addr(ir->ir_expr2);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = lit1 / lit2;
+		break;
+
+	case IR_MOD:
+		/*
+		 * This is really a bit upside down due to not having
+		 * a real typing system.  Cope for now.
+		 */
+		ir1 = ir_eval(ir->ir_expr1);
+		ir2 = ir_eval(ir->ir_expr2);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			/*
+			 * FIXME: check for division by const 0.
+			 */
+			lit1 = ir_eval_for_addr(ir->ir_expr1);
+			lit2 = ir_eval_for_addr(ir->ir_expr2);
+			ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 % lit2;
+
+		} else if (ir_is_string(ir1) || ir_is_string(ir2)) {
+			if (!ir_is_string(ir1))
+				ir1 = ir_eval_cvt_to_string(ir1);
+			if (!ir_is_string(ir2))
+				ir2 = ir_eval_cvt_to_string(ir2);
+			len = strlen(ir1->ir_lit_str)
+				+ strlen(ir2->ir_lit_str) + 1;
+			str = xmalloc(len);
+			strcpy(str, ir1->ir_lit_str);
+			strcat(str, ir2->ir_lit_str);
+			str[len - 1] = 0;
+			ir_new = ir_alloc(IR_LIT_STR, ir->ir_srcpos);
+			ir_new->ir_lit_str = str;
+		}
+		break;
+
+	case IR_BIT_COMPL:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = ~lit1;
+		break;
+
+	case IR_NOT:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = !lit1;
+		break;
+
+	case IR_UMINUS:
+		lit1 = ir_eval_for_addr(ir->ir_expr1);
+		ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		ir_new->ir_literal = -lit1;
+		break;
+
+	case IR_FUNC_CALL:
+		ir_new = ir_eval_func_call(ir);
+		break;
+
+	case IR_BUILTIN:
+		ir_new = ir_eval_builtin(ir);
+		break;
+
+	case IR_RANGE:
+		ir_new = ir_copy(ir);
+		ir_new->ir_expr1 = ir_eval(ir->ir_expr1);
+		ir_new->ir_expr2 = ir_eval(ir->ir_expr2);
+		break;
+
+	case IR_CELL:
+		ir_new = ir_eval(ir->ir_expr1);
+		if (ir_is_constant(ir_new)) {
+			/* FIXME: Check for 32-bit range here? */
+			ir_new->ir_type = IR_LIT_CELL;
+		} else if (ir_is_string(ir_new)) {
+			/* empty */
+		} else {
+			ir_error(ir, "Can't determine CELL value\n");
+		}
+		break;
+
+	case IR_LITERAL:
+		lit1 = 0;
+		if (ir_eval_literal_guessing(ir->ir_lit_str,
+					     0, 64, &lit1) == 0) {
+			/*
+			 * Smells like an number.
+			 */
+			ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+			ir_new->ir_literal = lit1;
+		} else {
+			/*
+			 * Dunno what it is.  Must be a string.
+			 * FIXME: ir_eval_for_c_string() here?
+			 */
+			ir_new = ir_alloc(IR_LIT_STR, ir->ir_srcpos);
+			ir_new->ir_lit_str = strdup(ir->ir_lit_str);
+		}
+		break;
+
+	case IR_INCBIN:
+		ir_new = ir_copy(ir);
+		ir_new->ir_expr1 = ir_eval(ir->ir_expr1);
+		ir_new->ir_expr2 = ir_eval(ir->ir_expr2);
+		ir_new->ir_expr3 = ir_eval(ir->ir_expr3);
+		break;
+
+	case IR_PROP_DEF:
+		ir_error(ir, "Can't evaluate IR_PROP_DEF here.\n");
+		break;
+
+	case IR_ROOT:
+	case IR_RETURN:
+	case IR_IF:
+	case IR_FOR:
+	case IR_ASSIGN:
+	case IR_MEM_RESERVE:
+	case IR_FUNC_DEF:
+	case IR_PARAMDECL:
+	case IR_NODE:
+		ir_error(ir,
+			 "Can't evaluate %s statements in expressions\n",
+			 ir_type_string(ir->ir_type));
+		break;
+
+	default:
+		ir_error(ir,
+			 "Unknown expression ir_type %s\n",
+			 ir_type_string(ir->ir_type));
+	}
+
+	return ir_new;
+}
+
+
+struct ir *
+ir_simplify(struct ir *ir, unsigned int ctxt)
+{
+	struct ir *ir1;
+	struct ir *ir2;
+	ir_type ir_type;
+	struct ir *ir_new;
+	unsigned long long lit1;
+	unsigned long long lit2;
+	unsigned long long ulit64;
+
+	if (ir == NULL)
+		return NULL;
+
+	/*
+	 * First determine what the evaluation context will be
+	 * for any sub-expression based on the current IR node.
+	 */
+	switch (ir->ir_type) {
+	case IR_CELL:
+		/*
+		 * Pass new context down.
+		 */
+		ctxt = IR_EVAL_CTXT_CELL;
+		break;
+
+	case IR_INCBIN:
+	case IR_IF:
+	case IR_FOR:
+	case IR_MEM_RESERVE:
+		/*
+		 * These are always done in an ANY context.
+		 */
+		ctxt = IR_EVAL_CTXT_ANY;
+		break;
+
+	default:
+		/*
+		 * Use the supplied (parameter) context.
+		 */
+		break;
+	}
+
+
+	/*
+	 * Perform IR node-specific optimizations.
+	 */
+	switch (ir->ir_type) {
+	case IR_ID:
+	case IR_LIT_STR:
+	case IR_LIT_BYTE:
+	case IR_LIT_CELL:
+	case IR_LIT_ADDR:
+	case IR_PROPNODENAME:
+	case IR_LABEL:
+	case IR_REF_PATH:
+		/*
+		 * Already as simple as they can be.
+		 */
+		ir_new = ir_copy(ir);
+		break;
+
+	case IR_REF_PHANDLE:
+		ir_new = ir_copy(ir);
+		ir_new->ir_label = ir_simplify(ir->ir_label, ctxt);
+		break;
+
+	case IR_RETURN:
+		ir_new = ir_copy(ir);
+		ir_new->ir_expr1 = ir_simplify(ir->ir_expr1, ctxt);
+		break;
+
+	case IR_MEM_RESERVE:
+	case IR_RANGE:
+		ir_new = ir_copy(ir);
+		ir_new->ir_expr1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir_new->ir_expr2 = ir_simplify(ir->ir_expr2, ctxt);
+		break;
+
+	case IR_CELL:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		if (ir1 && ir1->ir_type == IR_LIT_CELL) {
+			ir_new = ir1;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+		}
+		break;
+
+	case IR_PROP_DEF:
+		ir_new = ir_copy(ir);
+		ir_new->ir_label = ir_simplify(ir->ir_label, ctxt);
+		ir_new->ir_expr1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir_new->ir_expr2 = ir_simplify(ir->ir_expr2, ctxt);
+		break;
+
+	case IR_LITERAL:
+		/*
+		 * Based on context, evaluate literal into 32 or 64 bits.
+		 * LIT_ADDR could be a lie; it just means 64-bit.  Feh.
+		 */
+		if (ctxt == IR_EVAL_CTXT_CELL) {
+			ulit64 = ir_eval_literal_str(ir->ir_lit_str, 0, 32);
+			ir_new = ir_alloc(IR_LIT_CELL, ir->ir_srcpos);
+		} else {
+			ulit64 = ir_eval_literal_str(ir->ir_lit_str, 0, 64);
+			ir_new = ir_alloc(IR_LIT_ADDR, ir->ir_srcpos);
+		}
+		ir_new->ir_literal = ulit64;
+		break;
+
+	case IR_FUNC_CALL:
+		{
+			char *name;
+			irb_id irb;
+
+			ir_new = ir_copy(ir);
+			ir1 = ir_simplify(ir->ir_expr1, ctxt);
+			ir2 = ir_simplify(ir->ir_expr2, ctxt);
+			name = ir_eval_for_name(ir1);
+			if (name) {
+				irb = ir_lookup_builtin_by_name(name);
+				if (irb != IRB_UNDEF) {
+					debug("ir_simplify(): Use builtin %s\n",
+					      name);
+					ir_new->ir_type = IR_BUILTIN;
+					ir_new->ir_builtin_id = irb;
+					ir_new->ir_expr1 = ir2;
+				} else {
+					ir_new->ir_expr1 = ir1;
+					ir_new->ir_expr2 = ir2;
+				}
+			} else {
+				ir_error(ir1, "Unknown function %s\n", name);
+			}
+		}
+		break;
+
+	case IR_BUILTIN:
+		ir_new = ir_copy(ir);
+		ir_new->ir_expr1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir_new->ir_expr2 = ir_simplify(ir->ir_expr2, ctxt);
+		break;
+
+	case IR_LIST:
+		ir_new = ir_alloc(IR_LIST, ir->ir_srcpos);
+		for (ir1 = ir->ir_first; ir1 != NULL; ir1 = ir1->ir_next) {
+			ir_list_append(ir_new,
+				       ir_simplify(ir1, ctxt));
+		}
+		break;
+
+	case IR_INCBIN:
+		/*
+		 * Ponder loading and caching files?
+		 */
+		ir_new = ir_copy(ir);
+		ir_new->ir_expr1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir_new->ir_expr2 = ir_simplify(ir->ir_expr2, ctxt);
+		ir_new->ir_expr3 = ir_simplify(ir->ir_expr3, ctxt);
+		break;
+
+	case IR_ASSIGN:
+		ir_new = ir_copy(ir);
+		ir_new->ir_expr1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir_new->ir_expr2 = ir_simplify(ir->ir_expr2, ctxt);
+		break;
+
+	case IR_IF:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		if (ir_is_constant(ir1)) {
+			/*
+			 * Eliminate the IR_IF.
+			 * Pick the THEN or ELSE statements only.
+			 * FIXME: Fix leaking ir1 here.
+			 */
+			ulit64 = ir_eval_for_addr(ir1);
+			if (ulit64) {
+				/*
+				 * Keep the THEN statements.
+				 */
+				ir_new = ir_simplify(ir->ir_statements, ctxt);
+			} else {
+				/*
+				 * Keep the ELSE statements.
+				 */
+				ir_new = ir_simplify(ir->ir_statements2, ctxt);
+			}
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir1 = ir_simplify(ir->ir_statements, ctxt);
+			ir_new->ir_statements = ir1;
+			ir1 = ir_simplify(ir->ir_statements2, ctxt);
+			ir_new->ir_statements2 = ir1;
+		}
+		break;
+
+	case IR_FOR:
+		/*
+		 * Lots of optimizations possible here based on
+		 * empty statements and trivial ranges.  Later.
+		 * FIXME: Do "for" simplification optimizations.
+		 */
+		ir_new = ir_copy(ir);
+		ir_new->ir_expr1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir_new->ir_expr2 = ir_simplify(ir->ir_expr2, ctxt);
+		ir_new->ir_expr3 = ir_simplify(ir->ir_expr3, ctxt);
+		ir_new->ir_statements = ir_simplify(ir->ir_statements, ctxt);
+		break;
+
+	case IR_SELECT:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		if (ir_is_constant(ir1)) {
+			/*
+			 * Pick the ? or the : side.
+			 * FIXME: Fix leaking ir1.
+			 */
+			ulit64 = ir_eval_for_addr(ir1);
+			if (ulit64) {
+				ir_new = ir_simplify(ir->ir_expr2, ctxt);
+			} else {
+				ir_new = ir_simplify(ir->ir_expr3, ctxt);
+			}
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir_simplify(ir->ir_expr1, ctxt);
+			ir_new->ir_expr2 = ir_simplify(ir->ir_expr2, ctxt);
+			ir_new->ir_expr3 = ir_simplify(ir->ir_expr3, ctxt);
+		}
+		break;
+
+	case IR_CVT_PROPNODENAME:
+		/*
+		 * IR_CVT_PROPNODENAME(IR_PROPNODENAME) == IR_PROPNODENAME,
+		 * so drop the CVT.
+		 */
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		if (ir1 && ir1->ir_type == IR_PROPNODENAME) {
+			ir_new = ir1;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+		}
+		break;
+
+	case IR_CVT_STRING:
+		/*
+		 * IR_CVT_STRING(IR_LIT_STR) == IR_LIT_STR,
+		 * so drop the CVT.
+		 */
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		if (ir1 && ir1->ir_type == IR_LIT_STR) {
+			ir_new = ir1;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+		}
+		break;
+
+	case IR_OR:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		if (ir_is_constant(ir1)) {
+			ulit64 = ir_eval_for_addr(ir1);
+			if (ulit64) {
+				ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+					? IR_LIT_CELL : IR_LIT_ADDR;
+				ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+				ir_new->ir_literal = 1;
+				break;
+			}
+		}
+
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new->ir_literal = lit1 || lit2;
+
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir_simplify(ir1, ctxt);
+			ir_new->ir_expr2 = ir_simplify(ir2, ctxt);
+		}
+		break;
+
+	case IR_AND:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		if (ir_is_constant(ir1)) {
+			ulit64 = ir_eval_for_addr(ir1);
+			if (ulit64 == 0) {
+				ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+					? IR_LIT_CELL : IR_LIT_ADDR;
+				ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+				ir_new->ir_literal = 0;
+				break;
+			}
+		}
+
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new->ir_literal = lit1 && lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_BIT_OR:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 | lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_BIT_XOR:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 ^ lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_BIT_AND:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 & lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_EQ:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 == lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_LT:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 < lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_LE:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 <= lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_GT:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 > lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_GE:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 >= lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_NE:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 != lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_LSHIFT:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 << lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_RSHIFT:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 >> lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_ADD:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 + lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_MINUS:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 - lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_MULT:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 * lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_DIV:
+		/* FIXME: check for division by const 0 */
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 / lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_MOD:
+		/* FIXME: check for division by const 0 */
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir2 = ir_simplify(ir->ir_expr2, ctxt);
+		if (ir_is_constant(ir1) && ir_is_constant(ir2)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			lit2 = ir_eval_for_addr(ir2);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = lit1 % lit2;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+			ir_new->ir_expr2 = ir2;
+		}
+		break;
+
+	case IR_BIT_COMPL:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		if (ir_is_constant(ir1)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = ~lit1;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+		}
+		break;
+
+	case IR_NOT:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		if (ir_is_constant(ir1)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = !lit1;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+		}
+		break;
+
+	case IR_UMINUS:
+		ir1 = ir_simplify(ir->ir_expr1, ctxt);
+		if (ir_is_constant(ir1)) {
+			ir_type = (ctxt == IR_EVAL_CTXT_CELL)
+				? IR_LIT_CELL : IR_LIT_ADDR;
+			lit1 = ir_eval_for_addr(ir1);
+			ir_new = ir_alloc(ir_type, ir->ir_srcpos);
+			ir_new->ir_literal = -lit1;
+		} else {
+			ir_new = ir_copy(ir);
+			ir_new->ir_expr1 = ir1;
+		}
+		break;
+
+	case IR_ROOT:
+		ir_new = ir_copy(ir);
+		ir_new->ir_mem_reserves =
+			ir_simplify(ir->ir_mem_reserves, ctxt);
+		ir_new->ir_declarations =
+			ir_simplify(ir->ir_declarations, ctxt);
+		ir_new->ir_statements =
+			ir_simplify(ir->ir_statements, ctxt);
+		break;
+
+	case IR_NODE:
+		ir_new = ir_copy(ir);
+		ir_new->ir_label = ir_simplify(ir->ir_label, ctxt);
+		ir_new->ir_name = ir_simplify(ir->ir_name, ctxt);
+		ir_new->ir_statements =
+			ir_simplify(ir->ir_statements, ctxt);
+		break;
+
+	case IR_CONST_DEF:
+		ir_new = ir_copy(ir);
+		ir_new->ir_expr1 = ir_simplify(ir->ir_expr1, ctxt);
+		ir_new->ir_expr2 = ir_simplify(ir->ir_expr2, ctxt);
+		break;
+
+	case IR_FUNC_DEF:
+		ir_new = ir_copy(ir);
+		ir_new->ir_name = ir_simplify(ir->ir_name, ctxt);
+		ir_new->ir_declarations =
+			ir_simplify(ir->ir_declarations, ctxt);
+		ir_new->ir_statements =
+			ir_simplify(ir->ir_statements, ctxt);
+		break;
+
+	case IR_PARAMDECL:
+	default:
+		ir_new = NULL;
+		ir_error(ir,
+			 "Can't simplify unknown ir_type %s\n",
+			 ir_type_string(ir->ir_type));
+	}
+
+	return ir_new;
+}
-- 
1.6.0.90.g436ed

  parent reply	other threads:[~2008-09-26 20:25 UTC|newest]

Thread overview: 79+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-09-26 20:25 [PATCH 0/9 V3] Implement a new DTS Source Language Jon Loeliger
     [not found] ` <1222460748-20127-1-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>
2008-09-26 20:25   ` [PATCH 1/9 V3] Remove support for the legacy DTS source file format Jon Loeliger
     [not found]     ` <1222460748-20127-2-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>
2008-09-26 20:25       ` [PATCH 2/9 V3] Add conditionalized debug() print macro Jon Loeliger
     [not found]         ` <1222460748-20127-3-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>
2008-09-26 20:25           ` [PATCH 3/9 V3] Enhance source position implementation Jon Loeliger
     [not found]             ` <1222460748-20127-4-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>
2008-09-26 20:25               ` [PATCH 4/9 V3] Add header files for new Internal Representation form Jon Loeliger
     [not found]                 ` <1222460748-20127-5-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>
2008-09-26 20:25                   ` [PATCH 5/9 V3] Add most of the new IR implementation files Jon Loeliger
     [not found]                     ` <1222460748-20127-6-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>
2008-09-26 20:25                       ` Jon Loeliger [this message]
     [not found]                         ` <1222460748-20127-7-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>
2008-09-26 20:25                           ` [PATCH 7/9 V3] Introduce new DTS language Jon Loeliger
     [not found]                             ` <1222460748-20127-8-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>
2008-09-26 20:25                               ` [PATCH 8/9 V3] Add documentation for the " Jon Loeliger
     [not found]                                 ` <1222460748-20127-9-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>
2008-09-26 20:25                                   ` [PATCH 9/9 V3] Test constant expressions in cell contexts Jon Loeliger
     [not found]                                     ` <1222460748-20127-10-git-send-email-jdl-CYoMK+44s/E@public.gmane.org>
2008-09-30  6:04                                       ` David Gibson
     [not found]                                         ` <20080930060418.GD18695-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2008-09-30 15:46                                           ` Jon Loeliger
2008-09-30 14:55                                   ` [PATCH 8/9 V3] Add documentation for the new DTS language Grant Likely
     [not found]                                     ` <20080930145537.GJ18313-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org>
2008-10-01  3:46                                       ` David Gibson
     [not found]                                         ` <20081001034656.GF30810-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2008-10-01  4:01                                           ` Warner Losh
     [not found]                                             ` <20080930.220151.41675821.imp-uzTCJ5RojNnQT0dZR+AlfA@public.gmane.org>
2008-10-01  4:22                                               ` David Gibson
2008-10-01 15:26                                           ` Scott Wood
     [not found]                                             ` <48E396A3.809-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2008-10-01 15:43                                               ` Warner Losh
     [not found]                                                 ` <20081001.094306.71131107.imp-uzTCJ5RojNnQT0dZR+AlfA@public.gmane.org>
2008-10-02  1:20                                                   ` David Gibson
2008-10-02  1:18                                               ` David Gibson
     [not found]                                                 ` <20081002011800.GI25598-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2008-10-02 15:22                                                   ` Scott Wood
     [not found]                                                     ` <20081002152242.GB22258-VKaLA/mbEU932VTgPCOETVjVikpgYyvb5NbjCUgZEJk@public.gmane.org>
2008-10-02 16:11                                                       ` David Gibson
     [not found]                                                         ` <20081002161150.GA14351-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2008-10-02 17:22                                                           ` Scott Wood
     [not found]                                                             ` <48E5036D.9040509-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2008-10-03  2:24                                                               ` David Gibson
     [not found]                                                                 ` <20081003022424.GG3002-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2008-10-03 15:27                                                                   ` Scott Wood
     [not found]                                                                     ` <20081003152700.GA9115-VKaLA/mbEU932VTgPCOETVjVikpgYyvb5NbjCUgZEJk@public.gmane.org>
2008-10-04  4:52                                                                       ` David Gibson
2008-10-02 19:50                                                       ` M. Warner Losh
     [not found]                                                         ` <20081002.135004.1723231860.imp-uzTCJ5RojNnQT0dZR+AlfA@public.gmane.org>
2008-10-02 20:46                                                           ` Jon Loeliger
2008-10-03  0:23                                                             ` David Gibson
2008-10-03  0:23                                                           ` David Gibson
     [not found]                                                             ` <20081003002337.GB3002-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2008-10-03  1:17                                                               ` M. Warner Losh
     [not found]                                                                 ` <20081002.191705.-108805802.imp-uzTCJ5RojNnQT0dZR+AlfA@public.gmane.org>
2008-10-03  4:38                                                                   ` David Gibson
2010-02-20 16:13                                           ` Grant Likely
     [not found]                                             ` <fa686aa41002200813o3fea9a34s198be367ad81b367-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-02-21  6:30                                               ` John Williams
2010-02-22  1:30                                               ` David Gibson
2010-02-22  6:26                                                 ` Grant Likely
     [not found]                                                   ` <fa686aa41002212226i4c83376cn8d88a045dd13fe00-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-02-22 16:13                                                     ` Yoder Stuart-B08248
     [not found]                                                       ` <9696D7A991D0824DBA8DFAC74A9C5FA305B2021A-ofAVchDyotYzzZk0BCvKg5jmvxFtTJ+o0e7PPNI6Mm0@public.gmane.org>
2010-02-22 21:59                                                         ` Grant Likely
     [not found]                                                           ` <fa686aa41002221359m4d857e4cn3a1c56c32a24d21d-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-02-22 22:52                                                             ` Scott Wood
2010-02-23  2:04                                                             ` David Gibson
2010-03-01 19:15                                                             ` Grant Likely
     [not found]                                                               ` <fa686aa41003011115m1bb0b644g5014340f6c312ee9-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-03-01 19:38                                                                 ` Scott Wood
2010-03-01 20:30                                                                 ` Stephen Neuendorffer
     [not found]                                                                   ` <4B8C2C4C.8070901@freescale <4B8C44C8.6000105@freescale.com>
     [not found]                                                                     ` <4B8C44C8.6000105-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2010-03-01 22:56                                                                       ` Stephen Neuendorffer
     [not found]                                                                         ` <7c070166-6cd5-48e4-ab8e-cb062e3dbb00-RaUQJvECHiusiP+nND6G/7jjLBE8jN/0@public.gmane.org>
2010-03-02  1:22                                                                           ` David Gibson
2010-03-02  0:10                                                                       ` Grant Likely
2010-03-02  1:19                                                                       ` David Gibson
2010-03-02  2:10                                                                         ` Grant Likely
     [not found]                                                                           ` <fa686aa41003011810w2e7b6278t6aaaf192f8d7c8c1-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-03-02  2:16                                                                             ` Grant Likely
     [not found]                                                                               ` <fa686aa41003011816j534bf335o6fafe6f1c4a63436-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-03-02  4:20                                                                                 ` David Gibson
     [not found]                                                       ` <fa686aa41002221359m4d857e4cn3a1c56c32a24d21d@mail <4288fc0b-79a4-42fd-9e77-573dbad79210@SG2EHSMHS004.ehs.local>
     [not found]                                                         ` <4288fc0b-79a4-42fd-9e77-573dbad79210-RaUQJvECHiuXHCJdrdq+zrjjLBE8jN/0@public.gmane.org>
2010-03-01 21:06                                                           ` Scott Wood
     [not found]                                                             ` <4B8C2C4C.8070901-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2010-03-01 22:03                                                               ` Stephen Neuendorffer
     [not found]                                                                 ` <4d16ecf4-27b2-4c73-a3be-5b2a8ff95820-+Ck8Kgl/v0+J1bAq5m18RLjjLBE8jN/0@public.gmane.org>
2010-03-01 22:25                                                                   ` Grant Likely
     [not found]                                                                     ` <fa686aa41003011425i734ee434m95b62d57a271bd1f-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-03-02  1:11                                                                       ` David Gibson
2010-03-01 22:18                                                               ` Grant Likely
     [not found]                                                                 ` <fa686aa41003011418x339884c9md61c49948b31a8d1-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-03-01 22:26                                                                   ` Stephen Neuendorffer
     [not found]                                                                     ` <1012f9aa-1642-41ab-b8cd-a4ab4a7b269e-+Ck8Kgl/v0989VwWyyPjfbjjLBE8jN/0@public.gmane.org>
2010-03-02  0:03                                                                       ` Grant Likely
     [not found]                                                                         ` <fa686aa41003011603w12c0a7f1y88b5fc7a008af1d5-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-03-02  0:13                                                                           ` Stephen Neuendorffer
     [not found]                                                                             ` <f9885aa5-5c11-4118-9980-f17378d7cbd5-RaUQJvECHiuXHCJdrdq+zrjjLBE8jN/0@public.gmane.org>
2010-03-02  1:25                                                                               ` David Gibson
2010-03-02  2:08                                                                               ` Grant Likely
     [not found]                                                                                 ` <fa686aa41003011808h586e3dc3x11ef14af9c6e5fb8-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-03-02 17:06                                                                                   ` Scott Wood
2010-03-01 22:50                                                                   ` Scott Wood
2010-03-01 21:49                                                           ` Grant Likely
     [not found]                                                             ` <fa686aa41003011349i367a423cx2c59953e6afc9b75-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-03-01 22:15                                                               ` Mitch Bradley
     [not found]                                                                 ` <4B8C3C78.5010206-D5eQfiDGL7eakBO8gow8eQ@public.gmane.org>
2010-03-01 23:33                                                                   ` Grant Likely
     [not found]                                                                     ` <fa686aa41003011533x3d2d00abyb8d7cf33344a3bde-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-03-02  3:59                                                                       ` David Gibson
2010-03-01 22:17                                                               ` Stephen Neuendorffer
     [not found]                                                                 ` <72f497af-412c-4a05-90c2-5df0be00d93f-+Ck8Kgl/v09CYczPSvLbDrjjLBE8jN/0@public.gmane.org>
2010-03-01 23:42                                                                   ` Grant Likely
2010-03-02 23:12                                                                   ` David Gibson
2010-03-03 16:18                                                                     ` Grant Likely
2010-02-23  1:47                                                     ` David Gibson
2010-02-23  2:17                                                       ` Grant Likely
     [not found]                                                         ` <fa686aa41002221817s5f15dc4cy5ab873a61de2cb2f-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-02-23  4:10                                                           ` David Gibson
2008-10-02  8:25                               ` [PATCH 7/9 V3] Introduce " David Gibson
2008-09-30  6:03                   ` [PATCH 4/9 V3] Add header files for new Internal Representation form David Gibson
2008-09-30  6:00               ` [PATCH 3/9 V3] Enhance source position implementation David Gibson
2008-09-30  5:57       ` [PATCH 1/9 V3] Remove support for the legacy DTS source file format David Gibson
     [not found]         ` <20080930055716.GA18695-787xzQ0H9iRg7VrjXcPTGA@public.gmane.org>
2008-09-30 16:30           ` Scott Wood
     [not found]             ` <48E2541B.1000801-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2008-10-01  1:26               ` David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1222460748-20127-7-git-send-email-jdl@jdl.com \
    --to=jdl-cyomk+44s/e@public.gmane.org \
    --cc=devicetree-discuss-mnsaURCQ41sdnm+yROfE0A@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox