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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user