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
 | 
			
		||||
 | 
			
		||||
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_lit(quad opcode, int cc, int rd, int ra, quad value);
 | 
			
		||||
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. */
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +47,7 @@ void alu_instr_lit(quad op, int cc, int rd, int ra, quad value)
 | 
			
		|||
 | 
			
		||||
	/* 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));
 | 
			
		||||
| 
						 | 
				
			
			@ -99,6 +99,7 @@ void branch_instr(int bl, int cc, struct expr_t* expr)
 | 
			
		|||
{
 | 
			
		||||
	quad pc = DOTVAL;
 | 
			
		||||
	quad type = expr->typ & S_TYP;
 | 
			
		||||
	int d;
 | 
			
		||||
 | 
			
		||||
	/* Sanity checking. */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -107,71 +108,52 @@ void branch_instr(int bl, int cc, struct expr_t* expr)
 | 
			
		|||
	if (type == S_ABS)
 | 
			
		||||
		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:
 | 
			
		||||
			/* Calculate size of instructions only. For now we just assume
 | 
			
		||||
			 * that they're going to be the maximum size, 32 bits. */
 | 
			
		||||
		quad v, hiv, lov;
 | 
			
		||||
 | 
			
		||||
			emit4(0);
 | 
			
		||||
			break;
 | 
			
		||||
		if (!fitx(d, 27))
 | 
			
		||||
			toobig();
 | 
			
		||||
 | 
			
		||||
		case 1:
 | 
			
		||||
		case 2:
 | 
			
		||||
		{
 | 
			
		||||
			/* The VC4 branch instructions express distance in 2-byte
 | 
			
		||||
			 * words. */
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
			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
 | 
			
		||||
        	 * 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;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* 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;
 | 
			
		||||
        }
 | 
			
		||||
		v = maskx(d, 23);
 | 
			
		||||
		emit2(B16(10010000,00000000) | (cc<<8) | (v>>16));
 | 
			
		||||
		emit2(B16(00000000,00000000) | (v&0xffff));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
{
 | 
			
		||||
	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)
 | 
			
		||||
	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:
 | 
			
		||||
			/* Calculate size of instructions only. For now we just assume
 | 
			
		||||
			 * that they're going to be the maximum size, 48 bits. */
 | 
			
		||||
        emit2(B16(10101010,00000000) | (opcode<<5) | (rd<<0));
 | 
			
		||||
        emit2(scaledd);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
			emit2(0);
 | 
			
		||||
			emit4(0);
 | 
			
		||||
			break;
 | 
			
		||||
	/* Otherwise we need the full 48 bits. */
 | 
			
		||||
 | 
			
		||||
		case 1:
 | 
			
		||||
		case 2:
 | 
			
		||||
		{
 | 
			
		||||
			int d = expr->val - DOTVAL;
 | 
			
		||||
	newrelo(expr->typ, RELOVC4|RELPC);
 | 
			
		||||
 | 
			
		||||
        	/* We now know the worst case for the instruction layout. At
 | 
			
		||||
        	 * this point we can emit the instructions, which may shrink
 | 
			
		||||
        	 * the code. */
 | 
			
		||||
	/* 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 (type == DOTTYP)
 | 
			
		||||
			{
 | 
			
		||||
				int scaledd = d/size;
 | 
			
		||||
    if (!fitx(d, 27))
 | 
			
		||||
		toobig();
 | 
			
		||||
 | 
			
		||||
        	    /* 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;
 | 
			
		||||
                }
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* 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;
 | 
			
		||||
        }
 | 
			
		||||
	}
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
{
 | 
			
		||||
	quad type = expr->typ & S_TYP;
 | 
			
		||||
	int d;
 | 
			
		||||
 | 
			
		||||
	switch (pass)
 | 
			
		||||
	{
 | 
			
		||||
		case 0:
 | 
			
		||||
			/* Calculate size of instructions only. */
 | 
			
		||||
	if (type != DOTTYP)
 | 
			
		||||
		serror("can't use this type of branch to jump outside the section");
 | 
			
		||||
 | 
			
		||||
			emit2(0);
 | 
			
		||||
			break;
 | 
			
		||||
	/* The VC4 branch instructions express distance in 2-byte
 | 
			
		||||
	 * words. */
 | 
			
		||||
 | 
			
		||||
		case 1:
 | 
			
		||||
		case 2:
 | 
			
		||||
		{
 | 
			
		||||
			if (type != DOTTYP)
 | 
			
		||||
				serror("can't use this type of branch to jump outside the section");
 | 
			
		||||
	d = (expr->val - DOTVAL-2 + 4);
 | 
			
		||||
	if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
 | 
			
		||||
        d -= DOTGAIN;
 | 
			
		||||
    d /= 2;
 | 
			
		||||
 | 
			
		||||
			/* The VC4 branch instructions express distance in 2-byte
 | 
			
		||||
			 * words. */
 | 
			
		||||
	if (!fitx(d, bits))
 | 
			
		||||
		serror("target of branch is too far away");
 | 
			
		||||
 | 
			
		||||
			int d = (expr->val - DOTVAL-2 + 4) / 2;
 | 
			
		||||
 | 
			
		||||
			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)
 | 
			
		||||
| 
						 | 
				
			
			@ -518,6 +469,10 @@ void lea_address_instr(int rd, 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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue