/* Assemble an ALU instruction where rb is a literal. */
-void alu_instr_lit(quad op, int cc, int rd, int ra, quad value)
+void alu_instr_lit(quad op, int cc, int rd, int ra, long value)
{
/* 16 bit short form? */
- if ((cc == ALWAYS) && !(op & 1) && (value <= 0x1f) && (ra == rd) &&
- (ra < 0x10))
+ if ((cc == ALWAYS) && !(op & 1) && (value >= 0) && (value <= 0x1f) &&
+ (ra == rd) && (ra < 0x10))
{
emit2(B16(01100000,00000000) | (op<<8) | (value<<4) | (rd<<0));
return;
/* 32 bit medium form? */
- if (value <= 0x1f)
+ if ((value >= 0) && (value <= 0x1f))
{
emit2(B16(11000000,00000000) | (op<<5) | (rd<<0));
emit2(B16(00000000,01000000) | (ra<<11) | (cc<<7) | (value<<0));
{
quad pc = DOTVAL;
quad type = expr->typ & S_TYP;
+ int d;
/* Sanity checking. */
if (type == S_ABS)
serror("can't use absolute addresses here");
- switch (pass)
- {
- case 0:
- /* Calculate size of instructions only. For now we just assume
- * that they're going to be the maximum size, 32 bits. */
-
- emit4(0);
- break;
+ /* The VC4 branch instructions express distance in 2-byte
+ * words. */
- case 1:
- case 2:
- {
- /* The VC4 branch instructions express distance in 2-byte
- * words. */
+ d = (int32_t)expr->val - (int32_t)pc;
+ if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
+ d -= DOTGAIN;
+ d /= 2;
- int d = ((int32_t)expr->val - (int32_t)pc) / 2;
+ /* If this is a reference to code within this section, and it's
+ * close enough to the program counter, we can use a short-
+ * form instruction. */
- /* We now know the worst case for the instruction layout. At
- * this point we can emit the instructions, which may shrink
- * the code. */
-
- if (!bl && (type == DOTTYP))
- {
- /* This is a reference to code within this section. If it's
- * close enough to the program counter, we can use a short-
- * form instruction. */
-
- if (fitx(d, 7))
- {
- emit2(B16(00011000,00000000) | (cc<<7) | (d&0x7f));
- break;
- }
- }
+ if (small(!bl && (type == DOTTYP) && fitx(d, 7), 2))
+ {
+ emit2(B16(00011000,00000000) | (cc<<7) | (d&0x7f));
+ return;
+ }
- /* Absolute addresses and references to other sections
- * need the full 32 bits. */
+ /* Absolute addresses and references to other sections
+ * need the full 32 bits. */
- newrelo(expr->typ, RELOVC4|RELPC);
+ newrelo(expr->typ, RELOVC4|RELPC);
- if (bl)
- {
- quad v, hiv, lov;
+ if (bl)
+ {
+ quad v, hiv, lov;
- if (!fitx(d, 27))
- toobig();
+ if (!fitx(d, 27))
+ toobig();
- v = maskx(d, 27);
- hiv = v >> 23;
- lov = v & 0x007fffff;
- emit2(B16(10010000,10000000) | (lov>>16) | (hiv<<8));
- emit2(B16(00000000,00000000) | (lov&0xffff));
- }
- else
- {
- quad v;
+ v = maskx(d, 27);
+ hiv = v >> 23;
+ lov = v & 0x007fffff;
+ emit2(B16(10010000,10000000) | (lov>>16) | (hiv<<8));
+ emit2(B16(00000000,00000000) | (lov&0xffff));
+ }
+ else
+ {
+ quad v;
- if (!fitx(d, 23))
- toobig();
+ if (!fitx(d, 23))
+ toobig();
- v = maskx(d, 23);
- emit2(B16(10010000,00000000) | (cc<<8) | (v>>16));
- emit2(B16(00000000,00000000) | (v&0xffff));
- }
- break;
- }
+ v = maskx(d, 23);
+ emit2(B16(10010000,00000000) | (cc<<8) | (v>>16));
+ emit2(B16(00000000,00000000) | (v&0xffff));
}
}
void mem_address_instr(quad opcode, int rd, struct expr_t* expr)
{
- static const char sizes[] = {4, 2, 1, 2};
+ static const char sizes[] = {4, 4, 2, 2, 1, 1, 2, 2};
int size = sizes[opcode];
quad type = expr->typ & S_TYP;
+ int d, scaledd;
/* Sanity checking. */
if (type == S_ABS)
serror("can't use absolute addresses here");
- switch (pass)
- {
- case 0:
- /* Calculate size of instructions only. For now we just assume
- * that they're going to be the maximum size, 48 bits. */
-
- emit2(0);
- emit4(0);
- break;
-
- case 1:
- case 2:
- {
- int d = expr->val - DOTVAL;
+ d = expr->val - DOTVAL;
+ if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
+ d -= DOTGAIN;
+ scaledd = d/size;
- /* We now know the worst case for the instruction layout. At
- * this point we can emit the instructions, which may shrink
- * the code. */
+ /* If this is a reference to an address within this section, and
+ * it's close enough to the program counter, we can use a
+ * shorter instruction. */
- if (type == DOTTYP)
- {
- int scaledd = d/size;
-
- /* This is a reference to an address within this section. If
- * it's close enough to the program counter, we can use a
- * shorter instruction. */
-
- if (fitx(scaledd, 16))
- {
- emit2(B16(10101010,00000000) | (opcode<<5) | (rd<<0));
- emit2(scaledd);
- return;
- }
- }
+ if (small((type==DOTTYP) && fitx(scaledd, 16), 2))
+ {
+ emit2(B16(10101010,00000000) | (opcode<<5) | (rd<<0));
+ emit2(scaledd);
+ return;
+ }
- /* Otherwise we need the full 48 bits. */
+ /* Otherwise we need the full 48 bits. */
- newrelo(expr->typ, RELOVC4|RELPC);
+ newrelo(expr->typ, RELOVC4|RELPC);
- /* VC4 relocations store the PC-relative delta into the
- * destination section in the instruction data. The linker will
- * massage this, and scale it appropriately. */
+ /* VC4 relocations store the PC-relative delta into the
+ * destination section in the instruction data. The linker will
+ * massage this, and scale it appropriately. */
- if (!fitx(d, 27))
- toobig();
+ if (!fitx(d, 27))
+ toobig();
- emit2(B16(11100111,00000000) | (opcode<<5) | (rd<<0));
- emit4((31<<27) | maskx(d, 27));
- break;
- }
- }
+ emit2(B16(11100111,00000000) | (opcode<<5) | (rd<<0));
+ emit4((31<<27) | maskx(d, 27));
}
/* Common code for handling addcmp: merge in as much of expr as will fit to
static void branch_addcmp_common(quad opcode, int bits, struct expr_t* expr)
{
quad type = expr->typ & S_TYP;
+ int d;
- switch (pass)
- {
- case 0:
- /* Calculate size of instructions only. */
-
- emit2(0);
- break;
-
- case 1:
- case 2:
- {
- if (type != DOTTYP)
- serror("can't use this type of branch to jump outside the section");
+ if (type != DOTTYP)
+ serror("can't use this type of branch to jump outside the section");
- /* The VC4 branch instructions express distance in 2-byte
- * words. */
+ /* The VC4 branch instructions express distance in 2-byte
+ * words. */
- int d = (expr->val - DOTVAL-2 + 4) / 2;
+ d = (expr->val - DOTVAL-2 + 4);
+ if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
+ d -= DOTGAIN;
+ d /= 2;
- if (!fitx(d, bits))
- serror("target of branch is too far away");
+ if (!fitx(d, bits))
+ serror("target of branch is too far away");
- emit2(opcode | maskx(d, bits));
- break;
- }
- }
+ emit2(opcode | maskx(d, bits));
}
void branch_addcmp_reg_reg_instr(int cc, int rd, int ra, int rs, struct expr_t* expr)
{
quad pc = DOTVAL;
quad type = expr->typ & S_TYP;
+ int d = expr->val - pc;
+
+ if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
+ d -= DOTGAIN;
if (type == S_ABS)
serror("can't use absolute addresses here");