Eliminate the RELOH2 relocation, as it never worked --- the address would be

calculated incorrectly because of overflow errors.

Replace it with an extended RELOPPC relocation which understands addis/ori
pairs; add an la pseudoop to the assembler which generates these and the
appropriate relocation. Make good.

--HG--
branch : dtrg-experimental-powerpc-branch
This commit is contained in:
David Given 2016-09-17 12:43:15 +02:00
parent 45a950571d
commit 80cb6ba927
15 changed files with 96 additions and 64 deletions

View file

@ -66,7 +66,7 @@ struct outname {
#define RELO2 2 /* 2 bytes */
#define RELO4 3 /* 4 bytes */
#define RELOPPC 4 /* PowerPC 26-bit address */
#define RELOH2 5 /* write top 2 bytes of 4 byte word */
/* relo 5 is unused */
#define RELOVC4 6 /* VideoCore IV address in 32-bit instruction */
#define RELPC 0x2000 /* pc relative */

View file

@ -80,7 +80,7 @@
%token <y_word> OP_TO_RA_RB
%token <y_word> OP_TO_RA_SI
%token <y_word> OP_la
%token <y_word> OP_LA
/* Other token types */

View file

@ -98,7 +98,7 @@
/* Special instructions */
0, OP_la, 0, "la",
0, OP_LA, 0, "la",
/* Branch processor instructions (page 20) */

View file

@ -58,6 +58,7 @@ operation
| OP_LEV u7 { emit4($1 | ($2<<5)); }
| OP_LIA lia { emit4($1 | $2); }
| OP_LIL lil { emit4($1 | $2); }
| OP_LA la /* emitted in subrule */
;
c
@ -66,26 +67,12 @@ c
;
e16
: '<' expr
: absexp
{
DOTVAL += 2;
newrelo($2.typ, RELOH2 | FIXUPFLAGS);
DOTVAL -= 2;
$$ = ($2.val >> 16) & 0xFFFF;
}
| '>' expr
{
DOTVAL += 2;
newrelo($2.typ, RELO2 | FIXUPFLAGS);
DOTVAL -= 2;
$$ = $2.val & 0xFFFF;
}
| expr
{
DOTVAL += 2;
newrelo($1.typ, RELO2 | FIXUPFLAGS);
DOTVAL -= 2;
$$ = $1.val & 0xFFFF;
/* Allow signed or unsigned 16-bit values. */
if (($1 < -0x8000) || ($1 > 0xffff))
serror("16-bit value out of range");
$$ = (uint16_t) $1;
}
;
@ -206,6 +193,15 @@ bda
}
;
la
: GPR ',' expr
{
newrelo($3.typ, RELOPPC | FIXUPFLAGS);
emit4((15<<26) | ($1<<21) | (0<<16) | ($3.val >> 16)); /* addis */
emit4((24<<26) | ($1<<21) | ($1<<16) | ($3.val & 0xffff)); /* ori */
}
;
lil
: expr
{

View file

@ -16,8 +16,7 @@
.define .aar4
.aar4:
addis r0, r0, <.trap_earray
ori r0, r0, >.trap_earray
la r0, .trap_earray
mtspr ctr, r0 ! load CTR with trap address
lwz r0, 0(r3)

View file

@ -13,15 +13,15 @@
.define .cfu8
.cfu8:
la(r3, .fd_00000000)
la r3, .fd_00000000
lfd f0, 0(r3) ! f0 = 0.0
lfd f1, 0(sp) ! value to be converted
la(r3, .fd_FFFFFFFF)
la r3, .fd_FFFFFFFF
lfd f3, 0(r3) ! f3 = 0xFFFFFFFF
la(r3, .fd_80000000)
la r3, .fd_80000000
lfd f4, 0(r3) ! f4 = 0x80000000
fsel f2, f1, f1, f0

View file

@ -24,7 +24,7 @@
lfd f0, 0(sp) ! load value
la (r3, pivot)
la r3, pivot
lfd f1, 0(r3) ! load pivot value
fsub f0, f0, f1 ! adjust

View file

@ -20,7 +20,7 @@
lfd f0, 0(sp) ! load value
la (r3, pivot)
la r3, pivot
lfd f1, 0(r3) ! load pivot value
fsub f0, f0, f1 ! adjust

View file

@ -20,4 +20,3 @@
#define EQ 2
#define OV 3
#define la(reg, val) addis reg, r0, <val; ori reg, reg, >val

View file

@ -262,6 +262,7 @@ INSTRUCTIONS
fsub FD:wo, FD:ro, FD:ro.
fsubs FS:wo, FS:ro, FS:ro.
fmr FS+FD:wo, FS+FD:ro.
la GPRI:wo, LABEL:ro.
lbzx GPRI:wo, GPR:ro, GPR:ro.
lbz GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
lfd FD:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
@ -353,8 +354,7 @@ MOVES
from LABEL to GPR
gen
COMMENT("move LABEL->GPR")
addis %2, R0, {HILABEL, %1.adr}
ori %2, %2, {LOLABEL, %1.adr}
la %2, {LABEL, %1.adr}
/* Sign extension */

View file

@ -42,8 +42,7 @@ __syscall:
bc IFTRUE, GT, 2f
3:
addis r4, r0, <_errno
ori r4, r4, >_errno
la r4, _errno
stw r3, 0(r4)
addi r3, r0, -1
bclr ALWAYS, 0, 0

View file

@ -65,15 +65,13 @@ EUNIMPL = 63 ! unimplemented em-instruction called
addi r4, r0, 1
rlwnm r4, r4, r3, 0, 31 ! calculate trap bit
addis r5, r0, <.ignmask
ori r5, r5, >.ignmask
la r5, .ignmask
lwz r5, 0(r5) ! load ignore mask
and. r4, r4, r5 ! compare
bclr IFFALSE, EQ, 0 ! return if non-zero
1:
addis r4, r0, <.trppc
ori r4, r4, >.trppc
la r4, .trppc
lwz r5, 0(r4) ! load user trap routine
or. r5, r5, r5 ! test
bc IFTRUE, EQ, fatal ! if no user trap routine, bail out
@ -94,8 +92,7 @@ EUNIMPL = 63 ! unimplemented em-instruction called
fatal:
addi r3, r0, 1
addis r4, r0, <message
ori r4, r4, >message
la r4, message
addi r5, r0, 6
addi r0, r0, 4 ! write()
sc 0

View file

@ -140,9 +140,6 @@ showrelo()
case RELOPPC:
printf("\tPowerPC 26-bit address\n");
break;
case RELOH2:
printf("\ttop 2 bytes of a 4 byte word\n");
break;
case RELOVC4:
printf("\tVideoCore IV address in 32-bit instruction\n");
break;

View file

@ -158,12 +158,11 @@ struct outrelo {
/*
* relocation type bits
*/
#define RELSZ 0x0fffi /* relocation length */
#define RELSZ 0x0fff /* relocation length */
#define RELO1 0x01 /* 1 byte */
#define RELO2 0x02 /* 2 bytes */
#define RELO4 0x03 /* 4 bytes */
#define RELOPPC 0x04 /* 26-bit PowerPC address */
#define RELOH2 0x05 /* write top 2 bytes of 4 byte word */
#define RELOVC4 0x06 /* VideoCore IV address in 32-bit insruction */
#define RELPC 0x2000 /* pc relative */
#define RELBR 0x4000 /* High order byte lowest address. */

View file

@ -18,7 +18,7 @@ static char rcsid[] = "$Id$";
#define UBYTE(x) ((x) & BYTEMASK)
static long read2(char* addr, int type)
static uint16_t read2(char* addr, int type)
{
unsigned short word0, word1;
@ -28,7 +28,7 @@ static long read2(char* addr, int type)
return (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]);
}
static long read4(char* addr, int type)
static uint32_t read4(char* addr, int type)
{
unsigned short word0, word1;
@ -49,7 +49,7 @@ static long read4(char* addr, int type)
* one of several different ways (depending on what the instruction is).
*/
static long get_vc4_valu(char* addr)
static uint32_t get_vc4_valu(char* addr)
{
uint16_t opcode = read2(addr, 0);
@ -104,11 +104,36 @@ static long get_vc4_valu(char* addr)
assert(0 && "unrecognised VC4 instruction");
}
/* PowerPC fixups are complex as we need to patch up to the next two
* instructions in one of several different ways, depending on what the
* instructions area.
*/
static uint32_t get_powerpc_valu(char* addr, uint16_t type)
{
uint32_t opcode1 = read4(addr+0, type);
uint32_t opcode2 = read4(addr+4, type);
if ((opcode1 & 0xfc000000) == 0x48000000)
{
/* branch instruction */
return opcode1 & 0x03fffffd;
}
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
((opcode2 & 0xfc000000) == 0x60000000))
{
/* addis / ori instruction pair */
return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff);
}
assert(0 && "unrecognised PowerPC instruction");
}
/*
* The bits in type indicate how many bytes the value occupies and what
* significance should be attributed to each byte.
*/
static long getvalu(char* addr, uint16_t type)
static uint32_t getvalu(char* addr, uint16_t type)
{
switch (type & RELSZ) {
case RELO1:
@ -118,9 +143,7 @@ static long getvalu(char* addr, uint16_t type)
case RELO4:
return read4(addr, type);
case RELOPPC:
return read4(addr, type) & 0x03FFFFFD;
case RELOH2:
return read2(addr, type) << 16;
return get_powerpc_valu(addr, type);
case RELOVC4:
return get_vc4_valu(addr);
default:
@ -129,7 +152,7 @@ static long getvalu(char* addr, uint16_t type)
/* NOTREACHED */
}
static void write2(long valu, char* addr, int type)
static void write2(uint16_t valu, char* addr, int type)
{
unsigned short word0, word1;
@ -142,7 +165,7 @@ static void write2(long valu, char* addr, int type)
}
}
static void write4(long valu, char* addr, int type)
static void write4(uint32_t valu, char* addr, int type)
{
unsigned short word0, word1;
@ -170,7 +193,7 @@ static void write4(long valu, char* addr, int type)
* one of several different ways (depending on what the instruction is).
*/
static void put_vc4_valu(char* addr, long value)
static void put_vc4_valu(char* addr, uint32_t value)
{
uint16_t opcode = read2(addr, 0);
@ -220,12 +243,42 @@ static void put_vc4_valu(char* addr, long value)
assert(0 && "unrecognised VC4 instruction");
}
/* PowerPC fixups are complex as we need to patch up to the next two
* instructions in one of several different ways, depending on what the
* instructions area.
*/
static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
{
uint32_t opcode1 = read4(addr+0, type);
uint32_t opcode2 = read4(addr+4, type);
if ((opcode1 & 0xfc000000) == 0x48000000)
{
/* branch instruction */
uint32_t i = opcode1 & ~0x03fffffd;
i |= value & 0x03fffffd;
write4(i, addr, type);
}
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
((opcode2 & 0xfc000000) == 0x60000000))
{
uint16_t hi = value >> 16;
uint16_t lo = value & 0xffff;
write4((opcode1 & 0xffff0000) | hi, addr+0, type);
write4((opcode2 & 0xffff0000) | lo, addr+4, type);
}
else
assert(0 && "unrecognised PowerPC instruction");
}
/*
* The bits in type indicate how many bytes the value occupies and what
* significance should be attributed to each byte.
* We do not check for overflow.
*/
static putvalu(long valu, char* addr, uint16_t type)
static putvalu(uint32_t valu, char* addr, uint16_t type)
{
switch (type & RELSZ) {
@ -239,14 +292,7 @@ static putvalu(long valu, char* addr, uint16_t type)
write4(valu, addr, type);
break;
case RELOPPC:
{
long i = read4(addr, type) & ~0x03FFFFFD;
i |= valu & 0x03FFFFFD;
write4(i, addr, type);
break;
}
case RELOH2:
write2(valu>>16, addr, type);
put_powerpc_valu(addr, valu, type);
break;
case RELOVC4:
put_vc4_valu(addr, valu);