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();
}
Пример #2
0
Input AIManager::getInput(unsigned int playerNum)
{
	updateRecovery(playerNum);

	return followPath(playerNum);
	//return followRandomPath(playerNum);		//Test function
}
Пример #3
0
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);
}