void CallFrameShuffler::emitLoad(CachedRecovery& cachedRecovery) { if (!cachedRecovery.recovery().isInJSStack()) return; if (verbose) dataLog(" * Loading ", cachedRecovery.recovery(), " into "); VirtualRegister reg = cachedRecovery.recovery().virtualRegister(); MacroAssembler::Address address { addressForOld(reg) }; bool tryFPR { true }; GPRReg resultGPR { cachedRecovery.wantedJSValueRegs().gpr() }; // If we want a GPR and it's available, that's better than loading // into an FPR. if (resultGPR != InvalidGPRReg && !m_registers[resultGPR] && !m_lockedRegisters.get(resultGPR) && cachedRecovery.loadsIntoGPR()) tryFPR = false; // Otherwise, we prefer loading into FPRs if possible if (tryFPR && cachedRecovery.loadsIntoFPR()) { FPRReg resultFPR { cachedRecovery.wantedFPR() }; if (resultFPR == InvalidFPRReg || m_registers[resultFPR] || m_lockedRegisters.get(resultFPR)) resultFPR = getFreeFPR(); if (resultFPR != InvalidFPRReg) { m_jit.loadDouble(address, resultFPR); DataFormat dataFormat = DataFormatJS; // We could be transforming a DataFormatCell into a // DataFormatJS here - but that's OK. if (cachedRecovery.recovery().dataFormat() == DataFormatDouble) dataFormat = DataFormatDouble; updateRecovery(cachedRecovery, ValueRecovery::inFPR(resultFPR, dataFormat)); if (verbose) dataLog(cachedRecovery.recovery(), "\n"); if (reg == newAsOld(dangerFrontier())) updateDangerFrontier(); return; } } ASSERT(cachedRecovery.loadsIntoGPR()); if (resultGPR == InvalidGPRReg || m_registers[resultGPR] || m_lockedRegisters.get(resultGPR)) resultGPR = getFreeGPR(); ASSERT(resultGPR != InvalidGPRReg); m_jit.loadPtr(address, resultGPR); updateRecovery(cachedRecovery, ValueRecovery::inGPR(resultGPR, cachedRecovery.recovery().dataFormat())); if (verbose) dataLog(cachedRecovery.recovery(), "\n"); if (reg == newAsOld(dangerFrontier())) updateDangerFrontier(); }
Input AIManager::getInput(unsigned int playerNum) { updateRecovery(playerNum); return followPath(playerNum); //return followRandomPath(playerNum); //Test function }
Input AIManager::updateAI(int playerNum, bool switchType, vec3 pos) { if (switchType) { if (aiType == 2) { aiType = 0; cout << "Drive to point\n"; } else if (aiType == 1) { aiType += 1; cout << "Evade\n"; } else { aiType += 1; cout << "Chase\n"; } } updateRecovery(playerNum); /* // Keeps a sort of cyclical vector if (pastInfo[playerNum].size() < 20) { pastInfo[playerNum].erase(pastInfo[playerNum].begin()); } pastInfo[playerNum].push_back((*state->getPlayer(playerNum))); bool allSlow = true; for (int i = 0; i < pastInfo[playerNum].size(); i++) { if (pastInfo[playerNum][i].getFSpeed() > 1.0f || pastInfo[playerNum][i].getFSpeed() < 1.0f) { allSlow = false; } } if (collisionRecovery) { collisionRecoveryCounter++; if (collisionRecoveryCounter > collisionRecoveryCounterMax) { collisionRecovery = false; collisionRecoveryCounter = 0; } } if (allSlow) { collisionRecovery = true; infoAtCollision = *state->getPlayer(playerNum); return recover(playerNum); }*/ if (collisionRecovery) return recover(playerNum); if (aiType == 0) { return driveToPoint(playerNum, pos); } else if (aiType == 1) { return testAIChase(playerNum); } else { return testAIEvade(playerNum); } }
void CallFrameShuffler::emitLoad(CachedRecovery& location) { if (!location.recovery().isInJSStack()) return; if (verbose) dataLog(" * Loading ", location.recovery(), " into "); VirtualRegister reg { location.recovery().virtualRegister() }; MacroAssembler::Address address { addressForOld(reg) }; bool tryFPR { true }; JSValueRegs wantedJSValueRegs { location.wantedJSValueRegs() }; if (wantedJSValueRegs) { if (wantedJSValueRegs.payloadGPR() != InvalidGPRReg && !m_registers[wantedJSValueRegs.payloadGPR()] && !m_lockedRegisters.get(wantedJSValueRegs.payloadGPR())) tryFPR = false; if (wantedJSValueRegs.tagGPR() != InvalidGPRReg && !m_registers[wantedJSValueRegs.tagGPR()] && !m_lockedRegisters.get(wantedJSValueRegs.tagGPR())) tryFPR = false; } if (tryFPR && location.loadsIntoFPR()) { FPRReg resultFPR = location.wantedFPR(); if (resultFPR == InvalidFPRReg || m_registers[resultFPR] || m_lockedRegisters.get(resultFPR)) resultFPR = getFreeFPR(); if (resultFPR != InvalidFPRReg) { m_jit.loadDouble(address, resultFPR); DataFormat dataFormat = DataFormatJS; if (location.recovery().dataFormat() == DataFormatDouble) dataFormat = DataFormatDouble; updateRecovery(location, ValueRecovery::inFPR(resultFPR, dataFormat)); if (verbose) dataLog(location.recovery(), "\n"); if (reg == newAsOld(dangerFrontier())) updateDangerFrontier(); return; } } if (location.loadsIntoGPR()) { GPRReg resultGPR { wantedJSValueRegs.payloadGPR() }; if (resultGPR == InvalidGPRReg || m_registers[resultGPR] || m_lockedRegisters.get(resultGPR)) resultGPR = getFreeGPR(); ASSERT(resultGPR != InvalidGPRReg); m_jit.loadPtr(address.withOffset(PayloadOffset), resultGPR); updateRecovery(location, ValueRecovery::inGPR(resultGPR, location.recovery().dataFormat())); if (verbose) dataLog(location.recovery(), "\n"); if (reg == newAsOld(dangerFrontier())) updateDangerFrontier(); return; } ASSERT(location.recovery().technique() == DisplacedInJSStack); GPRReg payloadGPR { wantedJSValueRegs.payloadGPR() }; GPRReg tagGPR { wantedJSValueRegs.tagGPR() }; if (payloadGPR == InvalidGPRReg || m_registers[payloadGPR] || m_lockedRegisters.get(payloadGPR)) payloadGPR = getFreeGPR(); m_lockedRegisters.set(payloadGPR); if (tagGPR == InvalidGPRReg || m_registers[tagGPR] || m_lockedRegisters.get(tagGPR)) tagGPR = getFreeGPR(); m_lockedRegisters.clear(payloadGPR); ASSERT(payloadGPR != InvalidGPRReg && tagGPR != InvalidGPRReg && tagGPR != payloadGPR); m_jit.loadPtr(address.withOffset(PayloadOffset), payloadGPR); m_jit.loadPtr(address.withOffset(TagOffset), tagGPR); updateRecovery(location, ValueRecovery::inPair(tagGPR, payloadGPR)); if (verbose) dataLog(location.recovery(), "\n"); if (reg == newAsOld(dangerFrontier())) updateDangerFrontier(); }
void CallFrameShuffler::emitDisplace(CachedRecovery& location) { ASSERT(location.recovery().isInRegisters()); JSValueRegs wantedJSValueRegs { location.wantedJSValueRegs() }; ASSERT(wantedJSValueRegs); // We don't support wanted FPRs on 32bit platforms GPRReg wantedTagGPR { wantedJSValueRegs.tagGPR() }; GPRReg wantedPayloadGPR { wantedJSValueRegs.payloadGPR() }; if (wantedTagGPR != InvalidGPRReg) { ASSERT(!m_lockedRegisters.get(wantedTagGPR)); if (CachedRecovery* currentTag { m_registers[wantedTagGPR] }) { if (currentTag == &location) { if (verbose) dataLog(" + ", wantedTagGPR, " is OK\n"); } else { // This can never happen on 32bit platforms since we // have at most one wanted JSValueRegs, for the // callee, and no callee-save registers. RELEASE_ASSERT_NOT_REACHED(); } } } if (wantedPayloadGPR != InvalidGPRReg) { ASSERT(!m_lockedRegisters.get(wantedPayloadGPR)); if (CachedRecovery* currentPayload { m_registers[wantedPayloadGPR] }) { if (currentPayload == &location) { if (verbose) dataLog(" + ", wantedPayloadGPR, " is OK\n"); } else { // See above RELEASE_ASSERT_NOT_REACHED(); } } } if (location.recovery().technique() == InPair || location.recovery().isInGPR()) { GPRReg payloadGPR; if (location.recovery().technique() == InPair) payloadGPR = location.recovery().payloadGPR(); else payloadGPR = location.recovery().gpr(); if (wantedPayloadGPR == InvalidGPRReg) wantedPayloadGPR = payloadGPR; if (payloadGPR != wantedPayloadGPR) { if (location.recovery().technique() == InPair && wantedPayloadGPR == location.recovery().tagGPR()) { if (verbose) dataLog(" * Swapping ", payloadGPR, " and ", wantedPayloadGPR, "\n"); m_jit.swap(payloadGPR, wantedPayloadGPR); updateRecovery(location, ValueRecovery::inPair(payloadGPR, wantedPayloadGPR)); } else { if (verbose) dataLog(" * Moving ", payloadGPR, " into ", wantedPayloadGPR, "\n"); m_jit.move(payloadGPR, wantedPayloadGPR); if (location.recovery().technique() == InPair) { updateRecovery(location, ValueRecovery::inPair(location.recovery().tagGPR(), wantedPayloadGPR)); } else { updateRecovery(location, ValueRecovery::inGPR(wantedPayloadGPR, location.recovery().dataFormat())); } } } if (wantedTagGPR == InvalidGPRReg) wantedTagGPR = getFreeGPR(); switch (location.recovery().dataFormat()) { case DataFormatInt32: if (verbose) dataLog(" * Moving int32 tag into ", wantedTagGPR, "\n"); m_jit.move(MacroAssembler::TrustedImm32(JSValue::Int32Tag), wantedTagGPR); break; case DataFormatCell: if (verbose) dataLog(" * Moving cell tag into ", wantedTagGPR, "\n"); m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), wantedTagGPR); break; case DataFormatBoolean: if (verbose) dataLog(" * Moving boolean tag into ", wantedTagGPR, "\n"); m_jit.move(MacroAssembler::TrustedImm32(JSValue::BooleanTag), wantedTagGPR); break; case DataFormatJS: ASSERT(wantedTagGPR != location.recovery().payloadGPR()); if (wantedTagGPR != location.recovery().tagGPR()) { if (verbose) dataLog(" * Moving ", location.recovery().tagGPR(), " into ", wantedTagGPR, "\n"); m_jit.move(location.recovery().tagGPR(), wantedTagGPR); } break; default: RELEASE_ASSERT_NOT_REACHED(); } } else { ASSERT(location.recovery().isInFPR()); if (wantedTagGPR == InvalidGPRReg) { ASSERT(wantedPayloadGPR != InvalidGPRReg); m_lockedRegisters.set(wantedPayloadGPR); wantedTagGPR = getFreeGPR(); m_lockedRegisters.clear(wantedPayloadGPR); } if (wantedPayloadGPR == InvalidGPRReg) { m_lockedRegisters.set(wantedTagGPR); wantedPayloadGPR = getFreeGPR(); m_lockedRegisters.clear(wantedTagGPR); } m_jit.boxDouble(location.recovery().fpr(), wantedTagGPR, wantedPayloadGPR); } updateRecovery(location, ValueRecovery::inPair(wantedTagGPR, wantedPayloadGPR)); }
void CallFrameShuffler::emitBox(CachedRecovery& cachedRecovery) { ASSERT(canBox(cachedRecovery)); if (cachedRecovery.recovery().isConstant()) return; if (cachedRecovery.recovery().isInGPR()) { switch (cachedRecovery.recovery().dataFormat()) { case DataFormatInt32: if (verbose) dataLog(" * Boxing ", cachedRecovery.recovery()); m_jit.zeroExtend32ToPtr( cachedRecovery.recovery().gpr(), cachedRecovery.recovery().gpr()); m_lockedRegisters.set(cachedRecovery.recovery().gpr()); if (tryAcquireTagTypeNumber()) m_jit.or64(m_tagTypeNumber, cachedRecovery.recovery().gpr()); else { // We have to do this the hard way m_jit.or64(MacroAssembler::TrustedImm64(TagTypeNumber), cachedRecovery.recovery().gpr()); } m_lockedRegisters.clear(cachedRecovery.recovery().gpr()); cachedRecovery.setRecovery( ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatJS)); if (verbose) dataLog(" into ", cachedRecovery.recovery(), "\n"); return; case DataFormatInt52: if (verbose) dataLog(" * Boxing ", cachedRecovery.recovery()); m_jit.rshift64(MacroAssembler::TrustedImm32(JSValue::int52ShiftAmount), cachedRecovery.recovery().gpr()); cachedRecovery.setRecovery( ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatStrictInt52)); if (verbose) dataLog(" into ", cachedRecovery.recovery(), "\n"); FALLTHROUGH; case DataFormatStrictInt52: { if (verbose) dataLog(" * Boxing ", cachedRecovery.recovery()); FPRReg resultFPR = getFreeFPR(); ASSERT(resultFPR != InvalidFPRReg); m_jit.convertInt64ToDouble(cachedRecovery.recovery().gpr(), resultFPR); updateRecovery(cachedRecovery, ValueRecovery::inFPR(resultFPR, DataFormatDouble)); if (verbose) dataLog(" into ", cachedRecovery.recovery(), "\n"); break; } case DataFormatBoolean: if (verbose) dataLog(" * Boxing ", cachedRecovery.recovery()); m_jit.add32(MacroAssembler::TrustedImm32(ValueFalse), cachedRecovery.recovery().gpr()); cachedRecovery.setRecovery( ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatJS)); if (verbose) dataLog(" into ", cachedRecovery.recovery(), "\n"); return; default: return; } } if (cachedRecovery.recovery().isInFPR()) { if (cachedRecovery.recovery().dataFormat() == DataFormatDouble) { if (verbose) dataLog(" * Boxing ", cachedRecovery.recovery()); GPRReg resultGPR = cachedRecovery.wantedJSValueRegs().gpr(); if (resultGPR == InvalidGPRReg || m_registers[resultGPR]) resultGPR = getFreeGPR(); ASSERT(resultGPR != InvalidGPRReg); m_jit.purifyNaN(cachedRecovery.recovery().fpr()); m_jit.moveDoubleTo64(cachedRecovery.recovery().fpr(), resultGPR); m_lockedRegisters.set(resultGPR); if (tryAcquireTagTypeNumber()) m_jit.sub64(m_tagTypeNumber, resultGPR); else m_jit.sub64(MacroAssembler::TrustedImm64(TagTypeNumber), resultGPR); m_lockedRegisters.clear(resultGPR); updateRecovery(cachedRecovery, ValueRecovery::inGPR(resultGPR, DataFormatJS)); if (verbose) dataLog(" into ", cachedRecovery.recovery(), "\n"); return; } ASSERT(cachedRecovery.recovery().dataFormat() == DataFormatJS); return; } RELEASE_ASSERT_NOT_REACHED(); }
void CallFrameShuffler::emitDisplace(CachedRecovery& cachedRecovery) { Reg wantedReg; if (!(wantedReg = Reg { cachedRecovery.wantedJSValueRegs().gpr() })) wantedReg = Reg { cachedRecovery.wantedFPR() }; ASSERT(wantedReg); ASSERT(!m_lockedRegisters.get(wantedReg)); if (CachedRecovery* current = m_registers[wantedReg]) { if (current == &cachedRecovery) { if (verbose) dataLog(" + ", wantedReg, " is OK\n"); return; } // We could do a more complex thing by finding cycles // etc. in that case. // However, ending up in this situation will be super // rare, and should actually be outright impossible for // non-FTL tiers, since: // (a) All doubles have been converted into JSValues with // ValueRep nodes, so FPRs are initially free // // (b) The only recoveries with wanted registers are the // callee (which always starts out in a register) and // the callee-save registers // // (c) The callee-save registers are the first things we // load (after the return PC), and they are loaded as JSValues // // (d) We prefer loading JSValues into FPRs if their // wanted GPR is not available // // (e) If we end up spilling some registers with a // target, we won't load them again before the very // end of the algorithm // // Combined, this means that we will never load a recovery // with a wanted GPR into any GPR other than its wanted // GPR. The callee could however have been initially in // one of the callee-save registers - but since the wanted // GPR for the callee is always regT0, it will be the // first one to be displaced, and we won't see it when // handling any of the callee-save registers. // // Thus, the only way we could ever reach this path is in // the FTL, when there is so much pressure that we // absolutely need to load the callee-save registers into // different GPRs initially but not enough pressure to // then have to spill all of them. And even in that case, // depending on the order in which B3 saves the // callee-saves, we will probably still be safe. Anyway, // the couple extra move instructions compared to an // efficient cycle-based algorithm are not going to hurt // us. if (wantedReg.isFPR()) { FPRReg tempFPR = getFreeFPR(); if (verbose) dataLog(" * Moving ", wantedReg, " into ", tempFPR, "\n"); m_jit.moveDouble(wantedReg.fpr(), tempFPR); updateRecovery(*current, ValueRecovery::inFPR(tempFPR, current->recovery().dataFormat())); } else { GPRReg tempGPR = getFreeGPR(); if (verbose) dataLog(" * Moving ", wantedReg.gpr(), " into ", tempGPR, "\n"); m_jit.move(wantedReg.gpr(), tempGPR); updateRecovery(*current, ValueRecovery::inGPR(tempGPR, current->recovery().dataFormat())); } } ASSERT(!m_registers[wantedReg]); if (cachedRecovery.recovery().isConstant()) { // We only care about callee saves for wanted FPRs, and those are never constants ASSERT(wantedReg.isGPR()); if (verbose) dataLog(" * Loading ", cachedRecovery.recovery().constant(), " into ", wantedReg, "\n"); m_jit.moveTrustedValue(cachedRecovery.recovery().constant(), JSValueRegs { wantedReg.gpr() }); updateRecovery( cachedRecovery, ValueRecovery::inRegister(wantedReg, DataFormatJS)); } else if (cachedRecovery.recovery().isInGPR()) { if (verbose) dataLog(" * Moving ", cachedRecovery.recovery(), " into ", wantedReg, "\n"); if (wantedReg.isGPR()) m_jit.move(cachedRecovery.recovery().gpr(), wantedReg.gpr()); else m_jit.move64ToDouble(cachedRecovery.recovery().gpr(), wantedReg.fpr()); RELEASE_ASSERT(cachedRecovery.recovery().dataFormat() == DataFormatJS); updateRecovery(cachedRecovery, ValueRecovery::inRegister(wantedReg, DataFormatJS)); } else { ASSERT(cachedRecovery.recovery().isInFPR()); if (cachedRecovery.recovery().dataFormat() == DataFormatDouble) { // We only care about callee saves for wanted FPRs, and those are always DataFormatJS ASSERT(wantedReg.isGPR()); // This will automatically pick the wanted GPR emitBox(cachedRecovery); } else { if (verbose) dataLog(" * Moving ", cachedRecovery.recovery().fpr(), " into ", wantedReg, "\n"); if (wantedReg.isGPR()) m_jit.moveDoubleTo64(cachedRecovery.recovery().fpr(), wantedReg.gpr()); else m_jit.moveDouble(cachedRecovery.recovery().fpr(), wantedReg.fpr()); RELEASE_ASSERT(cachedRecovery.recovery().dataFormat() == DataFormatJS); updateRecovery(cachedRecovery, ValueRecovery::inRegister(wantedReg, DataFormatJS)); } } ASSERT(m_registers[wantedReg] == &cachedRecovery); }