From: Cerion Armour-Brown Date: Wed, 9 Feb 2005 17:29:49 +0000 (+0000) Subject: A whole bunch more ppc32 backend code X-Git-Tag: svn/VALGRIND_3_0_1^2~458 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=db1e84af4411e4ca36fddfd247d21d9d03395246;p=thirdparty%2Fvalgrind.git A whole bunch more ppc32 backend code - just the isel stuff so far, no assembly git-svn-id: svn://svn.valgrind.org/vex/trunk@876 --- diff --git a/VEX/priv/host-ppc32/hdefs.c b/VEX/priv/host-ppc32/hdefs.c index d459176999..667177e97f 100644 --- a/VEX/priv/host-ppc32/hdefs.c +++ b/VEX/priv/host-ppc32/hdefs.c @@ -140,82 +140,109 @@ HReg hregPPC32_FPR29 ( void ) { return mkHReg(29, HRcFlt64, False); } HReg hregPPC32_FPR30 ( void ) { return mkHReg(30, HRcFlt64, False); } HReg hregPPC32_FPR31 ( void ) { return mkHReg(31, HRcFlt64, False); } - void getAllocableRegs_PPC32 ( Int* nregs, HReg** arr ) { - *nregs = 64; + *nregs = 60; *arr = LibVEX_Alloc(*nregs * sizeof(HReg)); (*arr)[ 0] = hregPPC32_GPR0(); - (*arr)[ 1] = hregPPC32_GPR1(); - (*arr)[ 2] = hregPPC32_GPR2(); - (*arr)[ 3] = hregPPC32_GPR3(); - (*arr)[ 4] = hregPPC32_GPR4(); - (*arr)[ 5] = hregPPC32_GPR5(); - (*arr)[ 6] = hregPPC32_GPR6(); - (*arr)[ 7] = hregPPC32_GPR7(); - (*arr)[ 8] = hregPPC32_GPR8(); - (*arr)[ 9] = hregPPC32_GPR9(); - (*arr)[10] = hregPPC32_GPR10(); - (*arr)[11] = hregPPC32_GPR11(); - (*arr)[12] = hregPPC32_GPR12(); - (*arr)[13] = hregPPC32_GPR13(); - (*arr)[14] = hregPPC32_GPR14(); - (*arr)[15] = hregPPC32_GPR15(); - (*arr)[16] = hregPPC32_GPR16(); - (*arr)[17] = hregPPC32_GPR17(); - (*arr)[18] = hregPPC32_GPR18(); - (*arr)[19] = hregPPC32_GPR19(); - (*arr)[20] = hregPPC32_GPR20(); - (*arr)[21] = hregPPC32_GPR21(); - (*arr)[22] = hregPPC32_GPR22(); - (*arr)[23] = hregPPC32_GPR23(); - (*arr)[24] = hregPPC32_GPR24(); - (*arr)[25] = hregPPC32_GPR25(); - (*arr)[26] = hregPPC32_GPR26(); - (*arr)[27] = hregPPC32_GPR27(); - (*arr)[28] = hregPPC32_GPR28(); - (*arr)[29] = hregPPC32_GPR29(); - (*arr)[30] = hregPPC32_GPR30(); - (*arr)[31] = hregPPC32_GPR31(); - - (*arr)[32] = hregPPC32_FPR0(); - (*arr)[33] = hregPPC32_FPR1(); - (*arr)[34] = hregPPC32_FPR2(); - (*arr)[35] = hregPPC32_FPR3(); - (*arr)[36] = hregPPC32_FPR4(); - (*arr)[37] = hregPPC32_FPR5(); - (*arr)[38] = hregPPC32_FPR6(); - (*arr)[39] = hregPPC32_FPR7(); - (*arr)[40] = hregPPC32_FPR8(); - (*arr)[41] = hregPPC32_FPR9(); - (*arr)[42] = hregPPC32_FPR10(); - (*arr)[43] = hregPPC32_FPR11(); - (*arr)[44] = hregPPC32_FPR12(); - (*arr)[45] = hregPPC32_FPR13(); - (*arr)[46] = hregPPC32_FPR14(); - (*arr)[47] = hregPPC32_FPR15(); - (*arr)[48] = hregPPC32_FPR16(); - (*arr)[49] = hregPPC32_FPR17(); - (*arr)[50] = hregPPC32_FPR18(); - (*arr)[51] = hregPPC32_FPR19(); - (*arr)[52] = hregPPC32_FPR20(); - (*arr)[53] = hregPPC32_FPR21(); - (*arr)[54] = hregPPC32_FPR22(); - (*arr)[55] = hregPPC32_FPR23(); - (*arr)[56] = hregPPC32_FPR24(); - (*arr)[57] = hregPPC32_FPR25(); - (*arr)[58] = hregPPC32_FPR26(); - (*arr)[59] = hregPPC32_FPR27(); - (*arr)[60] = hregPPC32_FPR28(); - (*arr)[61] = hregPPC32_FPR29(); - (*arr)[62] = hregPPC32_FPR30(); - (*arr)[63] = hregPPC32_FPR31(); + // GPR1 = stack pointer + // GPR2 = TOC pointer + (*arr)[ 1] = hregPPC32_GPR3(); + (*arr)[ 2] = hregPPC32_GPR4(); + (*arr)[ 3] = hregPPC32_GPR5(); + (*arr)[ 4] = hregPPC32_GPR6(); + (*arr)[ 5] = hregPPC32_GPR7(); + (*arr)[ 6] = hregPPC32_GPR8(); + (*arr)[ 7] = hregPPC32_GPR9(); + (*arr)[ 8] = hregPPC32_GPR10(); + (*arr)[ 9] = hregPPC32_GPR11(); + (*arr)[10] = hregPPC32_GPR12(); + // GPR13 = thread specific pointer + (*arr)[11] = hregPPC32_GPR14(); + (*arr)[12] = hregPPC32_GPR15(); + (*arr)[13] = hregPPC32_GPR16(); + (*arr)[14] = hregPPC32_GPR17(); + (*arr)[15] = hregPPC32_GPR18(); + (*arr)[16] = hregPPC32_GPR19(); + (*arr)[17] = hregPPC32_GPR20(); + (*arr)[18] = hregPPC32_GPR21(); + (*arr)[19] = hregPPC32_GPR22(); + (*arr)[20] = hregPPC32_GPR23(); + (*arr)[21] = hregPPC32_GPR24(); + (*arr)[22] = hregPPC32_GPR25(); + (*arr)[23] = hregPPC32_GPR26(); + (*arr)[24] = hregPPC32_GPR27(); + (*arr)[25] = hregPPC32_GPR28(); + (*arr)[26] = hregPPC32_GPR29(); + (*arr)[27] = hregPPC32_GPR30(); + // GPR31 = GuestStatePtr + + (*arr)[28] = hregPPC32_FPR0(); + (*arr)[29] = hregPPC32_FPR1(); + (*arr)[30] = hregPPC32_FPR2(); + (*arr)[31] = hregPPC32_FPR3(); + (*arr)[32] = hregPPC32_FPR4(); + (*arr)[33] = hregPPC32_FPR5(); + (*arr)[34] = hregPPC32_FPR6(); + (*arr)[35] = hregPPC32_FPR7(); + (*arr)[36] = hregPPC32_FPR8(); + (*arr)[37] = hregPPC32_FPR9(); + (*arr)[38] = hregPPC32_FPR10(); + (*arr)[39] = hregPPC32_FPR11(); + (*arr)[40] = hregPPC32_FPR12(); + (*arr)[41] = hregPPC32_FPR13(); + (*arr)[42] = hregPPC32_FPR14(); + (*arr)[43] = hregPPC32_FPR15(); + (*arr)[44] = hregPPC32_FPR16(); + (*arr)[45] = hregPPC32_FPR17(); + (*arr)[46] = hregPPC32_FPR18(); + (*arr)[47] = hregPPC32_FPR19(); + (*arr)[48] = hregPPC32_FPR20(); + (*arr)[49] = hregPPC32_FPR21(); + (*arr)[50] = hregPPC32_FPR22(); + (*arr)[51] = hregPPC32_FPR23(); + (*arr)[52] = hregPPC32_FPR24(); + (*arr)[53] = hregPPC32_FPR25(); + (*arr)[54] = hregPPC32_FPR26(); + (*arr)[55] = hregPPC32_FPR27(); + (*arr)[56] = hregPPC32_FPR28(); + (*arr)[57] = hregPPC32_FPR29(); + (*arr)[58] = hregPPC32_FPR30(); + (*arr)[59] = hregPPC32_FPR31(); +} + + +/* --------- Condition codes, Intel encoding. --------- */ + +HChar* showPPC32CondCode ( PPC32CondCode cond ) +{ + switch (cond) { + case Pcc_O: return "o"; + case Pcc_NO: return "no"; + case Pcc_B: return "b"; + case Pcc_NB: return "nb"; + case Pcc_Z: return "z"; + case Pcc_NZ: return "nz"; + case Pcc_BE: return "be"; + case Pcc_NBE: return "nbe"; + case Pcc_S: return "s"; + case Pcc_NS: return "ns"; + case Pcc_P: return "p"; + case Pcc_NP: return "np"; + case Pcc_L: return "l"; + case Pcc_NL: return "nl"; + case Pcc_LE: return "le"; + case Pcc_NLE: return "nle"; + case Pcc_ALWAYS: return "ALWAYS"; + default: vpanic("ppPPC32CondCode"); + } } /* --------- PPCAMode: memory address expressions. --------- */ PPC32AMode* PPC32AMode_IR ( UInt idx, HReg base ) { + // CAB: Rem assert immediate PPC32AMode* am = LibVEX_Alloc(sizeof(PPC32AMode)); am->tag = Pam_IR; am->Pam.IR.base = base; @@ -261,7 +288,6 @@ void ppPPC32AMode ( PPC32AMode* am ) { } } -#if 0 static void addRegUsage_PPC32AMode ( HRegUsage* u, PPC32AMode* am ) { switch (am->tag) { case Pam_IR: @@ -275,9 +301,7 @@ static void addRegUsage_PPC32AMode ( HRegUsage* u, PPC32AMode* am ) { vpanic("addRegUsage_PPC32AMode"); } } -#endif -#if 0 static void mapRegs_PPC32AMode ( HRegRemap* m, PPC32AMode* am ) { switch (am->tag) { case Pam_IR: @@ -291,11 +315,11 @@ static void mapRegs_PPC32AMode ( HRegRemap* m, PPC32AMode* am ) { vpanic("mapRegs_PPC32AMode"); } } -#endif /* --------- Operand, which can be reg or immediate only. --------- */ PPC32RI* PPC32RI_Imm ( UInt imm32 ) { + // CAB: Rem assert immediate PPC32RI* op = LibVEX_Alloc(sizeof(PPC32RI)); op->tag = Pri_Imm; op->Pri.Imm.imm32 = imm32; @@ -358,13 +382,13 @@ static void mapRegs_PPC32RI ( HRegRemap* m, PPC32RI* op ) { //.. } //.. } -//.. HChar* showX86UnaryOp ( X86UnaryOp op ) { -//.. switch (op) { -//.. case Xun_NOT: return "not"; -//.. case Xun_NEG: return "neg"; -//.. default: vpanic("showX86UnaryOp"); -//.. } -//.. } +HChar* showPPC32UnaryOp ( PPC32UnaryOp op ) { + switch (op) { + case Pun_NOT: return "not"; + case Pun_NEG: return "neg"; + default: vpanic("showPPC32UnaryOp"); + } +} HChar* showPPC32AluOp ( PPC32AluOp op ) { switch (op) { @@ -434,20 +458,20 @@ PPC32Instr* PPC32Instr_Sh32 ( PPC32ShiftOp op, HReg dst, HReg src, PPC32RI* shft i->Pin.Sh32.shft = shft; return i; } -//.. X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst ) { -//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); -//.. i->tag = Xin_Test32; -//.. i->Xin.Test32.src = src; -//.. i->Xin.Test32.dst = dst; -//.. return i; -//.. } -//.. X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst ) { -//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); -//.. i->tag = Xin_Unary32; -//.. i->Xin.Unary32.op = op; -//.. i->Xin.Unary32.dst = dst; -//.. return i; -//.. } +PPC32Instr* PPC32Instr_Test32 ( HReg dst, PPC32RI* src ) { + PPC32Instr* i = LibVEX_Alloc(sizeof(PPC32Instr)); + i->tag = Pin_Test32; + i->Pin.Test32.dst = dst; + i->Pin.Test32.src = src; + return i; +} +PPC32Instr* PPC32Instr_Unary32 ( PPC32UnaryOp op, PPC32RI* dst ) { + PPC32Instr* i = LibVEX_Alloc(sizeof(PPC32Instr)); + i->tag = Pin_Unary32; + i->Pin.Unary32.op = op; + i->Pin.Unary32.dst = dst; + return i; +} //.. X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz ssz , X86RM* src ) { //.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); //.. i->tag = Xin_MulL; @@ -480,23 +504,23 @@ PPC32Instr* PPC32Instr_Sh32 ( PPC32ShiftOp op, HReg dst, HReg src, PPC32RI* shft //.. i->Xin.Push.src = src; //.. return i; //.. } -//.. X86Instr* X86Instr_Call ( X86CondCode cond, Addr32 target, Int regparms ) { -//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); -//.. i->tag = Xin_Call; -//.. i->Xin.Call.cond = cond; -//.. i->Xin.Call.target = target; -//.. i->Xin.Call.regparms = regparms; -//.. vassert(regparms >= 0 && regparms <= 3); -//.. return i; -//.. } -//.. X86Instr* X86Instr_Goto ( IRJumpKind jk, X86CondCode cond, X86RI* dst ) { -//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); -//.. i->tag = Xin_Goto; -//.. i->Xin.Goto.cond = cond; -//.. i->Xin.Goto.dst = dst; -//.. i->Xin.Goto.jk = jk; -//.. return i; -//.. } +PPC32Instr* PPC32Instr_Call ( PPC32CondCode cond, Addr32 target, Int regparms ) { + PPC32Instr* i = LibVEX_Alloc(sizeof(PPC32Instr)); + i->tag = Pin_Call; + i->Pin.Call.cond = cond; + i->Pin.Call.target = target; + i->Pin.Call.regparms = regparms; + vassert(regparms >= 0 && regparms < PPC32_N_REGPARMS); + return i; +} +PPC32Instr* PPC32Instr_Goto ( IRJumpKind jk, PPC32CondCode cond, PPC32RI* dst ) { + PPC32Instr* i = LibVEX_Alloc(sizeof(PPC32Instr)); + i->tag = Pin_Goto; + i->Pin.Goto.cond = cond; + i->Pin.Goto.dst = dst; + i->Pin.Goto.jk = jk; + return i; +} //.. X86Instr* X86Instr_CMov32 ( X86CondCode cond, X86RM* src, HReg dst ) { //.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); //.. i->tag = Xin_CMov32; @@ -506,15 +530,15 @@ PPC32Instr* PPC32Instr_Sh32 ( PPC32ShiftOp op, HReg dst, HReg src, PPC32RI* shft //.. vassert(cond != Xcc_ALWAYS); //.. return i; //.. } -PPC32Instr* PPC32Instr_LoadEX ( UChar szSmall, Bool syned, +PPC32Instr* PPC32Instr_LoadEX ( UChar sz, Bool syned, HReg dst, PPC32AMode* src ) { - PPC32Instr* i = LibVEX_Alloc(sizeof(PPC32Instr)); - i->tag = Pin_LoadEX; - i->Pin.LoadEX.szSmall = szSmall; - i->Pin.LoadEX.syned = syned; - i->Pin.LoadEX.src = src; - i->Pin.LoadEX.dst = dst; - vassert(szSmall == 1 || szSmall == 2 || szSmall == 4); + PPC32Instr* i = LibVEX_Alloc(sizeof(PPC32Instr)); + i->tag = Pin_LoadEX; + i->Pin.LoadEX.sz = sz; + i->Pin.LoadEX.syned = syned; + i->Pin.LoadEX.src = src; + i->Pin.LoadEX.dst = dst; + vassert(sz == 1 || sz == 2 || sz == 4); return i; } PPC32Instr* PPC32Instr_Store ( UChar sz, PPC32AMode* dst, HReg src ) { @@ -631,12 +655,29 @@ void ppPPC32Instr ( PPC32Instr* i ) { switch (i->tag) { case Pin_Alu32: - vex_printf("%sl ", showPPC32AluOp(i->Pin.Alu32.op)); - ppHRegPPC32(i->Pin.Alu32.dst); - vex_printf(","); - ppHRegPPC32(i->Pin.Alu32.src1); - vex_printf(","); - ppPPC32RI(i->Pin.Alu32.src2); + if (i->Pin.Alu32.op == Palu_OR && // or Rd,Rs,Rs == mr Rd,Rs + i->Pin.Alu32.src2->tag == Pri_Reg && + i->Pin.Alu32.src2->Pri.Reg.reg == i->Pin.Alu32.src1) { + vex_printf("mr "); + ppHRegPPC32(i->Pin.Alu32.dst); + vex_printf(","); + ppHRegPPC32(i->Pin.Alu32.src1); + return; + } + if (i->Pin.Alu32.op == Palu_ADD && // add Rd,R0,Rs == li Rd,Rs + i->Pin.Alu32.src1 == hregPPC32_GPR0()) { + vex_printf("li "); + ppHRegPPC32(i->Pin.Alu32.dst); + vex_printf(","); + ppPPC32RI(i->Pin.Alu32.src2); + return; + } + vex_printf("%s ", showPPC32AluOp(i->Pin.Alu32.op)); + ppHRegPPC32(i->Pin.Alu32.dst); + vex_printf(","); + ppHRegPPC32(i->Pin.Alu32.src1); + vex_printf(","); + ppPPC32RI(i->Pin.Alu32.src2); return; case Pin_Sh32: vex_printf("%sl ", showPPC32ShiftOp(i->Pin.Sh32.op)); @@ -646,12 +687,12 @@ void ppPPC32Instr ( PPC32Instr* i ) vex_printf(","); ppPPC32RI(i->Pin.Sh32.shft); return; -//.. case Xin_Test32: -//.. vex_printf("testl "); -//.. ppX86RI(i->Xin.Test32.src); -//.. vex_printf(","); -//.. ppX86RM(i->Xin.Test32.dst); -//.. return; + case Pin_Test32: + vex_printf("testl "); + ppHRegPPC32(i->Pin.Test32.dst); + vex_printf(","); + ppPPC32RI(i->Pin.Test32.src); + return; //.. case Xin_Unary32: //.. vex_printf("%sl ", showX86UnaryOp(i->Xin.Unary32.op)); //.. ppX86RM(i->Xin.Unary32.dst); @@ -682,30 +723,33 @@ void ppPPC32Instr ( PPC32Instr* i ) //.. vex_printf("pushl "); //.. ppX86RMI(i->Xin.Push.src); //.. return; -//.. case Xin_Call: -//.. vex_printf("call%s[%d] ", -//.. i->Xin.Call.cond==Xcc_ALWAYS -//.. ? "" : showX86CondCode(i->Xin.Call.cond), -//.. i->Xin.Call.regparms); -//.. vex_printf("0x%x", i->Xin.Call.target); -//.. break; -//.. case Xin_Goto: -//.. if (i->Xin.Goto.cond != Xcc_ALWAYS) { -//.. vex_printf("if (%%eflags.%s) { ", -//.. showX86CondCode(i->Xin.Goto.cond)); -//.. } -//.. if (i->Xin.Goto.jk != Ijk_Boring) { -//.. vex_printf("movl $"); -//.. ppIRJumpKind(i->Xin.Goto.jk); -//.. vex_printf(",%%ebp ; "); -//.. } -//.. vex_printf("movl "); -//.. ppX86RI(i->Xin.Goto.dst); -//.. vex_printf(",%%eax ; ret"); -//.. if (i->Xin.Goto.cond != Xcc_ALWAYS) { -//.. vex_printf(" }"); -//.. } -//.. return; + case Pin_Call: +// CAB: not 'bc' ? + vex_printf("call%s[%d] ", + i->Pin.Call.cond==Pcc_ALWAYS + ? "" : showPPC32CondCode(i->Pin.Call.cond), + i->Pin.Call.regparms); + vex_printf("0x%x", i->Pin.Call.target); + break; + case Pin_Goto: + if (i->Pin.Goto.cond != Pcc_ALWAYS) { + vex_printf("if (%%eflags.%s) { ", + showPPC32CondCode(i->Pin.Goto.cond)); + } + if (i->Pin.Goto.jk != Ijk_Boring) { + vex_printf("movl $"); + ppIRJumpKind(i->Pin.Goto.jk); + vex_printf(",%%r31 ; "); + } +// CAB: what instead of movl ? + vex_printf("movl "); + ppPPC32RI(i->Pin.Goto.dst); +// CAB: eax? + vex_printf(",%%eax ; ret"); + if (i->Pin.Goto.cond != Pcc_ALWAYS) { + vex_printf(" }"); + } + return; //.. case Xin_CMov32: //.. vex_printf("cmov%s ", showX86CondCode(i->Xin.CMov32.cond)); //.. ppX86RM(i->Xin.CMov32.src); @@ -713,17 +757,16 @@ void ppPPC32Instr ( PPC32Instr* i ) //.. ppHRegX86(i->Xin.CMov32.dst); //.. return; case Pin_LoadEX: { - UChar sz = i->Pin.LoadEX.szSmall; + UChar sz = i->Pin.LoadEX.sz; Bool syned = i->Pin.LoadEX.syned; - Bool update = False; // CAB: ? +// CAB: How to get 'update'... ? + Bool update = False; Bool idxd = (i->Pin.LoadEX.src->tag == Pam_IR) ? True : False; - vex_printf("l%c%c%s%s ", - (sz==1) ? 'b' : sz==1 ? 'h' : 'w', + (sz==1) ? 'b' : (sz==2 ? 'h' : 'w'), syned ? 'a' : 'z', update ? "u" : "", idxd ? "x" : "" ); - ppHRegPPC32(i->Pin.LoadEX.dst); vex_printf(","); ppPPC32AMode(i->Pin.LoadEX.src); @@ -731,26 +774,18 @@ void ppPPC32Instr ( PPC32Instr* i ) } case Pin_Store: { UChar sz = i->Pin.Store.sz; - Bool update = False; // CAB: ? +// CAB: How to get 'update'... ? + Bool update = False; Bool idxd = (i->Pin.Store.dst->tag == Pam_IR) ? True : False; - vex_printf("st%c%s%s ", - (sz==1) ? 'b' : sz==1 ? 'h' : 'w', + (sz==1) ? 'b' : (sz==2 ? 'h' : 'w'), update ? "u" : "", idxd ? "x" : "" ); - ppHRegPPC32(i->Pin.Store.src); vex_printf(","); ppPPC32AMode(i->Pin.Store.dst); return; } -#if 0 - vex_printf("mov%c ", i->Xin.Store.sz==1 ? 'b' : 'w'); - ppHRegX86(i->Xin.Store.src); - vex_printf(","); - ppX86AMode(i->Xin.Store.dst); -#endif - return; //.. case Xin_Set32: //.. vex_printf("setl%s ", showX86CondCode(i->Xin.Set32.cond)); //.. ppHRegX86(i->Xin.Set32.dst); @@ -919,22 +954,20 @@ void getRegUsage_PPC32Instr ( HRegUsage* u, PPC32Instr* i ) return; } addHRegUse(u, HRmWrite, i->Pin.Alu32.dst); - - // CAB: Any circumstance where dst is read & written? +// CAB TODO: Any circumstance where dst is read & written? return; case Pin_Sh32: addHRegUse(u, HRmWrite, i->Pin.Sh32.dst); addHRegUse(u, HRmRead, i->Pin.Sh32.src); addRegUsage_PPC32RI(u, i->Pin.Sh32.shft); - - // CAB: Any circumstance where dst is read & written? +// CAB TODO: Any circumstance where dst is read & written? return; -//.. case Xin_Test32: -//.. addRegUsage_X86RI(u, i->Xin.Test32.src); -//.. addRegUsage_X86RM(u, i->Xin.Test32.dst, HRmRead); -//.. return; + case Pin_Test32: + addHRegUse(u, HRmRead, i->Pin.Test32.dst); + addRegUsage_PPC32RI(u, i->Pin.Test32.src); + return; //.. case Xin_Unary32: //.. addRegUsage_X86RM(u, i->Xin.Unary32.dst, HRmModify); //.. return; @@ -958,55 +991,64 @@ void getRegUsage_PPC32Instr ( HRegUsage* u, PPC32Instr* i ) //.. addRegUsage_X86RMI(u, i->Xin.Push.src); //.. addHRegUse(u, HRmModify, hregX86_ESP()); //.. return; -//.. case Xin_Call: -//.. /* This is a bit subtle. */ -//.. /* First off, claim it trashes all the callee-saved regs */ -//.. /* which I believe to be %eax,%ecx,%edx. */ -//.. addHRegUse(u, HRmWrite, hregX86_EAX()); -//.. addHRegUse(u, HRmWrite, hregX86_ECX()); -//.. addHRegUse(u, HRmWrite, hregX86_EDX()); -//.. /* Now we have to state any parameter-carrying registers -//.. which might be read. This depends on the regparmness. */ -//.. switch (i->Xin.Call.regparms) { -//.. case 3: addHRegUse(u, HRmRead, hregX86_ECX()); /*fallthru*/ -//.. case 2: addHRegUse(u, HRmRead, hregX86_EDX()); /*fallthru*/ -//.. case 1: addHRegUse(u, HRmRead, hregX86_EAX()); break; -//.. case 0: break; -//.. default: vpanic("getRegUsage_X86Instr:Call:regparms"); -//.. } -//.. /* Finally, there is the issue that the insn trashes a -//.. register because the literal target address has to be -//.. loaded into a register. Fortunately, for the 0/1/2 -//.. regparm case, we can use EAX, EDX and ECX respectively, so -//.. this does not cause any further damage. For the 3-regparm -//.. case, we'll have to choose another register arbitrarily -- -//.. since A, D and C are used for parameters -- and so we might -//.. as well choose EDI. */ -//.. if (i->Xin.Call.regparms == 3) -//.. addHRegUse(u, HRmWrite, hregX86_EDI()); -//.. /* Upshot of this is that the assembler really must observe -//.. the here-stated convention of which register to use as an -//.. address temporary, depending on the regparmness: 0==EAX, -//.. 1==EDX, 2==ECX, 3==EDI. */ -//.. return; -//.. case Xin_Goto: -//.. addRegUsage_X86RI(u, i->Xin.Goto.dst); -//.. addHRegUse(u, HRmWrite, hregX86_EAX()); -//.. if (i->Xin.Goto.jk != Ijk_Boring) -//.. addHRegUse(u, HRmWrite, hregX86_EBP()); -//.. return; + case Pin_Call: + /* This is a bit subtle. */ + /* First off, claim it trashes all the caller-saved regs + which fall within the register allocator's jurisdiction. + These I believe to be: r0,r3:12 + */ + addHRegUse(u, HRmWrite, hregPPC32_GPR0()); + addHRegUse(u, HRmWrite, hregPPC32_GPR3()); + addHRegUse(u, HRmWrite, hregPPC32_GPR4()); + addHRegUse(u, HRmWrite, hregPPC32_GPR5()); + addHRegUse(u, HRmWrite, hregPPC32_GPR6()); + addHRegUse(u, HRmWrite, hregPPC32_GPR7()); + addHRegUse(u, HRmWrite, hregPPC32_GPR8()); + addHRegUse(u, HRmWrite, hregPPC32_GPR9()); + addHRegUse(u, HRmWrite, hregPPC32_GPR10()); + addHRegUse(u, HRmWrite, hregPPC32_GPR11()); + addHRegUse(u, HRmWrite, hregPPC32_GPR12()); + + /* Now we have to state any parameter-carrying registers + which might be read. This depends on the regparmness. */ + switch (i->Pin.Call.regparms) { + case 8: addHRegUse(u, HRmRead, hregPPC32_GPR10()); /*fallthru*/ + case 7: addHRegUse(u, HRmRead, hregPPC32_GPR9() ); /*fallthru*/ + case 6: addHRegUse(u, HRmRead, hregPPC32_GPR8() ); /*fallthru*/ + case 5: addHRegUse(u, HRmRead, hregPPC32_GPR7() ); /*fallthru*/ + case 4: addHRegUse(u, HRmRead, hregPPC32_GPR6() ); /*fallthru*/ + case 3: addHRegUse(u, HRmRead, hregPPC32_GPR5() ); /*fallthru*/ + case 2: addHRegUse(u, HRmRead, hregPPC32_GPR4() ); /*fallthru*/ + case 1: addHRegUse(u, HRmRead, hregPPC32_GPR3() ); /*fallthru*/ + case 0: break; + default: vpanic("getRegUsage_PPC32Instr:Call:regparms"); + } + /* Finally, there is the issue that the insn trashes a + register because the literal target address has to be + loaded into a register. Fortunately, ?CAB? is stated in the + ABI as a scratch register, and so seems a suitable victim. */ + addHRegUse(u, HRmWrite, hregPPC32_GPR3()); + /* Upshot of this is that the assembler really must use ?CAB?, + and no other, as a destination temporary. */ + return; + case Pin_Goto: + addRegUsage_PPC32RI(u, i->Pin.Goto.dst); + addHRegUse(u, HRmWrite, hregPPC32_GPR4()); + if (i->Pin.Goto.jk != Ijk_Boring) + addHRegUse(u, HRmWrite, GuestStatePtr); + return; //.. case Xin_CMov32: //.. addRegUsage_X86RM(u, i->Xin.CMov32.src, HRmRead); //.. addHRegUse(u, HRmModify, i->Xin.CMov32.dst); //.. return; -//.. case Xin_LoadEX: -//.. addRegUsage_X86AMode(u, i->Xin.LoadEX.src); -//.. addHRegUse(u, HRmWrite, i->Xin.LoadEX.dst); -//.. return; -//.. case Xin_Store: -//.. addHRegUse(u, HRmRead, i->Xin.Store.src); -//.. addRegUsage_X86AMode(u, i->Xin.Store.dst); -//.. return; + case Pin_LoadEX: + addRegUsage_PPC32AMode(u, i->Pin.LoadEX.src); + addHRegUse(u, HRmWrite, i->Pin.LoadEX.dst); + return; + case Pin_Store: + addHRegUse(u, HRmRead, i->Pin.Store.src); + addRegUsage_PPC32AMode(u, i->Pin.Store.dst); + return; //.. case Xin_Set32: //.. addHRegUse(u, HRmWrite, i->Xin.Set32.dst); //.. return; @@ -1149,10 +1191,10 @@ void mapRegs_PPC32Instr (HRegRemap* m, PPC32Instr* i) mapReg(m, &i->Pin.Sh32.src); mapRegs_PPC32RI(m, i->Pin.Sh32.shft); return; -//.. case Xin_Test32: -//.. mapRegs_X86RI(m, i->Xin.Test32.src); -//.. mapRegs_X86RM(m, i->Xin.Test32.dst); -//.. return; + case Pin_Test32: + mapReg(m, &i->Pin.Test32.dst); + mapRegs_PPC32RI(m, i->Pin.Test32.src); + return; //.. case Xin_Unary32: //.. mapRegs_X86RM(m, i->Xin.Unary32.dst); //.. return; @@ -1169,23 +1211,23 @@ void mapRegs_PPC32Instr (HRegRemap* m, PPC32Instr* i) //.. case Xin_Push: //.. mapRegs_X86RMI(m, i->Xin.Push.src); //.. return; -//.. case Xin_Call: -//.. return; -//.. case Xin_Goto: -//.. mapRegs_X86RI(m, i->Xin.Goto.dst); -//.. return; + case Pin_Call: + return; + case Pin_Goto: + mapRegs_PPC32RI(m, i->Pin.Goto.dst); + return; //.. case Xin_CMov32: //.. mapRegs_X86RM(m, i->Xin.CMov32.src); //.. mapReg(m, &i->Xin.CMov32.dst); //.. return; -//.. case Xin_LoadEX: -//.. mapRegs_X86AMode(m, i->Xin.LoadEX.src); -//.. mapReg(m, &i->Xin.LoadEX.dst); -//.. return; -//.. case Xin_Store: -//.. mapReg(m, &i->Xin.Store.src); -//.. mapRegs_X86AMode(m, i->Xin.Store.dst); -//.. return; + case Pin_LoadEX: + mapRegs_PPC32AMode(m, i->Pin.LoadEX.src); + mapReg(m, &i->Pin.LoadEX.dst); + return; + case Pin_Store: + mapReg(m, &i->Pin.Store.src); + mapRegs_PPC32AMode(m, i->Pin.Store.dst); + return; //.. case Xin_Set32: //.. mapReg(m, &i->Xin.Set32.dst); //.. return; @@ -1615,8 +1657,8 @@ Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) //.. GrpN insns, in which the greg field is used as a sub-opcode //.. and does not really contain a register. */ //.. # define fake(_n) mkHReg((_n), HRcInt32, False) -//.. -//.. /* vex_printf("asm ");ppX86Instr(i); vex_printf("\n"); */ + + vex_printf("asm ");ppPPC32Instr(i); vex_printf("\n"); switch (i->tag) { @@ -1724,7 +1766,7 @@ Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) //.. goto bad; //.. } //.. break; -//.. + //.. case Xin_Alu32M: //.. /* Deal specially with MOV */ //.. if (i->Xin.Alu32M.op == Xalu_MOV) { @@ -1773,7 +1815,7 @@ Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) //.. goto bad; //.. } //.. break; -//.. + //.. case Xin_Sh32: //.. opc_cl = opc_imm = subopc = 0; //.. switch (i->Xin.Sh32.op) { @@ -1805,7 +1847,7 @@ Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) //.. } //.. } //.. break; -//.. + //.. case Xin_Test32: //.. if (i->Xin.Test32.src->tag == Xri_Imm //.. && i->Xin.Test32.dst->tag == Xrm_Reg) { @@ -1816,7 +1858,7 @@ Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) //.. goto done; //.. } //.. break; -//.. + //.. case Xin_Unary32: //.. if (i->Xin.Unary32.op == Xun_NOT) { //.. *p++ = 0xF7; @@ -1856,7 +1898,7 @@ Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) //.. } //.. } //.. break; -//.. + //.. case Xin_Div: //.. subopc = i->Xin.Div.syned ? 7 : 6; //.. if (i->Xin.Div.ssz == Xss_32) { @@ -1875,7 +1917,7 @@ Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) //.. } //.. } //.. break; -//.. + //.. case Xin_Sh3232: //.. vassert(i->Xin.Sh3232.op == Xsh_SHL || i->Xin.Sh3232.op == Xsh_SHR); //.. if (i->Xin.Sh3232.amt == 0) { @@ -1890,7 +1932,7 @@ Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) //.. goto done; //.. } //.. break; -//.. + //.. case Xin_Push: //.. switch (i->Xin.Push.src->tag) { //.. case Xrmi_Mem: @@ -1907,7 +1949,7 @@ Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) //.. default: //.. goto bad; //.. } -//.. + //.. case Xin_Call: //.. /* See detailed comment for Xin_Call in getRegUsage_X86Instr above //.. for explanation of this. */ @@ -1931,7 +1973,7 @@ Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) //.. *p++ = 0xFF; //.. *p++ = 0xD0 + irno; //.. goto done; -//.. + //.. case Xin_Goto: //.. /* Use ptmp for backpatching conditional jumps. */ //.. ptmp = NULL; diff --git a/VEX/priv/host-ppc32/hdefs.h b/VEX/priv/host-ppc32/hdefs.h index 9c77820b1e..2c55d5b589 100644 --- a/VEX/priv/host-ppc32/hdefs.h +++ b/VEX/priv/host-ppc32/hdefs.h @@ -36,6 +36,9 @@ #ifndef __LIBVEX_HOST_PPC32_HDEFS_H #define __LIBVEX_HOST_PPC32_HDEFS_H +/* Num registers used for function calls */ +#define PPC32_N_REGPARMS 8 + /* --------- Registers. --------- */ @@ -45,20 +48,20 @@ extern void ppHRegPPC32 ( HReg ); -extern HReg hregPPC32_GPR0 ( void ); -extern HReg hregPPC32_GPR1 ( void ); -extern HReg hregPPC32_GPR2 ( void ); -extern HReg hregPPC32_GPR3 ( void ); -extern HReg hregPPC32_GPR4 ( void ); -extern HReg hregPPC32_GPR5 ( void ); -extern HReg hregPPC32_GPR6 ( void ); -extern HReg hregPPC32_GPR7 ( void ); -extern HReg hregPPC32_GPR8 ( void ); -extern HReg hregPPC32_GPR9 ( void ); +extern HReg hregPPC32_GPR0 ( void ); +extern HReg hregPPC32_GPR1 ( void ); // Stack Frame Pointer +extern HReg hregPPC32_GPR2 ( void ); // TOC pointer - not used +extern HReg hregPPC32_GPR3 ( void ); +extern HReg hregPPC32_GPR4 ( void ); +extern HReg hregPPC32_GPR5 ( void ); +extern HReg hregPPC32_GPR6 ( void ); +extern HReg hregPPC32_GPR7 ( void ); +extern HReg hregPPC32_GPR8 ( void ); +extern HReg hregPPC32_GPR9 ( void ); extern HReg hregPPC32_GPR10 ( void ); extern HReg hregPPC32_GPR11 ( void ); extern HReg hregPPC32_GPR12 ( void ); -extern HReg hregPPC32_GPR13 ( void ); +extern HReg hregPPC32_GPR13 ( void ); // thread specific pointer - not used extern HReg hregPPC32_GPR14 ( void ); extern HReg hregPPC32_GPR15 ( void ); extern HReg hregPPC32_GPR16 ( void ); @@ -76,18 +79,18 @@ extern HReg hregPPC32_GPR27 ( void ); extern HReg hregPPC32_GPR28 ( void ); extern HReg hregPPC32_GPR29 ( void ); extern HReg hregPPC32_GPR30 ( void ); -extern HReg hregPPC32_GPR31 ( void ); - -extern HReg hregPPC32_FPR0 ( void ); -extern HReg hregPPC32_FPR1 ( void ); -extern HReg hregPPC32_FPR2 ( void ); -extern HReg hregPPC32_FPR3 ( void ); -extern HReg hregPPC32_FPR4 ( void ); -extern HReg hregPPC32_FPR5 ( void ); -extern HReg hregPPC32_FPR6 ( void ); -extern HReg hregPPC32_FPR7 ( void ); -extern HReg hregPPC32_FPR8 ( void ); -extern HReg hregPPC32_FPR9 ( void ); +extern HReg hregPPC32_GPR31 ( void ); // GuestStatePtr + +extern HReg hregPPC32_FPR0 ( void ); +extern HReg hregPPC32_FPR1 ( void ); +extern HReg hregPPC32_FPR2 ( void ); +extern HReg hregPPC32_FPR3 ( void ); +extern HReg hregPPC32_FPR4 ( void ); +extern HReg hregPPC32_FPR5 ( void ); +extern HReg hregPPC32_FPR6 ( void ); +extern HReg hregPPC32_FPR7 ( void ); +extern HReg hregPPC32_FPR8 ( void ); +extern HReg hregPPC32_FPR9 ( void ); extern HReg hregPPC32_FPR10 ( void ); extern HReg hregPPC32_FPR11 ( void ); extern HReg hregPPC32_FPR12 ( void ); @@ -112,40 +115,44 @@ extern HReg hregPPC32_FPR30 ( void ); extern HReg hregPPC32_FPR31 ( void ); +#define StackFramePtr hregPPC32_GPR1() +#define GuestStatePtr hregPPC32_GPR31() -//.. /* --------- Condition codes, Intel encoding. --------- */ -//.. -//.. typedef -//.. enum { -//.. Xcc_O = 0, /* overflow */ -//.. Xcc_NO = 1, /* no overflow */ -//.. -//.. Xcc_B = 2, /* below */ -//.. Xcc_NB = 3, /* not below */ -//.. -//.. Xcc_Z = 4, /* zero */ -//.. Xcc_NZ = 5, /* not zero */ -//.. -//.. Xcc_BE = 6, /* below or equal */ -//.. Xcc_NBE = 7, /* not below or equal */ -//.. -//.. Xcc_S = 8, /* negative */ -//.. Xcc_NS = 9, /* not negative */ -//.. -//.. Xcc_P = 10, /* parity even */ -//.. Xcc_NP = 11, /* not parity even */ -//.. -//.. Xcc_L = 12, /* jump less */ -//.. Xcc_NL = 13, /* not less */ -//.. -//.. Xcc_LE = 14, /* less or equal */ -//.. Xcc_NLE = 15, /* not less or equal */ -//.. -//.. Xcc_ALWAYS = 16 /* the usual hack */ -//.. } -//.. X86CondCode; -//.. -//.. extern HChar* showX86CondCode ( X86CondCode ); + + +/* --------- Condition codes, Intel encoding. --------- */ + +typedef + enum { + Pcc_O = 0, /* overflow */ + Pcc_NO = 1, /* no overflow */ + + Pcc_B = 2, /* below */ + Pcc_NB = 3, /* not below */ + + Pcc_Z = 4, /* zero */ + Pcc_NZ = 5, /* not zero */ + + Pcc_BE = 6, /* below or equal */ + Pcc_NBE = 7, /* not below or equal */ + + Pcc_S = 8, /* negative */ + Pcc_NS = 9, /* not negative */ + + Pcc_P = 10, /* parity even */ + Pcc_NP = 11, /* not parity even */ + + Pcc_L = 12, /* jump less */ + Pcc_NL = 13, /* not less */ + + Pcc_LE = 14, /* less or equal */ + Pcc_NLE = 15, /* not less or equal */ + + Pcc_ALWAYS = 16 /* the usual hack */ + } + PPC32CondCode; + +extern HChar* showPPC32CondCode ( PPC32CondCode ); /* --------- Memory address expressions (amodes). --------- */ @@ -223,15 +230,15 @@ extern void ppPPC32RI ( PPC32RI* ); //.. //.. extern HChar* showX86ScalarSz ( X86ScalarSz ); -//.. /* --------- */ -//.. typedef -//.. enum { -//.. Pun_NEG, -//.. Pun_NOT -//.. } -//.. PPC32UnaryOp; -//.. -//.. extern HChar* showPPC32UnaryOp ( PPC32UnaryOp ); +/* --------- */ +typedef + enum { + Pun_NEG, + Pun_NOT + } + PPC32UnaryOp; + +extern HChar* showPPC32UnaryOp ( PPC32UnaryOp ); /* --------- */ @@ -281,14 +288,14 @@ typedef enum { Pin_Alu32, /* 32-bit mov/arith/logical */ Pin_Sh32, /* 32-bit shift/rotate */ -//.. Xin_Test32, /* 32-bit test (AND, set flags, discard result) */ -//.. Xin_Unary32, /* 32-bit not and neg */ + Pin_Test32, /* 32-bit test (AND, set flags, discard result) */ + Pin_Unary32, /* 32-bit not and neg */ //.. Xin_MulL, /* widening multiply */ //.. Xin_Div, /* div and mod */ //.. Xin_Sh3232, /* shldl or shrdl */ //.. Xin_Push, /* push (32-bit?) value on stack */ -//.. Xin_Call, /* call to address in register */ -//.. Xin_Goto, /* conditional/unconditional jmp to dst */ + Pin_Call, /* call to address in register */ + Pin_Goto, /* conditional/unconditional jmp to dst */ //.. Xin_CMov32, /* conditional move */ Pin_LoadEX, /* load a 8|16|32 bit value from mem */ Pin_Store, /* store a 8|16|32 bit value to mem */ @@ -327,15 +334,15 @@ typedef HReg src; PPC32RI* shft; } Sh32; -//.. struct { -//.. X86RI* src; -//.. X86RM* dst; -//.. } Test32; -//.. /* Not and Neg */ -//.. struct { -//.. X86UnaryOp op; -//.. X86RM* dst; -//.. } Unary32; + struct { + HReg dst; + PPC32RI* src; + } Test32; + /* Not and Neg */ + struct { + PPC32UnaryOp op; + PPC32RI* dst; + } Unary32; //.. /* DX:AX = AX *s/u r/m16, or EDX:EAX = EAX *s/u r/m32 */ //.. struct { //.. Bool syned; @@ -358,23 +365,23 @@ typedef //.. struct { //.. X86RMI* src; //.. } Push; -//.. /* Pseudo-insn. Call target (an absolute address), on given -//.. condition (which could be Xcc_ALWAYS). */ -//.. struct { -//.. X86CondCode cond; -//.. Addr32 target; -//.. Int regparms; /* 0 .. 3 */ -//.. } Call; -//.. /* Pseudo-insn. Goto dst, on given condition (which could be -//.. Xcc_ALWAYS). Note importantly that if the jump is -//.. conditional (not Xcc_ALWAYS) the jump kind *must* be -//.. Ijk_Boring. Ie non-Boring conditional jumps are -//.. not allowed. */ -//.. struct { -//.. IRJumpKind jk; -//.. X86CondCode cond; -//.. X86RI* dst; -//.. } Goto; + /* Pseudo-insn. Call target (an absolute address), on given + condition (which could be Pcc_ALWAYS). */ + struct { + PPC32CondCode cond; + Addr32 target; + Int regparms; /* 0 .. 9 */ + } Call; + /* Pseudo-insn. Goto dst, on given condition (which could be + Pcc_ALWAYS). Note importantly that if the jump is + conditional (not Pcc_ALWAYS) the jump kind *must* be + Ijk_Boring. Ie non-Boring conditional jumps are + not allowed. */ + struct { + IRJumpKind jk; + PPC32CondCode cond; + PPC32RI* dst; + } Goto; //.. /* Mov src to dst on the given condition, which may not //.. be the bogus Xcc_ALWAYS. */ //.. struct { @@ -384,7 +391,7 @@ typedef //.. } CMov32; /* Sign/Zero extending loads. Dst size is always 32 bits. */ struct { - UChar szSmall; /* 1|2|4 */ + UChar sz; /* 1|2|4 */ Bool syned; HReg dst; PPC32AMode* src; @@ -482,17 +489,17 @@ typedef extern PPC32Instr* PPC32Instr_Alu32 ( PPC32AluOp, HReg, HReg, PPC32RI* ); -//.. extern X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst ); extern PPC32Instr* PPC32Instr_Sh32 ( PPC32ShiftOp, HReg, HReg, PPC32RI* ); -//.. extern X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst ); +extern PPC32Instr* PPC32Instr_Test32 ( HReg dst, PPC32RI* src ); +extern PPC32Instr* PPC32Instr_Unary32 ( PPC32UnaryOp op, PPC32RI* dst ); //.. extern X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz, X86RM* ); //.. extern X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz, X86RM* ); //.. extern X86Instr* X86Instr_Sh3232 ( X86ShiftOp, UInt amt, HReg src, HReg dst ); //.. extern X86Instr* X86Instr_Push ( X86RMI* ); -//.. extern X86Instr* X86Instr_Call ( X86CondCode, Addr32, Int ); -//.. extern X86Instr* X86Instr_Goto ( IRJumpKind, X86CondCode cond, X86RI* dst ); +extern PPC32Instr* PPC32Instr_Call ( PPC32CondCode, Addr32, Int ); +extern PPC32Instr* PPC32Instr_Goto ( IRJumpKind, PPC32CondCode cond, PPC32RI* dst ); //.. extern X86Instr* X86Instr_CMov32 ( X86CondCode, X86RM* src, HReg dst ); -extern PPC32Instr* PPC32Instr_LoadEX ( UChar szSmall, Bool syned, +extern PPC32Instr* PPC32Instr_LoadEX ( UChar sz, Bool syned, HReg dst, PPC32AMode* src ); extern PPC32Instr* PPC32Instr_Store ( UChar sz, PPC32AMode* dst, HReg src ); //.. extern X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ); diff --git a/VEX/priv/host-ppc32/isel.c b/VEX/priv/host-ppc32/isel.c index 5d75214ded..41e76b76e8 100644 --- a/VEX/priv/host-ppc32/isel.c +++ b/VEX/priv/host-ppc32/isel.c @@ -70,19 +70,18 @@ /*--- misc helpers ---*/ /*---------------------------------------------------------*/ -#define GuestStateReg hregPPC32_GPR0() - -#if 0 /* These are duplicated in guest-ppc32/toIR.c */ static IRExpr* unop ( IROp op, IRExpr* a ) { return IRExpr_Unop(op, a); } +#if 0 static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 ) { return IRExpr_Binop(op, a1, a2); } +#endif //.. static IRExpr* mkU64 ( ULong i ) //.. { @@ -98,7 +97,6 @@ static IRExpr* bind ( Int binder ) { return IRExpr_Binder(binder); } -#endif @@ -209,22 +207,25 @@ static HReg newVRegI ( ISelEnv* env ) checks that all returned registers are virtual. You should not call the _wrk version directly. */ -#if 0 static PPC32RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e ); static PPC32RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e ); -#endif static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ); static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ); -#if 0 static PPC32AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e ); static PPC32AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e ); + +#if 0 +static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, + ISelEnv* env, IRExpr* e ); +static void iselInt64Expr ( HReg* rHi, HReg* rLo, + ISelEnv* env, IRExpr* e ); #endif -//.. static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e ); -//.. static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e ); -//.. +static PPC32CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e ); +static PPC32CondCode iselCondCode ( ISelEnv* env, IRExpr* e ); + //.. static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ); //.. static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ); //.. @@ -250,11 +251,22 @@ static PPC32AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e ); /* Make an int reg-reg move. */ -static PPC32Instr* mk_iMOVsd_RR ( HReg dst, HReg src ) +static PPC32Instr* mk_iMOVds_RR ( HReg dst, HReg src ) { vassert(hregClass(dst) == HRcInt32); vassert(hregClass(src) == HRcInt32); - return PPC32Instr_Alu32(Palu_OR,dst,src,PPC32RI_Imm(0)); + return PPC32Instr_Alu32(Palu_OR, dst, src, PPC32RI_Reg(src)); +} + + +/* Make an int reg<-ri move. */ + +static PPC32Instr* mk_iMOVds_RRI ( HReg dst, PPC32RI* src ) +{ + vassert(hregClass(dst) == HRcInt32); +// CAB: assert src... + HReg tmp = hregPPC32_GPR0(); // Gives value 0 in this context + return PPC32Instr_Alu32(Palu_ADD, dst, tmp, src); } @@ -325,229 +337,208 @@ static PPC32Instr* mk_iMOVsd_RR ( HReg dst, HReg src ) //.. } -//.. /* Complete the call to a helper function, by calling the -//.. helper and clearing the args off the stack. */ -//.. -//.. static -//.. void callHelperAndClearArgs ( ISelEnv* env, X86CondCode cc, -//.. IRCallee* cee, Int n_arg_ws ) -//.. { -//.. /* Complication. Need to decide which reg to use as the fn address -//.. pointer, in a way that doesn't trash regparm-passed -//.. parameters. */ -//.. vassert(sizeof(void*) == 4); -//.. -//.. addInstr(env, X86Instr_Call( cc, (UInt)cee->addr, cee->regparms)); -//.. if (n_arg_ws > 0) -//.. add_to_esp(env, 4*n_arg_ws); -//.. } +/* Used only in doHelperCall. See big comment in doHelperCall re + handling of register-parameter args. This function figures out + whether evaluation of an expression might require use of a fixed + register. If in doubt return True (safe but suboptimal). +*/ +static +Bool mightRequireFixedRegs ( IRExpr* e ) +{ + switch (e->tag) { + case Iex_Tmp: case Iex_Const: case Iex_Get: + return False; + default: + return True; + } +} -//.. /* Used only in doHelperCall. See big comment in doHelperCall re -//.. handling of regparm args. This function figures out whether -//.. evaluation of an expression might require use of a fixed register. -//.. If in doubt return True (safe but suboptimal). -//.. */ -//.. static -//.. Bool mightRequireFixedRegs ( IRExpr* e ) -//.. { -//.. switch (e->tag) { -//.. case Iex_Tmp: case Iex_Const: case Iex_Get: -//.. return False; -//.. default: -//.. return True; -//.. } -//.. } +/* Do a complete function call. guard is a Ity_Bit expression + indicating whether or not the call happens. If guard==NULL, the + call is unconditional. */ +static +void doHelperCall ( ISelEnv* env, + Bool passBBP, + IRExpr* guard, IRCallee* cee, IRExpr** args ) +{ + PPC32CondCode cc; + HReg argregs[PPC32_N_REGPARMS]; + HReg tmpregs[PPC32_N_REGPARMS]; + Bool go_fast; + Int n_args, i, argreg; + + /* Marshal args for a call and do the call. + + If passBBP is True, %rbp (the baseblock pointer) is to be passed + as the first arg. + + This function only deals with a tiny set of possibilities, which + cover all helpers in practice. The restrictions are that only + arguments in registers are supported, hence only PPC32_N_REGPARMSx32 + integer bits in total can be passed. In fact the only supported + arg type is I32. + + Generating code which is both efficient and correct when + parameters are to be passed in registers is difficult, for the + reasons elaborated in detail in comments attached to + doHelperCall() in priv/host-x86/isel.c. Here, we use a variant + of the method described in those comments. + + The problem is split into two cases: the fast scheme and the + slow scheme. In the fast scheme, arguments are computed + directly into the target (real) registers. This is only safe + when we can be sure that computation of each argument will not + trash any real registers set by computation of any other + argument. + + In the slow scheme, all args are first computed into vregs, and + once they are all done, they are moved to the relevant real + regs. This always gives correct code, but it also gives a bunch + of vreg-to-rreg moves which are usually redundant but are hard + for the register allocator to get rid of. + + To decide which scheme to use, all argument expressions are + first examined. If they are all so simple that it is clear they + will be evaluated without use of any fixed registers, use the + fast scheme, else use the slow scheme. Note also that only + unconditional calls may use the fast scheme, since having to + compute a condition expression could itself trash real + registers. + + Note this requires being able to examine an expression and + determine whether or not evaluation of it might use a fixed + register. That requires knowledge of how the rest of this insn + selector works. Currently just the following 3 are regarded as + safe -- hopefully they cover the majority of arguments in + practice: IRExpr_Tmp IRExpr_Const IRExpr_Get. + */ + + /* Note that the cee->regparms field is meaningless on PPC32 host + (since there is only one calling convention) and so we always + ignore it. */ + + n_args = 0; + for (i = 0; args[i]; i++) + n_args++; + + if (PPC32_N_REGPARMS < n_args + (passBBP ? 1 : 0)) { + vpanic("doHelperCall(PPC32): cannot currently handle > 8 args"); + // PPC32_N_REGPARMS + } -//.. /* Do a complete function call. guard is a Ity_Bit expression -//.. indicating whether or not the call happens. If guard==NULL, the -//.. call is unconditional. */ -//.. -//.. static -//.. void doHelperCall ( ISelEnv* env, -//.. Bool passBBP, -//.. IRExpr* guard, IRCallee* cee, IRExpr** args ) -//.. { -//.. X86CondCode cc; -//.. HReg argregs[3]; -//.. HReg tmpregs[3]; -//.. Bool danger; -//.. Int not_done_yet, n_args, n_arg_ws, stack_limit, -//.. i, argreg, argregX; -//.. -//.. /* Marshal args for a call, do the call, and clear the stack. -//.. Complexities to consider: -//.. -//.. * if passBBP is True, %ebp (the baseblock pointer) is to be -//.. passed as the first arg. -//.. -//.. * If the callee claims regparmness of 1, 2 or 3, we must pass the -//.. first 1, 2 or 3 args in registers (EAX, EDX, and ECX -//.. respectively). To keep things relatively simple, only args of -//.. type I32 may be passed as regparms -- just bomb out if anything -//.. else turns up. Clearly this depends on the front ends not -//.. trying to pass any other types as regparms. -//.. */ -//.. -//.. /* 16 Nov 2004: the regparm handling is complicated by the -//.. following problem. -//.. -//.. Consider a call two a function with two regparm parameters: -//.. f(e1,e2). We need to compute e1 into %eax and e2 into %edx. -//.. Suppose code is first generated to compute e1 into %eax. Then, -//.. code is generated to compute e2 into %edx. Unfortunately, if -//.. the latter code sequence uses %eax, it will trash the value of -//.. e1 computed by the former sequence. This could happen if (for -//.. example) e2 itself involved a function call. In the code below, -//.. args are evaluated right-to-left, not left-to-right, but the -//.. principle and the problem are the same. -//.. -//.. One solution is to compute all regparm-bound args into vregs -//.. first, and once they are all done, move them to the relevant -//.. real regs. This always gives correct code, but it also gives -//.. a bunch of vreg-to-rreg moves which are usually redundant but -//.. are hard for the register allocator to get rid of. -//.. -//.. A compromise is to first examine all regparm'd argument -//.. expressions. If they are all so simple that it is clear -//.. they will be evaluated without use of any fixed registers, -//.. use the old compute-directly-to-fixed-target scheme. If not, -//.. be safe and use the via-vregs scheme. -//.. -//.. Note this requires being able to examine an expression and -//.. determine whether or not evaluation of it might use a fixed -//.. register. That requires knowledge of how the rest of this -//.. insn selector works. Currently just the following 3 are -//.. regarded as safe -- hopefully they cover the majority of -//.. arguments in practice: IRExpr_Tmp IRExpr_Const IRExpr_Get. -//.. */ -//.. vassert(cee->regparms >= 0 && cee->regparms <= 3); -//.. -//.. n_args = n_arg_ws = 0; -//.. while (args[n_args]) n_args++; -//.. -//.. not_done_yet = n_args; -//.. if (passBBP) -//.. not_done_yet++; -//.. -//.. stack_limit = cee->regparms; -//.. if (cee->regparms > 0 && passBBP) stack_limit--; -//.. -//.. /* ------ BEGIN marshall all arguments ------ */ -//.. -//.. /* Push (R to L) the stack-passed args, [n_args-1 .. stack_limit] */ -//.. for (i = n_args-1; i >= stack_limit; i--) { -//.. n_arg_ws += pushArg(env, args[i]); -//.. not_done_yet--; -//.. } -//.. -//.. /* args [stack_limit-1 .. 0] and possibly %ebp are to be passed in -//.. registers. */ -//.. -//.. if (cee->regparms > 0) { -//.. -//.. /* ------ BEGIN deal with regparms ------ */ -//.. -//.. /* deal with regparms, not forgetting %ebp if needed. */ -//.. argregs[0] = hregX86_EAX(); -//.. argregs[1] = hregX86_EDX(); -//.. argregs[2] = hregX86_ECX(); -//.. tmpregs[0] = tmpregs[1] = tmpregs[2] = INVALID_HREG; -//.. -//.. argreg = cee->regparms; -//.. -//.. /* In keeping with big comment above, detect potential danger -//.. and use the via-vregs scheme if needed. */ -//.. danger = False; -//.. for (i = stack_limit-1; i >= 0; i--) { -//.. if (mightRequireFixedRegs(args[i])) { -//.. danger = True; -//.. break; -//.. } -//.. } -//.. -//.. if (danger) { -//.. -//.. /* Move via temporaries */ -//.. argregX = argreg; -//.. for (i = stack_limit-1; i >= 0; i--) { -//.. -//.. if (0) { -//.. vex_printf("x86 host: register param is complex: "); -//.. ppIRExpr(args[i]); -//.. vex_printf("\n"); -//.. } -//.. -//.. argreg--; -//.. vassert(argreg >= 0); -//.. vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32); -//.. tmpregs[argreg] = iselIntExpr_R(env, args[i]); -//.. not_done_yet--; -//.. } -//.. for (i = stack_limit-1; i >= 0; i--) { -//.. argregX--; -//.. vassert(argregX >= 0); -//.. addInstr( env, mk_iMOVsd_RR( tmpregs[argregX], argregs[argregX] ) ); -//.. } -//.. -//.. } else { -//.. /* It's safe to compute all regparm args directly into their -//.. target registers. */ -//.. for (i = stack_limit-1; i >= 0; i--) { -//.. argreg--; -//.. vassert(argreg >= 0); -//.. vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32); -//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, -//.. iselIntExpr_RMI(env, args[i]), -//.. argregs[argreg])); -//.. not_done_yet--; -//.. } -//.. -//.. } -//.. -//.. /* Not forgetting %ebp if needed. */ -//.. if (passBBP) { -//.. vassert(argreg == 1); -//.. addInstr(env, mk_iMOVsd_RR( hregX86_EBP(), argregs[0])); -//.. not_done_yet--; -//.. } -//.. -//.. /* ------ END deal with regparms ------ */ -//.. -//.. } else { -//.. -//.. /* No regparms. Heave %ebp on the stack if needed. */ -//.. if (passBBP) { -//.. addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP()))); -//.. n_arg_ws++; -//.. not_done_yet--; -//.. } -//.. -//.. } -//.. -//.. vassert(not_done_yet == 0); -//.. -//.. /* ------ END marshall all arguments ------ */ -//.. -//.. /* Now we can compute the condition. We can't do it earlier -//.. because the argument computations could trash the condition -//.. codes. Be a bit clever to handle the common case where the -//.. guard is 1:Bit. */ -//.. cc = Xcc_ALWAYS; -//.. if (guard) { -//.. if (guard->tag == Iex_Const -//.. && guard->Iex.Const.con->tag == Ico_U1 -//.. && guard->Iex.Const.con->Ico.U1 == True) { -//.. /* unconditional -- do nothing */ -//.. } else { -//.. cc = iselCondCode( env, guard ); -//.. } -//.. } -//.. -//.. /* call the helper, and get the args off the stack afterwards. */ -//.. callHelperAndClearArgs( env, cc, cee, n_arg_ws ); -//.. } + argregs[0] = hregPPC32_GPR3(); + argregs[1] = hregPPC32_GPR4(); + argregs[2] = hregPPC32_GPR5(); + argregs[3] = hregPPC32_GPR6(); + argregs[4] = hregPPC32_GPR7(); + argregs[5] = hregPPC32_GPR8(); + argregs[6] = hregPPC32_GPR9(); + argregs[7] = hregPPC32_GPR10(); + + tmpregs[0] = tmpregs[1] = tmpregs[2] = + tmpregs[3] = tmpregs[4] = tmpregs[5] = + tmpregs[6] = tmpregs[7] = INVALID_HREG; + + /* First decide which scheme (slow or fast) is to be used. First + assume the fast scheme, and select slow if any contraindications + (wow) appear. */ + + go_fast = True; + + if (guard) { + if (guard->tag == Iex_Const + && guard->Iex.Const.con->tag == Ico_U1 + && guard->Iex.Const.con->Ico.U1 == True) { + /* unconditional */ + } else { + /* Not manifestly unconditional -- be conservative. */ + go_fast = False; + } + } + + if (go_fast) { + for (i = 0; i < n_args; i++) { + if (mightRequireFixedRegs(args[i])) { + go_fast = False; + break; + } + } + } + + /* At this point the scheme to use has been established. Generate + code to get the arg values into the argument rregs. */ + + if (go_fast) { + + /* FAST SCHEME */ + argreg = 0; + if (passBBP) { + addInstr(env, mk_iMOVds_RR( argregs[argreg], GuestStatePtr )); + argreg++; + } + + for (i = 0; i < n_args; i++) { + vassert(argreg < PPC32_N_REGPARMS); + vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32); + addInstr(env, mk_iMOVds_RR( argregs[argreg], + iselIntExpr_R(env, args[i]) )); + argreg++; + } + + /* Fast scheme only applies for unconditional calls. Hence: */ + cc = Pcc_ALWAYS; + + } else { + + /* SLOW SCHEME; move via temporaries */ + argreg = 0; + + if (passBBP) { + /* This is pretty stupid; better to move directly to r3 + after the rest of the args are done. */ + tmpregs[argreg] = newVRegI(env); + addInstr(env, mk_iMOVds_RR( tmpregs[argreg], GuestStatePtr )); + argreg++; + } + + for (i = 0; i < n_args; i++) { + vassert(argreg < PPC32_N_REGPARMS); + vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32); + tmpregs[argreg] = iselIntExpr_R(env, args[i]); + argreg++; + } + + /* Now we can compute the condition. We can't do it earlier + because the argument computations could trash the condition + codes. Be a bit clever to handle the common case where the + guard is 1:Bit. */ + cc = Pcc_ALWAYS; + if (guard) { + if (guard->tag == Iex_Const + && guard->Iex.Const.con->tag == Ico_U1 + && guard->Iex.Const.con->Ico.U1 == True) { + /* unconditional -- do nothing */ + } else { + cc = iselCondCode( env, guard ); + } + } + + /* Move the args to their final destinations. */ + for (i = 0; i < argreg; i++) { + /* None of these insns, including any spill code that might + be generated, may alter the condition codes. */ + addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) ); + } + + } + + /* Finally, the call itself. */ + addInstr(env, PPC32Instr_Call( cc, + Ptr_to_ULong(cee->addr), + n_args + (passBBP ? 1 : 0) )); +} //.. /* Given a guest-state array descriptor, an index expression and a @@ -706,12 +697,14 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ) /* DO NOT CALL THIS DIRECTLY ! */ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) { -// MatchInfo mi; -// DECLARE_PATTERN(p_32to1_then_1Uto8); + MatchInfo mi; + DECLARE_PATTERN(p_32to1_then_1Uto8); IRType ty = typeOfIRExpr(env->type_env,e); vassert(ty == Ity_I32 || Ity_I16 || Ity_I8); + vex_printf("@iselIntExpr_R_wrk: tag=%d\n", e->tag); + switch (e->tag) { /* --------- TEMP --------- */ @@ -739,47 +732,46 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) //.. break; //.. } -//.. /* --------- BINARY OP --------- */ -//.. case Iex_Binop: { -//.. X86AluOp aluOp; -//.. X86ShiftOp shOp; -//.. + /* --------- BINARY OP --------- */ + case Iex_Binop: { + PPC32AluOp aluOp; + PPC32ShiftOp shOp; + //.. /* Pattern: Sub32(0,x) */ //.. if (e->Iex.Binop.op == Iop_Sub32 && isZero32(e->Iex.Binop.arg1)) { //.. HReg dst = newVRegI(env); //.. HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg2); //.. addInstr(env, mk_iMOVsd_RR(reg,dst)); -//.. addInstr(env, X86Instr_Unary32(Xun_NEG,X86RM_Reg(dst))); -//.. return dst; -//.. } -//.. -//.. /* Is it an addition or logical style op? */ -//.. switch (e->Iex.Binop.op) { -//.. case Iop_Add8: case Iop_Add16: case Iop_Add32: -//.. aluOp = Xalu_ADD; break; -//.. case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: -//.. aluOp = Xalu_SUB; break; -//.. case Iop_And8: case Iop_And16: case Iop_And32: -//.. aluOp = Xalu_AND; break; -//.. case Iop_Or8: case Iop_Or16: case Iop_Or32: -//.. aluOp = Xalu_OR; break; -//.. case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: -//.. aluOp = Xalu_XOR; break; -//.. case Iop_Mul16: case Iop_Mul32: -//.. aluOp = Xalu_MUL; break; -//.. default: -//.. aluOp = Xalu_INVALID; break; -//.. } -//.. /* For commutative ops we assume any literal -//.. values are on the second operand. */ -//.. if (aluOp != Xalu_INVALID) { -//.. HReg dst = newVRegI(env); -//.. HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg1); -//.. X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2); -//.. addInstr(env, mk_iMOVsd_RR(reg,dst)); -//.. addInstr(env, X86Instr_Alu32R(aluOp, rmi, dst)); +//.. addInstr(env, PPC32Instr_Unary32(Xun_NEG,PPC32RM_Reg(dst))); //.. return dst; //.. } + + /* Is it an addition or logical style op? */ + switch (e->Iex.Binop.op) { + case Iop_Add8: case Iop_Add16: case Iop_Add32: + aluOp = Palu_ADD; break; + case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: + aluOp = Palu_SUB; break; + case Iop_And8: case Iop_And16: case Iop_And32: + aluOp = Palu_AND; break; + case Iop_Or8: case Iop_Or16: case Iop_Or32: + aluOp = Palu_OR; break; + case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: + aluOp = Palu_XOR; break; + case Iop_Mul16: case Iop_Mul32: + aluOp = Palu_MUL; break; + default: + aluOp = Palu_INVALID; break; + } + /* For commutative ops we assume any literal + values are on the second operand. */ + if (aluOp != Palu_INVALID) { + HReg dst = newVRegI(env); + HReg src = iselIntExpr_R(env, e->Iex.Binop.arg1); + PPC32RI* ri = iselIntExpr_RI(env, e->Iex.Binop.arg2); + addInstr(env, PPC32Instr_Alu32(aluOp, dst, src, ri)); + return dst; + } //.. /* Could do better here; forcing the first arg into a reg //.. isn't always clever. //.. -- t70 = Xor32(And32(Xor32(LDle:I32(Add32(t41,0xFFFFFFA0:I32)), @@ -798,94 +790,85 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) //.. movl %vr104,%vr70 //.. */ -//.. /* Perhaps a shift op? */ -//.. switch (e->Iex.Binop.op) { -//.. case Iop_Shl32: case Iop_Shl16: case Iop_Shl8: -//.. shOp = Xsh_SHL; break; -//.. case Iop_Shr32: case Iop_Shr16: case Iop_Shr8: -//.. shOp = Xsh_SHR; break; -//.. case Iop_Sar32: case Iop_Sar16: case Iop_Sar8: -//.. shOp = Xsh_SAR; break; -//.. default: -//.. shOp = Xsh_INVALID; break; -//.. } -//.. if (shOp != Xsh_INVALID) { -//.. HReg dst = newVRegI(env); -//.. -//.. /* regL = the value to be shifted */ -//.. HReg regL = iselIntExpr_R(env, e->Iex.Binop.arg1); -//.. addInstr(env, mk_iMOVsd_RR(regL,dst)); -//.. -//.. /* Do any necessary widening for 16/8 bit operands */ -//.. switch (e->Iex.Binop.op) { -//.. case Iop_Shr8: -//.. addInstr(env, X86Instr_Alu32R( -//.. Xalu_AND, X86RMI_Imm(0xFF), dst)); -//.. break; -//.. case Iop_Shr16: -//.. addInstr(env, X86Instr_Alu32R( -//.. Xalu_AND, X86RMI_Imm(0xFFFF), dst)); -//.. break; -//.. case Iop_Sar8: -//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 24, X86RM_Reg(dst))); -//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 24, X86RM_Reg(dst))); -//.. break; -//.. case Iop_Sar16: -//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(dst))); -//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 16, X86RM_Reg(dst))); -//.. break; -//.. default: break; -//.. } -//.. -//.. /* Now consider the shift amount. If it's a literal, we -//.. can do a much better job than the general case. */ -//.. if (e->Iex.Binop.arg2->tag == Iex_Const) { -//.. /* assert that the IR is well-typed */ -//.. Int nshift; -//.. vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8); -//.. nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8; -//.. vassert(nshift >= 0); -//.. if (nshift > 0) -//.. /* Can't allow nshift==0 since that means %cl */ -//.. addInstr(env, X86Instr_Sh32( -//.. shOp, -//.. nshift, -//.. X86RM_Reg(dst))); -//.. } else { -//.. /* General case; we have to force the amount into %cl. */ -//.. HReg regR = iselIntExpr_R(env, e->Iex.Binop.arg2); -//.. addInstr(env, mk_iMOVsd_RR(regR,hregX86_ECX())); -//.. addInstr(env, X86Instr_Sh32(shOp, 0/* %cl */, X86RM_Reg(dst))); -//.. } -//.. return dst; -//.. } + /* Perhaps a shift op? */ + switch (e->Iex.Binop.op) { + case Iop_Shl32: case Iop_Shl16: case Iop_Shl8: + shOp = Psh_SHL; break; + case Iop_Shr32: case Iop_Shr16: case Iop_Shr8: + shOp = Psh_SHR; break; + case Iop_Sar32: case Iop_Sar16: case Iop_Sar8: + shOp = Psh_SAR; break; + default: + shOp = Psh_INVALID; break; + } + if (shOp != Psh_INVALID) { + HReg dst = newVRegI(env); -//.. /* Handle misc other ops. */ -//.. if (e->Iex.Binop.op == Iop_8HLto16) { -//.. HReg hi8 = newVRegI(env); -//.. HReg lo8 = newVRegI(env); -//.. HReg hi8s = iselIntExpr_R(env, e->Iex.Binop.arg1); -//.. HReg lo8s = iselIntExpr_R(env, e->Iex.Binop.arg2); -//.. addInstr(env, mk_iMOVsd_RR(hi8s, hi8)); -//.. addInstr(env, mk_iMOVsd_RR(lo8s, lo8)); -//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 8, X86RM_Reg(hi8))); -//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFF), lo8)); -//.. addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo8), hi8)); -//.. return hi8; -//.. } + /* regL = the value to be shifted */ + HReg src = iselIntExpr_R(env, e->Iex.Binop.arg1); + + /* Do any necessary widening for 16/8 bit operands */ + switch (e->Iex.Binop.op) { + case Iop_Shr8: + addInstr(env, PPC32Instr_Alu32(Palu_AND, dst, dst, PPC32RI_Imm(0xFF))); + break; + case Iop_Shr16: + addInstr(env, PPC32Instr_Alu32(Palu_AND, dst, dst, PPC32RI_Imm(0xFFFF))); + break; + case Iop_Sar8: + addInstr(env, PPC32Instr_Sh32(Psh_SHL, dst, dst, PPC32RI_Imm(24))); + addInstr(env, PPC32Instr_Sh32(Psh_SAR, dst, dst, PPC32RI_Imm(24))); + break; + case Iop_Sar16: + addInstr(env, PPC32Instr_Sh32(Psh_SHL, dst, dst, PPC32RI_Imm(16))); + addInstr(env, PPC32Instr_Sh32(Psh_SAR, dst, dst, PPC32RI_Imm(16))); + break; + default: break; + } + + /* Now consider the shift amount. If it's a literal, we + can do a much better job than the general case. */ + if (e->Iex.Binop.arg2->tag == Iex_Const) { + /* assert that the IR is well-typed */ + Int nshift; + vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8); + nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8; + vassert(nshift >= 0); + +// CAB: no problem with nshift==0, I think. +// if (nshift > 0) + addInstr(env, PPC32Instr_Sh32(shOp, dst, src, PPC32RI_Imm(nshift))); + + } else { + /* General case; we have to force the amount into %cl. */ + HReg shft = iselIntExpr_R(env, e->Iex.Binop.arg2); + addInstr(env, PPC32Instr_Sh32(shOp, dst, src, PPC32RI_Reg(shft))); + } + return dst; + } -//.. if (e->Iex.Binop.op == Iop_16HLto32) { -//.. HReg hi16 = newVRegI(env); -//.. HReg lo16 = newVRegI(env); -//.. HReg hi16s = iselIntExpr_R(env, e->Iex.Binop.arg1); -//.. HReg lo16s = iselIntExpr_R(env, e->Iex.Binop.arg2); -//.. addInstr(env, mk_iMOVsd_RR(hi16s, hi16)); -//.. addInstr(env, mk_iMOVsd_RR(lo16s, lo16)); -//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(hi16))); -//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFFFF), lo16)); -//.. addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo16), hi16)); -//.. return hi16; -//.. } + /* Handle misc other ops. */ + if (e->Iex.Binop.op == Iop_8HLto16) { + HReg hi8 = newVRegI(env); + HReg lo8 = newVRegI(env); + HReg hi8s = iselIntExpr_R(env, e->Iex.Binop.arg1); + HReg lo8s = iselIntExpr_R(env, e->Iex.Binop.arg2); + addInstr(env, PPC32Instr_Sh32(Psh_SHL, hi8, hi8s, PPC32RI_Imm(8))); + addInstr(env, PPC32Instr_Alu32(Palu_AND, lo8, lo8s, PPC32RI_Imm(0xFF))); + addInstr(env, PPC32Instr_Alu32(Palu_OR, hi8, hi8, PPC32RI_Reg(lo8))); + return hi8; + } + + if (e->Iex.Binop.op == Iop_16HLto32) { + HReg hi16 = newVRegI(env); + HReg lo16 = newVRegI(env); + HReg hi16s = iselIntExpr_R(env, e->Iex.Binop.arg1); + HReg lo16s = iselIntExpr_R(env, e->Iex.Binop.arg2); + addInstr(env, PPC32Instr_Sh32(Psh_SHL, hi16, hi16s, PPC32RI_Imm(16))); + addInstr(env, PPC32Instr_Alu32(Palu_AND, lo16, lo16s, PPC32RI_Imm(0xFFFF))); + addInstr(env, PPC32Instr_Alu32(Palu_OR, hi16, hi16, PPC32RI_Reg(lo16))); + return hi16; + } //.. if (e->Iex.Binop.op == Iop_MullS16 || e->Iex.Binop.op == Iop_MullS8 //.. || e->Iex.Binop.op == Iop_MullU16 || e->Iex.Binop.op == Iop_MullU8) { @@ -983,106 +966,105 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) //.. return dst; //.. } //.. -//.. break; -//.. } + break; + } -//.. /* --------- UNARY OP --------- */ -//.. case Iex_Unop: { -//.. /* 1Uto8(32to1(expr32)) */ -//.. DEFINE_PATTERN(p_32to1_then_1Uto8, -//.. unop(Iop_1Uto8,unop(Iop_32to1,bind(0)))); -//.. if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) { -//.. IRExpr* expr32 = mi.bindee[0]; -//.. HReg dst = newVRegI(env); -//.. HReg src = iselIntExpr_R(env, expr32); -//.. addInstr(env, mk_iMOVsd_RR(src,dst) ); -//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, -//.. X86RMI_Imm(1), dst)); -//.. return dst; -//.. } + /* --------- UNARY OP --------- */ + case Iex_Unop: { + /* 1Uto8(32to1(expr32)) */ + DEFINE_PATTERN(p_32to1_then_1Uto8, + unop(Iop_1Uto8,unop(Iop_32to1,bind(0)))); + if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) { + IRExpr* expr32 = mi.bindee[0]; + HReg dst = newVRegI(env); + HReg src = iselIntExpr_R(env, expr32); + addInstr(env, PPC32Instr_Alu32(Palu_AND, dst, src, PPC32RI_Imm(1))); + return dst; + } -//.. /* 16Uto32(LDle(expr32)) */ -//.. { -//.. DECLARE_PATTERN(p_LDle16_then_16Uto32); -//.. DEFINE_PATTERN(p_LDle16_then_16Uto32, -//.. unop(Iop_16Uto32,IRExpr_LDle(Ity_I16,bind(0))) ); -//.. if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) { -//.. HReg dst = newVRegI(env); -//.. X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] ); -//.. addInstr(env, X86Instr_LoadEX(2,False,amode,dst)); -//.. return dst; -//.. } -//.. } + /* 16Uto32(LDle(expr32)) */ + { + DECLARE_PATTERN(p_LDle16_then_16Uto32); + DEFINE_PATTERN(p_LDle16_then_16Uto32, + unop(Iop_16Uto32,IRExpr_LDle(Ity_I16,bind(0))) ); + if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) { + HReg dst = newVRegI(env); + PPC32AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] ); + addInstr(env, PPC32Instr_LoadEX(2,False,dst,amode)); + return dst; + } + } + + switch (e->Iex.Unop.op) { + case Iop_8Uto16: + case Iop_8Uto32: + case Iop_16Uto32: { + HReg dst = newVRegI(env); + HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); + UInt mask = e->Iex.Unop.op==Iop_16Uto32 ? 0xFFFF : 0xFF; + addInstr(env, PPC32Instr_Alu32(Palu_AND,dst,src,PPC32RI_Imm(mask))); + return dst; + } + case Iop_8Sto16: + case Iop_8Sto32: + case Iop_16Sto32: { + HReg dst = newVRegI(env); + HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); + UInt amt = e->Iex.Unop.op==Iop_16Sto32 ? 16 : 24; + addInstr(env, PPC32Instr_Sh32(Psh_SHL, dst, src, PPC32RI_Imm(amt))); + addInstr(env, PPC32Instr_Sh32(Psh_SAR, dst, dst, PPC32RI_Imm(amt))); + return dst; + } + case Iop_Not8: + case Iop_Not16: + case Iop_Not32: { + HReg dst = newVRegI(env); + HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); + addInstr(env, mk_iMOVds_RR(dst,src) ); + addInstr(env, PPC32Instr_Unary32(Pun_NOT,PPC32RI_Reg(dst))); + return dst; + } +#if 0 + case Iop_64HIto32: { + HReg rHi, rLo; + iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg); + return rHi; /* and abandon rLo .. poor wee thing :-) */ + } + case Iop_64to32: { + HReg rHi, rLo; + iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg); + return rLo; /* similar stupid comment to the above ... */ + } +#endif + case Iop_16HIto8: + case Iop_32HIto16: { + HReg dst = newVRegI(env); + HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); + UInt shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16; + addInstr(env, PPC32Instr_Sh32(Psh_SHR, dst, src, PPC32RI_Imm(shift))); + return dst; + } +#if 0 + case Iop_1Uto32: + case Iop_1Uto8: { + HReg dst = newVRegI(env); + PPC32CondCode cond = iselCondCode(env, e->Iex.Unop.arg); + addInstr(env, PPC32Instr_Set32(cond,dst)); + return dst; + } + case Iop_1Sto8: + case Iop_1Sto16: + case Iop_1Sto32: { + /* could do better than this, but for now ... */ + HReg dst = newVRegI(env); + PPC32CondCode cond = iselCondCode(env, e->Iex.Unop.arg); + addInstr(env, PPC32Instr_Set32(cond,dst)); + addInstr(env, PPC32Instr_Sh32(Psh_SHL, 31, PPC32RI_Reg(dst))); + addInstr(env, PPC32Instr_Sh32(Psh_SAR, 31, PPC32RI_Reg(dst))); + return dst; + } +#endif -//.. switch (e->Iex.Unop.op) { -//.. case Iop_8Uto16: -//.. case Iop_8Uto32: -//.. case Iop_16Uto32: { -//.. HReg dst = newVRegI(env); -//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); -//.. UInt mask = e->Iex.Unop.op==Iop_16Uto32 ? 0xFFFF : 0xFF; -//.. addInstr(env, mk_iMOVsd_RR(src,dst) ); -//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, -//.. X86RMI_Imm(mask), dst)); -//.. return dst; -//.. } -//.. case Iop_8Sto16: -//.. case Iop_8Sto32: -//.. case Iop_16Sto32: { -//.. HReg dst = newVRegI(env); -//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); -//.. UInt amt = e->Iex.Unop.op==Iop_16Sto32 ? 16 : 24; -//.. addInstr(env, mk_iMOVsd_RR(src,dst) ); -//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, amt, X86RM_Reg(dst))); -//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, amt, X86RM_Reg(dst))); -//.. return dst; -//.. } -//.. case Iop_Not8: -//.. case Iop_Not16: -//.. case Iop_Not32: { -//.. HReg dst = newVRegI(env); -//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); -//.. addInstr(env, mk_iMOVsd_RR(src,dst) ); -//.. addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(dst))); -//.. return dst; -//.. } -//.. case Iop_64HIto32: { -//.. HReg rHi, rLo; -//.. iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg); -//.. return rHi; /* and abandon rLo .. poor wee thing :-) */ -//.. } -//.. case Iop_64to32: { -//.. HReg rHi, rLo; -//.. iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg); -//.. return rLo; /* similar stupid comment to the above ... */ -//.. } -//.. case Iop_16HIto8: -//.. case Iop_32HIto16: { -//.. HReg dst = newVRegI(env); -//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); -//.. Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16; -//.. addInstr(env, mk_iMOVsd_RR(src,dst) ); -//.. addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst))); -//.. return dst; -//.. } -//.. case Iop_1Uto32: -//.. case Iop_1Uto8: { -//.. HReg dst = newVRegI(env); -//.. X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg); -//.. addInstr(env, X86Instr_Set32(cond,dst)); -//.. return dst; -//.. } -//.. case Iop_1Sto8: -//.. case Iop_1Sto16: -//.. case Iop_1Sto32: { -//.. /* could do better than this, but for now ... */ -//.. HReg dst = newVRegI(env); -//.. X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg); -//.. addInstr(env, X86Instr_Set32(cond,dst)); -//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, X86RM_Reg(dst))); -//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(dst))); -//.. return dst; -//.. } //.. case Iop_Ctz32: { //.. /* Count trailing zeroes, implemented by x86 'bsfl' */ //.. HReg dst = newVRegI(env); @@ -1116,27 +1098,24 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) //.. return dst; //.. } -//.. case Iop_16to8: -//.. case Iop_32to8: -//.. case Iop_32to16: -//.. /* These are no-ops. */ -//.. return iselIntExpr_R(env, e->Iex.Unop.arg); -//.. -//.. default: -//.. break; -//.. } -//.. break; -//.. } + case Iop_16to8: + case Iop_32to8: + case Iop_32to16: + /* These are no-ops. */ + return iselIntExpr_R(env, e->Iex.Unop.arg); + + default: + break; + } + break; + } /* --------- GET --------- */ case Iex_Get: { if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32) { HReg dst = newVRegI(env); - addInstr(env, PPC32Instr_LoadEX( - (ty==Ity_I8) ? 1 : ((ty==Ity_I16) ? 2 : 4), - False, - dst, - PPC32AMode_IR(e->Iex.Get.offset, GuestStateReg ))); + PPC32AMode* am_src = PPC32AMode_IR(e->Iex.Get.offset, GuestStatePtr ); + addInstr(env, PPC32Instr_LoadEX( sizeofIRType( ty ), False, dst, am_src )); return dst; } break; @@ -1155,31 +1134,31 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) //.. break; //.. } -//.. /* --------- CCALL --------- */ -//.. case Iex_CCall: { -//.. HReg dst = newVRegI(env); -//.. vassert(ty == Ity_I32); -//.. -//.. /* be very restrictive for now. Only 32/64-bit ints allowed -//.. for args, and 32 bits for return type. */ -//.. if (e->Iex.CCall.retty != Ity_I32) -//.. goto irreducible; -//.. -//.. /* Marshal args, do the call, clear stack. */ -//.. doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args ); -//.. -//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst)); -//.. return dst; -//.. } + /* --------- CCALL --------- */ + case Iex_CCall: { + HReg dst = newVRegI(env); + vassert(ty == Ity_I32); -//.. /* --------- LITERAL --------- */ -//.. /* 32/16/8-bit literals */ -//.. case Iex_Const: { -//.. X86RMI* rmi = iselIntExpr_RMI ( env, e ); -//.. HReg r = newVRegI(env); -//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, rmi, r)); -//.. return r; -//.. } + /* be very restrictive for now. Only 32/64-bit ints allowed + for args, and 32 bits for return type. */ + if (e->Iex.CCall.retty != Ity_I32) + goto irreducible; + + /* Marshal args, do the call, clear stack. */ + doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args ); + + addInstr(env, mk_iMOVds_RR(dst, hregPPC32_GPR0())); + return dst; + } + + /* --------- LITERAL --------- */ + /* 32/16/8-bit literals */ + case Iex_Const: { + PPC32RI* ri = iselIntExpr_RI ( env, e ); + HReg dst = newVRegI(env); + addInstr(env, mk_iMOVds_RRI(dst, ri)); + return dst; + } //.. /* --------- MULTIPLEX --------- */ //.. case Iex_Mux0X: { @@ -1221,20 +1200,22 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) result. The expression may only be a 32-bit one. */ -#if 0 static Bool sane_AMode ( PPC32AMode* am ) { switch (am->tag) { case Pam_IR: - return hregClass(am->Pam.IR.base) == HRcInt32 - && (hregIsVirtual(am->Pam.IR.base)); + return (hregClass(am->Pam.IR.base) == HRcInt32 + && hregIsVirtual(am->Pam.IR.base)); + case Pam_RR: + return (hregClass(am->Pam.RR.base) == HRcInt32 + && hregIsVirtual(am->Pam.IR.base) + && hregClass(am->Pam.RR.base) == HRcInt32 + && hregIsVirtual(am->Pam.IR.base)); default: vpanic("sane_AMode: unknown ppc32 amode tag"); } } -#endif -#if 0 static PPC32AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e ) { PPC32AMode* am = iselIntExpr_AMode_wrk(env, e); @@ -1248,6 +1229,14 @@ static PPC32AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e ) IRType ty = typeOfIRExpr(env->type_env,e); vassert(ty == Ity_I32); + vex_printf("@iselIntExpr_AMode_wrk@\n"); + + // CAB: + // Can only make IR variant if + // e->Iex.Binop.arg2->Iex.Const.con->Ico.U32 + // is small enough... + // else an RR... + /* Add32(expr,i) */ if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add32 @@ -1264,7 +1253,6 @@ static PPC32AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e ) return PPC32AMode_IR(0, r1); } } -#endif /* --------------------- RIs --------------------- */ @@ -1272,7 +1260,6 @@ static PPC32AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e ) /* Calculate an expression into an PPC32RI operand. As with iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */ -#if 0 static PPC32RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e ) { PPC32RI* ri = iselIntExpr_RI_wrk(env, e); @@ -1295,6 +1282,8 @@ static PPC32RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e ) IRType ty = typeOfIRExpr(env->type_env,e); vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8); + vex_printf("@iselIntExpr_RI_wrk@\n"); + /* special case: immediate */ if (e->tag == Iex_Const) { UInt u; @@ -1313,32 +1302,33 @@ static PPC32RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e ) return PPC32RI_Reg(r); } } -#endif -//.. /* --------------------- CONDCODE --------------------- */ -//.. -//.. /* Generate code to evaluated a bit-typed expression, returning the -//.. condition code which would correspond when the expression would -//.. notionally have returned 1. */ -//.. -//.. static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e ) -//.. { -//.. /* Uh, there's nothing we can sanity check here, unfortunately. */ -//.. return iselCondCode_wrk(env,e); -//.. } -//.. -//.. /* DO NOT CALL THIS DIRECTLY ! */ -//.. static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e ) -//.. { -//.. MatchInfo mi; -//.. DECLARE_PATTERN(p_32to1); +/* --------------------- CONDCODE --------------------- */ + +/* Generate code to evaluated a bit-typed expression, returning the + condition code which would correspond when the expression would + notionally have returned 1. */ + +static PPC32CondCode iselCondCode ( ISelEnv* env, IRExpr* e ) +{ + /* Uh, there's nothing we can sanity check here, unfortunately. */ + return iselCondCode_wrk(env,e); +} + +/* DO NOT CALL THIS DIRECTLY ! */ +static PPC32CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e ) +{ + MatchInfo mi; + DECLARE_PATTERN(p_32to1); //.. DECLARE_PATTERN(p_1Uto32_then_32to1); //.. DECLARE_PATTERN(p_1Sto32_then_32to1); -//.. -//.. vassert(e); -//.. vassert(typeOfIRExpr(env->type_env,e) == Ity_I1); -//.. + + vassert(e); + vassert(typeOfIRExpr(env->type_env,e) == Ity_I1); + + vex_printf("@iselCondCode_wrk\n"); + //.. /* Constant 1:Bit */ //.. if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) { //.. HReg r; @@ -1348,13 +1338,13 @@ static PPC32RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e ) //.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(r),r)); //.. return Xcc_Z; //.. } -//.. -//.. /* Not1(...) */ -//.. if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) { -//.. /* Generate code for the arg, and negate the test condition */ -//.. return 1 ^ iselCondCode(env, e->Iex.Unop.arg); -//.. } -//.. + + /* Not1(...) */ + if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) { + /* Generate code for the arg, and negate the test condition */ + return 1 ^ iselCondCode(env, e->Iex.Unop.arg); + } + //.. /* 32to1(1Uto32(expr1)) -- the casts are pointless, ignore them */ //.. DEFINE_PATTERN(p_1Uto32_then_32to1, //.. unop(Iop_32to1,unop(Iop_1Uto32,bind(0)))); @@ -1370,17 +1360,17 @@ static PPC32RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e ) //.. IRExpr* expr1 = mi.bindee[0]; //.. return iselCondCode(env, expr1); //.. } -//.. -//.. /* pattern: 32to1(expr32) */ -//.. DEFINE_PATTERN(p_32to1, -//.. unop(Iop_32to1,bind(0)) -//.. ); -//.. if (matchIRExpr(&mi,p_32to1,e)) { -//.. X86RM* rm = iselIntExpr_RM(env, mi.bindee[0]); -//.. addInstr(env, X86Instr_Test32(X86RI_Imm(1),rm)); -//.. return Xcc_NZ; -//.. } -//.. + + /* pattern: 32to1(expr32) */ + DEFINE_PATTERN(p_32to1, + unop(Iop_32to1,bind(0)) + ); + if (matchIRExpr(&mi,p_32to1,e)) { + HReg dst = iselIntExpr_R(env, mi.bindee[0]); + addInstr(env, PPC32Instr_Test32(dst,PPC32RI_Imm(1))); + return Pcc_NZ; + } + //.. /* CmpEQ8 / CmpNE8 */ //.. if (e->tag == Iex_Binop //.. && (e->Iex.Binop.op == Iop_CmpEQ8 @@ -1494,7 +1484,7 @@ static PPC32RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e ) //.. default: vpanic("iselCondCode(x86): CmpXX64"); //.. } //.. } -//.. + //.. /* var */ //.. if (e->tag == Iex_Tmp) { //.. HReg r32 = lookupIRTemp(env, e->Iex.Tmp.tmp); @@ -1503,11 +1493,669 @@ static PPC32RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e ) //.. addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(1),dst)); //.. return Xcc_NZ; //.. } -//.. -//.. ppIRExpr(e); -//.. vpanic("iselCondCode"); -//.. } + ppIRExpr(e); + vpanic("iselCondCode(ppc32)"); +} + + +#if 0 +/*---------------------------------------------------------*/ +/*--- ISEL: Integer expressions (64 bit) ---*/ +/*---------------------------------------------------------*/ + +/* Compute a 64-bit value into a register pair, which is returned as + the first two parameters. As with iselIntExpr_R, these may be + either real or virtual regs; in any case they must not be changed + by subsequent code emitted by the caller. */ + +static void iselInt64Expr ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e ) +{ + iselInt64Expr_wrk(rHi, rLo, env, e); +# if 0 + vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); +# endif + vassert(hregClass(*rHi) == HRcInt32); + vassert(hregIsVirtual(*rHi)); + vassert(hregClass(*rLo) == HRcInt32); + vassert(hregIsVirtual(*rLo)); +} + +/* DO NOT CALL THIS DIRECTLY ! */ +static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e ) +{ + HWord fn = 0; /* helper fn for most SIMD64 stuff */ + vassert(e); + vassert(typeOfIRExpr(env->type_env,e) == Ity_I64); + + /* 64-bit literal */ + if (e->tag == Iex_Const) { + ULong w64 = e->Iex.Const.con->Ico.U64; + UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF; + UInt wLo = ((UInt)w64) & 0xFFFFFFFF; + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + vassert(e->Iex.Const.con->tag == Ico_U64); + addInstr(env, PPC32Instr_Alu32R(Palu_MOV, PPC32RI_Imm(wHi), tHi)); + addInstr(env, PPC32Instr_Alu32R(Palu_MOV, PPC32RI_Imm(wLo), tLo)); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* read 64-bit IRTemp */ + if (e->tag == Iex_Tmp) { + lookupIRTemp64( rHi, rLo, env, e->Iex.Tmp.tmp); + return; + } + + /* 64-bit load */ + if (e->tag == Iex_LDle) { + HReg tLo, tHi; + PPC32AMode *am0, *am4; + vassert(e->Iex.LDle.ty == Ity_I64); + tLo = newVRegI(env); + tHi = newVRegI(env); + am0 = iselIntExpr_AMode(env, e->Iex.LDle.addr); + am4 = advance4(am0); + addInstr(env, PPC32Instr_Alu32R( Palu_MOV, PPC32RI_Mem(am0), tLo )); + addInstr(env, PPC32Instr_Alu32R( Palu_MOV, PPC32RI_Mem(am4), tHi )); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* 64-bit GET */ + if (e->tag == Iex_Get) { + PPC32AMode* am = PPC32AMode_IR(e->Iex.Get.offset, hregPPC32_EBP()); + PPC32AMode* am4 = advance4(am); + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + addInstr(env, PPC32Instr_Alu32R( Palu_MOV, PPC32RI_Mem(am), tLo )); + addInstr(env, PPC32Instr_Alu32R( Palu_MOV, PPC32RI_Mem(am4), tHi )); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* 64-bit GETI */ + if (e->tag == Iex_GetI) { + PPC32AMode* am + = genGuestArrayOffset( env, e->Iex.GetI.descr, + e->Iex.GetI.ix, e->Iex.GetI.bias ); + PPC32AMode* am4 = advance4(am); + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + addInstr(env, PPC32Instr_Alu32R( Palu_MOV, PPC32RI_Mem(am), tLo )); + addInstr(env, PPC32Instr_Alu32R( Palu_MOV, PPC32RI_Mem(am4), tHi )); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* 64-bit Mux0X */ + if (e->tag == Iex_Mux0X) { + HReg e0Lo, e0Hi, eXLo, eXHi, r8; + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.Mux0X.expr0); + iselInt64Expr(&eXHi, &eXLo, env, e->Iex.Mux0X.exprX); + addInstr(env, mk_iMOVsd_RR(eXHi, tHi)); + addInstr(env, mk_iMOVsd_RR(eXLo, tLo)); + r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond); + addInstr(env, PPC32Instr_Test32(PPC32RI_Imm(0xFF), PPC32RM_Reg(r8))); + /* This assumes the first cmov32 doesn't trash the condition + codes, so they are still available for the second cmov32 */ + addInstr(env, PPC32Instr_CMov32(Pcc_Z,PPC32RM_Reg(e0Hi),tHi)); + addInstr(env, PPC32Instr_CMov32(Pcc_Z,PPC32RM_Reg(e0Lo),tLo)); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* --------- BINARY ops --------- */ + if (e->tag == Iex_Binop) { + switch (e->Iex.Binop.op) { + /* 32 x 32 -> 64 multiply */ + case Iop_MullU32: + case Iop_MullS32: { + /* get one operand into %eax, and the other into a R/M. + Need to make an educated guess about which is better in + which. */ + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + Bool syned = e->Iex.Binop.op == Iop_MullS32; + PPC32RM* rmLeft = iselIntExpr_RM(env, e->Iex.Binop.arg1); + HReg rRight = iselIntExpr_R(env, e->Iex.Binop.arg2); + addInstr(env, mk_iMOVsd_RR(rRight, hregPPC32_EAX())); + addInstr(env, PPC32Instr_MulL(syned, Pss_32, rmLeft)); + /* Result is now in EDX:EAX. Tell the caller. */ + addInstr(env, mk_iMOVsd_RR(hregPPC32_EDX(), tHi)); + addInstr(env, mk_iMOVsd_RR(hregPPC32_EAX(), tLo)); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* 64 x 32 -> (32(rem),32(div)) division */ + case Iop_DivModU64to32: + case Iop_DivModS64to32: { + /* Get the 64-bit operand into edx:eax, and the other into + any old R/M. */ + HReg sHi, sLo; + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + Bool syned = e->Iex.Binop.op == Iop_DivModS64to32; + PPC32RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2); + iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1); + addInstr(env, mk_iMOVsd_RR(sHi, hregPPC32_EDX())); + addInstr(env, mk_iMOVsd_RR(sLo, hregPPC32_EAX())); + addInstr(env, PPC32Instr_Div(syned, Pss_32, rmRight)); + addInstr(env, mk_iMOVsd_RR(hregPPC32_EDX(), tHi)); + addInstr(env, mk_iMOVsd_RR(hregPPC32_EAX(), tLo)); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* Or64/And64/Xor64 */ + case Iop_Or64: + case Iop_And64: + case Iop_Xor64: { + HReg xLo, xHi, yLo, yHi; + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + PPC32AluOp op = e->Iex.Binop.op==Iop_Or64 ? Palu_OR + : e->Iex.Binop.op==Iop_And64 ? Palu_AND + : Palu_XOR; + iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); + addInstr(env, mk_iMOVsd_RR(xHi, tHi)); + addInstr(env, mk_iMOVsd_RR(xLo, tLo)); + iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); + addInstr(env, PPC32Instr_Alu32R(op, PPC32RI_Reg(yHi), tHi)); + addInstr(env, PPC32Instr_Alu32R(op, PPC32RI_Reg(yLo), tLo)); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* Add64/Sub64 */ + case Iop_Add64: + case Iop_Sub64: { + HReg xLo, xHi, yLo, yHi; + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); + addInstr(env, mk_iMOVsd_RR(xHi, tHi)); + addInstr(env, mk_iMOVsd_RR(xLo, tLo)); + iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); + if (e->Iex.Binop.op==Iop_Add64) { + addInstr(env, PPC32Instr_Alu32R(Palu_ADD, PPC32RI_Reg(yLo), tLo)); + addInstr(env, PPC32Instr_Alu32R(Palu_ADC, PPC32RI_Reg(yHi), tHi)); + } else { + addInstr(env, PPC32Instr_Alu32R(Palu_SUB, PPC32RI_Reg(yLo), tLo)); + addInstr(env, PPC32Instr_Alu32R(Palu_SBB, PPC32RI_Reg(yHi), tHi)); + } + *rHi = tHi; + *rLo = tLo; + return; + } + + /* 32HLto64(e1,e2) */ + case Iop_32HLto64: + *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1); + *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2); + return; + + /* 64-bit shifts */ + case Iop_Shl64: { + /* We use the same ingenious scheme as gcc. Put the value + to be shifted into %hi:%lo, and the shift amount into + %cl. Then (dsts on right, a la ATT syntax): + + shldl %cl, %lo, %hi -- make %hi be right for the + -- shift amt %cl % 32 + shll %cl, %lo -- make %lo be right for the + -- shift amt %cl % 32 + + Now, if (shift amount % 64) is in the range 32 .. 63, + we have to do a fixup, which puts the result low half + into the result high half, and zeroes the low half: + + testl $32, %ecx + + cmovnz %lo, %hi + movl $0, %tmp -- sigh; need yet another reg + cmovnz %tmp, %lo + */ + HReg rAmt, sHi, sLo, tHi, tLo, tTemp; + tLo = newVRegI(env); + tHi = newVRegI(env); + tTemp = newVRegI(env); + rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2); + iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1); + addInstr(env, mk_iMOVsd_RR(rAmt, hregPPC32_ECX())); + addInstr(env, mk_iMOVsd_RR(sHi, tHi)); + addInstr(env, mk_iMOVsd_RR(sLo, tLo)); + /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo + and those regs are legitimately modifiable. */ + addInstr(env, PPC32Instr_Sh3232(Psh_SHL, 0/*%cl*/, tLo, tHi)); + addInstr(env, PPC32Instr_Sh32(Psh_SHL, 0/*%cl*/, PPC32RM_Reg(tLo))); + addInstr(env, PPC32Instr_Test32(PPC32RI_Imm(32), + PPC32RM_Reg(hregPPC32_ECX()))); + addInstr(env, PPC32Instr_CMov32(Pcc_NZ, PPC32RM_Reg(tLo), tHi)); + addInstr(env, PPC32Instr_Alu32R(Palu_MOV, PPC32RI_Imm(0), tTemp)); + addInstr(env, PPC32Instr_CMov32(Pcc_NZ, PPC32RM_Reg(tTemp), tLo)); + *rHi = tHi; + *rLo = tLo; + return; + } + + case Iop_Shr64: { + /* We use the same ingenious scheme as gcc. Put the value + to be shifted into %hi:%lo, and the shift amount into + %cl. Then: + + shrdl %cl, %hi, %lo -- make %lo be right for the + -- shift amt %cl % 32 + shrl %cl, %hi -- make %hi be right for the + -- shift amt %cl % 32 + + Now, if (shift amount % 64) is in the range 32 .. 63, + we have to do a fixup, which puts the result high half + into the result low half, and zeroes the high half: + + testl $32, %ecx + + cmovnz %hi, %lo + movl $0, %tmp -- sigh; need yet another reg + cmovnz %tmp, %hi + */ + HReg rAmt, sHi, sLo, tHi, tLo, tTemp; + tLo = newVRegI(env); + tHi = newVRegI(env); + tTemp = newVRegI(env); + rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2); + iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1); + addInstr(env, mk_iMOVsd_RR(rAmt, hregPPC32_ECX())); + addInstr(env, mk_iMOVsd_RR(sHi, tHi)); + addInstr(env, mk_iMOVsd_RR(sLo, tLo)); + /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo + and those regs are legitimately modifiable. */ + addInstr(env, PPC32Instr_Sh3232(Psh_SHR, 0/*%cl*/, tHi, tLo)); + addInstr(env, PPC32Instr_Sh32(Psh_SHR, 0/*%cl*/, PPC32RM_Reg(tHi))); + addInstr(env, PPC32Instr_Test32(PPC32RI_Imm(32), + PPC32RM_Reg(hregPPC32_ECX()))); + addInstr(env, PPC32Instr_CMov32(Pcc_NZ, PPC32RM_Reg(tHi), tLo)); + addInstr(env, PPC32Instr_Alu32R(Palu_MOV, PPC32RI_Imm(0), tTemp)); + addInstr(env, PPC32Instr_CMov32(Pcc_NZ, PPC32RM_Reg(tTemp), tHi)); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* F64 -> I64 */ + /* Sigh, this is an almost exact copy of the F64 -> I32/I16 + case. Unfortunately I see no easy way to avoid the + duplication. */ + case Iop_F64toI64: { + HReg rf = iselDblExpr(env, e->Iex.Binop.arg2); + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + + /* Used several times ... */ + /* Careful ... this sharing is only safe because + zero_esp/four_esp do not hold any registers which the + register allocator could attempt to swizzle later. */ + PPC32AMode* zero_esp = PPC32AMode_IR(0, hregPPC32_ESP()); + PPC32AMode* four_esp = PPC32AMode_IR(4, hregPPC32_ESP()); + + /* rf now holds the value to be converted, and rrm holds + the rounding mode value, encoded as per the + IRRoundingMode enum. The first thing to do is set the + FPU's rounding mode accordingly. */ + + /* Create a space for the format conversion. */ + /* subl $8, %esp */ + sub_from_esp(env, 8); + + /* Set host rounding mode */ + set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); + + /* gistll %rf, 0(%esp) */ + addInstr(env, PPC32Instr_FpLdStI(False/*store*/, 8, rf, zero_esp)); + + /* movl 0(%esp), %dstLo */ + /* movl 4(%esp), %dstHi */ + addInstr(env, PPC32Instr_Alu32R( + Palu_MOV, PPC32RI_Mem(zero_esp), tLo)); + addInstr(env, PPC32Instr_Alu32R( + Palu_MOV, PPC32RI_Mem(four_esp), tHi)); + + /* Restore default FPU rounding. */ + set_FPU_rounding_default( env ); + + /* addl $8, %esp */ + add_to_esp(env, 8); + + *rHi = tHi; + *rLo = tLo; + return; + } + + case Iop_Add8x8: + fn = (HWord)h_generic_calc_Add8x8; goto binnish; + case Iop_Add16x4: + fn = (HWord)h_generic_calc_Add16x4; goto binnish; + case Iop_Add32x2: + fn = (HWord)h_generic_calc_Add32x2; goto binnish; + + case Iop_Avg8Ux8: + fn = (HWord)h_generic_calc_Avg8Ux8; goto binnish; + case Iop_Avg16Ux4: + fn = (HWord)h_generic_calc_Avg16Ux4; goto binnish; + + case Iop_CmpEQ8x8: + fn = (HWord)h_generic_calc_CmpEQ8x8; goto binnish; + case Iop_CmpEQ16x4: + fn = (HWord)h_generic_calc_CmpEQ16x4; goto binnish; + case Iop_CmpEQ32x2: + fn = (HWord)h_generic_calc_CmpEQ32x2; goto binnish; + + case Iop_CmpGT8Sx8: + fn = (HWord)h_generic_calc_CmpGT8Sx8; goto binnish; + case Iop_CmpGT16Sx4: + fn = (HWord)h_generic_calc_CmpGT16Sx4; goto binnish; + case Iop_CmpGT32Sx2: + fn = (HWord)h_generic_calc_CmpGT32Sx2; goto binnish; + + case Iop_InterleaveHI8x8: + fn = (HWord)h_generic_calc_InterleaveHI8x8; goto binnish; + case Iop_InterleaveLO8x8: + fn = (HWord)h_generic_calc_InterleaveLO8x8; goto binnish; + case Iop_InterleaveHI16x4: + fn = (HWord)h_generic_calc_InterleaveHI16x4; goto binnish; + case Iop_InterleaveLO16x4: + fn = (HWord)h_generic_calc_InterleaveLO16x4; goto binnish; + case Iop_InterleaveHI32x2: + fn = (HWord)h_generic_calc_InterleaveHI32x2; goto binnish; + case Iop_InterleaveLO32x2: + fn = (HWord)h_generic_calc_InterleaveLO32x2; goto binnish; + + case Iop_Max8Ux8: + fn = (HWord)h_generic_calc_Max8Ux8; goto binnish; + case Iop_Max16Sx4: + fn = (HWord)h_generic_calc_Max16Sx4; goto binnish; + case Iop_Min8Ux8: + fn = (HWord)h_generic_calc_Min8Ux8; goto binnish; + case Iop_Min16Sx4: + fn = (HWord)h_generic_calc_Min16Sx4; goto binnish; + + case Iop_Mul16x4: + fn = (HWord)h_generic_calc_Mul16x4; goto binnish; + case Iop_MulHi16Sx4: + fn = (HWord)h_generic_calc_MulHi16Sx4; goto binnish; + case Iop_MulHi16Ux4: + fn = (HWord)h_generic_calc_MulHi16Ux4; goto binnish; + + case Iop_QAdd8Sx8: + fn = (HWord)h_generic_calc_QAdd8Sx8; goto binnish; + case Iop_QAdd16Sx4: + fn = (HWord)h_generic_calc_QAdd16Sx4; goto binnish; + case Iop_QAdd8Ux8: + fn = (HWord)h_generic_calc_QAdd8Ux8; goto binnish; + case Iop_QAdd16Ux4: + fn = (HWord)h_generic_calc_QAdd16Ux4; goto binnish; + + case Iop_QNarrow32Sx2: + fn = (HWord)h_generic_calc_QNarrow32Sx2; goto binnish; + case Iop_QNarrow16Sx4: + fn = (HWord)h_generic_calc_QNarrow16Sx4; goto binnish; + case Iop_QNarrow16Ux4: + fn = (HWord)h_generic_calc_QNarrow16Ux4; goto binnish; + + case Iop_QSub8Sx8: + fn = (HWord)h_generic_calc_QSub8Sx8; goto binnish; + case Iop_QSub16Sx4: + fn = (HWord)h_generic_calc_QSub16Sx4; goto binnish; + case Iop_QSub8Ux8: + fn = (HWord)h_generic_calc_QSub8Ux8; goto binnish; + case Iop_QSub16Ux4: + fn = (HWord)h_generic_calc_QSub16Ux4; goto binnish; + + case Iop_Sub8x8: + fn = (HWord)h_generic_calc_Sub8x8; goto binnish; + case Iop_Sub16x4: + fn = (HWord)h_generic_calc_Sub16x4; goto binnish; + case Iop_Sub32x2: + fn = (HWord)h_generic_calc_Sub32x2; goto binnish; + + binnish: { + /* Note: the following assumes all helpers are of + signature + ULong fn ( ULong, ULong ), and they are + not marked as regparm functions. + */ + HReg xLo, xHi, yLo, yHi; + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); + addInstr(env, PPC32Instr_Push(PPC32RI_Reg(yHi))); + addInstr(env, PPC32Instr_Push(PPC32RI_Reg(yLo))); + iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); + addInstr(env, PPC32Instr_Push(PPC32RI_Reg(xHi))); + addInstr(env, PPC32Instr_Push(PPC32RI_Reg(xLo))); + addInstr(env, PPC32Instr_Call( Pcc_ALWAYS, (UInt)fn, 0 )); + add_to_esp(env, 4*4); + addInstr(env, mk_iMOVsd_RR(hregPPC32_EDX(), tHi)); + addInstr(env, mk_iMOVsd_RR(hregPPC32_EAX(), tLo)); + *rHi = tHi; + *rLo = tLo; + return; + } + + case Iop_ShlN32x2: + fn = (HWord)h_generic_calc_ShlN32x2; goto shifty; + case Iop_ShlN16x4: + fn = (HWord)h_generic_calc_ShlN16x4; goto shifty; + case Iop_ShrN32x2: + fn = (HWord)h_generic_calc_ShrN32x2; goto shifty; + case Iop_ShrN16x4: + fn = (HWord)h_generic_calc_ShrN16x4; goto shifty; + case Iop_SarN32x2: + fn = (HWord)h_generic_calc_SarN32x2; goto shifty; + case Iop_SarN16x4: + fn = (HWord)h_generic_calc_SarN16x4; goto shifty; + shifty: { + /* Note: the following assumes all helpers are of + signature + ULong fn ( ULong, UInt ), and they are + not marked as regparm functions. + */ + HReg xLo, xHi; + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + PPC32RI* y = iselIntExpr_RI(env, e->Iex.Binop.arg2); + addInstr(env, PPC32Instr_Push(y)); + iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); + addInstr(env, PPC32Instr_Push(PPC32RI_Reg(xHi))); + addInstr(env, PPC32Instr_Push(PPC32RI_Reg(xLo))); + addInstr(env, PPC32Instr_Call( Pcc_ALWAYS, (UInt)fn, 0 )); + add_to_esp(env, 3*4); + addInstr(env, mk_iMOVsd_RR(hregPPC32_EDX(), tHi)); + addInstr(env, mk_iMOVsd_RR(hregPPC32_EAX(), tLo)); + *rHi = tHi; + *rLo = tLo; + return; + } + + default: + break; + } + } /* if (e->tag == Iex_Binop) */ + + + /* --------- UNARY ops --------- */ + if (e->tag == Iex_Unop) { + switch (e->Iex.Unop.op) { + + /* 32Sto64(e) */ + case Iop_32Sto64: { + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); + addInstr(env, mk_iMOVsd_RR(src,tHi)); + addInstr(env, mk_iMOVsd_RR(src,tLo)); + addInstr(env, PPC32Instr_Sh32(Psh_SAR, 31, PPC32RM_Reg(tHi))); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* 32Uto64(e) */ + case Iop_32Uto64: { + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); + addInstr(env, mk_iMOVsd_RR(src,tLo)); + addInstr(env, PPC32Instr_Alu32R(Palu_MOV, PPC32RI_Imm(0), tHi)); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* V128{HI}to64 */ + case Iop_V128HIto64: + case Iop_V128to64: { + Int off = e->Iex.Unop.op==Iop_V128HIto64 ? 8 : 0; + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + HReg vec = iselVecExpr(env, e->Iex.Unop.arg); + PPC32AMode* esp0 = PPC32AMode_IR(0, hregPPC32_ESP()); + PPC32AMode* espLO = PPC32AMode_IR(off, hregPPC32_ESP()); + PPC32AMode* espHI = PPC32AMode_IR(off+4, hregPPC32_ESP()); + sub_from_esp(env, 16); + addInstr(env, PPC32Instr_SseLdSt(False/*store*/, vec, esp0)); + addInstr(env, PPC32Instr_Alu32R( Palu_MOV, + PPC32RI_Mem(espLO), tLo )); + addInstr(env, PPC32Instr_Alu32R( Palu_MOV, + PPC32RI_Mem(espHI), tHi )); + add_to_esp(env, 16); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* could do better than this, but for now ... */ + case Iop_1Sto64: { + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + PPC32CondCode cond = iselCondCode(env, e->Iex.Unop.arg); + addInstr(env, PPC32Instr_Set32(cond,tLo)); + addInstr(env, PPC32Instr_Sh32(Psh_SHL, 31, PPC32RM_Reg(tLo))); + addInstr(env, PPC32Instr_Sh32(Psh_SAR, 31, PPC32RM_Reg(tLo))); + addInstr(env, mk_iMOVsd_RR(tLo, tHi)); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* Not64(e) */ + case Iop_Not64: { + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + HReg sHi, sLo; + iselInt64Expr(&sHi, &sLo, env, e->Iex.Unop.arg); + addInstr(env, mk_iMOVsd_RR(sHi, tHi)); + addInstr(env, mk_iMOVsd_RR(sLo, tLo)); + addInstr(env, PPC32Instr_Unary32(Xun_NOT,PPC32RM_Reg(tHi))); + addInstr(env, PPC32Instr_Unary32(Xun_NOT,PPC32RM_Reg(tLo))); + *rHi = tHi; + *rLo = tLo; + return; + } + + /* ReinterpF64asI64(e) */ + /* Given an IEEE754 double, produce an I64 with the same bit + pattern. */ + case Iop_ReinterpF64asI64: { + HReg rf = iselDblExpr(env, e->Iex.Unop.arg); + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + PPC32AMode* zero_esp = PPC32AMode_IR(0, hregPPC32_ESP()); + PPC32AMode* four_esp = PPC32AMode_IR(4, hregPPC32_ESP()); + /* paranoia */ + set_FPU_rounding_default(env); + /* subl $8, %esp */ + sub_from_esp(env, 8); + /* gstD %rf, 0(%esp) */ + addInstr(env, + PPC32Instr_FpLdSt(False/*store*/, 8, rf, zero_esp)); + /* movl 0(%esp), %tLo */ + addInstr(env, + PPC32Instr_Alu32R(Palu_MOV, PPC32RI_Mem(zero_esp), tLo)); + /* movl 4(%esp), %tHi */ + addInstr(env, + PPC32Instr_Alu32R(Palu_MOV, PPC32RI_Mem(four_esp), tHi)); + /* addl $8, %esp */ + add_to_esp(env, 8); + *rHi = tHi; + *rLo = tLo; + return; + } + + case Iop_CmpNEZ32x2: + fn = (HWord)h_generic_calc_CmpNEZ32x2; goto unish; + case Iop_CmpNEZ16x4: + fn = (HWord)h_generic_calc_CmpNEZ16x4; goto unish; + case Iop_CmpNEZ8x8: + fn = (HWord)h_generic_calc_CmpNEZ8x8; goto unish; + unish: { + /* Note: the following assumes all helpers are of + signature + ULong fn ( ULong ), and they are + not marked as regparm functions. + */ + HReg xLo, xHi; + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg); + addInstr(env, PPC32Instr_Push(PPC32RI_Reg(xHi))); + addInstr(env, PPC32Instr_Push(PPC32RI_Reg(xLo))); + addInstr(env, PPC32Instr_Call( Pcc_ALWAYS, (UInt)fn, 0 )); + add_to_esp(env, 2*4); + addInstr(env, mk_iMOVsd_RR(hregPPC32_EDX(), tHi)); + addInstr(env, mk_iMOVsd_RR(hregPPC32_EAX(), tLo)); + *rHi = tHi; + *rLo = tLo; + return; + } + + default: + break; + } + } /* if (e->tag == Iex_Unop) */ + + + /* --------- CCALL --------- */ + if (e->tag == Iex_CCall) { + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + + /* Marshal args, do the call, clear stack. */ + doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args ); + + addInstr(env, mk_iMOVsd_RR(hregPPC32_EDX(), tHi)); + addInstr(env, mk_iMOVsd_RR(hregPPC32_EAX(), tLo)); + *rHi = tHi; + *rLo = tLo; + return; + } + + ppIRExpr(e); + vpanic("iselInt64Expr"); +} +#endif //.. /*---------------------------------------------------------*/ //.. /*--- ISEL: Floating point expressions (32 bit) ---*/ @@ -2349,31 +2997,27 @@ static PPC32RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e ) static void iselStmt ( ISelEnv* env, IRStmt* stmt ) { if (vex_traceflags & VEX_TRACE_VCODE) { - vex_printf("\n-- "); + vex_printf("\n -- "); ppIRStmt(stmt); vex_printf("\n"); } + + vex_printf("@iselStmt: tag=%d\n", stmt->tag); switch (stmt->tag) { -//.. /* --------- STORE --------- */ -//.. case Ist_STle: { -//.. X86AMode* am; -//.. IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr); -//.. IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data); -//.. vassert(tya == Ity_I32); -//.. am = iselIntExpr_AMode(env, stmt->Ist.STle.addr); -//.. if (tyd == Ity_I32) { -//.. X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data); -//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am)); -//.. return; -//.. } -//.. if (tyd == Ity_I8 || tyd == Ity_I16) { -//.. HReg r = iselIntExpr_R(env, stmt->Ist.STle.data); -//.. addInstr(env, X86Instr_Store(tyd==Ity_I8 ? 1 : 2, -//.. r,am)); -//.. return; -//.. } + /* --------- STORE --------- */ + case Ist_STle: { + PPC32AMode* am_dst; + IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr); + IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data); + vassert(tya == Ity_I32); + am_dst = iselIntExpr_AMode(env, stmt->Ist.STle.addr); + if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32) { + HReg src = iselIntExpr_R(env, stmt->Ist.STle.data); + addInstr(env, PPC32Instr_Store(sizeofIRType(tyd),am_dst,src)); + return; + } //.. if (tyd == Ity_F64) { //.. HReg r = iselDblExpr(env, stmt->Ist.STle.data); //.. addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, r, am)); @@ -2399,18 +3043,16 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) //.. addInstr(env, X86Instr_SseLdSt(False/*store*/, r, am)); //.. return; //.. } -//.. break; -//.. } + break; + } /* --------- PUT --------- */ case Ist_Put: { IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data); if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32) { HReg src = iselIntExpr_R(env, stmt->Ist.Put.data); - addInstr(env, PPC32Instr_Store( - (ty==Ity_I8) ? 1 : ((ty==Ity_I8) ? 2 : 4), - PPC32AMode_IR(stmt->Ist.Put.offset, GuestStateReg), - src)); + PPC32AMode* am_dst = PPC32AMode_IR(stmt->Ist.Put.offset, GuestStatePtr); + addInstr(env, PPC32Instr_Store( sizeofIRType(ty), am_dst, src )); return; } //.. if (ty == Ity_I64) { @@ -2475,7 +3117,7 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) { HReg dst = lookupIRTemp(env, tmp); HReg src = iselIntExpr_R(env, stmt->Ist.Tmp.data); - addInstr(env, mk_iMOVsd_RR( dst, src )); + addInstr(env, mk_iMOVds_RR( dst, src )); return; } //.. if (ty == Ity_I64) { @@ -2580,17 +3222,17 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) /*---------------------------------------------------------*/ static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk ) -{ vassert(0); -//.. X86RI* ri; -//.. if (vex_traceflags & VEX_TRACE_VCODE) { -//.. vex_printf("\n-- goto {"); -//.. ppIRJumpKind(jk); -//.. vex_printf("} "); -//.. ppIRExpr(next); -//.. vex_printf("\n"); -//.. } -//.. ri = iselIntExpr_RI(env, next); -//.. addInstr(env, X86Instr_Goto(jk, Xcc_ALWAYS,ri)); +{ + PPC32RI* ri; + if (vex_traceflags & VEX_TRACE_VCODE) { + vex_printf("\n-- goto {"); + ppIRJumpKind(jk); + vex_printf("} "); + ppIRExpr(next); + vex_printf("\n"); + } + ri = iselIntExpr_RI(env, next); + addInstr(env, PPC32Instr_Goto(jk, Pcc_ALWAYS,ri)); }