Major bugfix where instructions weren't being shrunk correctly. (Turns out there's built-in support for doing this, which I hadn't found.)
--HG-- branch : dtrg-videocore
This commit is contained in:
parent
b6680a48cc
commit
3b07fee160
2 changed files with 88 additions and 133 deletions
|
@ -10,7 +10,7 @@
|
||||||
#define ALWAYS 14
|
#define ALWAYS 14
|
||||||
|
|
||||||
extern void alu_instr_reg(quad opcode, int cc, int rd, int ra, int rb);
|
extern void alu_instr_reg(quad opcode, int cc, int rd, int ra, int rb);
|
||||||
extern void alu_instr_lit(quad opcode, int cc, int rd, int ra, quad value);
|
extern void alu_instr_lit(quad opcode, int cc, int rd, int ra, long value);
|
||||||
extern void misc_instr_reg(quad opcode, int cc, int rd, int ra, int rb);
|
extern void misc_instr_reg(quad opcode, int cc, int rd, int ra, int rb);
|
||||||
extern void misc_instr_lit(quad opcode, int cc, int rd, int ra, quad value);
|
extern void misc_instr_lit(quad opcode, int cc, int rd, int ra, quad value);
|
||||||
extern void branch_instr(int bl, int cc, struct expr_t* expr);
|
extern void branch_instr(int bl, int cc, struct expr_t* expr);
|
||||||
|
|
|
@ -34,12 +34,12 @@ void alu_instr_reg(quad op, int cc, int rd, int ra, int rb)
|
||||||
|
|
||||||
/* Assemble an ALU instruction where rb is a literal. */
|
/* 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? */
|
/* 16 bit short form? */
|
||||||
|
|
||||||
if ((cc == ALWAYS) && !(op & 1) && (value <= 0x1f) && (ra == rd) &&
|
if ((cc == ALWAYS) && !(op & 1) && (value >= 0) && (value <= 0x1f) &&
|
||||||
(ra < 0x10))
|
(ra == rd) && (ra < 0x10))
|
||||||
{
|
{
|
||||||
emit2(B16(01100000,00000000) | (op<<8) | (value<<4) | (rd<<0));
|
emit2(B16(01100000,00000000) | (op<<8) | (value<<4) | (rd<<0));
|
||||||
return;
|
return;
|
||||||
|
@ -47,7 +47,7 @@ void alu_instr_lit(quad op, int cc, int rd, int ra, quad value)
|
||||||
|
|
||||||
/* 32 bit medium form? */
|
/* 32 bit medium form? */
|
||||||
|
|
||||||
if (value <= 0x1f)
|
if ((value >= 0) && (value <= 0x1f))
|
||||||
{
|
{
|
||||||
emit2(B16(11000000,00000000) | (op<<5) | (rd<<0));
|
emit2(B16(11000000,00000000) | (op<<5) | (rd<<0));
|
||||||
emit2(B16(00000000,01000000) | (ra<<11) | (cc<<7) | (value<<0));
|
emit2(B16(00000000,01000000) | (ra<<11) | (cc<<7) | (value<<0));
|
||||||
|
@ -99,6 +99,7 @@ void branch_instr(int bl, int cc, struct expr_t* expr)
|
||||||
{
|
{
|
||||||
quad pc = DOTVAL;
|
quad pc = DOTVAL;
|
||||||
quad type = expr->typ & S_TYP;
|
quad type = expr->typ & S_TYP;
|
||||||
|
int d;
|
||||||
|
|
||||||
/* Sanity checking. */
|
/* Sanity checking. */
|
||||||
|
|
||||||
|
@ -107,71 +108,52 @@ void branch_instr(int bl, int cc, struct expr_t* expr)
|
||||||
if (type == S_ABS)
|
if (type == S_ABS)
|
||||||
serror("can't use absolute addresses here");
|
serror("can't use absolute addresses here");
|
||||||
|
|
||||||
switch (pass)
|
/* 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;
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
|
||||||
|
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. */
|
||||||
|
|
||||||
|
newrelo(expr->typ, RELOVC4|RELPC);
|
||||||
|
|
||||||
|
if (bl)
|
||||||
{
|
{
|
||||||
case 0:
|
quad v, hiv, lov;
|
||||||
/* Calculate size of instructions only. For now we just assume
|
|
||||||
* that they're going to be the maximum size, 32 bits. */
|
|
||||||
|
|
||||||
emit4(0);
|
if (!fitx(d, 27))
|
||||||
break;
|
toobig();
|
||||||
|
|
||||||
case 1:
|
v = maskx(d, 27);
|
||||||
case 2:
|
hiv = v >> 23;
|
||||||
{
|
lov = v & 0x007fffff;
|
||||||
/* The VC4 branch instructions express distance in 2-byte
|
emit2(B16(10010000,10000000) | (lov>>16) | (hiv<<8));
|
||||||
* words. */
|
emit2(B16(00000000,00000000) | (lov&0xffff));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
quad v;
|
||||||
|
|
||||||
int d = ((int32_t)expr->val - (int32_t)pc) / 2;
|
if (!fitx(d, 23))
|
||||||
|
toobig();
|
||||||
|
|
||||||
/* We now know the worst case for the instruction layout. At
|
v = maskx(d, 23);
|
||||||
* this point we can emit the instructions, which may shrink
|
emit2(B16(10010000,00000000) | (cc<<8) | (v>>16));
|
||||||
* the code. */
|
emit2(B16(00000000,00000000) | (v&0xffff));
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Absolute addresses and references to other sections
|
|
||||||
* need the full 32 bits. */
|
|
||||||
|
|
||||||
newrelo(expr->typ, RELOVC4|RELPC);
|
|
||||||
|
|
||||||
if (bl)
|
|
||||||
{
|
|
||||||
quad v, hiv, lov;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (!fitx(d, 23))
|
|
||||||
toobig();
|
|
||||||
|
|
||||||
v = maskx(d, 23);
|
|
||||||
emit2(B16(10010000,00000000) | (cc<<8) | (v>>16));
|
|
||||||
emit2(B16(00000000,00000000) | (v&0xffff));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,66 +334,45 @@ void mem_postincr_instr(quad opcode, int cc, int rd, int rs)
|
||||||
|
|
||||||
void mem_address_instr(quad opcode, int rd, struct expr_t* expr)
|
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];
|
int size = sizes[opcode];
|
||||||
quad type = expr->typ & S_TYP;
|
quad type = expr->typ & S_TYP;
|
||||||
|
int d, scaledd;
|
||||||
|
|
||||||
/* Sanity checking. */
|
/* Sanity checking. */
|
||||||
|
|
||||||
if (type == S_ABS)
|
if (type == S_ABS)
|
||||||
serror("can't use absolute addresses here");
|
serror("can't use absolute addresses here");
|
||||||
|
|
||||||
switch (pass)
|
d = expr->val - DOTVAL;
|
||||||
|
if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
|
||||||
|
d -= DOTGAIN;
|
||||||
|
scaledd = d/size;
|
||||||
|
|
||||||
|
/* 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 (small((type==DOTTYP) && fitx(scaledd, 16), 2))
|
||||||
{
|
{
|
||||||
case 0:
|
emit2(B16(10101010,00000000) | (opcode<<5) | (rd<<0));
|
||||||
/* Calculate size of instructions only. For now we just assume
|
emit2(scaledd);
|
||||||
* that they're going to be the maximum size, 48 bits. */
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
emit2(0);
|
/* Otherwise we need the full 48 bits. */
|
||||||
emit4(0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
newrelo(expr->typ, RELOVC4|RELPC);
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
int d = expr->val - DOTVAL;
|
|
||||||
|
|
||||||
/* We now know the worst case for the instruction layout. At
|
/* VC4 relocations store the PC-relative delta into the
|
||||||
* this point we can emit the instructions, which may shrink
|
* destination section in the instruction data. The linker will
|
||||||
* the code. */
|
* massage this, and scale it appropriately. */
|
||||||
|
|
||||||
if (type == DOTTYP)
|
if (!fitx(d, 27))
|
||||||
{
|
toobig();
|
||||||
int scaledd = d/size;
|
|
||||||
|
|
||||||
/* This is a reference to an address within this section. If
|
emit2(B16(11100111,00000000) | (opcode<<5) | (rd<<0));
|
||||||
* it's close enough to the program counter, we can use a
|
emit4((31<<27) | maskx(d, 27));
|
||||||
* shorter instruction. */
|
|
||||||
|
|
||||||
if (fitx(scaledd, 16))
|
|
||||||
{
|
|
||||||
emit2(B16(10101010,00000000) | (opcode<<5) | (rd<<0));
|
|
||||||
emit2(scaledd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise we need the full 48 bits. */
|
|
||||||
|
|
||||||
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. */
|
|
||||||
|
|
||||||
if (!fitx(d, 27))
|
|
||||||
toobig();
|
|
||||||
|
|
||||||
emit2(B16(11100111,00000000) | (opcode<<5) | (rd<<0));
|
|
||||||
emit4((31<<27) | maskx(d, 27));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Common code for handling addcmp: merge in as much of expr as will fit to
|
/* Common code for handling addcmp: merge in as much of expr as will fit to
|
||||||
|
@ -420,33 +381,23 @@ void mem_address_instr(quad opcode, int rd, struct expr_t* expr)
|
||||||
static void branch_addcmp_common(quad opcode, int bits, struct expr_t* expr)
|
static void branch_addcmp_common(quad opcode, int bits, struct expr_t* expr)
|
||||||
{
|
{
|
||||||
quad type = expr->typ & S_TYP;
|
quad type = expr->typ & S_TYP;
|
||||||
|
int d;
|
||||||
|
|
||||||
switch (pass)
|
if (type != DOTTYP)
|
||||||
{
|
serror("can't use this type of branch to jump outside the section");
|
||||||
case 0:
|
|
||||||
/* Calculate size of instructions only. */
|
|
||||||
|
|
||||||
emit2(0);
|
/* The VC4 branch instructions express distance in 2-byte
|
||||||
break;
|
* words. */
|
||||||
|
|
||||||
case 1:
|
d = (expr->val - DOTVAL-2 + 4);
|
||||||
case 2:
|
if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
|
||||||
{
|
d -= DOTGAIN;
|
||||||
if (type != DOTTYP)
|
d /= 2;
|
||||||
serror("can't use this type of branch to jump outside the section");
|
|
||||||
|
|
||||||
/* The VC4 branch instructions express distance in 2-byte
|
if (!fitx(d, bits))
|
||||||
* words. */
|
serror("target of branch is too far away");
|
||||||
|
|
||||||
int d = (expr->val - DOTVAL-2 + 4) / 2;
|
emit2(opcode | maskx(d, bits));
|
||||||
|
|
||||||
if (!fitx(d, bits))
|
|
||||||
serror("target of branch is too far away");
|
|
||||||
|
|
||||||
emit2(opcode | maskx(d, bits));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void branch_addcmp_reg_reg_instr(int cc, int rd, int ra, int rs, struct expr_t* expr)
|
void branch_addcmp_reg_reg_instr(int cc, int rd, int ra, int rs, struct expr_t* expr)
|
||||||
|
@ -518,6 +469,10 @@ void lea_address_instr(int rd, struct expr_t* expr)
|
||||||
{
|
{
|
||||||
quad pc = DOTVAL;
|
quad pc = DOTVAL;
|
||||||
quad type = expr->typ & S_TYP;
|
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)
|
if (type == S_ABS)
|
||||||
serror("can't use absolute addresses here");
|
serror("can't use absolute addresses here");
|
||||||
|
|
Loading…
Reference in a new issue