Pentium pairability testing (without float ops)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Determine which argument references memory, if any | |
| static void determineMem(const TInst *inst, const TArg **mem) | |
| { | |
| int nSrcs = inst->getNumSrcs(); | |
| int nDsts = inst->getNumDsts(); | |
| for (int i=0; i < nSrcs; i++) | |
| { | |
| const TArg& arg = inst->getSrc(i); | |
| if (arg.isIndirect()) *mem = &arg; | |
| } | |
| for (int i=0; i < nDsts; i++) | |
| { | |
| const TArg &arg = inst->getDst(i); | |
| if (arg.isIndirect()) *mem = &arg; | |
| } | |
| } | |
| /* 1) TEST [MEM], IMM is !pairable | |
| 2) TEST REG , IMM is only pairable if REG = {AL, AX, RAX} */ | |
| static bool isTestPairable(const TInst* inst) | |
| { | |
| using namespace OpType; | |
| if (inst->getOp() == eTEST && inst->getSrc(1).isImmediate()) { | |
| const TArg& src0 = inst->getSrc(0); | |
| if(src0.isIndirect()) | |
| return false; | |
| /* TODO: If we ever generate AL, support must be added */ | |
| if(src0.getBaseRegNum() != RegNames::eRAX || | |
| src0.getBaseRegNum() != RegNames::eEAX) | |
| return false; | |
| } | |
| return true; | |
| } | |
| /* PUSH/POP are !pairable if their argument is either a [MEM] or the SR */ | |
| static bool isPushPopPairable(const TInst* inst) | |
| { | |
| using namespace OpType; | |
| const TOp& op = inst->getOp(); | |
| if(op == ePUSH && inst->getSrc(0).isIndirect()) | |
| return false; | |
| if(op == ePOP && inst->getDst(0).isIndirect()) | |
| return false; | |
| /* TODO: If we ever generate SR, support must be added */ | |
| return true; | |
| } | |
| /* SHR/SAR/SHL/SAL are U-pairable with immediate count */ | |
| static bool isShiftUPairable(const TInst *inst) | |
| { | |
| using namespace OpType; | |
| const TOp& op = inst->getOp(); | |
| if ((op == eSHR || op == eSAR || op == eSHL || op == eSAL) && | |
| !inst->getSrc(inst->getNumSrcs() - 1).isImmediate()) | |
| return false; | |
| return true; | |
| } | |
| /* ROR, ROL, RCR, RCL are U-pairable with an immediate count == 1 */ | |
| static bool isRotateUPairable(const TInst *inst) | |
| { | |
| using namespace OpType; | |
| const TOp& op = inst->getOp(); | |
| if (op == eROR || op == eROL || op == eRCR || op == eRCL) { | |
| TArg lastSrc = inst->getSrc(inst->getNumSrcs() - 1); | |
| if (!lastSrc.isImmediate() || !(lastSrc.getIVal() == 1)) | |
| return false; | |
| } | |
| return true; | |
| } | |
| /* Listed ops are !pairable if address contains a displacement */ | |
| static bool hasDispImmPair(const TInst *inst, const TArg* memAccess) | |
| { | |
| using namespace OpType; | |
| using namespace AddrMode; | |
| /* TODO: Check that it is indeed the case that there can be no memory | |
| operands on both dst & src positions simultaneously, as well | |
| as a src memory operand coupled with an immediate. */ | |
| if (memAccess && inst->getNumDsts() && | |
| inst->getSrc(inst->getNumSrcs() - 1).isImmediate()) | |
| { | |
| // @ryg Why is this only checking destination arg? Doesn't seem right! | |
| if (inst->getDst(0).getAddrMode() & _eDisplacement) | |
| return inst->getDst(0).getDisplacement() != 0; | |
| } | |
| return false; | |
| } | |
| enum tSizeClass | |
| { | |
| SizeBelow8b, | |
| Size8b, | |
| SizeAbove8b, | |
| }; | |
| // *RAD* | |
| /* Determine whether an op is <8b, =8b or >8b. This influences pairability. */ | |
| static tSizeClass getSizeClass(const TInst *inst, const TArg *memAccess) | |
| { | |
| using namespace OpType; | |
| using namespace AddrMode; | |
| // MOVs can have 64-bit immediates - either an actual immediate or a label | |
| const TOp& op = inst->getOp(); | |
| if (op == eMOV && | |
| (inst->getSrc(0).isLabel() || | |
| inst->getSrc(0).isImmediate() && inst->getDst(0).isDirect() && | |
| (inst->getSrc(0).getImmedType() == DataType::uint64 || inst->getSrc(0).getImmedType() == DataType::sint64) && | |
| (inst->getSrc(0).getU64Val() >> 32) != 0)) | |
| return SizeAbove8b; | |
| // Anything else without a memory access is <8b (TODO double-check this!) | |
| if (!memAccess) | |
| return SizeBelow8b; | |
| // Most ops we need to worry about have displacements | |
| tAddrMode addrMode = memAccess->getAddrMode(); | |
| bool hasDisp = (addrMode == eDisplacement || addrMode == eBaseDisplacement || | |
| addrMode == eBaseIndexDisplacement); | |
| bool hasSIB = (addrMode == eBaseIndex || addrMode == eBaseIndexDisplacement); | |
| // If there's a displacement, determine if it requires disp32 | |
| bool hasDisp32 = false; | |
| if (hasDisp) | |
| { | |
| _sint64 disp = memAccess->getDisplacement(); | |
| int granularity = memGranularity(inst); | |
| if ((disp & (granularity - 1)) || | |
| disp < -128 * granularity || disp > 127 * granularity) | |
| hasDisp32 = true; | |
| } | |
| // Now, the actual size class depends on the instruction | |
| if (op == eMOV || op == eLEA) | |
| { | |
| // Here it gets ugly: mov reg, [mem] or mov [mem], reg hit 8b iff | |
| // there's a REX byte, a SIB, and a 32-bit displacement | |
| // Same for LEA, though of course there's no [mem], reg variant. | |
| if (hasSIB && hasDisp32) | |
| { | |
| const TArg *regOp = &inst->getSrc(0); | |
| if (regOp == memAccess) // oops, other one! | |
| regOp = &inst->getDst(0); | |
| // We get REX if we have a 64-bit operand or one of the register numbers involved is >=8 | |
| if (regOp->getGPRWidth() == RegWidth::eWidth64 || regOp->getBaseRegNum() >= 8 || | |
| memAccess->getBaseRegNum() >= 8 || memAccess->getIndexRegNum() >= 8) | |
| return Size8b; | |
| } | |
| } | |
| return SizeBelow8b; | |
| } | |
| bool doPair(TContext &context, const TInst *uInst, const TInst *vInst, bool ignoreBankConflicts) | |
| { | |
| using namespace Pipe; | |
| using namespace OpType; | |
| const TOp& uOp = uInst->getOp(); | |
| const TOp& vOp = vInst->getOp(); | |
| TCorePipe uPairability = uOp.getCorePipe(); | |
| TCorePipe vPairability = vOp.getCorePipe(); | |
| /* We can only pair if the U-pipe's getting something that's pairable | |
| on U and the V-pipe's getting something that is pairable on V :) */ | |
| if ((uPairability == eUPairable || uPairability == eUVPairable) && | |
| (vPairability == eVPairable || vPairability == eUVPairable)) | |
| { | |
| /* Determine which arguments access memory (if any) and how many | |
| vector read ports are used. */ | |
| const TArg *uMem = NULL; | |
| const TArg *vMem = NULL; | |
| determineMem(uInst, &uMem); | |
| determineMem(vInst, &vMem); | |
| /* Check for bank collisions. TODO what to do with non-{0,1} probabilities? */ | |
| if (!ignoreBankConflicts && | |
| computeBankCollisionProbability(context, uInst, uMem, vInst, vMem) == 1.0f) | |
| return false; | |
| /* Neither inst can contain a disp and an immediate simultaneously */ | |
| if (hasDispImmPair(uInst, uMem) || hasDispImmPair(vInst, vMem)) | |
| return false; | |
| /* Two 8b instructions can't pair with each other, and any inst >8b is unpairable */ | |
| tSizeClass uSize = getSizeClass(uInst, uMem); | |
| tSizeClass vSize = getSizeClass(vInst, vMem); | |
| if ((uSize == Size8b && vSize == Size8b) || uSize == SizeAbove8b || vSize == SizeAbove8b) | |
| return false; | |
| /* PUSH/POP are !pairable if their argument is either a [MEM] or the SR */ | |
| if (!isPushPopPairable(uInst)) return false; | |
| if (!isPushPopPairable(vInst)) return false; | |
| /* TEST REG,IMM is only pairable if REG = {AX, RAX}; [MEM],IMM is !pairable */ | |
| if (!isTestPairable(uInst)) return false; | |
| if (!isTestPairable(vInst)) return false; | |
| /* SHR/SAR/SHL/SAL are U-pairable with immediate count */ | |
| if (!isShiftUPairable(uInst)) return false; | |
| /* ROR, ROL, RCR, RCL are U-pairable with an immediate count == 1 */ | |
| if (!isRotateUPairable(uInst)) return false; | |
| /* TODO: JMP, CALL to a far location are NP */ | |
| } | |
| else /* Well, these can't pair */ | |
| return false; | |
| return true; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment