Assembler: added support for large constants for 2-reg variants (macros)

of 3-reg instructions (add, addu, and, or, slt, sltu, sub, subu, xor).
When mode ".set at" enabled, an additional LI instruction is inserted
sing $1 as a scratch register.
This commit is contained in:
Sergey
2014-05-03 16:34:19 -07:00
parent 777ad1471b
commit 51a8fd3313

View File

@@ -1238,7 +1238,7 @@ void emitword (w, r, clobber_reg)
reorder_word = w;
reorder_rel = *r;
reorder_full = 1;
reorder_clobber = clobber_reg;
reorder_clobber = clobber_reg & 15;
} else {
fputword (w, sfile[segm]);
fputrel (r, rfile[segm]);
@@ -1317,10 +1317,9 @@ void makecmd (opcode, type, emitfunc)
unsigned opcode;
void (*emitfunc) (unsigned, struct reloc*);
{
register int clex;
register unsigned offset;
unsigned offset, orig_opcode = 0;
struct reloc relinfo;
int cval, segment, clobber_reg, negate_literal;
int clex, cval, segment, clobber_reg, negate_literal;
offset = 0;
relinfo.flags = RABS;
@@ -1480,6 +1479,7 @@ frs1: clex = getlex (&cval);
cval = (opcode >> 11) & 31; /* get 1-st register */
newop |= cval << 16; /* set 1-st register */
newop |= opcode & (31 << 21); /* set 2-nd register */
orig_opcode = opcode;
opcode = newop;
type = FRT1 | FRS2 | FOFF16 | FMOD;
goto foff16;
@@ -1572,6 +1572,8 @@ fsa: offset = getexpr (&segment);
}
} else if (type & (FOFF16 | FOFF18 | FAOFF18 | FAOFF28 | FHIGH16)) {
/* Relocatable offset */
int valid_range;
if ((type & (FOFF16 | FOFF18 | FHIGH16)) && getlex (&cval) != ',')
uerror ("comma expected");
foff16: expr_flags = 0;
@@ -1589,7 +1591,48 @@ foff16: expr_flags = 0;
relinfo.flags |= RGPREL;
switch (type & (FOFF16 | FOFF18 | FAOFF18 | FAOFF28 | FHIGH16)) {
case FOFF16: /* low 16-bit byte address */
opcode |= offset & 0xffff;
/* Test whether the immediate is in valid range
* for the opcode. */
switch (opcode & 0xfc000000) {
case 0x20000000: // addi
case 0x24000000: // addiu
case 0x28000000: // slti
case 0x2c000000: // sltiu
/* 16-bit signed value. */
valid_range = (offset >= -0x8000) && (offset <= 0x7fff);
break;
case 0x30000000: // andi
case 0x34000000: // ori
case 0x38000000: // xori
default:
/* 16-bit unsigned value. */
valid_range = (offset >= 0) && (offset <= 0xffff);
break;
}
if (valid_range) {
opcode |= offset & 0xffff;
} else if (orig_opcode == 0) {
uerror ("value out of range");
} else {
/* Convert back to 3-reg opcode.
* Insert an extra LI instruction. */
if (segment != SABS)
uerror ("absolute value required");
if (offset <= 0xffff) {
/* ori $1, $zero, value */
emitword (0x34010000 | offset, &relabs, 1);
} else if (offset >= -0x8000) {
/* addiu $1, $zero, value */
emitword (0x24010000 | (offset & 0xffff), &relabs, 1);
} else {
/* lui $1, value[31:16]
* ori $1, $1, value[15:0]) */
emitword (0x3c010000 | (offset >> 16), &relabs, 1);
emitword (0x34210000 | (offset & 0xffff), &relabs, 1);
}
opcode = orig_opcode | 0x10000;
}
break;
case FHIGH16: /* high 16-bit byte address */
if (expr_flags & EXPR_HI) {