From 8edbff9795ef559eaefefefdf1760f57b3a926c8 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 15 Jan 2017 00:15:01 +0100 Subject: [PATCH] Add assembler support for fixing up arbitrary oris/addi pairs of instructions; this should allow oris/lwz constant value loads, which will save an opcode. --- mach/powerpc/as/mach2.c | 3 ++ mach/powerpc/as/mach3.c | 5 ++- mach/powerpc/as/mach4.c | 88 +++++++++++++++++++++++++++++------------ mach/powerpc/as/mach5.c | 1 - mach/powerpc/ncg/table | 24 ++++++++--- util/led/relocate.c | 19 +++++---- 6 files changed, 97 insertions(+), 43 deletions(-) diff --git a/mach/powerpc/as/mach2.c b/mach/powerpc/as/mach2.c index 480c5faa3..a07f21b99 100644 --- a/mach/powerpc/as/mach2.c +++ b/mach/powerpc/as/mach2.c @@ -84,6 +84,9 @@ %token OP_LA %token OP_LI32 +%token OP_POWERPC_FIXUP +%token OP_HI OP_LO + /* Other token types */ %type c diff --git a/mach/powerpc/as/mach3.c b/mach/powerpc/as/mach3.c index 0f0bfdae7..62ed20471 100644 --- a/mach/powerpc/as/mach3.c +++ b/mach/powerpc/as/mach3.c @@ -102,6 +102,9 @@ 0, OP_LA, 0, "la", 0, OP_LA, 0, "li", 0, OP_RS_RA_RA_C, 31<<26 | 444<<1, "mr", +0, OP_POWERPC_FIXUP, 0, ".powerpcfixup", +0, OP_HI, 0, "hi", +0, OP_LO, 0, "lo", /* Branch processor instructions (page 20) */ @@ -270,7 +273,7 @@ 0, OP_RS_RA_SH_ME6_SH_C, 30<<26 | 1<<2, "rldicr", 0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 2<<2, "rldic", 0, OP_RS_RA_SH_MB5_ME5_C, 21<<26, "rlwinm", -0, OP_RS_RA_RB_MB6_C, 30<<26 | 8<<1, "rldcl", +0, OP_RS_RA_RB_MB6_C, 30<<26 | 8<<1, "rldcl", 0, OP_RS_RA_RB_ME6_C, 30<<26 | 9<<1, "rldcr", 0, OP_RS_RA_RB_MB5_ME5_C, 23<<26, "rlwnm", 0, OP_RS_RA_SH_MB6_SH_C, 30<<26 | 3<<2, "rldimi", diff --git a/mach/powerpc/as/mach4.c b/mach/powerpc/as/mach4.c index e1fb3fdf0..d9e4b0371 100644 --- a/mach/powerpc/as/mach4.c +++ b/mach/powerpc/as/mach4.c @@ -19,9 +19,9 @@ operation | OP_FRS_RA_D FPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_FRS_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_FRT_FRA_FRB_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); } - | OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); } + | OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); } | OP_FRT_FRA_FRC_C c FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<6)); } - | OP_FRT_FRB_C c FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<11)); } + | OP_FRT_FRB_C c FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<11)); } | OP_FRT_RA_D FPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_FRT_RA_RB FPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_FRT_C c FPR { emit4($1 | $2 | ($3<<21)); } @@ -40,15 +40,15 @@ operation | OP_RS_RA_D GPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_RS_RA_DS GPR ',' ds '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } | OP_RS_RA_NB GPR ',' GPR ',' nb { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } - | OP_RS_RA_UI GPR ',' GPR ',' e16 { emit4($1 | ($4<<21) | ($2<<16) | $6); } - | OP_RS_RA_UI_CC C GPR ',' GPR ',' e16 { emit4($1 | ($5<<21) | ($3<<16) | $7); } + | OP_RS_RA_UI GPR ',' GPR ',' e16 { emit4($1 | ($4<<21) | ($2<<16) | $6); } + | OP_RS_RA_UI_CC C GPR ',' GPR ',' e16 { emit4($1 | ($5<<21) | ($3<<16) | $7); } | OP_RS_RA_RB GPR ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_RS_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); } | OP_RS_RA_RA_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); } - | OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } + | OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } | OP_RS_RA_RB_MB6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); } | OP_RS_RA_RB_ME6_C c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); } - | OP_RS_RA_SH_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } + | OP_RS_RA_SH_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); } | OP_RS_RA_SH_MB6_SH_C c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); } | OP_RS_RA_SH_ME6_SH_C c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); } | OP_RS_RA_SH5_C c GPR ',' GPR ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); } @@ -60,13 +60,14 @@ operation | OP_LIA lia { emit4($1 | $2); } | OP_LIL lil { emit4($1 | $2); } | OP_LI32 li32 /* emitted in subrule */ + | OP_POWERPC_FIXUP powerpcfixup /* emitted in subrule */ ; c : /* nothing */ { $$ = 0; } | C { $$ = 1; } ; - + e16 : absexp { @@ -75,8 +76,34 @@ e16 serror("16-bit value out of range"); $$ = (uint16_t) $1; } + | OP_HI expr + { + /* If this is a symbol reference, discard the symbol and keep only the + * offset part. */ + quad type = $2.typ & S_TYP; + quad val = $2.val; + + /* If the assembler stored a symbol for relocation later, we need to + * abandon it (because we're not going to generate a relocation). */ + if (type != S_ABS) + relonami = 0; + + $$ = ((quad)val) >> 16; + } + | OP_LO expr + { + quad type = $2.typ & S_TYP; + quad val = $2.val; + + /* If the assembler stored a symbol for relocation later, we need to + * abandon it (because we're not going to generate a relocation). */ + if (type != S_ABS) + relonami = 0; + + $$ = val & 0xffff; + } ; - + u8 : absexp { @@ -85,7 +112,7 @@ u8 $$ = $1; } ; - + u7 : absexp { @@ -94,7 +121,7 @@ u7 $$ = $1; } ; - + u6 : absexp { @@ -103,7 +130,7 @@ u6 $$ = $1; } ; - + u5 : absexp { @@ -112,7 +139,7 @@ u5 $$ = $1; } ; - + u4 : absexp { @@ -121,7 +148,7 @@ u4 $$ = $1; } ; - + u1 : absexp { @@ -130,7 +157,7 @@ u1 $$ = $1; } ; - + u2 : absexp { @@ -139,7 +166,7 @@ u2 $$ = $1; } ; - + ds : e16 { @@ -148,26 +175,26 @@ ds $$ = $1; } ; - + nb : absexp { if (($1 < 1) || ($1 > 32)) serror("register count must be in the range 1..32"); - + if ($1 == 32) $$ = 0; else - $$ = $1; + $$ = $1; } ; - + bdl : expr { int dist = $1.val - DOTVAL; fit(fitx(dist, 25)); - + if (dist & 0x3) serror("jump targets must be 4-aligned"); @@ -183,7 +210,7 @@ bda { int target = $1.val; fit(fitx(target, 16)); - + if (target & 0x3) serror("jump targets must be 4-aligned"); @@ -193,7 +220,7 @@ bda $$ = target & 0xFFFD; } ; - + li32 : GPR ',' expr { @@ -215,7 +242,7 @@ lil { int dist = $1.val - DOTVAL; fit(fitx(dist, 26)); - + if (dist & 0x3) serror("jump targets must be 4-aligned"); @@ -223,13 +250,13 @@ lil $$ = dist & 0x03FFFFFD; } ; - + lia : expr { int target = $1.val; fit(fitx(target, 26)); - + if (target & 0x3) serror("jump targets must be 4-aligned"); @@ -248,3 +275,14 @@ spr_num $$ = ($1 >> 5) | (($1 & 0x1f) << 5); } ; + +powerpcfixup + : expr + { + quad type = $1.typ & S_TYP; + quad val = $1.val; + if (type == S_ABS) + serror(".powerpcfixup is useless on absolute values"); + newrelo($1.typ, RELOPPC | FIXUPFLAGS); + } + ; diff --git a/mach/powerpc/as/mach5.c b/mach/powerpc/as/mach5.c index 998cd8d9c..5b8eb9167 100644 --- a/mach/powerpc/as/mach5.c +++ b/mach/powerpc/as/mach5.c @@ -2,4 +2,3 @@ * $Source$ * $State$ */ - diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index 52f335c3d..29353a259 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -169,11 +169,14 @@ TOKENS /* Used only in instruction descriptions (to generate the correct syntax). */ GPRINDIRECT = { GPR reg; INT off; } 4 off "(" reg ")". + GPRINDIRECT_OFFSET_LO = { GPR reg; ADDR adr; } 4 "lo [" adr "](" reg ")". CONST = { INT val; } 4 val. /* Primitives */ LABEL = { ADDR adr; } 4 adr. + LABEL_OFFSET_HI = { ADDR adr; } 4 "hi " adr. + LABEL_OFFSET_LO = { ADDR adr; } 4 "lo " adr. LOCAL = { INT off; } 4. /* Allows us to use regvar() to refer to registers */ @@ -282,7 +285,7 @@ INSTRUCTIONS add GPR:wo, GPR:ro, GPR:ro. addX "add." GPR:wo, GPR:ro, GPR:ro. addi GPR:wo, GPR:ro, CONST:ro. - addis GPR:wo, GPR:ro, CONST:ro. + addis GPR:wo, GPR:ro, CONST+LABEL_OFFSET_HI:ro. and GPR:wo, GPR:ro, GPR:ro. andc GPR:wo, GPR:ro, GPR:ro. andiX "andi." GPR:wo:cc, GPR:ro, CONST:ro. @@ -329,10 +332,9 @@ INSTRUCTIONS lhz GPR:wo, GPRINDIRECT:ro cost(4, 3). lhzx GPR:wo, GPR:ro, GPR:ro cost(4, 3). li32 GPR:wo, CONST:ro cost(8, 2). - li32 GPR:wo, LABEL:ro cost(8, 2). lwzu GPR:wo, GPRINDIRECT:ro cost(4, 3). lwzx GPR:wo, GPR:ro, GPR:ro cost(4, 3). - lwz GPR:wo, GPRINDIRECT:ro cost(4, 3). + lwz GPR:wo, GPRINDIRECT+GPRINDIRECT_OFFSET_LO:ro cost(4, 3). nand GPR:wo, GPR:ro, GPR:ro. neg GPR:wo, GPR:ro. nor GPR:wo, GPR:ro, GPR:ro. @@ -342,7 +344,7 @@ INSTRUCTIONS mtspr SPR:wo, GPR:ro cost(4, 2). or GPR:wo, GPR:ro, GPR:ro. orc GPR:wo, GPR:ro, GPR:ro. - ori GPR:wo, GPR:ro, CONST:ro. + ori GPR:wo, GPR:ro, CONST+LABEL_OFFSET_LO:ro. oris GPR:wo, GPR:ro, CONST:ro. orX "or." GPR:wo:cc, GPR:ro, GPR:ro. rlwinm GPR:wo, GPR:ro, CONST:ro, CONST:ro, CONST:ro. @@ -368,7 +370,8 @@ INSTRUCTIONS xori GPR:wo, GPR:ro, CONST:ro. xoris GPR:wo, GPR:ro, CONST:ro. - comment "!" LABEL:ro cost(0, 0). + fixup ".powerpcfixup" LABEL:ro. + comment "!" LABEL:ro cost(0, 0). @@ -405,7 +408,9 @@ MOVES from LABEL to GPR gen COMMENT("move LABEL->GPR") - li32 %2, {LABEL, %1.adr} + fixup {LABEL, %1.adr} + addis %2, R0, {LABEL_OFFSET_HI, %1.adr} + ori %2, %2, {LABEL_OFFSET_LO, %1.adr} /* Sign extension */ @@ -1142,6 +1147,13 @@ PATTERNS yields {IND_RC_H, %1.reg, %1.off} pat loi $1==INT32 /* Load word indirect */ + with LABEL + uses REG + gen + fixup {LABEL, %1.adr} + addis %a, R0, {LABEL_OFFSET_HI, %1.adr} + lwz %a, {GPRINDIRECT_OFFSET_LO, %a, %1.adr} + yields %a with GPR yields {IND_RC_W, %1, 0} with SUM_RC diff --git a/util/led/relocate.c b/util/led/relocate.c index c72965e75..02b0be381 100644 --- a/util/led/relocate.c +++ b/util/led/relocate.c @@ -119,14 +119,13 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type) /* branch instruction */ return opcode1 & 0x03fffffd; } - else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && - ((opcode2 & 0xfc000000) == 0x60000000)) + else { - /* addis / ori instruction pair */ + /* If it's not a branch, we're just going to assume that the user + * knows what they're doing and this is a addis/ori pair (or + * compatible). */ return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff); } - - assert(0 && "unrecognised PowerPC instruction"); } /* @@ -260,17 +259,17 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type) i |= value & 0x03fffffd; write4(i, addr, type); } - else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && - ((opcode2 & 0xfc000000) == 0x60000000)) + else { + /* If it's not a branch, we're just going to assume that the user + * knows what they're doing and this is a addis/ori pair (or + * compatible). */ 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"); } /* @@ -339,7 +338,7 @@ addrelo(relo, names, valu_out) extern int hash(); extern struct outname *searchname(); extern unsigned indexof(); - extern struct outhead outhead; + extern struct outhead outhead; name = searchname(local->on_mptr, hash(local->on_mptr)); if (name == (struct outname *)0)