Commit 1f4ba149 authored by Jean-Philip Desjardins's avatar Jean-Philip Desjardins
Browse files

Block link WIP.

parent 890708fc
......@@ -87,6 +87,7 @@ void CBasicBlock::Compile()
}
}
jitter->GetCodeGen()->SetExternalSymbolReferencedHandler([&](auto symbol, auto offset) { HandleExternalFunctionReference(symbol, offset); });
jitter->SetStream(&stream);
jitter->Begin();
CompileRange(jitter);
......@@ -192,6 +193,23 @@ void CBasicBlock::CompileRange(CMipsJitter* jitter)
void CBasicBlock::CompileProlog(CMipsJitter* jitter)
{
//Update cycle quota
jitter->PushRel(offsetof(CMIPS, m_State.cycleQuota));
jitter->PushCst(((m_end - m_begin) / 4) + 1);
jitter->Sub();
jitter->PullRel(offsetof(CMIPS, m_State.cycleQuota));
jitter->PushRel(offsetof(CMIPS, m_State.cycleQuota));
jitter->PushCst(0);
jitter->BeginIf(Jitter::CONDITION_LE);
{
jitter->PushRel(offsetof(CMIPS, m_State.nHasException));
jitter->PushCst(MIPS_EXECUTION_STATUS_QUOTADONE);
jitter->Or();
jitter->PullRel(offsetof(CMIPS, m_State.nHasException));
}
jitter->EndIf();
//We probably don't need to pay for this since we know in advance if there's a branch
jitter->PushCst(MIPS_INVALID_PC);
jitter->PushRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
......@@ -202,19 +220,29 @@ void CBasicBlock::CompileProlog(CMipsJitter* jitter)
jitter->PushCst(MIPS_INVALID_PC);
jitter->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
jitter->PushRel(offsetof(CMIPS, m_State.nHasException));
jitter->PushCst(0);
jitter->BeginIf(Jitter::CONDITION_EQ);
{
jitter->JumpTo(&NextBlockTrampoline);
}
jitter->EndIf();
}
jitter->Else();
{
jitter->PushCst(m_end + 4);
jitter->PullRel(offsetof(CMIPS, m_State.nPC));
jitter->PushRel(offsetof(CMIPS, m_State.nHasException));
jitter->PushCst(0);
jitter->BeginIf(Jitter::CONDITION_EQ);
{
jitter->JumpTo(&NextBlockTrampoline);
}
jitter->EndIf();
}
jitter->EndIf();
//Update cycle quota
jitter->PushRel(offsetof(CMIPS, m_State.cycleQuota));
jitter->PushCst(((m_end - m_begin) / 4) + 1);
jitter->Sub();
jitter->PullRel(offsetof(CMIPS, m_State.cycleQuota));
}
void CBasicBlock::Execute()
......@@ -259,7 +287,47 @@ bool CBasicBlock::IsEmpty() const
(m_end == MIPS_INVALID_PC);
}
void CBasicBlock::LinkNextBlock(CBasicBlock* otherBlock)
{
assert(!IsEmpty());
assert(!otherBlock->IsEmpty());
assert(m_nextBlockTrampolineOffset != -1);
auto patchValue = reinterpret_cast<uintptr_t>(otherBlock->m_function.GetCode());
auto code = reinterpret_cast<uint8*>(m_function.GetCode());
*reinterpret_cast<uintptr_t*>(code + m_nextBlockTrampolineOffset) = patchValue;
}
void CBasicBlock::LinkBranchBlock(CBasicBlock* otherBlock)
{
assert(!IsEmpty());
assert(!otherBlock->IsEmpty());
assert(m_branchBlockTrampolineOffset != -1);
auto patchValue = reinterpret_cast<uintptr_t>(otherBlock->m_function.GetCode());
auto code = reinterpret_cast<uint8*>(m_function.GetCode());
*reinterpret_cast<uintptr_t*>(code + m_branchBlockTrampolineOffset) = patchValue;
}
void CBasicBlock::HandleExternalFunctionReference(uintptr_t symbol, uint32 offset)
{
if(symbol == reinterpret_cast<uintptr_t>(&NextBlockTrampoline))
{
if(m_branchBlockTrampolineOffset == -1)
{
m_branchBlockTrampolineOffset = offset;
}
else
{
m_nextBlockTrampolineOffset = offset;
}
}
}
void CBasicBlock::EmptyBlockHandler(CMIPS* context)
{
context->m_emptyBlockHandler(context);
}
void CBasicBlock::NextBlockTrampoline(CMIPS* context)
{
}
......@@ -53,6 +53,9 @@ public:
bool IsCompiled() const;
bool IsEmpty() const;
void LinkNextBlock(CBasicBlock*);
void LinkBranchBlock(CBasicBlock*);
#ifdef AOT_BUILD_CACHE
static void SetAotBlockOutputStream(Framework::CStdStream*);
#endif
......@@ -66,7 +69,10 @@ protected:
void CompileProlog(CMipsJitter*);
private:
void HandleExternalFunctionReference(uintptr_t, uint32);
static void EmptyBlockHandler(CMIPS*);
static void NextBlockTrampoline(CMIPS*);
#ifdef AOT_BUILD_CACHE
static Framework::CStdStream* m_aotBlockOutputStream;
......@@ -78,4 +84,6 @@ private:
#else
void (*m_function)(void*);
#endif
uint32 m_nextBlockTrampolineOffset = -1;
uint32 m_branchBlockTrampolineOffset = -1;
};
......@@ -42,6 +42,8 @@ enum
MIPS_EXCEPTION_CALLMS,
};
#define MIPS_EXECUTION_STATUS_QUOTADONE 0x80
struct MIPSSTATE
{
uint32 nPC;
......
......@@ -199,7 +199,7 @@ public:
assert(TranslateFunction == m_context.m_pAddrTranslator);
auto block = m_emptyBlock.get();
m_context.m_State.cycleQuota = cycles;
while(m_context.m_State.cycleQuota > 0)
while(m_context.m_State.nHasException == 0)
{
uint32 address = TranslateFunction(&m_context, m_context.m_State.nPC);
if(address != block->GetBeginAddress())
......@@ -212,8 +212,8 @@ public:
m_breakpointsDisabledOnce = false;
#endif
block->Execute();
if(m_context.m_State.nHasException) break;
}
m_context.m_State.nHasException &= ~MIPS_EXECUTION_STATUS_QUOTADONE;
return m_context.m_State.cycleQuota;
}
......@@ -274,6 +274,7 @@ public:
protected:
typedef std::list<BasicBlockPtr> BlockList;
typedef std::multimap<uint32, uint32> BlockLinkMap;
bool HasBlockAt(uint32 address) const
{
......@@ -296,15 +297,72 @@ protected:
return result;
}
void SetupBlockLinks(uint32 startAddress, uint32 endAddress, uint32 branchAddress)
{
auto block = m_blockLookup.FindBlockAt(startAddress);
{
uint32 nextBlockAddress = endAddress + 4;
auto nextBlock = m_blockLookup.FindBlockAt(nextBlockAddress);
if(!nextBlock->IsEmpty())
{
block->LinkNextBlock(nextBlock);
}
else
{
m_pendingNextBlockLinks.insert(std::make_pair(nextBlockAddress, startAddress));
}
}
if(branchAddress != 0)
{
auto branchBlock = m_blockLookup.FindBlockAt(branchAddress);
if(!branchBlock->IsEmpty())
{
block->LinkBranchBlock(branchBlock);
}
else
{
m_pendingBranchBlockLinks.insert(std::make_pair(branchAddress, startAddress));
}
}
//Resolve any block links that could be valid now that block has been created
{
auto lowerBound = m_pendingNextBlockLinks.lower_bound(startAddress);
auto upperBound = m_pendingNextBlockLinks.upper_bound(startAddress);
for(auto blockLinkIterator = lowerBound; blockLinkIterator != upperBound; blockLinkIterator++)
{
auto referringBlock = m_blockLookup.FindBlockAt(blockLinkIterator->second);
if(referringBlock->IsEmpty()) continue;
referringBlock->LinkNextBlock(block);
}
m_pendingNextBlockLinks.erase(lowerBound, upperBound);
}
{
auto lowerBound = m_pendingBranchBlockLinks.lower_bound(startAddress);
auto upperBound = m_pendingBranchBlockLinks.upper_bound(startAddress);
for(auto blockLinkIterator = lowerBound; blockLinkIterator != upperBound; blockLinkIterator++)
{
auto referringBlock = m_blockLookup.FindBlockAt(blockLinkIterator->second);
if(referringBlock->IsEmpty()) continue;
referringBlock->LinkBranchBlock(block);
}
m_pendingBranchBlockLinks.erase(lowerBound, upperBound);
}
}
virtual void PartitionFunction(uint32 startAddress)
{
uint32 endAddress = startAddress + MAX_BLOCK_SIZE;
uint32 branchAddress = 0;
for(uint32 address = startAddress; address < endAddress; address += 4)
{
uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
auto branchType = m_context.m_pArch->IsInstructionBranch(&m_context, address, opcode);
if(branchType == MIPS_BRANCH_NORMAL)
{
branchAddress = m_context.m_pArch->GetInstructionEffectiveAddress(&m_context, address, opcode);
endAddress = address + 4;
break;
}
......@@ -316,6 +374,7 @@ protected:
}
assert((endAddress - startAddress) <= MAX_BLOCK_SIZE);
CreateBlock(startAddress, endAddress);
SetupBlockLinks(startAddress, endAddress, branchAddress);
}
void ClearActiveBlocksInRangeInternal(uint32 start, uint32 end, CBasicBlock* protectedBlock)
......@@ -344,6 +403,8 @@ protected:
BlockList m_blocks;
BasicBlockPtr m_emptyBlock;
BlockLinkMap m_pendingNextBlockLinks;
BlockLinkMap m_pendingBranchBlockLinks;
CMIPS& m_context;
uint32 m_maxAddress = 0;
......
......@@ -61,6 +61,7 @@ BasicBlockPtr CVuExecutor::BlockFactory(CMIPS& context, uint32 begin, uint32 end
void CVuExecutor::PartitionFunction(uint32 startAddress)
{
uint32 endAddress = startAddress + MAX_BLOCK_SIZE;
uint32 branchAddress = 0;
for(uint32 address = startAddress; address < endAddress; address += 8)
{
uint32 addrLo = address + 0;
......@@ -76,6 +77,7 @@ void CVuExecutor::PartitionFunction(uint32 startAddress)
}
else if(branchType == MIPS_BRANCH_NORMAL)
{
branchAddress = m_context.m_pArch->GetInstructionEffectiveAddress(&m_context, addrLo, lowerOp);
endAddress = address + 0xC;
break;
}
......@@ -87,4 +89,5 @@ void CVuExecutor::PartitionFunction(uint32 startAddress)
}
assert((endAddress - startAddress) <= MAX_BLOCK_SIZE);
CreateBlock(startAddress, endAddress);
SetupBlockLinks(startAddress, endAddress, branchAddress);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment