aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--amd64/emit.c6
-rw-r--r--regalloc.c11
-rw-r--r--ssa.c12
-rw-r--r--test/fib.c11
4 files changed, 29 insertions, 11 deletions
diff --git a/amd64/emit.c b/amd64/emit.c
index 5b3a298..70386be 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -382,8 +382,8 @@ static void Xmov(uchar **pcode, enum irclass k, struct oper dst, struct oper src
{8, PFPR, PFPR, "\xF2\x0F\x10", EN_RR}, /* MOVSD xmm, xmm */
{8, PFPR, PMEM, "\xF2\x0F\x10", EN_RM}, /* MOVSD xmm, m64 */
{8, PMEM, PFPR, "\xF2\x0F\x11", EN_MR}, /* MOVSS m64, xmm */
- {4|8, PGPR, PFPR, "\x66\x0F\x6E", EN_RRX}, /* MOVD/Q r64/32, xmm */
- {4|8, PFPR, PGPR, "\x66\x0F\x6E", EN_RR}, /* MOVD/Q xmm, r64/32 */
+ {4|8, PFPR, PGPR, "\x66\x0F\x6E", EN_RR}, /* MOVD/Q xmm, r64/32 */
+ {4|8, PGPR, PFPR, "\x66\x0F\x7E", EN_RRX}, /* MOVD/Q r64/32, xmm */
};
static const uchar k2off[] = {
[KI4] = 0,
@@ -646,7 +646,7 @@ gencopy(uchar **pcode, enum irclass cls, struct block *blk, int curi, struct ope
} else {
struct oper src = mkimmdatregoper(val);
if (memcmp(&dst, &src, sizeof dst) != 0)
- Xmov(pcode, cls, dst, src);
+ Xmov(pcode, cls == KF8 && src.reg < XMM0 ? KI8 : cls, dst, src);
}
}
diff --git a/regalloc.c b/regalloc.c
index a49330d..ae81fcf 100644
--- a/regalloc.c
+++ b/regalloc.c
@@ -7,7 +7,7 @@ static regset gpregset, fpregset;
static regset globusage;
#define isfpr(reg) in_range((reg), mctarg->fpr0, mctarg->fpr0 + mctarg->nfpr - 1)
-#define isgpr(reg) (!isfpr(reg))
+#define isgpr(reg) in_range((reg), mctarg->gpr0, mctarg->gpr0 + mctarg->nfpr - 1)
enum { ADEAD, AREG, ASTACK } ;
struct alloc { ushort t : 2, a : 14; };
@@ -125,7 +125,7 @@ def(struct rega *ra, struct instr *ins, struct block *blk, int curi)
if ((ins->op == Ocopy || ins->inplace) && ins->l.t == RREG) {
int hint = ins->l.i;
- if (rstest(ra->m.free, hint)) {
+ if (rstest(ra->m.free, hint) && kisflt(insrescls(*ins)) == isfpr(hint)) {
take(ra, reg = hint, mkref(RTMP, var));
assert(ra->m.regs[reg] == var && !rstest(ra->m.free, hint));
}
@@ -301,7 +301,8 @@ use(struct rega *ra, struct block *blk, int curi, enum op op, int hint, union re
/* for '%x = copy Rx', hint %x to use Rx */
hint = ins->l.i;
- if (hint != -1 && !rstest(excl, hint) && rstest(ra->m.free, hint)) {
+ if (hint != -1 && !rstest(excl, hint) && rstest(ra->m.free, hint)
+ && kisflt(insrescls(*ins)) == isfpr(hint)) {
take(ra, hint, *ref);
reg = hint;
} else {
@@ -568,9 +569,9 @@ regalloc(struct function *fn)
/* setup */
if (!fpregset || !gpregset) {
for (int i = 0; i < MAXREGS; ++i) {
- if (in_range(i, mctarg->fpr0, mctarg->fpr0 + mctarg->nfpr - 1))
+ if (isfpr(i))
fpregset = rsset(fpregset, i);
- else if (in_range(i, mctarg->gpr0, mctarg->gpr0 + mctarg->ngpr - 1))
+ else if (isgpr(i))
gpregset = rsset(gpregset, i);
}
}
diff --git a/ssa.c b/ssa.c
index 4a4ed4d..fc4464b 100644
--- a/ssa.c
+++ b/ssa.c
@@ -12,11 +12,17 @@ copyopt(struct function *fn)
struct use *use, *uend;
union ref var = mkref(RTMP, blk->ins.p[i]);
struct instr *ins = &instrtab[var.i];
+ enum irclass k;
if (ins->op == Ocopy) {
- assert(ins->l.t != RREG);
-
- replcuses(var, ins->l);
+ union ref arg = ins->l;
+ if (arg.t == RTMP) k = insrescls(instrtab[arg.i]);
+ else if (arg.t == RICON) k = cls2siz[ins->cls] == 4 ? KI4 : KI8;
+ else if (arg.t == RXCON) k = isnumcon(arg) ? conht[arg.i].cls : KPTR;
+ else assert(0);
+ if (ins->cls != k) continue;
+
+ replcuses(var, arg);
*ins = mkinstr(Onop,0,);
deluses(var.i);
}
diff --git a/test/fib.c b/test/fib.c
index eadce03..5fe430a 100644
--- a/test/fib.c
+++ b/test/fib.c
@@ -13,6 +13,16 @@ unsigned fibr(unsigned x) {
return fibr(x-1) + fibr(x-2);
}
+double fibf(unsigned x) {
+ double r = 0., q = 1.;
+ while (x-- > 1) {
+ double s = r + q;
+ r = q;
+ q = s;
+ }
+ return q;
+}
+
int atoi(const char *);
int printf(const char *, ...);
@@ -20,6 +30,7 @@ int main(int argc, char **argv) {
unsigned n = argv[1] ? atoi(argv[1]) : 10;
printf("fib(%u) = %u\n", n, fib(n));
printf("fibr(%u) = %u\n", n, fibr(n));
+ printf("fibf(%u) = %g\n", n, fibf(n));
}
/* vim:set ts=3 sw=3 expandtab: */