diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 5b2a1b93d..667562e8d 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -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)