From: Julian Seward Date: Sun, 25 Nov 2012 15:17:42 +0000 (+0000) Subject: ARM back end changes, to support code generation for IR guarded loads X-Git-Tag: svn/VALGRIND_3_9_0^2~152^2~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3133e8fce41ed90d93b0144d48d52a0a86e63d59;p=thirdparty%2Fvalgrind.git ARM back end changes, to support code generation for IR guarded loads and stores. git-svn-id: svn://svn.valgrind.org/vex/branches/COMEM@2571 --- diff --git a/VEX/priv/host_arm_defs.c b/VEX/priv/host_arm_defs.c index 64b4af108e..28808a5ab6 100644 --- a/VEX/priv/host_arm_defs.c +++ b/VEX/priv/host_arm_defs.c @@ -1144,30 +1144,48 @@ ARMInstr* ARMInstr_Imm32 ( HReg dst, UInt imm32 ) { i->ARMin.Imm32.imm32 = imm32; return i; } -ARMInstr* ARMInstr_LdSt32 ( Bool isLoad, HReg rD, ARMAMode1* amode ) { +ARMInstr* ARMInstr_LdSt32 ( ARMCondCode cc, + Bool isLoad, HReg rD, ARMAMode1* amode ) { ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr)); i->tag = ARMin_LdSt32; + i->ARMin.LdSt32.cc = cc; i->ARMin.LdSt32.isLoad = isLoad; i->ARMin.LdSt32.rD = rD; i->ARMin.LdSt32.amode = amode; + vassert(cc != ARMcc_NV); return i; } -ARMInstr* ARMInstr_LdSt16 ( Bool isLoad, Bool signedLoad, +ARMInstr* ARMInstr_LdSt16 ( ARMCondCode cc, + Bool isLoad, Bool signedLoad, HReg rD, ARMAMode2* amode ) { ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr)); i->tag = ARMin_LdSt16; + i->ARMin.LdSt16.cc = cc; i->ARMin.LdSt16.isLoad = isLoad; i->ARMin.LdSt16.signedLoad = signedLoad; i->ARMin.LdSt16.rD = rD; i->ARMin.LdSt16.amode = amode; + vassert(cc != ARMcc_NV); return i; } -ARMInstr* ARMInstr_LdSt8U ( Bool isLoad, HReg rD, ARMAMode1* amode ) { +ARMInstr* ARMInstr_LdSt8U ( ARMCondCode cc, + Bool isLoad, HReg rD, ARMAMode1* amode ) { ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr)); i->tag = ARMin_LdSt8U; + i->ARMin.LdSt8U.cc = cc; i->ARMin.LdSt8U.isLoad = isLoad; i->ARMin.LdSt8U.rD = rD; i->ARMin.LdSt8U.amode = amode; + vassert(cc != ARMcc_NV); + return i; +} +ARMInstr* ARMInstr_Ld8S ( ARMCondCode cc, HReg rD, ARMAMode2* amode ) { + ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr)); + i->tag = ARMin_Ld8S; + i->ARMin.Ld8S.cc = cc; + i->ARMin.Ld8S.rD = rD; + i->ARMin.Ld8S.amode = amode; + vassert(cc != ARMcc_NV); return i; } ARMInstr* ARMInstr_XDirect ( Addr32 dstGA, ARMAMode1* amR15T, @@ -1208,12 +1226,15 @@ ARMInstr* ARMInstr_CMov ( ARMCondCode cond, HReg dst, ARMRI84* src ) { vassert(cond != ARMcc_AL); return i; } -ARMInstr* ARMInstr_Call ( ARMCondCode cond, HWord target, Int nArgRegs ) { +ARMInstr* ARMInstr_Call ( ARMCondCode cond, HWord target, Int nArgRegs, + RetLoc rloc ) { ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr)); i->tag = ARMin_Call; i->ARMin.Call.cond = cond; i->ARMin.Call.target = target; i->ARMin.Call.nArgRegs = nArgRegs; + i->ARMin.Call.rloc = rloc; + vassert(rloc != RetLocINVALID); return i; } ARMInstr* ARMInstr_Mul ( ARMMulOp op ) { @@ -1559,12 +1580,14 @@ void ppARMInstr ( ARMInstr* i ) { return; case ARMin_LdSt32: if (i->ARMin.LdSt32.isLoad) { - vex_printf("ldr "); + vex_printf("ldr%s ", i->ARMin.LdSt32.cc == ARMcc_AL ? " " + : showARMCondCode(i->ARMin.LdSt32.cc)); ppHRegARM(i->ARMin.LdSt32.rD); vex_printf(", "); ppARMAMode1(i->ARMin.LdSt32.amode); } else { - vex_printf("str "); + vex_printf("str%s ", i->ARMin.LdSt32.cc == ARMcc_AL ? " " + : showARMCondCode(i->ARMin.LdSt32.cc)); ppARMAMode1(i->ARMin.LdSt32.amode); vex_printf(", "); ppHRegARM(i->ARMin.LdSt32.rD); @@ -1572,13 +1595,18 @@ void ppARMInstr ( ARMInstr* i ) { return; case ARMin_LdSt16: if (i->ARMin.LdSt16.isLoad) { - vex_printf("%s", i->ARMin.LdSt16.signedLoad - ? "ldrsh " : "ldrh " ); + vex_printf("%s%s%s", + i->ARMin.LdSt16.signedLoad ? "ldrsh" : "ldrh", + i->ARMin.LdSt16.cc == ARMcc_AL ? " " + : showARMCondCode(i->ARMin.LdSt16.cc), + i->ARMin.LdSt16.signedLoad ? " " : " "); ppHRegARM(i->ARMin.LdSt16.rD); vex_printf(", "); ppARMAMode2(i->ARMin.LdSt16.amode); } else { - vex_printf("strh "); + vex_printf("strh%s ", + i->ARMin.LdSt16.cc == ARMcc_AL ? " " + : showARMCondCode(i->ARMin.LdSt16.cc)); ppARMAMode2(i->ARMin.LdSt16.amode); vex_printf(", "); ppHRegARM(i->ARMin.LdSt16.rD); @@ -1586,19 +1614,26 @@ void ppARMInstr ( ARMInstr* i ) { return; case ARMin_LdSt8U: if (i->ARMin.LdSt8U.isLoad) { - vex_printf("ldrb "); + vex_printf("ldrb%s ", i->ARMin.LdSt8U.cc == ARMcc_AL ? " " + : showARMCondCode(i->ARMin.LdSt8U.cc)); ppHRegARM(i->ARMin.LdSt8U.rD); vex_printf(", "); ppARMAMode1(i->ARMin.LdSt8U.amode); } else { - vex_printf("strb "); + vex_printf("strb%s ", i->ARMin.LdSt8U.cc == ARMcc_AL ? " " + : showARMCondCode(i->ARMin.LdSt8U.cc)); ppARMAMode1(i->ARMin.LdSt8U.amode); vex_printf(", "); ppHRegARM(i->ARMin.LdSt8U.rD); } return; case ARMin_Ld8S: - goto unhandled; + vex_printf("ldrsb%s ", i->ARMin.Ld8S.cc == ARMcc_AL ? " " + : showARMCondCode(i->ARMin.Ld8S.cc)); + ppARMAMode2(i->ARMin.Ld8S.amode); + vex_printf(", "); + ppHRegARM(i->ARMin.Ld8S.rD); + return; case ARMin_XDirect: vex_printf("(xDirect) "); vex_printf("if (%%cpsr.%s) { ", @@ -1651,8 +1686,10 @@ void ppARMInstr ( ARMInstr* i ) { vex_printf("call%s ", i->ARMin.Call.cond==ARMcc_AL ? "" : showARMCondCode(i->ARMin.Call.cond)); - vex_printf("0x%lx [nArgRegs=%d]", + vex_printf("0x%lx [nArgRegs=%d, ", i->ARMin.Call.target, i->ARMin.Call.nArgRegs); + ppRetLoc(i->ARMin.Call.rloc); + vex_printf("]"); return; case ARMin_Mul: vex_printf("%-5s ", showARMMulOp(i->ARMin.Mul.op)); @@ -1951,7 +1988,6 @@ void ppARMInstr ( ARMInstr* i ) { "str r11,[r12+4]"); return; default: - unhandled: vex_printf("ppARMInstr: unhandled case (tag %d)", (Int)i->tag); vpanic("ppARMInstr(1)"); return; @@ -1995,6 +2031,8 @@ void getRegUsage_ARMInstr ( HRegUsage* u, ARMInstr* i, Bool mode64 ) addRegUsage_ARMAMode1(u, i->ARMin.LdSt32.amode); if (i->ARMin.LdSt32.isLoad) { addHRegUse(u, HRmWrite, i->ARMin.LdSt32.rD); + if (i->ARMin.LdSt32.cc != ARMcc_AL) + addHRegUse(u, HRmRead, i->ARMin.LdSt32.rD); } else { addHRegUse(u, HRmRead, i->ARMin.LdSt32.rD); } @@ -2003,6 +2041,8 @@ void getRegUsage_ARMInstr ( HRegUsage* u, ARMInstr* i, Bool mode64 ) addRegUsage_ARMAMode2(u, i->ARMin.LdSt16.amode); if (i->ARMin.LdSt16.isLoad) { addHRegUse(u, HRmWrite, i->ARMin.LdSt16.rD); + if (i->ARMin.LdSt16.cc != ARMcc_AL) + addHRegUse(u, HRmRead, i->ARMin.LdSt16.rD); } else { addHRegUse(u, HRmRead, i->ARMin.LdSt16.rD); } @@ -2011,12 +2051,18 @@ void getRegUsage_ARMInstr ( HRegUsage* u, ARMInstr* i, Bool mode64 ) addRegUsage_ARMAMode1(u, i->ARMin.LdSt8U.amode); if (i->ARMin.LdSt8U.isLoad) { addHRegUse(u, HRmWrite, i->ARMin.LdSt8U.rD); + if (i->ARMin.LdSt8U.cc != ARMcc_AL) + addHRegUse(u, HRmRead, i->ARMin.LdSt8U.rD); } else { addHRegUse(u, HRmRead, i->ARMin.LdSt8U.rD); } return; case ARMin_Ld8S: - goto unhandled; + addRegUsage_ARMAMode2(u, i->ARMin.Ld8S.amode); + addHRegUse(u, HRmWrite, i->ARMin.Ld8S.rD); + if (i->ARMin.Ld8S.cc != ARMcc_AL) + addHRegUse(u, HRmRead, i->ARMin.Ld8S.rD); + return; /* XDirect/XIndir/XAssisted are also a bit subtle. They conditionally exit the block. Hence we only need to list (1) the registers that they read, and (2) the registers that they @@ -2246,7 +2292,6 @@ void getRegUsage_ARMInstr ( HRegUsage* u, ARMInstr* i, Bool mode64 ) addHRegUse(u, HRmWrite, hregARM_R12()); addHRegUse(u, HRmWrite, hregARM_R11()); return; - unhandled: default: ppARMInstr(i); vpanic("getRegUsage_ARMInstr"); @@ -2296,7 +2341,9 @@ void mapRegs_ARMInstr ( HRegRemap* m, ARMInstr* i, Bool mode64 ) mapRegs_ARMAMode1(m, i->ARMin.LdSt8U.amode); return; case ARMin_Ld8S: - goto unhandled; + i->ARMin.Ld8S.rD = lookupHRegRemap(m, i->ARMin.Ld8S.rD); + mapRegs_ARMAMode2(m, i->ARMin.Ld8S.amode); + return; case ARMin_XDirect: mapRegs_ARMAMode1(m, i->ARMin.XDirect.amR15T); return; @@ -2437,7 +2484,6 @@ void mapRegs_ARMInstr ( HRegRemap* m, ARMInstr* i, Bool mode64 ) case ARMin_ProfInc: /* hardwires r11 and r12 -- nothing to modify. */ return; - unhandled: default: ppARMInstr(i); vpanic("mapRegs_ARMInstr"); @@ -2504,7 +2550,7 @@ void genSpill_ARM ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2, switch (rclass) { case HRcInt32: vassert(offsetB <= 4095); - *i1 = ARMInstr_LdSt32( False/*!isLoad*/, + *i1 = ARMInstr_LdSt32( ARMcc_AL, False/*!isLoad*/, rreg, ARMAMode1_RI(hregARM_R8(), offsetB) ); return; @@ -2559,7 +2605,7 @@ void genReload_ARM ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2, switch (rclass) { case HRcInt32: vassert(offsetB <= 4095); - *i1 = ARMInstr_LdSt32( True/*isLoad*/, + *i1 = ARMInstr_LdSt32( ARMcc_AL, True/*isLoad*/, rreg, ARMAMode1_RI(hregARM_R8(), offsetB) ); return; @@ -3006,20 +3052,24 @@ Int emit_ARMInstr ( /*MB_MOD*/Bool* is_profInc, } case ARMin_LdSt32: case ARMin_LdSt8U: { - UInt bL, bB; - HReg rD; - ARMAMode1* am; + UInt bL, bB; + HReg rD; + ARMAMode1* am; + ARMCondCode cc; if (i->tag == ARMin_LdSt32) { bB = 0; bL = i->ARMin.LdSt32.isLoad ? 1 : 0; am = i->ARMin.LdSt32.amode; rD = i->ARMin.LdSt32.rD; + cc = i->ARMin.LdSt32.cc; } else { bB = 1; bL = i->ARMin.LdSt8U.isLoad ? 1 : 0; am = i->ARMin.LdSt8U.amode; rD = i->ARMin.LdSt8U.rD; + cc = i->ARMin.LdSt8U.cc; } + vassert(cc != ARMcc_NV); if (am->tag == ARMam1_RI) { Int simm12; UInt instr, bP; @@ -3031,7 +3081,7 @@ Int emit_ARMInstr ( /*MB_MOD*/Bool* is_profInc, simm12 = am->ARMam1.RI.simm13; } vassert(simm12 >= 0 && simm12 <= 4095); - instr = XXXXX___(X1110,X0101,BITS4(bP,bB,0,bL), + instr = XXXXX___(cc,X0101,BITS4(bP,bB,0,bL), iregNo(am->ARMam1.RI.reg), iregNo(rD)); instr |= simm12; @@ -3043,10 +3093,12 @@ Int emit_ARMInstr ( /*MB_MOD*/Bool* is_profInc, } } case ARMin_LdSt16: { - HReg rD = i->ARMin.LdSt16.rD; - UInt bS = i->ARMin.LdSt16.signedLoad ? 1 : 0; - UInt bL = i->ARMin.LdSt16.isLoad ? 1 : 0; - ARMAMode2* am = i->ARMin.LdSt16.amode; + HReg rD = i->ARMin.LdSt16.rD; + UInt bS = i->ARMin.LdSt16.signedLoad ? 1 : 0; + UInt bL = i->ARMin.LdSt16.isLoad ? 1 : 0; + ARMAMode2* am = i->ARMin.LdSt16.amode; + ARMCondCode cc = i->ARMin.LdSt16.cc; + vassert(cc != ARMcc_NV); if (am->tag == ARMam2_RI) { HReg rN = am->ARMam2.RI.reg; Int simm8; @@ -3064,20 +3116,24 @@ Int emit_ARMInstr ( /*MB_MOD*/Bool* is_profInc, vassert(!(bL == 0 && bS == 1)); // "! signed store" /**/ if (bL == 0 && bS == 0) { // strh - instr = XXXXXXXX(X1110,X0001, BITS4(bP,1,0,0), iregNo(rN), + instr = XXXXXXXX(cc,X0001, BITS4(bP,1,0,0), iregNo(rN), iregNo(rD), imm8hi, X1011, imm8lo); *p++ = instr; goto done; } else if (bL == 1 && bS == 0) { // ldrh - instr = XXXXXXXX(X1110,X0001, BITS4(bP,1,0,1), iregNo(rN), + instr = XXXXXXXX(cc,X0001, BITS4(bP,1,0,1), iregNo(rN), iregNo(rD), imm8hi, X1011, imm8lo); *p++ = instr; goto done; } else if (bL == 1 && bS == 1) { - goto bad; + // ldrsh + instr = XXXXXXXX(cc,X0001, BITS4(bP,1,0,1), iregNo(rN), + iregNo(rD), imm8hi, X1111, imm8lo); + *p++ = instr; + goto done; } else vassert(0); // ill-constructed insn } else { @@ -3085,8 +3141,35 @@ Int emit_ARMInstr ( /*MB_MOD*/Bool* is_profInc, goto bad; } } - case ARMin_Ld8S: - goto bad; + case ARMin_Ld8S: { + HReg rD = i->ARMin.Ld8S.rD; + ARMAMode2* am = i->ARMin.Ld8S.amode; + ARMCondCode cc = i->ARMin.Ld8S.cc; + vassert(cc != ARMcc_NV); + if (am->tag == ARMam2_RI) { + HReg rN = am->ARMam2.RI.reg; + Int simm8; + UInt bP, imm8hi, imm8lo, instr; + if (am->ARMam2.RI.simm9 < 0) { + bP = 0; + simm8 = -am->ARMam2.RI.simm9; + } else { + bP = 1; + simm8 = am->ARMam2.RI.simm9; + } + vassert(simm8 >= 0 && simm8 <= 255); + imm8hi = (simm8 >> 4) & 0xF; + imm8lo = simm8 & 0xF; + // ldrsb + instr = XXXXXXXX(cc,X0001, BITS4(bP,1,0,1), iregNo(rN), + iregNo(rD), imm8hi, X1101, imm8lo); + *p++ = instr; + goto done; + } else { + // RR case + goto bad; + } + } case ARMin_XDirect: { /* NB: what goes on here has to be very closely coordinated @@ -3267,6 +3350,7 @@ Int emit_ARMInstr ( /*MB_MOD*/Bool* is_profInc, *p++ = instr; goto done; } + case ARMin_Call: { UInt instr; /* Decide on a scratch reg used to hold to the call address. @@ -3280,14 +3364,82 @@ Int emit_ARMInstr ( /*MB_MOD*/Bool* is_profInc, case 4: scratchNo = 11; break; default: vassert(0); } - // r"scratchNo" = &target - p = imm32_to_iregNo( (UInt*)p, - scratchNo, (UInt)i->ARMin.Call.target ); - // blx{cond} r"scratchNo" - instr = XXX___XX(i->ARMin.Call.cond, X0001, X0010, /*___*/ - X0011, scratchNo); - instr |= 0xFFF << 8; // stick in the SBOnes - *p++ = instr; + /* If we don't need to do any fixup actions in the case that + the call doesn't happen, just do the simple thing and emit + straight-line code. We hope this is the common case. */ + if (i->ARMin.Call.cond == ARMcc_AL/*call always happens*/ + || i->ARMin.Call.rloc == RetLocNone/*no fixup action*/) { + // r"scratchNo" = &target + p = imm32_to_iregNo( (UInt*)p, + scratchNo, (UInt)i->ARMin.Call.target ); + // blx{cond} r"scratchNo" + instr = XXX___XX(i->ARMin.Call.cond, X0001, X0010, /*___*/ + X0011, scratchNo); + instr |= 0xFFF << 8; // stick in the SBOnes + *p++ = instr; + } else { + Int delta; + /* Complex case. We have to generate an if-then-else + diamond. */ + // before: + // b{!cond} else: + // r"scratchNo" = &target + // blx{AL} r"scratchNo" + // preElse: + // b after: + // else: + // mvn r0, #0 // possibly + // mvn r1, #0 // possibly + // after: + + // before: + UInt* pBefore = p; + + // b{!cond} else: // ptmp1 points here + *p++ = 0; // filled in later + + // r"scratchNo" = &target + p = imm32_to_iregNo( (UInt*)p, + scratchNo, (UInt)i->ARMin.Call.target ); + + // blx{AL} r"scratchNo" + instr = XXX___XX(ARMcc_AL, X0001, X0010, /*___*/ + X0011, scratchNo); + instr |= 0xFFF << 8; // stick in the SBOnes + *p++ = instr; + + // preElse: + UInt* pPreElse = p; + + // b after: + *p++ = 0; // filled in later + + // else: + delta = (UChar*)p - (UChar*)pBefore; + delta = (delta >> 2) - 2; + *pBefore + = XX______(1 ^ i->ARMin.Call.cond, X1010) | (delta & 0xFFFFFF); + + /* Do the 'else' actions */ + switch (i->ARMin.Call.rloc) { + case RetLocInt: + *p++ = 0xE3E00000; break; // mvn r0, #0 + case RetLoc2Int: + // mvn r0, #0 ; mvn r1, #0 + vassert(0); //ATC + *p++ = 0xE3E00000; *p++ = 0xE3E01000; break; + case RetLocNone: + case RetLocINVALID: + default: + vassert(0); + } + + // after: + delta = (UChar*)p - (UChar*)pPreElse; + delta = (delta >> 2) - 2; + *pPreElse = XX______(ARMcc_AL, X1010) | (delta & 0xFFFFFF); + } + goto done; } case ARMin_Mul: { diff --git a/VEX/priv/host_arm_defs.h b/VEX/priv/host_arm_defs.h index 7635acca13..6f780334ea 100644 --- a/VEX/priv/host_arm_defs.h +++ b/VEX/priv/host_arm_defs.h @@ -659,29 +659,33 @@ typedef HReg dst; UInt imm32; } Imm32; - /* 32-bit load or store */ + /* 32-bit load or store, may be conditional */ struct { - Bool isLoad; - HReg rD; - ARMAMode1* amode; + ARMCondCode cc; /* ARMcc_NV is not allowed */ + Bool isLoad; + HReg rD; + ARMAMode1* amode; } LdSt32; - /* 16-bit load or store */ + /* 16-bit load or store, may be conditional */ struct { - Bool isLoad; - Bool signedLoad; - HReg rD; - ARMAMode2* amode; + ARMCondCode cc; /* ARMcc_NV is not allowed */ + Bool isLoad; + Bool signedLoad; + HReg rD; + ARMAMode2* amode; } LdSt16; - /* 8-bit (unsigned) load or store */ + /* 8-bit (unsigned) load or store, may be conditional */ struct { - Bool isLoad; - HReg rD; - ARMAMode1* amode; + ARMCondCode cc; /* ARMcc_NV is not allowed */ + Bool isLoad; + HReg rD; + ARMAMode1* amode; } LdSt8U; - /* 8-bit signed load */ + /* 8-bit signed load, may be conditional */ struct { - HReg rD; - ARMAMode2* amode; + ARMCondCode cc; /* ARMcc_NV is not allowed */ + HReg rD; + ARMAMode2* amode; } Ld8S; /* Update the guest R15T value, then exit requesting to chain to it. May be conditional. Urr, use of Addr32 implicitly @@ -720,6 +724,7 @@ typedef ARMCondCode cond; HWord target; Int nArgRegs; /* # regs carrying args: 0 .. 4 */ + RetLoc rloc; /* where the return value will be */ } Call; /* (PLAIN) 32 * 32 -> 32: r0 = r2 * r3 (ZX) 32 *u 32 -> 64: r1:r0 = r2 *u r3 @@ -949,11 +954,14 @@ extern ARMInstr* ARMInstr_Unary ( ARMUnaryOp, HReg, HReg ); extern ARMInstr* ARMInstr_CmpOrTst ( Bool isCmp, HReg, ARMRI84* ); extern ARMInstr* ARMInstr_Mov ( HReg, ARMRI84* ); extern ARMInstr* ARMInstr_Imm32 ( HReg, UInt ); -extern ARMInstr* ARMInstr_LdSt32 ( Bool isLoad, HReg, ARMAMode1* ); -extern ARMInstr* ARMInstr_LdSt16 ( Bool isLoad, Bool signedLoad, +extern ARMInstr* ARMInstr_LdSt32 ( ARMCondCode, + Bool isLoad, HReg, ARMAMode1* ); +extern ARMInstr* ARMInstr_LdSt16 ( ARMCondCode, + Bool isLoad, Bool signedLoad, HReg, ARMAMode2* ); -extern ARMInstr* ARMInstr_LdSt8U ( Bool isLoad, HReg, ARMAMode1* ); -extern ARMInstr* ARMInstr_Ld8S ( HReg, ARMAMode2* ); +extern ARMInstr* ARMInstr_LdSt8U ( ARMCondCode, + Bool isLoad, HReg, ARMAMode1* ); +extern ARMInstr* ARMInstr_Ld8S ( ARMCondCode, HReg, ARMAMode2* ); extern ARMInstr* ARMInstr_XDirect ( Addr32 dstGA, ARMAMode1* amR15T, ARMCondCode cond, Bool toFastEP ); extern ARMInstr* ARMInstr_XIndir ( HReg dstGA, ARMAMode1* amR15T, @@ -961,7 +969,8 @@ extern ARMInstr* ARMInstr_XIndir ( HReg dstGA, ARMAMode1* amR15T, extern ARMInstr* ARMInstr_XAssisted ( HReg dstGA, ARMAMode1* amR15T, ARMCondCode cond, IRJumpKind jk ); extern ARMInstr* ARMInstr_CMov ( ARMCondCode, HReg dst, ARMRI84* src ); -extern ARMInstr* ARMInstr_Call ( ARMCondCode, HWord, Int nArgRegs ); +extern ARMInstr* ARMInstr_Call ( ARMCondCode, HWord, Int nArgRegs, + RetLoc rloc ); extern ARMInstr* ARMInstr_Mul ( ARMMulOp op ); extern ARMInstr* ARMInstr_LdrEX ( Int szB ); extern ARMInstr* ARMInstr_StrEX ( Int szB ); diff --git a/VEX/priv/host_arm_isel.c b/VEX/priv/host_arm_isel.c index 8a6326303e..31375af902 100644 --- a/VEX/priv/host_arm_isel.c +++ b/VEX/priv/host_arm_isel.c @@ -378,7 +378,8 @@ Bool mightRequireFixedRegs ( IRExpr* e ) static Bool doHelperCall ( ISelEnv* env, Bool passBBP, - IRExpr* guard, IRCallee* cee, IRExpr** args ) + IRExpr* guard, IRCallee* cee, IRExpr** args, + RetLoc rloc ) { ARMCondCode cc; HReg argregs[ARM_N_ARGREGS]; @@ -615,7 +616,7 @@ Bool doHelperCall ( ISelEnv* env, values. But that's too much hassle. */ /* Finally, the call itself. */ - addInstr(env, ARMInstr_Call( cc, target, nextArgReg )); + addInstr(env, ARMInstr_Call( cc, target, nextArgReg, rloc )); return True; /* success */ } @@ -1087,7 +1088,6 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) { IRType ty = typeOfIRExpr(env->type_env,e); vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8); -// vassert(ty == Ity_I64 || ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8); switch (e->tag) { @@ -1105,29 +1105,21 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) if (ty == Ity_I32) { ARMAMode1* amode = iselIntExpr_AMode1 ( env, e->Iex.Load.addr ); - addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, dst, amode)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, True/*isLoad*/, dst, amode)); return dst; } if (ty == Ity_I16) { ARMAMode2* amode = iselIntExpr_AMode2 ( env, e->Iex.Load.addr ); - addInstr(env, ARMInstr_LdSt16(True/*isLoad*/, False/*!signedLoad*/, + addInstr(env, ARMInstr_LdSt16(ARMcc_AL, + True/*isLoad*/, False/*!signedLoad*/, dst, amode)); return dst; } if (ty == Ity_I8) { ARMAMode1* amode = iselIntExpr_AMode1 ( env, e->Iex.Load.addr ); - addInstr(env, ARMInstr_LdSt8U(True/*isLoad*/, dst, amode)); + addInstr(env, ARMInstr_LdSt8U(ARMcc_AL, True/*isLoad*/, dst, amode)); return dst; } - -//zz if (ty == Ity_I16) { -//zz addInstr(env, X86Instr_LoadEX(2,False,amode,dst)); -//zz return dst; -//zz } -//zz if (ty == Ity_I8) { -//zz addInstr(env, X86Instr_LoadEX(1,False,amode,dst)); -//zz return dst; -//zz } break; } @@ -1378,7 +1370,8 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) HReg res = newVRegI(env); addInstr(env, mk_iMOVds_RR(hregARM_R0(), regL)); addInstr(env, mk_iMOVds_RR(hregARM_R1(), regR)); - addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn), 2 )); + addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn), + 2, RetLocInt )); addInstr(env, mk_iMOVds_RR(res, hregARM_R0())); return res; } @@ -1665,7 +1658,8 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) HReg arg = iselIntExpr_R(env, e->Iex.Unop.arg); HReg res = newVRegI(env); addInstr(env, mk_iMOVds_RR(hregARM_R0(), arg)); - addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn), 1 )); + addInstr(env, ARMInstr_Call( ARMcc_AL, (HWord)Ptr_to_ULong(fn), + 1, RetLocInt )); addInstr(env, mk_iMOVds_RR(res, hregARM_R0())); return res; } @@ -1680,7 +1674,7 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) && e->Iex.Get.offset < 4096-4) { HReg dst = newVRegI(env); addInstr(env, ARMInstr_LdSt32( - True/*isLoad*/, + ARMcc_AL, True/*isLoad*/, dst, ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset))); return dst; @@ -1719,14 +1713,16 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) HReg dst = newVRegI(env); vassert(ty == e->Iex.CCall.retty); - /* be very restrictive for now. Only 32/64-bit ints allowed - for args, and 32 bits for return type. */ + /* be very restrictive for now. Only 32/64-bit ints allowed for + args, and 32 bits for return type. Don't forget to change + the RetLoc if more types are allowed in future. */ if (e->Iex.CCall.retty != Ity_I32) goto irreducible; /* Marshal args, do the call, clear stack. */ Bool ok = doHelperCall( env, False, - NULL, e->Iex.CCall.cee, e->Iex.CCall.args ); + NULL, e->Iex.CCall.cee, e->Iex.CCall.args, + RetLocInt ); if (ok) { addInstr(env, mk_iMOVds_RR(dst, hregARM_R0())); return dst; @@ -1858,8 +1854,10 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e ) rA = iselIntExpr_R(env, e->Iex.Load.addr); tHi = newVRegI(env); tLo = newVRegI(env); - addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tHi, ARMAMode1_RI(rA, 4))); - addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tLo, ARMAMode1_RI(rA, 0))); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, True/*isLoad*/, + tHi, ARMAMode1_RI(rA, 4))); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, True/*isLoad*/, + tLo, ARMAMode1_RI(rA, 0))); *rHi = tHi; *rLo = tLo; return; @@ -1871,8 +1869,8 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e ) ARMAMode1* am4 = ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset + 4); HReg tHi = newVRegI(env); HReg tLo = newVRegI(env); - addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tHi, am4)); - addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tLo, am0)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, True/*isLoad*/, tHi, am4)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, True/*isLoad*/, tLo, am0)); *rHi = tHi; *rLo = tLo; return; @@ -4257,13 +4255,17 @@ static HReg iselNeonExpr_wrk ( ISelEnv* env, IRExpr* e ) /* Store the less significant 64 bits */ iselInt64Expr(&w1, &w0, env, e->Iex.Binop.arg2); - addInstr(env, ARMInstr_LdSt32(False/*store*/, w0, sp_0)); - addInstr(env, ARMInstr_LdSt32(False/*store*/, w1, sp_4)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*store*/, + w0, sp_0)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*store*/, + w1, sp_4)); /* Store the more significant 64 bits */ iselInt64Expr(&w3, &w2, env, e->Iex.Binop.arg1); - addInstr(env, ARMInstr_LdSt32(False/*store*/, w2, sp_8)); - addInstr(env, ARMInstr_LdSt32(False/*store*/, w3, sp_12)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*store*/, + w2, sp_8)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*store*/, + w3, sp_12)); /* Load result back from stack. */ addInstr(env, ARMInstr_NLdStQ(True/*load*/, res, @@ -5641,20 +5643,21 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) if (tyd == Ity_I32) { HReg rD = iselIntExpr_R(env, stmt->Ist.Store.data); ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Store.addr); - addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rD, am)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!isLoad*/, rD, am)); return; } if (tyd == Ity_I16) { HReg rD = iselIntExpr_R(env, stmt->Ist.Store.data); ARMAMode2* am = iselIntExpr_AMode2(env, stmt->Ist.Store.addr); - addInstr(env, ARMInstr_LdSt16(False/*!isLoad*/, + addInstr(env, ARMInstr_LdSt16(ARMcc_AL, + False/*!isLoad*/, False/*!isSignedLoad*/, rD, am)); return; } if (tyd == Ity_I8) { HReg rD = iselIntExpr_R(env, stmt->Ist.Store.data); ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Store.addr); - addInstr(env, ARMInstr_LdSt8U(False/*!isLoad*/, rD, am)); + addInstr(env, ARMInstr_LdSt8U(ARMcc_AL, False/*!isLoad*/, rD, am)); return; } if (tyd == Ity_I64) { @@ -5666,9 +5669,9 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) HReg rDhi, rDlo, rA; iselInt64Expr(&rDhi, &rDlo, env, stmt->Ist.Store.data); rA = iselIntExpr_R(env, stmt->Ist.Store.addr); - addInstr(env, ARMInstr_LdSt32(False/*!load*/, rDhi, + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!load*/, rDhi, ARMAMode1_RI(rA,4))); - addInstr(env, ARMInstr_LdSt32(False/*!load*/, rDlo, + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!load*/, rDlo, ARMAMode1_RI(rA,0))); } return; @@ -5695,6 +5698,88 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) break; } + /* --------- CONDITIONAL STORE --------- */ + /* conditional little-endian write to memory */ + case Ist_StoreG: { + IRStoreG* sg = stmt->Ist.StoreG.details; + IRType tya = typeOfIRExpr(env->type_env, sg->addr); + IRType tyd = typeOfIRExpr(env->type_env, sg->data); + IREndness end = sg->end; + + if (tya != Ity_I32 || end != Iend_LE) + goto stmt_fail; + + switch (tyd) { + case Ity_I8: + case Ity_I32: { + HReg rD = iselIntExpr_R(env, sg->data); + ARMAMode1* am = iselIntExpr_AMode1(env, sg->addr); + ARMCondCode cc = iselCondCode(env, sg->guard); + addInstr(env, (tyd == Ity_I32 ? ARMInstr_LdSt32 : ARMInstr_LdSt8U) + (cc, False/*!isLoad*/, rD, am)); + return; + } + case Ity_I16: { + HReg rD = iselIntExpr_R(env, sg->data); + ARMAMode2* am = iselIntExpr_AMode2(env, sg->addr); + ARMCondCode cc = iselCondCode(env, sg->guard); + addInstr(env, ARMInstr_LdSt16(cc, + False/*!isLoad*/, + False/*!isSignedLoad*/, rD, am)); + return; + } + default: + break; + } + break; + } + + /* --------- CONDITIONAL LOAD --------- */ + /* conditional little-endian load from memory */ + case Ist_LoadG: { + IRLoadG* lg = stmt->Ist.LoadG.details; + IRType tya = typeOfIRExpr(env->type_env, lg->addr); + IREndness end = lg->end; + + if (tya != Ity_I32 || end != Iend_LE) + goto stmt_fail; + + switch (lg->cvt) { + case ILGop_8Uto32: + case ILGop_Ident32: { + HReg rAlt = iselIntExpr_R(env, lg->alt); + ARMAMode1* am = iselIntExpr_AMode1(env, lg->addr); + HReg rD = lookupIRTemp(env, lg->dst); + addInstr(env, mk_iMOVds_RR(rD, rAlt)); + ARMCondCode cc = iselCondCode(env, lg->guard); + addInstr(env, (lg->cvt == ILGop_Ident32 ? ARMInstr_LdSt32 + : ARMInstr_LdSt8U) + (cc, True/*isLoad*/, rD, am)); + return; + } + case ILGop_16Sto32: + case ILGop_16Uto32: + case ILGop_8Sto32: { + HReg rAlt = iselIntExpr_R(env, lg->alt); + ARMAMode2* am = iselIntExpr_AMode2(env, lg->addr); + HReg rD = lookupIRTemp(env, lg->dst); + addInstr(env, mk_iMOVds_RR(rD, rAlt)); + ARMCondCode cc = iselCondCode(env, lg->guard); + if (lg->cvt == ILGop_8Sto32) { + addInstr(env, ARMInstr_Ld8S(cc, rD, am)); + } else { + vassert(lg->cvt == ILGop_16Sto32 || lg->cvt == ILGop_16Uto32); + Bool sx = lg->cvt == ILGop_16Sto32; + addInstr(env, ARMInstr_LdSt16(cc, True/*isLoad*/, sx, rD, am)); + } + return; + } + default: + break; + } + break; + } + /* --------- PUT --------- */ /* write guest state, fixed offset */ case Ist_Put: { @@ -5703,7 +5788,7 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) if (tyd == Ity_I32) { HReg rD = iselIntExpr_R(env, stmt->Ist.Put.data); ARMAMode1* am = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset); - addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rD, am)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!isLoad*/, rD, am)); return; } if (tyd == Ity_I64) { @@ -5720,8 +5805,10 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) ARMAMode1* am4 = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset + 4); iselInt64Expr(&rDhi, &rDlo, env, stmt->Ist.Put.data); - addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rDhi, am4)); - addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rDlo, am0)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!isLoad*/, + rDhi, am4)); + addInstr(env, ARMInstr_LdSt32(ARMcc_AL, False/*!isLoad*/, + rDlo, am0)); } return; } @@ -5752,25 +5839,6 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) break; } -//zz /* --------- Indexed PUT --------- */ -//zz /* write guest state, run-time offset */ -//zz case Ist_PutI: { -//zz ARMAMode2* am2 -//zz = genGuestArrayOffset( -//zz env, stmt->Ist.PutI.descr, -//zz stmt->Ist.PutI.ix, stmt->Ist.PutI.bias ); -//zz -//zz IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data); -//zz -//zz if (tyd == Ity_I8) { -//zz HReg reg = iselIntExpr_R(env, stmt->Ist.PutI.data); -//zz addInstr(env, ARMInstr_StoreB(reg, am2)); -//zz return; -//zz } -//zz// CAB: Ity_I32, Ity_I16 ? -//zz break; -//zz } - /* --------- TMP --------- */ /* assign value to temporary */ case Ist_WrTmp: { @@ -5829,7 +5897,6 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) /* --------- Call to DIRTY helper --------- */ /* call complex ("dirty") helper function */ case Ist_Dirty: { - IRType retty; IRDirty* d = stmt->Ist.Dirty.details; Bool passBBP = False; @@ -5838,8 +5905,31 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) passBBP = toBool(d->nFxState > 0 && d->needsBBP); - /* Marshal args, do the call, clear stack. */ - Bool ok = doHelperCall( env, passBBP, d->guard, d->cee, d->args ); + /* Figure out the return type, if any. */ + IRType retty = Ity_INVALID; + if (d->tmp != IRTemp_INVALID) + retty = typeOfIRTemp(env->type_env, d->tmp); + + /* Marshal args, do the call, clear stack, set the return value + to all-ones if this is a conditional call that returns a + value and the call is skipped. We need to set the ret-loc + correctly in order to implement the IRDirty semantics that + the return value is all-ones if the call doesn't happen. */ + RetLoc rloc = RetLocINVALID; + switch (retty) { + case Ity_INVALID: /* function doesn't return anything */ + rloc = RetLocNone; break; + case Ity_I64: + rloc = RetLoc2Int; break; + case Ity_I32: case Ity_I16: case Ity_I8: + rloc = RetLocInt; break; + default: + break; + } + if (rloc == RetLocINVALID) + break; /* will go to stmt_fail: */ + + Bool ok = doHelperCall( env, passBBP, d->guard, d->cee, d->args, rloc ); if (!ok) break; /* will go to stmt_fail: */ @@ -5848,8 +5938,6 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) /* No return value. Nothing to do. */ return; - retty = typeOfIRTemp(env->type_env, d->tmp); - if (retty == Ity_I64) { if (env->hwcaps & VEX_HWCAPS_ARM_NEON) { HReg tmp = lookupIRTemp(env, d->tmp); @@ -6164,6 +6252,9 @@ HInstrArray* iselSB_ARM ( IRSB* bb, /* sanity ... */ vassert(arch_host == VexArchARM); + /* guard against unexpected space regressions */ + vassert(sizeof(ARMInstr) <= 28); + /* hwcaps should not change from one ISEL call to another. */ arm_hwcaps = hwcaps_host; // JRS 2012 Mar 31: FIXME (RM) diff --git a/VEX/priv/host_generic_regs.c b/VEX/priv/host_generic_regs.c index 016d949fe0..dfaf06a15b 100644 --- a/VEX/priv/host_generic_regs.c +++ b/VEX/priv/host_generic_regs.c @@ -218,6 +218,22 @@ void addHInstr ( HInstrArray* ha, HInstr* instr ) } +/*---------------------------------------------------------*/ +/*--- C-Call return-location actions ---*/ +/*---------------------------------------------------------*/ + +void ppRetLoc ( RetLoc ska ) +{ + switch (ska) { + case RetLocINVALID: vex_printf("RetLocINVALID"); return; + case RetLocNone: vex_printf("RetLocNone"); return; + case RetLocInt: vex_printf("RetLocInt"); return; + case RetLoc2Int: vex_printf("RetLoc2Int"); return; + default: vpanic("ppRetLoc"); + } +} + + /*---------------------------------------------------------------*/ /*--- end host_generic_regs.c ---*/ /*---------------------------------------------------------------*/ diff --git a/VEX/priv/host_generic_regs.h b/VEX/priv/host_generic_regs.h index 580895e972..e0b31de256 100644 --- a/VEX/priv/host_generic_regs.h +++ b/VEX/priv/host_generic_regs.h @@ -233,6 +233,27 @@ extern HInstrArray* newHInstrArray ( void ); extern void addHInstr ( HInstrArray*, HInstr* ); +/*---------------------------------------------------------*/ +/*--- C-Call return-location descriptions ---*/ +/*---------------------------------------------------------*/ + +/* This is common to all back ends. It describes where the return + value from a C call is located. This is important in the case that + the call is conditional, since the return locations will need to be + set to all-ones in the case that the call does not happen. */ + +typedef + enum { + RetLocINVALID, /* INVALID */ + RetLocNone, /* no return value (a.k.a C "void") */ + RetLocInt, /* in the primary int return reg */ + RetLoc2Int /* in both primary and secondary int ret regs */ + } + RetLoc; + +extern void ppRetLoc ( RetLoc rloc ); + + /*---------------------------------------------------------*/ /*--- Reg alloc: TODO: move somewhere else ---*/ /*---------------------------------------------------------*/