From: Carl Love Date: Wed, 2 Oct 2013 16:25:57 +0000 (+0000) Subject: Power PC, Approach 1, add Transactional Memory instruction support X-Git-Tag: svn/VALGRIND_3_9_0^2~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ba64a5b9b43ae484f3e79a4c261e5d66f2a155f;p=thirdparty%2Fvalgrind.git Power PC, Approach 1, add Transactional Memory instruction support The following Transactional Memory instructions are added: tbegin., tend., tsr., tcheck., tabortwc., tabortdc., tabortwci., tabortdci., tabort. The patch implements the first proposal by Julian on how to handle the TM instructions. The proposal is as follows: translate "XBEGIN fail-addr" as "goto fail-addr"; that is: push simulated execution directly onto the failure path. This is simple but will have poor performance, if (as is likely) the failure path uses normal locking and is not tuned for speed. The tbegin instruction on Power sets the condition code register to indicate if the tbegin instruction suceeded or failed. The compiler then generates a conditional branch instruction to take the success or failure code path for the tbegin instruction. In order to fail the tbegin instruction, the condition code register is updated to indicate that the tbegin instruction failed. This patch assumes that there is always an error handler for the tbegin instruction. The other TM instructions are all treated as no ops as we shouldn't be executing the sucess transactional code path. Signed-off-by: Carl Love Bugzilla 323803 git-svn-id: svn://svn.valgrind.org/vex/trunk@2780 --- diff --git a/VEX/priv/guest_ppc_helpers.c b/VEX/priv/guest_ppc_helpers.c index f320149f4f..4b50547aac 100644 --- a/VEX/priv/guest_ppc_helpers.c +++ b/VEX/priv/guest_ppc_helpers.c @@ -511,7 +511,8 @@ void LibVEX_GuestPPC32_initialise ( /*OUT*/VexGuestPPC32State* vex_state ) vex_state->guest_IP_AT_SYSCALL = 0; vex_state->guest_SPRG3_RO = 0; - vex_state->padding = 0; + vex_state->padding1 = 0; + vex_state->padding2 = 0; } @@ -676,10 +677,9 @@ void LibVEX_GuestPPC64_initialise ( /*OUT*/VexGuestPPC64State* vex_state ) vex_state->guest_IP_AT_SYSCALL = 0; vex_state->guest_SPRG3_RO = 0; - - vex_state->padding2 = 0; - vex_state->padding3 = 0; - vex_state->padding4 = 0; + vex_state->guest_TFHAR = 0; + vex_state->guest_TFIAR = 0; + vex_state->guest_TEXASR = 0; } diff --git a/VEX/priv/guest_ppc_toIR.c b/VEX/priv/guest_ppc_toIR.c index 8f17b64cdf..1c343ce7a6 100644 --- a/VEX/priv/guest_ppc_toIR.c +++ b/VEX/priv/guest_ppc_toIR.c @@ -232,6 +232,9 @@ static void* fnptr_to_fnentry( VexAbiInfo* vbi, void* f ) #define OFFB_TILEN offsetofPPCGuestState(guest_TILEN) #define OFFB_NRADDR offsetofPPCGuestState(guest_NRADDR) #define OFFB_NRADDR_GPR2 offsetofPPCGuestState(guest_NRADDR_GPR2) +#define OFFB_TFHAR offsetofPPCGuestState(guest_TFHAR) +#define OFFB_TEXASR offsetofPPCGuestState(guest_TEXASR) +#define OFFB_TFIAR offsetofPPCGuestState(guest_TFIAR) /*------------------------------------------------------------*/ @@ -378,6 +381,9 @@ typedef enum { PPC_GST_TILEN, // For icbi: length of area to invalidate PPC_GST_IP_AT_SYSCALL, // the CIA of the most recently executed SC insn PPC_GST_SPRG3_RO, // SPRG3 + PPC_GST_TFHAR, // Transactional Failure Handler Address Register + PPC_GST_TFIAR, // Transactional Failure Instruction Address Register + PPC_GST_TEXASR, // Transactional EXception And Summary Register PPC_GST_MAX } PPC_GST; @@ -2546,6 +2552,15 @@ static IRExpr* /* :: Ity_I32/64 */ getGST ( PPC_GST reg ) binop( Iop_Shl32, getXER_CA32(), mkU8(29)), getXER_BC32())); + case PPC_GST_TFHAR: + return IRExpr_Get( OFFB_TFHAR, ty ); + + case PPC_GST_TEXASR: + return IRExpr_Get( OFFB_TEXASR, ty ); + + case PPC_GST_TFIAR: + return IRExpr_Get( OFFB_TFIAR, ty ); + default: vex_printf("getGST(ppc): reg = %u", reg); vpanic("getGST(ppc)"); @@ -2707,6 +2722,18 @@ static void putGST ( PPC_GST reg, IRExpr* src ) stmt( IRStmt_Put( OFFB_TILEN, src) ); break; + case PPC_GST_TEXASR: + vassert( ty_src == Ity_I64 ); + stmt( IRStmt_Put( OFFB_TEXASR, src ) ); + break; + case PPC_GST_TFIAR: + vassert( ty_src == Ity_I64 ); + stmt( IRStmt_Put( OFFB_TFIAR, src ) ); + break; + case PPC_GST_TFHAR: + vassert( ty_src == Ity_I64 ); + stmt( IRStmt_Put( OFFB_TFHAR, src ) ); + break; default: vex_printf("putGST(ppc): reg = %u", reg); vpanic("putGST(ppc)"); @@ -3052,6 +3079,50 @@ static IRTemp getNegatedResult_32(IRTemp intermediateResult) return negatedResult; } +/*------------------------------------------------------------*/ +/* Transactional memory helpers + * + *------------------------------------------------------------*/ + +static ULong generate_TMreason( UInt failure_code, + UInt persistant, + UInt nest_overflow, + UInt tm_exact ) +{ + ULong tm_err_code = + ( (ULong) 0) << (63-6) /* Failure code */ + | ( (ULong) persistant) << (63-7) /* Failure persistant */ + | ( (ULong) 0) << (63-8) /* Disallowed */ + | ( (ULong) nest_overflow) << (63-9) /* Nesting Overflow */ + | ( (ULong) 0) << (63-10) /* Footprint Overflow */ + | ( (ULong) 0) << (63-11) /* Self-Induced Conflict */ + | ( (ULong) 0) << (63-12) /* Non-Transactional Conflict */ + | ( (ULong) 0) << (63-13) /* Transactional Conflict */ + | ( (ULong) 0) << (63-14) /* Translation Invalidation Conflict */ + | ( (ULong) 0) << (63-15) /* Implementation-specific */ + | ( (ULong) 0) << (63-16) /* Instruction Fetch Conflict */ + | ( (ULong) 0) << (63-30) /* Reserved */ + | ( (ULong) 0) << (63-31) /* Abort */ + | ( (ULong) 0) << (63-32) /* Suspend */ + | ( (ULong) 0) << (63-33) /* Reserved */ + | ( (ULong) 0) << (63-35) /* Privilege */ + | ( (ULong) 0) << (63-36) /* Failure Summary */ + | ( (ULong) tm_exact) << (63-37) /* TFIAR Exact */ + | ( (ULong) 0) << (63-38) /* ROT */ + | ( (ULong) 0) << (63-51) /* Reserved */ + | ( (ULong) 0) << (63-63); /* Transaction Level */ + + return tm_err_code; +} + +static void storeTMfailure( Addr64 err_address, ULong tm_reason, + Addr64 handler_address ) +{ + putGST( PPC_GST_TFIAR, mkU64( err_address ) ); + putGST( PPC_GST_TEXASR, mkU64( tm_reason ) ); + putGST( PPC_GST_TFHAR, mkU64( handler_address ) ); +} + /*------------------------------------------------------------*/ /*--- Integer Instruction Translation --- */ /*------------------------------------------------------------*/ @@ -6680,6 +6751,18 @@ static Bool dis_proc_ctl ( VexAbiInfo* vbi, UInt theInstr ) DIP("mfctr r%u\n", rD_addr); putIReg( rD_addr, getGST( PPC_GST_CTR ) ); break; + case 0x80: // 128 + DIP("mfspr r%u (TFHAR)\n", rD_addr); + putIReg( rD_addr, getGST( PPC_GST_TFHAR) ); + break; + case 0x81: // 129 + DIP("mfspr r%u (TFIAR)\n", rD_addr); + putIReg( rD_addr, getGST( PPC_GST_TFIAR) ); + break; + case 0x82: // 130 + DIP("mfspr r%u (TEXASR)\n", rD_addr); + putIReg( rD_addr, getGST( PPC_GST_TEXASR) ); + break; case 0x100: DIP("mfvrsave r%u\n", rD_addr); putIReg( rD_addr, mkWidenFrom32(ty, getGST( PPC_GST_VRSAVE ), @@ -6824,7 +6907,18 @@ static Bool dis_proc_ctl ( VexAbiInfo* vbi, UInt theInstr ) DIP("mtvrsave r%u\n", rS_addr); putGST( PPC_GST_VRSAVE, mkNarrowTo32(ty, mkexpr(rS)) ); break; - + case 0x80: // 128 + DIP("mtspr r%u (TFHAR)\n", rS_addr); + putGST( PPC_GST_TFHAR, mkexpr(rS) ); + break; + case 0x81: // 129 + DIP("mtspr r%u (TFIAR)\n", rS_addr); + putGST( PPC_GST_TFIAR, mkexpr(rS) ); + break; + case 0x82: // 130 + DIP("mtspr r%u (TEXASR)\n", rS_addr); + putGST( PPC_GST_TEXASR, mkexpr(rS) ); + break; default: vex_printf("dis_proc_ctl(ppc)(mtspr,SPR)(%u)\n", SPR); return False; @@ -16894,6 +16988,148 @@ static Bool dis_av_fp_convert ( UInt theInstr ) return True; } +static Bool dis_transactional_memory ( UInt theInstr, UInt nextInstr, + VexAbiInfo* vbi, + /*OUT*/DisResult* dres, + Bool (*resteerOkFn)(void*,Addr64), + void* callback_opaque ) +{ + UInt opc2 = IFIELD( theInstr, 1, 10 ); + + switch (opc2) { + case 0x28E: { //tbegin. + /* The current implementation is to just fail the tbegin and execute + * the failure path. The failure path is assumed to be functionaly + * equivalent to the transactional path with the needed data locking + * to ensure correctness. The tend is just a noop and shouldn't + * actually get executed. + * 1) set cr0 to 0x2 + * 2) Initialize TFHAR to CIA+4 + * 3) Initialize TEXASR + * 4) Initialize TFIAR (probably to CIA, ie, the address of tbegin.) + * 5) Continue executing at the next instruction. + */ + UInt R = IFIELD( theInstr, 21, 1 ); + + ULong tm_reason; + UInt failure_code = 0; /* Forcing failure, will not be due to tabort + * or treclaim. + */ + UInt persistant = 1; /* set persistant since we are always failing + * the tbegin. + */ + UInt nest_overflow = 1; /* Alowed nesting depth overflow, we use this + as the reason for failing the trasaction */ + UInt tm_exact = 1; /* have exact address for failure */ + + DIP("tbegin. %d\n", R); + + /* Set the CR0 field to indicate the tbegin failed. Then let + * the code do the branch to the failure path. + * + * 000 || 0 Transaction initiation successful, + * unnested (Transaction state of + * Non-transactional prior to tbegin.) + * 010 || 0 Transaction initiation successful, nested + * (Transaction state of Transactional + * prior to tbegin.) + * 001 || 0 Transaction initiation unsuccessful, + * (Transaction state of Suspended prior + * to tbegin.) + */ + putCR321( 0, mkU8( 0x2 ) ); + + tm_reason = generate_TMreason( failure_code, persistant, + nest_overflow, tm_exact ); + + storeTMfailure( guest_CIA_curr_instr, tm_reason, + guest_CIA_curr_instr+4 ); + + return True; + + break; + } + + case 0x2AE: { //tend. + /* The tend. is just a noop. Do nothing */ + UInt A = IFIELD( theInstr, 25, 1 ); + + DIP("tend. %d\n", A); + break; + } + + case 0x2EE: { //tsr. + /* The tsr. is just a noop. Do nothing */ + UInt L = IFIELD( theInstr, 21, 1 ); + + DIP("tsr. %d\n", L); + break; + } + + case 0x2CE: { //tcheck. + /* The tcheck. is just a noop. Do nothing */ + UInt BF = IFIELD( theInstr, 25, 1 ); + + DIP("tcheck. %d\n", BF); + break; + } + + case 0x30E: { //tbortwc. + /* The tabortwc. is just a noop. Do nothing */ + UInt TO = IFIELD( theInstr, 25, 1 ); + UInt RA = IFIELD( theInstr, 16, 5 ); + UInt RB = IFIELD( theInstr, 11, 5 ); + + DIP("tabortwc. %d,%d,%d\n", TO, RA, RB); + break; + } + + case 0x32E: { //tbortdc. + /* The tabortdc. is just a noop. Do nothing */ + UInt TO = IFIELD( theInstr, 25, 1 ); + UInt RA = IFIELD( theInstr, 16, 5 ); + UInt RB = IFIELD( theInstr, 11, 5 ); + + DIP("tabortdc. %d,%d,%d\n", TO, RA, RB); + break; + } + + case 0x34E: { //tbortwci. + /* The tabortwci. is just a noop. Do nothing */ + UInt TO = IFIELD( theInstr, 25, 1 ); + UInt RA = IFIELD( theInstr, 16, 5 ); + UInt SI = IFIELD( theInstr, 11, 5 ); + + DIP("tabortwci. %d,%d,%d\n", TO, RA, SI); + break; + } + + case 0x36E: { //tbortdci. + /* The tabortdci. is just a noop. Do nothing */ + UInt TO = IFIELD( theInstr, 25, 1 ); + UInt RA = IFIELD( theInstr, 16, 5 ); + UInt SI = IFIELD( theInstr, 11, 5 ); + + DIP("tabortdci. %d,%d,%d\n", TO, RA, SI); + break; + } + + case 0x38E: { //tbort. + /* The tabort. is just a noop. Do nothing */ + UInt RA = IFIELD( theInstr, 16, 5 ); + + DIP("tabort. %d\n", RA); + break; + } + + default: + vex_printf("dis_transactional_memory(ppc): unrecognized instruction\n"); + return False; + } + + return True; +} + /* The 0x3C primary opcode (VSX category) uses several different forms of * extended opcodes: @@ -17951,6 +18187,17 @@ DisResult disInstr_PPC_WRK ( if (dis_int_logic( theInstr )) goto decode_success; goto decode_failure; + case 0x28E: case 0x2AE: // tbegin., tend. + case 0x2EE: case 0x2CE: case 0x30E: // tsr., tcheck., tabortwc. + case 0x32E: case 0x34E: case 0x36E: // tabortdc., tabortwci., tabortdci. + case 0x38E: // tabort. + if (dis_transactional_memory( theInstr, + getUIntBigendianly( (UChar*)(&guest_code[delta + 4])), + abiinfo, &dres, + resteerOkFn, callback_opaque)) + goto decode_success; + goto decode_failure; + /* 64bit Integer Logical Instructions */ case 0x3DA: case 0x03A: // extsw, cntlzd if (!mode64) goto decode_failure; diff --git a/VEX/pub/libvex_guest_ppc32.h b/VEX/pub/libvex_guest_ppc32.h index d90b7d3bde..11938cc652 100644 --- a/VEX/pub/libvex_guest_ppc32.h +++ b/VEX/pub/libvex_guest_ppc32.h @@ -237,9 +237,14 @@ typedef /* SPRG3, which AIUI is readonly in user space. Needed for threading on AIX. */ /* 1352 */ UInt guest_SPRG3_RO; + /* 1356 */ UInt padding1; + /* 1360 */ ULong guest_TFHAR; // Transaction Failure Handler Address Register + /* 1368 */ ULong guest_TEXASR; // Transaction EXception And Summary Register + /* 1376 */ ULong guest_TFIAR; // Transaction Failure Instruction Address Register /* Padding to make it have an 8-aligned size */ - /* 1356 */ UInt padding; + /* 1384 */ UInt padding2; + } VexGuestPPC32State; diff --git a/VEX/pub/libvex_guest_ppc64.h b/VEX/pub/libvex_guest_ppc64.h index 1c9502c240..d5a7f2d3b4 100644 --- a/VEX/pub/libvex_guest_ppc64.h +++ b/VEX/pub/libvex_guest_ppc64.h @@ -279,11 +279,10 @@ typedef threading on AIX. */ /* 1648 */ ULong guest_SPRG3_RO; - /* offsets in comments are wrong ..*/ - /* Padding to make it have an 16-aligned size */ - /* 1656 */ ULong padding2; - /* 16XX */ ULong padding3; - /* 16XX */ ULong padding4; + /* 1656 */ ULong guest_TFHAR; // Transaction Failure Handler Address Register + /* 1664 */ ULong guest_TEXASR; // Transaction EXception And Summary Register + /* 1672 */ ULong guest_TFIAR; // Transaction Failure Instruction Address Register + } VexGuestPPC64State;