From: Julian Seward Date: Thu, 17 Dec 2020 16:40:46 +0000 (+0100) Subject: arm64 front end: ufbm/sfbm: handle plain shifts explicitly X-Git-Tag: VALGRIND_3_17_0~89 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=41504d33dec8773c591d45192d1dda6e9c670031;p=thirdparty%2Fvalgrind.git arm64 front end: ufbm/sfbm: handle plain shifts explicitly The ufbm and sfbm instructions implement some kind of semi-magical rotate, mask and sign/zero-extend functionality. Boring old left and right shifts are special cases of it. The existing translation into IR is correct, but has the disadvantage that the IR optimiser isn't clever enough to simplify the resulting IR back into a single shift in the case where the instruction is used simply to encode a shift. This induces inefficiency and it also makes the resulting disassembly pretty difficult to read, if you're into that kind of thing. This commit does the obvious thing: detects cases where the required behaviour is just a single shift, and emits IR and disassembly-printing accordingly. All other cases fall through to the existing general-case handling and so are unchanged. --- diff --git a/VEX/priv/guest_arm64_toIR.c b/VEX/priv/guest_arm64_toIR.c index d242d43c07..14cbd1ea3d 100644 --- a/VEX/priv/guest_arm64_toIR.c +++ b/VEX/priv/guest_arm64_toIR.c @@ -2694,6 +2694,65 @@ Bool dis_ARM64_data_processing_immediate(/*MB_OUT*/DisResult* dres, Bool is64 = sf == 1; IRType ty = is64 ? Ity_I64 : Ity_I32; + // Handle plain shifts explicitly. These are functionally identical to + // the general case below, but iropt isn't clever enough to reduce those + // sequences to plain shifts. So give it a hand. + if (is64 && immS == 63 && immR >= 1 && immR <= 63) { + if (opc == BITS2(0,0)) { + // 64-bit signed shift right + putIReg64orZR(dd, binop(Iop_Sar64, getIReg64orZR(nn), mkU8(immR))); + DIP("asr %s, %s, #%u\n", + nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn), immR); + return True; + } + if (opc == BITS2(1,0)) { + // 64-bit unsigned shift right + putIReg64orZR(dd, binop(Iop_Shr64, getIReg64orZR(nn), mkU8(immR))); + DIP("lsr %s, %s, #%u\n", + nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn), immR); + return True; + } + } + + if (!is64 && immS == 31 && immR >= 1 && immR <= 31) { + if (opc == BITS2(0,0)) { + // 32-bit signed shift right + putIReg32orZR(dd, binop(Iop_Sar32, getIReg32orZR(nn), mkU8(immR))); + DIP("asr %s, %s, #%u\n", + nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn), immR); + return True; + } + if (opc == BITS2(1,0)) { + // 32-bit unsigned shift right + putIReg32orZR(dd, binop(Iop_Shr32, getIReg32orZR(nn), mkU8(immR))); + DIP("lsr %s, %s, #%u\n", + nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn), immR); + return True; + } + } + + if (is64 && immS >= 0 && immS <= 62 + && immR == immS + 1 && opc == BITS2(1,0)) { + // 64-bit shift left + UInt shift = 64 - immR; + vassert(shift >= 1 && shift <= 63); + putIReg64orZR(dd, binop(Iop_Shl64, getIReg64orZR(nn), mkU8(shift))); + DIP("lsl %s, %s, #%u\n", + nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn), shift); + return True; + } + if (!is64 && immS >= 0 && immS <= 30 + && immR == immS + 1 && opc == BITS2(1,0)) { + // 32-bit shift left + UInt shift = 32 - immR; + vassert(shift >= 1 && shift <= 31); + putIReg32orZR(dd, binop(Iop_Shl32, getIReg32orZR(nn), mkU8(shift))); + DIP("lsl %s, %s, #%u\n", + nameIRegOrZR(is64, dd), nameIRegOrZR(is64, nn), shift); + return True; + } + + // No luck. We have to use the (slow) general case. IRTemp dst = newTemp(ty); IRTemp src = newTemp(ty); IRTemp bot = newTemp(ty);