📄 asmout.c
字号:
#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_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_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_OR OPVCC(31,444,0,0)#define OP_ORI OPVCC(24,0,0,0)#define OP_RLWINM OPVCC(21,0,0,0)#define OP_SUBF OPVCC(31,40,0,0)#define oclass(v) ((v).class-1)long oprrr(int), opirr(int), opload(int), opstore(int), oploadx(int), opstorex(int);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);}static voidreloc(Adr *a, long pc, int sext){ if(a->name == D_EXTERN || a->name == D_STATIC) dynreloc(a->sym, pc, 1, 1, sext);} intasmout(Prog *p, Optab *o, int aflag){ long o1, o2, o3, o4, o5, v, t; 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 + 4; 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 */ v = regoff(&p->from); r = p->from.reg; if(r == NREG) r = o->param; a = OP_ADDI; if(o->a1 == C_UCON) { a = OP_ADDIS; v >>= 16; } if(r0iszero && p->to.reg == 0 && (r != 0 || v != 0)) diag("literal operation on R0\n%P", p); 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<<25)) diag("branch too far\n%P", p); o1 = OP_BR(opirr(p->as), v, 0); break; case 12: /* movb r,r (signed); extsb is on PowerPC but not POWER */ o1 = LOP_RRR(OP_EXTSB, p->to.reg, p->from.reg, 0); break; case 13: /* mov[bh]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 diag("internal: bad mov[bh]z\n%P", p); break;/*14 */ 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<<16)) 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 */ v = regoff(&p->from); o1 = AOP_IRR(OP_ADDIS, p->to.reg, REGZERO, v>>16); o2 = LOP_IRR(OP_ORI, p->to.reg, p->to.reg, v); 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 */ v = regoff(&p->from); if(p->to.reg == REGTMP || p->reg == REGTMP) diag("cant synthesize large constant\n%P", p); o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16); o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v); 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. */ v = regoff(&p->from); if(p->to.reg == REGTMP || p->reg == REGTMP) diag("cant synthesize large constant\n%P", p); o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16); o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v); 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 26: /* mov $lsext/auto/oreg,,r2 ==> cau+add */ v = regoff(&p->from); if(v & 0x8000L) v += 0x10000L; if(p->to.reg == REGTMP) diag("can't synthesize large constant\n%P", p); r = p->from.reg; if(r == NREG) r = o->param; o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16); o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, v); break; case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */ v = regoff(&p->from3); r = p->from.reg; o1 = AOP_IRR(opirr(p->as), p->to.reg, r, v); break; case 28: /* subc r1,$lcon,r2 ==> cau+or+subfc */ v = regoff(&p->from3); if(p->to.reg == REGTMP || p->from.reg == REGTMP) diag("can't synthesize large constant\n%P", p); o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, v>>16); o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, v); o3 = AOP_RRR(oprrr(p->as), p->to.reg, p->from.reg, REGTMP); if(dlm) reloc(&p->from3, p->pc, 0); break;/*29, 30, 31 */ case 32: /* fmul frc,fra,frd */ r = p->reg; if(r == NREG) r = p->to.reg; o1 = AOP_RRR(oprrr(p->as), p->to.reg, r, 0)|((p->from.reg&31L)<<6); break; case 33: /* fabs [frb,]frd; fmr. frb,frd */ r = p->from.reg; if(oclass(p->from) == C_NONE) r = p->to.reg; o1 = AOP_RRR(oprrr(p->as), p->to.reg, 0, r); break; case 34: /* FMADDx fra,frb,frc,frd (d=a*b+c) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -