MCPcopy Create free account
hub / github.com/danoon2/Boxedwine / calculateLongestBlock

Method calculateLongestBlock

source/emulation/cpu/jit/jitCodeGen.cpp:110–280  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

108#endif
109
110bool JitCodeGen::calculateLongestBlock(DecodedOp* op) {
111 U32 eip = this->startingEip;
112 DecodedOp* nextOp = op;
113 U32 furthestJump = 0;
114
115 // find the longest block we can compile
116 // branches that jump out of the block will be the end of the block
117
118 // 1st pass, find longest block including all direct jumps (conditional jumps, direct jumps, loop, etc)
119
120 // jumpTo will keep track of valid jump targets. We need this if we are going to decode more instructions (cpu->getOp)
121 // Without this the next byte of instruction may actually be invalid, I have seen skipped bytes in the instructions,
122 // I assume its for alignment/performance reasons. Firefight installer will trigger this
123 BHashTable<U32, DecodedOp*> jumpTo;
124
125 // opentdd will trigger this isValid check
126 while (nextOp && nextOp->isValid()) {
127 // could be ret, call, int. Basically this is an instruction where we are not guaranteed to see a next instruction
128 if (nextOp->isBranch() && !nextOp->isDirectJumpBranch()) {
129 // is this the last return, if so, then don't decode more
130 if (nextOp->isRet() && furthestJump < eip) {
131 break;
132 }
133 if (nextOp->isIndirectJump()) {
134 // opentdd needs this when creating a new game, I'm not sure why data.cpu->memory->getDecodedOp(eip + nextOp->len) will find an op but its not correct, might be another bug
135 break;
136 }
137 // These next 4 look aheads, nextOp->next =
138 // They don't improve performance on Quake 2, but do make a significant improvement for Cinebench, 10-20%
139 if (!nextOp->next) {
140 // don't call cpu->getOp since that will decode and we are not sure the next byte is a valid instruction.
141 // we can call memory->getDecodedOp to see if this instruction has already been decoded, in that case we know its valid.
142 nextOp->next = this->cpu->memory->getDecodedOp(eip + nextOp->len);
143 }
144 if (!nextOp->next && nextOp->isDirectBranchWithNext()) {
145 nextOp->next = this->cpu->getOp(eip + nextOp->len, 0);
146 }
147 if (!nextOp->next && nextOp->isCall() && furthestJump > eip) {
148 nextOp->next = this->cpu->getOp(eip + nextOp->len, 0);
149 }
150 if (!nextOp->next && jumpTo.contains(eip + nextOp->len)) {
151 // this gives a 30% improvement to cinebench, but makes F-16 unstable. I wonder if something is wrong with this line of code
152 // or if by creating a larger block it increases the chance that self modifying code will hit it and there is someting wrong
153 // with how I handle self modifying code
154 nextOp->next = this->cpu->getOp(eip + nextOp->len, 0);
155 }
156
157 if (!nextOp->next) {
158 // since we couldn't figure out if the next byte is part of a valid instruction, we are done looking
159 break;
160 }
161 }
162 if (nextOp->isDirectJumpBranch() && (eip + nextOp->len + nextOp->imm) < this->startingEip) {
163 // if we have somewhere to go after this, then continue
164
165 // see if we can restart this JIT with the target of this jump to before the incoming op argument to create a bigger JIT block
166 DecodedOp* targetOp = this->cpu->memory->getDecodedOp(eip + nextOp->len + nextOp->imm);
167 if (!targetOp) {

Callers

nothing calls this directly

Calls 15

maxFunction · 0.85
isValidMethod · 0.80
isBranchMethod · 0.80
isDirectJumpBranchMethod · 0.80
isRetMethod · 0.80
isIndirectJumpMethod · 0.80
getDecodedOpMethod · 0.80
getOpMethod · 0.80
isDirectBranchMethod · 0.80
startNewJITFunction · 0.50
isCallMethod · 0.45

Tested by

no test coverage detected