Fix a bunch of issues with pushing and popping mismatched sizes, which the B

compiler does a lot; dup 8 for pairs of words is now optimised.
This commit is contained in:
David Given 2017-01-07 18:47:00 +01:00
parent 5a38ce2a69
commit efab08178b

View file

@ -30,6 +30,18 @@ static void push(struct ir* ir)
stack[stackptr++] = ir;
}
/* Returns the size of the top item on the stack. */
static int peek(int delta)
{
if (stackptr <= delta)
return EM_wordsize;
else
{
struct ir* ir = stack[stackptr-1-delta];
return ir->size;
}
}
static struct ir* pop(int size)
{
if (size < EM_wordsize)
@ -58,7 +70,6 @@ static struct ir* pop(int size)
if (size < EM_wordsize)
ir = convertu(ir, size);
#endif
if (ir->size != size)
{
if ((size == (EM_wordsize*2)) && (ir->size == EM_wordsize))
@ -875,17 +886,17 @@ static void insn_ivalue(int opcode, arith value)
struct ir* ptr = pop(EM_pointersize);
int offset = 0;
/* FIXME: this is awful; need a better way of dealing with
* non-standard EM sizes. */
if (value > (EM_wordsize*2))
{
/* We're going to need to do multiple stores; fix the address
* so it'll go into a register and we can do maths on it. */
appendir(ptr);
}
while (value > 0)
{
int s;
if (value > (EM_wordsize*2))
s = EM_wordsize*2;
else
int s = EM_wordsize*2;
if (value < s)
s = value;
push(
@ -934,24 +945,25 @@ static void insn_ivalue(int opcode, arith value)
struct ir* ptr = pop(EM_pointersize);
int offset = 0;
/* FIXME: this is awful; need a better way of dealing with
* non-standard EM sizes. */
if (value > (EM_wordsize*2))
if (value > peek(0))
{
/* We're going to need to do multiple stores; fix the address
* so it'll go into a register and we can do maths on it. */
appendir(ptr);
}
while (value > 0)
{
int s;
if (value > (EM_wordsize*2))
s = EM_wordsize*2;
else
struct ir* v = pop(peek(0));
int s = v->size;
if (value < s)
s = value;
appendir(
store(
s,
ptr, offset,
pop(s)
v
)
);
@ -1044,10 +1056,22 @@ static void insn_ivalue(int opcode, arith value)
case op_dup:
{
struct ir* v = pop(value);
appendir(v);
push(v);
push(v);
sequence_point();
if ((value == (EM_wordsize*2)) && (peek(0) == EM_wordsize) && (peek(1) == EM_wordsize))
{
struct ir* v1 = pop(EM_wordsize);
struct ir* v2 = pop(EM_wordsize);
push(v2);
push(v1);
push(v2);
push(v1);
}
else
{
struct ir* v = pop(value);
push(v);
push(v);
}
break;
}
@ -1077,8 +1101,11 @@ static void insn_ivalue(int opcode, arith value)
default:
while ((value > 0) && (stackptr > 0))
{
struct ir* ir = pop(stack[stackptr-1]->size);
value -= ir->size;
int s = peek(0);
if (s > value)
s = value;
pop(s);
value -= s;
}
if (value != 0)