#include "l.h" #define OPVCC(o,xo,oe,rc) (((o)<<26)|((xo)<<1)|((oe)<<10)|((rc)&1))#define OPCC(o,xo,rc) OPVCC((o),(xo),0,(rc))#define OP(o,xo) OPVCC((o),(xo),0,0) /* the order is dest, a/s, b/imm for both arithmetic and logical operations */#define AOP_RRR(op,d,a,b) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))#define AOP_IRR(op,d,a,simm) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|((simm)&0xFFFF))#define LOP_RRR(op,a,s,b) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))#define LOP_IRR(op,a,s,uimm) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|((uimm)&0xFFFF))#define OP_BR(op,li,aa) ((op)|((li)&0x03FFFFFC)|((aa)<<1))#define OP_BC(op,bo,bi,bd,aa) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16)|((bd)&0xFFFC)|((aa)<<1))#define OP_BCR(op,bo,bi) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16))#define OP_RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\ (((mb)&31L)<<6)|(((me)&31L)<<1)) #define OP_ADD OPVCC(31,266,0,0)#define OP_ADDI OPVCC(14,0,0,0)#define OP_ADDIS OPVCC(15,0,0,0)#define OP_ANDI OPVCC(28,0,0,0)#define OP_EXTSB OPVCC(31,954,0,0)#define OP_EXTSH OPVCC(31,922,0,0)#define OP_EXTSW OPVCC(31,986,0,0)#define OP_MCRF OPVCC(19,0,0,0)#define OP_MCRFS OPVCC(63,64,0,0)#define OP_MCRXR OPVCC(31,512,0,0)#define OP_MFCR OPVCC(31,19,0,0)#define OP_MFFS OPVCC(63,583,0,0)#define OP_MFMSR OPVCC(31,83,0,0)#define OP_MFSPR OPVCC(31,339,0,0)#define OP_MFSR OPVCC(31,595,0,0)#define OP_MFSRIN OPVCC(31,659,0,0)#define OP_MTCRF OPVCC(31,144,0,0)#define OP_MTFSF OPVCC(63,711,0,0)#define OP_MTFSFI OPVCC(63,134,0,0)#define OP_MTMSR OPVCC(31,146,0,0)#define OP_MTMSRD OPVCC(31,178,0,0)#define OP_MTSPR OPVCC(31,467,0,0)#define OP_MTSR OPVCC(31,210,0,0)#define OP_MTSRIN OPVCC(31,242,0,0)#define OP_MULLW OPVCC(31,235,0,0)#define OP_MULLD OPVCC(31,233,0,0)#define OP_OR OPVCC(31,444,0,0)#define OP_ORI OPVCC(24,0,0,0)#define OP_ORIS OPVCC(25,0,0,0)#define OP_RLWINM OPVCC(21,0,0,0)#define OP_SUBF OPVCC(31,40,0,0)#define OP_RLDIC OPVCC(30,4,0,0)#define OP_RLDICR OPVCC(30,2,0,0)#define OP_RLDICL OPVCC(30,0,0,0) #define oclass(v) ((v).class-1) long oprrr(int), opirr(int), opload(int), opstore(int), oploadx(int), opstorex(int); /* * 32-bit masks */intgetmask(uchar *m, ulong v){ int i; m[0] = m[1] = 0; if(v != ~0L && v & (1<<31) && v & 1){ /* MB > ME */ if(getmask(m, ~v)){ i = m[0]; m[0] = m[1]+1; m[1] = i-1; return 1; } return 0; } for(i=0; i<32; i++) if(v & (1<<(31-i))){ m[0] = i; do { m[1] = i; } while(++i<32 && (v & (1<<(31-i))) != 0); for(; i<32; i++) if(v & (1<<(31-i))) return 0; return 1; } return 0;} voidmaskgen(Prog *p, uchar *m, ulong v){ if(!getmask(m, v)) diag("cannot generate mask #%lux\n%P", v, p);} /* * 64-bit masks (rldic etc) */intgetmask64(uchar *m, uvlong v){ int i; m[0] = m[1] = 0; for(i=0; i<64; i++) if(v & ((uvlong)1<<(63-i))){ m[0] = i; do { m[1] = i; } while(++i<64 && (v & ((uvlong)1<<(63-i))) != 0); for(; i<64; i++) if(v & ((uvlong)1<<(63-i))) return 0; return 1; } return 0;} voidmaskgen64(Prog *p, uchar *m, uvlong v){ if(!getmask64(m, v)) diag("cannot generate mask #%llux\n%P", v, p);} static voidreloc(Adr *a, long pc, int sext){ if(a->name == D_EXTERN || a->name == D_STATIC) dynreloc(a->sym, pc, 1, 1, sext);} static ulongloadu32(int r, vlong d){ long v; v = d>>16; if(isuint32(d)) return LOP_IRR(OP_ORIS, r, REGZERO, v); return AOP_IRR(OP_ADDIS, r, REGZERO, v);} intasmout(Prog *p, Optab *o, int aflag){ long o1, o2, o3, o4, o5, v, t; vlong d; Prog *ct; int r, a; uchar mask[2]; o1 = 0; o2 = 0; o3 = 0; o4 = 0; o5 = 0; switch(o->type) { default: if(aflag) return 0; diag("unknown type %d", o->type); if(!debug['a']) prasm(p); break; case 0: /* pseudo ops */ if(aflag) { if(p->link) { if(p->as == ATEXT) { ct = curtext; o2 = autosize; curtext = p; autosize = p->to.offset + 8; o1 = asmout(p->link, oplook(p->link), aflag); curtext = ct; autosize = o2; } else o1 = asmout(p->link, oplook(p->link), aflag); } return o1; } break; case 1: /* mov r1,r2 ==> OR Rs,Rs,Ra */ if(p->to.reg == REGZERO && p->from.type == D_CONST) { v = regoff(&p->from); if(r0iszero && v != 0) { nerrors--; diag("literal operation on R0\n%P", p); } o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v); break; } o1 = LOP_RRR(OP_OR, p->to.reg, p->from.reg, p->from.reg); break; case 2: /* int/cr/fp op Rb,[Ra],Rd */ r = p->reg; if(r == NREG) r = p->to.reg; o1 = AOP_RRR(oprrr(p->as), p->to.reg, r, p->from.reg); break; case 3: /* mov $soreg/addcon/ucon, r ==> addis/addi $i,reg',r */ d = vregoff(&p->from); v = d; r = p->from.reg; if(r == NREG) r = o->param; if(r0iszero && p->to.reg == 0 && (r != 0 || v != 0)) diag("literal operation on R0\n%P", p); a = OP_ADDI; if(o->a1 == C_UCON) { v >>= 16; if(r == REGZERO && isuint32(d)){ o1 = LOP_IRR(OP_ORIS, p->to.reg, REGZERO, v); break; } a = OP_ADDIS; } o1 = AOP_IRR(a, p->to.reg, r, v); break; case 4: /* add/mul $scon,[r1],r2 */ v = regoff(&p->from); r = p->reg; if(r == NREG) r = p->to.reg; if(r0iszero && p->to.reg == 0) diag("literal operation on R0\n%P", p); o1 = AOP_IRR(opirr(p->as), p->to.reg, r, v); break; case 5: /* syscall */ if(aflag) return 0; o1 = oprrr(p->as); break; case 6: /* logical op Rb,[Rs,]Ra; no literal */ r = p->reg; if(r == NREG) r = p->to.reg; o1 = LOP_RRR(oprrr(p->as), p->to.reg, r, p->from.reg); break; case 7: /* mov r, soreg ==> stw o(r) */ r = p->to.reg; if(r == NREG) r = o->param; v = regoff(&p->to); if(p->to.type == D_OREG && p->reg != NREG) { if(v) diag("illegal indexed instruction\n%P", p); o1 = AOP_RRR(opstorex(p->as), p->from.reg, p->reg, r); } else o1 = AOP_IRR(opstore(p->as), p->from.reg, r, v); break; case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */ r = p->from.reg; if(r == NREG) r = o->param; v = regoff(&p->from); if(p->from.type == D_OREG && p->reg != NREG) { if(v) diag("illegal indexed instruction\n%P", p); o1 = AOP_RRR(oploadx(p->as), p->to.reg, p->reg, r); } else o1 = AOP_IRR(opload(p->as), p->to.reg, r, v); break; case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */ r = p->from.reg; if(r == NREG) r = o->param; v = regoff(&p->from); if(p->from.type == D_OREG && p->reg != NREG) { if(v) diag("illegal indexed instruction\n%P", p); o1 = AOP_RRR(oploadx(p->as), p->to.reg, p->reg, r); } else o1 = AOP_IRR(opload(p->as), p->to.reg, r, v); o2 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0); break; case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */ r = p->reg; if(r == NREG) r = p->to.reg; o1 = AOP_RRR(oprrr(p->as), p->to.reg, p->from.reg, r); break; case 11: /* br/bl lbra */ if(aflag) return 0; v = 0; if(p->cond == UP){ if(p->to.sym->type != SUNDEF) diag("bad branch sym type"); v = (ulong)p->to.sym->value >> (Roffset-2); dynreloc(p->to.sym, p->pc, 0, 0, 0); } else if(p->cond) v = p->cond->pc - p->pc; if(v & 03) { diag("odd branch target address\n%P", p); v &= ~03; } if(v < -(1L<<25) || v >= (1L<<24)) diag("branch too far\n%P", p); o1 = OP_BR(opirr(p->as), v, 0); break; case 12: /* movb r,r (extsb); movw r,r (extsw) */ if(p->to.reg == REGZERO && p->from.type == D_CONST) { v = regoff(&p->from); if(r0iszero && v != 0) { nerrors--; diag("literal operation on R0\n%P", p); } o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v); break; } if(p->as == AMOVW) o1 = LOP_RRR(OP_EXTSW, p->to.reg, p->from.reg, 0); else o1 = LOP_RRR(OP_EXTSB, p->to.reg, p->from.reg, 0); break; case 13: /* mov[bhw]z r,r; uses rlwinm not andi. to avoid changing CC */ if(p->as == AMOVBZ) o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 24, 31); else if(p->as == AMOVH) o1 = LOP_RRR(OP_EXTSH, p->to.reg, p->from.reg, 0); else if(p->as == AMOVHZ) o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 16, 31); else if(p->as == AMOVWZ) o1 = OP_RLW(OP_RLDIC, p->to.reg, p->from.reg, 0, 0, 0) | (1<<5); /* MB=32 */ else diag("internal: bad mov[bhw]z\n%P", p); break; case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */ r = p->reg; if(r == NREG) r = p->to.reg; d = vregoff(&p->from3); maskgen64(p, mask, d); switch(p->as){ case ARLDCL: case ARLDCLCC: a = mask[0]; /* MB */ if(mask[1] != 63) diag("invalid mask for rotate: %llux (end != bit 63)\n%P", d, p); break; case ARLDCR: case ARLDCRCC: a = mask[1]; /* ME */ if(mask[0] != 0) diag("invalid mask for rotate: %llux (start != 0)\n%P", d, p); break; default: diag("unexpected op in rldc case\n%P", p); a = 0; } o1 = LOP_RRR(oprrr(p->as), p->to.reg, r, p->from.reg); o1 |= (a&31L)<<6; if(a & 0x20) o1 |= 1<<5; /* mb[5] is top bit */ break; case 17: /* bc bo,bi,lbra (same for now) */ case 16: /* bc bo,bi,sbra */ if(aflag) return 0; a = 0; if(p->from.type == D_CONST) a = regoff(&p->from); r = p->reg; if(r == NREG) r = 0; v = 0; if(p->cond) v = p->cond->pc - p->pc; if(v & 03) { diag("odd branch target address\n%P", p); v &= ~03; } if(v < -(1L<<16) || v >= (1L<<15)) diag("branch too far\n%P", p); o1 = OP_BC(opirr(p->as), a, r, v, 0); break; case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */ if(aflag) return 0; if(p->as == ABC || p->as == ABCL) v = regoff(&p->to)&31L; else v = 20; /* unconditional */ r = p->reg; if(r == NREG) r = 0; o1 = AOP_RRR(OP_MTSPR, p->to.reg, 0, 0) | ((D_LR&0x1f)<<16) | (((D_LR>>5)&0x1f)<<11); o2 = OPVCC(19, 16, 0, 0); if(p->as == ABL || p->as == ABCL) o2 |= 1; o2 = OP_BCR(o2, v, r); break; case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */ if(aflag) return 0; if(p->as == ABC || p->as == ABCL) v = regoff(&p->from)&31L; else v = 20; /* unconditional */ r = p->reg; if(r == NREG) r = 0; switch(oclass(p->to)) { case C_CTR: o1 = OPVCC(19, 528, 0, 0); break; case C_LR: o1 = OPVCC(19, 16, 0, 0); break; default: diag("bad optab entry (18): %d\n%P", p->to.class, p); v = 0; } if(p->as == ABL || p->as == ABCL) o1 |= 1; o1 = OP_BCR(o1, v, r); break; case 19: /* mov $lcon,r ==> cau+or */ d = vregoff(&p->from); o1 = loadu32(p->to.reg, d); o2 = LOP_IRR(OP_ORI, p->to.reg, p->to.reg, (long)d); if(dlm) reloc(&p->from, p->pc, 0); break; case 20: /* add $ucon,,r */ v = regoff(&p->from); r = p->reg; if(r == NREG) r = p->to.reg; if(p->as == AADD && (!r0iszero && p->reg == 0 || r0iszero && p->to.reg == 0)) diag("literal operation on R0\n%P", p); o1 = AOP_IRR(opirr(p->as+AEND), p->to.reg, r, v>>16); break; case 22: /* add $lcon,r1,r2 ==> cau+or+add */ /* could do add/sub more efficiently */ if(p->to.reg == REGTMP || p->reg == REGTMP) diag("cant synthesize large constant\n%P", p); d = vregoff(&p->from); o1 = loadu32(REGTMP, d); o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (long)d); r = p->reg; if(r == NREG) r = p->to.reg; o3 = AOP_RRR(oprrr(p->as), p->to.reg, REGTMP, r); if(dlm) reloc(&p->from, p->pc, 0); break; case 23: /* and $lcon,r1,r2 ==> cau+or+and */ /* masks could be done using rlnm etc. */ if(p->to.reg == REGTMP || p->reg == REGTMP) diag("cant synthesize large constant\n%P", p); d = vregoff(&p->from); o1 = loadu32(REGTMP, d); o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (long)d); r = p->reg; if(r == NREG) r = p->to.reg; o3 = LOP_RRR(oprrr(p->as), p->to.reg, REGTMP, r); if(dlm) reloc(&p->from, p->pc, 0); break;/*24*/ case 25: /* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */ v = regoff(&p->from); if(v < 0) v = 0; else if(v > 63) v = 63; r = p->reg; if(r == NREG) r = p->to.reg; switch(p->as){ case ASLD: case ASLDCC: a = 63-v; o1 = OP_RLDICR; break; case ASRD: case ASRDCC: a = v; v = 64-v; o1 = OP_RLDICL; break;Lines 1–500 of 1485. Load more
#include "l.h" #define OPVCC(o,xo,oe,rc) (((o)<<26)|((xo)<<1)|((oe)<<10)|((rc)&1)) #define OPCC(o,xo,rc) OPVCC((o),(xo),0,(rc)) #define OP(o,xo) OPVCC((o),(xo),0,0) /* the order is dest, a/s, b/imm for both arithmetic and logical operations */ #define AOP_RRR(op,d,a,b) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11)) #define AOP_IRR(op,d,a,simm) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|((simm)&0xFFFF)) #define LOP_RRR(op,a,s,b) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11)) #define LOP_IRR(op,a,s,uimm) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|((uimm)&0xFFFF)) #define OP_BR(op,li,aa) ((op)|((li)&0x03FFFFFC)|((aa)<<1)) #define OP_BC(op,bo,bi,bd,aa) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16)|((bd)&0xFFFC)|((aa)<<1)) #define OP_BCR(op,bo,bi) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16)) #define OP_RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\ (((mb)&31L)<<6)|(((me)&31L)<<1)) #define OP_ADD OPVCC(31,266,0,0) #define OP_ADDI OPVCC(14,0,0,0) #define OP_ADDIS OPVCC(15,0,0,0) #define OP_ANDI OPVCC(28,0,0,0) #define OP_EXTSB OPVCC(31,954,0,0) #define OP_EXTSH OPVCC(31,922,0,0) #define OP_EXTSW OPVCC(31,986,0,0) #define OP_MCRF OPVCC(19,0,0,0) #define OP_MCRFS OPVCC(63,64,0,0) #define OP_MCRXR OPVCC(31,512,0,0) #define OP_MFCR OPVCC(31,19,0,0) #define OP_MFFS OPVCC(63,583,0,0) #define OP_MFMSR OPVCC(31,83,0,0) #define OP_MFSPR OPVCC(31,339,0,0) #define OP_MFSR OPVCC(31,595,0,0) #define OP_MFSRIN OPVCC(31,659,0,0) #define OP_MTCRF OPVCC(31,144,0,0) #define OP_MTFSF OPVCC(63,711,0,0) #define OP_MTFSFI OPVCC(63,134,0,0) #define OP_MTMSR OPVCC(31,146,0,0) #define OP_MTMSRD OPVCC(31,178,0,0) #define OP_MTSPR OPVCC(31,467,0,0) #define OP_MTSR OPVCC(31,210,0,0) #define OP_MTSRIN OPVCC(31,242,0,0) #define OP_MULLW OPVCC(31,235,0,0) #define OP_MULLD OPVCC(31,233,0,0) #define OP_OR OPVCC(31,444,0,0) #define OP_ORI OPVCC(24,0,0,0) #define OP_ORIS OPVCC(25,0,0,0) #define OP_RLWINM OPVCC(21,0,0,0) #define OP_SUBF OPVCC(31,40,0,0) #define OP_RLDIC OPVCC(30,4,0,0) #define OP_RLDICR OPVCC(30,2,0,0) #define OP_RLDICL OPVCC(30,0,0,0) #define oclass(v) ((v).class-1) long oprrr(int), opirr(int), opload(int), opstore(int), oploadx(int), opstorex(int); /* * 32-bit masks */ int getmask(uchar *m, ulong v) { int i; m[0] = m[1] = 0; if(v != ~0L && v & (1<<31) && v & 1){ /* MB > ME */ if(getmask(m, ~v)){ i = m[0]; m[0] = m[1]+1; m[1] = i-1; return 1; } return 0; } for(i=0; i<32; i++) if(v & (1<<(31-i))){ m[0] = i; do { m[1] = i; } while(++i<32 && (v & (1<<(31-i))) != 0); for(; i<32; i++) if(v & (1<<(31-i))) return 0; return 1; } return 0; } void maskgen(Prog *p, uchar *m, ulong v) { if(!getmask(m, v)) diag("cannot generate mask #%lux\n%P", v, p); } /* * 64-bit masks (rldic etc) */ int getmask64(uchar *m, uvlong v) { int i; m[0] = m[1] = 0; for(i=0; i<64; i++) if(v & ((uvlong)1<<(63-i))){ m[0] = i; do { m[1] = i; } while(++i<64 && (v & ((uvlong)1<<(63-i))) != 0); for(; i<64; i++) if(v & ((uvlong)1<<(63-i))) return 0; return 1; } return 0; } void maskgen64(Prog *p, uchar *m, uvlong v) { if(!getmask64(m, v)) diag("cannot generate mask #%llux\n%P", v, p); } static void reloc(Adr *a, long pc, int sext) { if(a->name == D_EXTERN || a->name == D_STATIC) dynreloc(a->sym, pc, 1, 1, sext); } static ulong loadu32(int r, vlong d) { long v; v = d>>16; if(isuint32(d)) return LOP_IRR(OP_ORIS, r, REGZERO, v); return AOP_IRR(OP_ADDIS, r, REGZERO, v); } int asmout(Prog *p, Optab *o, int aflag) { long o1, o2, o3, o4, o5, v, t; vlong d; Prog *ct; int r, a; uchar mask[2]; o1 = 0; o2 = 0; o3 = 0; o4 = 0; o5 = 0; switch(o->type) { default: if(aflag) return 0; diag("unknown type %d", o->type); if(!debug['a']) prasm(p); break; case 0: /* pseudo ops */ if(aflag) { if(p->link) { if(p->as == ATEXT) { ct = curtext; o2 = autosize; curtext = p; autosize = p->to.offset + 8; o1 = asmout(p->link, oplook(p->link), aflag); curtext = ct; autosize = o2; } else o1 = asmout(p->link, oplook(p->link), aflag); } return o1; } break; case 1: /* mov r1,r2 ==> OR Rs,Rs,Ra */ if(p->to.reg == REGZERO && p->from.type == D_CONST) { v = regoff(&p->from); if(r0iszero && v != 0) { nerrors--; diag("literal operation on R0\n%P", p); } o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v); break; } o1 = LOP_RRR(OP_OR, p->to.reg, p->from.reg, p->from.reg); break; case 2: /* int/cr/fp op Rb,[Ra],Rd */ r = p->reg; if(r == NREG) r = p->to.reg; o1 = AOP_RRR(oprrr(p->as), p->to.reg, r, p->from.reg); break; case 3: /* mov $soreg/addcon/ucon, r ==> addis/addi $i,reg',r */ d = vregoff(&p->from); v = d; r = p->from.reg; if(r == NREG) r = o->param; if(r0iszero && p->to.reg == 0 && (r != 0 || v != 0)) diag("literal operation on R0\n%P", p); a = OP_ADDI; if(o->a1 == C_UCON) { v >>= 16; if(r == REGZERO && isuint32(d)){ o1 = LOP_IRR(OP_ORIS, p->to.reg, REGZERO, v); break; } a = OP_ADDIS; } o1 = AOP_IRR(a, p->to.reg, r, v); break; case 4: /* add/mul $scon,[r1],r2 */ v = regoff(&p->from); r = p->reg; if(r == NREG) r = p->to.reg; if(r0iszero && p->to.reg == 0) diag("literal operation on R0\n%P", p); o1 = AOP_IRR(opirr(p->as), p->to.reg, r, v); break; case 5: /* syscall */ if(aflag) return 0; o1 = oprrr(p->as); break; case 6: /* logical op Rb,[Rs,]Ra; no literal */ r = p->reg; if(r == NREG) r = p->to.reg; o1 = LOP_RRR(oprrr(p->as), p->to.reg, r, p->from.reg); break; case 7: /* mov r, soreg ==> stw o(r) */ r = p->to.reg; if(r == NREG) r = o->param; v = regoff(&p->to); if(p->to.type == D_OREG && p->reg != NREG) { if(v) diag("illegal indexed instruction\n%P", p); o1 = AOP_RRR(opstorex(p->as), p->from.reg, p->reg, r); } else o1 = AOP_IRR(opstore(p->as), p->from.reg, r, v); break; case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */ r = p->from.reg; if(r == NREG) r = o->param; v = regoff(&p->from); if(p->from.type == D_OREG && p->reg != NREG) { if(v) diag("illegal indexed instruction\n%P", p); o1 = AOP_RRR(oploadx(p->as), p->to.reg, p->reg, r); } else o1 = AOP_IRR(opload(p->as), p->to.reg, r, v); break; case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */ r = p->from.reg; if(r == NREG) r = o->param; v = regoff(&p->from); if(p->from.type == D_OREG && p->reg != NREG) { if(v) diag("illegal indexed instruction\n%P", p); o1 = AOP_RRR(oploadx(p->as), p->to.reg, p->reg, r); } else o1 = AOP_IRR(opload(p->as), p->to.reg, r, v); o2 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0); break; case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */ r = p->reg; if(r == NREG) r = p->to.reg; o1 = AOP_RRR(oprrr(p->as), p->to.reg, p->from.reg, r); break; case 11: /* br/bl lbra */ if(aflag) return 0; v = 0; if(p->cond == UP){ if(p->to.sym->type != SUNDEF) diag("bad branch sym type"); v = (ulong)p->to.sym->value >> (Roffset-2); dynreloc(p->to.sym, p->pc, 0, 0, 0); } else if(p->cond) v = p->cond->pc - p->pc; if(v & 03) { diag("odd branch target address\n%P", p); v &= ~03; } if(v < -(1L<<25) || v >= (1L<<24)) diag("branch too far\n%P", p); o1 = OP_BR(opirr(p->as), v, 0); break; case 12: /* movb r,r (extsb); movw r,r (extsw) */ if(p->to.reg == REGZERO && p->from.type == D_CONST) { v = regoff(&p->from); if(r0iszero && v != 0) { nerrors--; diag("literal operation on R0\n%P", p); } o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, v); break; } if(p->as == AMOVW) o1 = LOP_RRR(OP_EXTSW, p->to.reg, p->from.reg, 0); else o1 = LOP_RRR(OP_EXTSB, p->to.reg, p->from.reg, 0); break; case 13: /* mov[bhw]z r,r; uses rlwinm not andi. to avoid changing CC */ if(p->as == AMOVBZ) o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 24, 31); else if(p->as == AMOVH) o1 = LOP_RRR(OP_EXTSH, p->to.reg, p->from.reg, 0); else if(p->as == AMOVHZ) o1 = OP_RLW(OP_RLWINM, p->to.reg, p->from.reg, 0, 16, 31); else if(p->as == AMOVWZ) o1 = OP_RLW(OP_RLDIC, p->to.reg, p->from.reg, 0, 0, 0) | (1<<5); /* MB=32 */ else diag("internal: bad mov[bhw]z\n%P", p); break; case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */ r = p->reg; if(r == NREG) r = p->to.reg; d = vregoff(&p->from3); maskgen64(p, mask, d); switch(p->as){ case ARLDCL: case ARLDCLCC: a = mask[0]; /* MB */ if(mask[1] != 63) diag("invalid mask for rotate: %llux (end != bit 63)\n%P", d, p); break; case ARLDCR: case ARLDCRCC: a = mask[1]; /* ME */ if(mask[0] != 0) diag("invalid mask for rotate: %llux (start != 0)\n%P", d, p); break; default: diag("unexpected op in rldc case\n%P", p); a = 0; } o1 = LOP_RRR(oprrr(p->as), p->to.reg, r, p->from.reg); o1 |= (a&31L)<<6; if(a & 0x20) o1 |= 1<<5; /* mb[5] is top bit */ break; case 17: /* bc bo,bi,lbra (same for now) */ case 16: /* bc bo,bi,sbra */ if(aflag) return 0; a = 0; if(p->from.type == D_CONST) a = regoff(&p->from); r = p->reg; if(r == NREG) r = 0; v = 0; if(p->cond) v = p->cond->pc - p->pc; if(v & 03) { diag("odd branch target address\n%P", p); v &= ~03; } if(v < -(1L<<16) || v >= (1L<<15)) diag("branch too far\n%P", p); o1 = OP_BC(opirr(p->as), a, r, v, 0); break; case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */ if(aflag) return 0; if(p->as == ABC || p->as == ABCL) v = regoff(&p->to)&31L; else v = 20; /* unconditional */ r = p->reg; if(r == NREG) r = 0; o1 = AOP_RRR(OP_MTSPR, p->to.reg, 0, 0) | ((D_LR&0x1f)<<16) | (((D_LR>>5)&0x1f)<<11); o2 = OPVCC(19, 16, 0, 0); if(p->as == ABL || p->as == ABCL) o2 |= 1; o2 = OP_BCR(o2, v, r); break; case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */ if(aflag) return 0; if(p->as == ABC || p->as == ABCL) v = regoff(&p->from)&31L; else v = 20; /* unconditional */ r = p->reg; if(r == NREG) r = 0; switch(oclass(p->to)) { case C_CTR: o1 = OPVCC(19, 528, 0, 0); break; case C_LR: o1 = OPVCC(19, 16, 0, 0); break; default: diag("bad optab entry (18): %d\n%P", p->to.class, p); v = 0; } if(p->as == ABL || p->as == ABCL) o1 |= 1; o1 = OP_BCR(o1, v, r); break; case 19: /* mov $lcon,r ==> cau+or */ d = vregoff(&p->from); o1 = loadu32(p->to.reg, d); o2 = LOP_IRR(OP_ORI, p->to.reg, p->to.reg, (long)d); if(dlm) reloc(&p->from, p->pc, 0); break; case 20: /* add $ucon,,r */ v = regoff(&p->from); r = p->reg; if(r == NREG) r = p->to.reg; if(p->as == AADD && (!r0iszero && p->reg == 0 || r0iszero && p->to.reg == 0)) diag("literal operation on R0\n%P", p); o1 = AOP_IRR(opirr(p->as+AEND), p->to.reg, r, v>>16); break; case 22: /* add $lcon,r1,r2 ==> cau+or+add */ /* could do add/sub more efficiently */ if(p->to.reg == REGTMP || p->reg == REGTMP) diag("cant synthesize large constant\n%P", p); d = vregoff(&p->from); o1 = loadu32(REGTMP, d); o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (long)d); r = p->reg; if(r == NREG) r = p->to.reg; o3 = AOP_RRR(oprrr(p->as), p->to.reg, REGTMP, r); if(dlm) reloc(&p->from, p->pc, 0); break; case 23: /* and $lcon,r1,r2 ==> cau+or+and */ /* masks could be done using rlnm etc. */ if(p->to.reg == REGTMP || p->reg == REGTMP) diag("cant synthesize large constant\n%P", p); d = vregoff(&p->from); o1 = loadu32(REGTMP, d); o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, (long)d); r = p->reg; if(r == NREG) r = p->to.reg; o3 = LOP_RRR(oprrr(p->as), p->to.reg, REGTMP, r); if(dlm) reloc(&p->from, p->pc, 0); break; /*24*/ case 25: /* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */ v = regoff(&p->from); if(v < 0) v = 0; else if(v > 63) v = 63; r = p->reg; if(r == NREG) r = p->to.reg; switch(p->as){ case ASLD: case ASLDCC: a = 63-v; o1 = OP_RLDICR; break; case ASRD: case ASRDCC: a = v; v = 64-v; o1 = OP_RLDICL; break;