summary refs log tree commit diff
path: root/fold.c
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2021-11-18 01:45:27 -0800
committerQuentin Carbonneaux <quentin@c9x.me>2021-11-22 18:07:50 +0100
commitbf153b359e9ce3ebef9bca899eb7ed5bd9045c11 (patch)
tree20857b60dfd9a0f5bb98dee40a1f4b140ba76447 /fold.c
parentb0f16dad64d14f36ffe235b2e9cca96aa3ce35ba (diff)
downloadroux-bf153b359e9ce3ebef9bca899eb7ed5bd9045c11.tar.gz
reuse previous address constants in fold()
parseref() has code to reuse address constants, but this is not
done in other passes such as fold or isel. Introduce a new function
newcon() which takes a Con and returns a Ref for that constant, and
use this whenever creating address constants.

This is necessary to fix folding of address constants when one
operand is already folded. For example, in

	%a =l add $x, 1
	%b =l add %a, 2
	%c =w loadw %b

%a and %b were folded to $x+1 and $x+3 respectively, but then the
second add is visited again since it uses %a. This gets folded to
$x+3 as well, but as a new distinct constant. This results in %b
getting labeled as bottom instead of either constant, disabling the
replacement of %b by a constant in subsequent instructions (such
as the loadw).
Diffstat (limited to 'fold.c')
-rw-r--r--fold.c12
1 files changed, 3 insertions, 9 deletions
diff --git a/fold.c b/fold.c
index 50a862e..348e532 100644
--- a/fold.c
+++ b/fold.c
@@ -496,7 +496,7 @@ foldflt(Con *res, int op, int w, Con *cl, Con *cr)
 static int
 opfold(int op, int cls, Con *cl, Con *cr, Fn *fn)
 {
-	int nc;
+	Ref r;
 	Con c;
 
 	if ((op == Odiv || op == Oudiv
@@ -507,13 +507,7 @@ opfold(int op, int cls, Con *cl, Con *cr, Fn *fn)
 			return Bot;
 	} else
 		foldflt(&c, op, cls == Kd, cl, cr);
-	if (c.type == CBits)
-		nc = getcon(c.bits.i, fn).val;
-	else {
-		nc = fn->ncon;
-		vgrow(&fn->con, ++fn->ncon);
-	}
+	r = newcon(&c, fn);
 	assert(!(cls == Ks || cls == Kd) || c.flt);
-	fn->con[nc] = c;
-	return nc;
+	return r.val;
 }