diff --git a/server/TracySourceView.cpp b/server/TracySourceView.cpp index 90e788fb..e6d5e39c 100644 --- a/server/TracySourceView.cpp +++ b/server/TracySourceView.cpp @@ -1858,7 +1858,7 @@ void SourceView::RenderLine( const Line& line, int lineNum, uint32_t ipcnt, uint draw->AddLine( wpos + ImVec2( 0, ty+2 ), wpos + ImVec2( w, ty+2 ), 0x08FFFFFF ); } -void SourceView::RenderAsmLine( const AsmLine& line, uint32_t ipcnt, uint32_t iptotal, uint32_t ipmax, const Worker& worker, uint64_t& jumpOut, int maxAddrLen, const View& view ) +void SourceView::RenderAsmLine( AsmLine& line, uint32_t ipcnt, uint32_t iptotal, uint32_t ipmax, const Worker& worker, uint64_t& jumpOut, int maxAddrLen, const View& view ) { const auto ty = ImGui::GetFontSize(); auto draw = ImGui::GetWindowDrawList(); @@ -2274,10 +2274,40 @@ void SourceView::RenderAsmLine( const AsmLine& line, uint32_t ipcnt, uint32_t ip if( ImGui::IsMouseClicked( 0 ) ) { m_asmSelected = asmIdx; + ResetAsm(); + int idx = 0; + for(;;) + { + if( line.readX86[idx] == RegsX86::invalid ) break; + line.regData[idx] = ReadBit | (int)line.readX86[idx]; + FollowWrite( asmIdx, line.readX86[idx++], 128 ); + } + idx = 0; + for(;;) + { + if( line.writeX86[idx] == RegsX86::invalid ) break; + int ridx = 0; + for(;;) + { + if( line.regData[ridx] == 0 ) + { + line.regData[ridx] = WriteBit | (int)line.writeX86[idx]; + break; + } + else if( ( line.regData[ridx] & RegMask ) == (int)line.writeX86[idx] ) + { + line.regData[ridx] |= WriteBit; + break; + } + ridx++; + } + FollowRead( asmIdx, line.writeX86[idx++], 128 ); + } } else if( ImGui::IsMouseClicked( 1 ) ) { m_asmSelected = -1; + ResetAsm(); } } @@ -2776,4 +2806,164 @@ void SourceView::ResetAsm() for( auto& line : m_asm ) memset( line.regData, 0, sizeof( line.regData ) ); } +void SourceView::FollowRead( int line, RegsX86 reg, int limit ) +{ + if( limit == 0 ) return; + const auto& data = m_asm[line]; + if( m_jumpOut.find( data.addr ) != m_jumpOut.end() && !data.jumpConditional ) return; + if( data.jumpAddr != 0 ) + { + auto fit = std::lower_bound( m_asm.begin(), m_asm.end(), data.jumpAddr, []( const auto& l, const auto& r ) { return l.addr < r; } ); + if( fit != m_asm.end() && fit->addr == data.jumpAddr ) + { + CheckRead( fit - m_asm.begin(), reg, limit ); + } + if( !data.jumpConditional ) return; + } + if( line+1 < m_asm.size() ) + { + CheckRead( line+1, reg, limit ); + } +} + +void SourceView::FollowWrite( int line, RegsX86 reg, int limit ) +{ + if( limit == 0 ) return; + const auto& data = m_asm[line]; + if( m_jumpOut.find( data.addr ) != m_jumpOut.end() && !data.jumpConditional ) return; + auto it = m_jumpTable.find( data.addr ); + if( it != m_jumpTable.end() ) + { + for( auto& v : it->second.source ) + { + auto fit = std::lower_bound( m_asm.begin(), m_asm.end(), v, []( const auto& l, const auto& r ) { return l.addr < r; } ); + assert( fit != m_asm.end() && fit->addr == v ); + CheckWrite( fit - m_asm.begin(), reg, limit ); + } + } + if( line-1 >= 0 ) + { + CheckWrite( line-1, reg, limit ); + } +} + +void SourceView::CheckRead( int line, RegsX86 reg, int limit ) +{ + auto& data = m_asm[line]; + int idx = 0; + for(;;) + { + if( data.readX86[idx] == RegsX86::invalid ) + { + idx = 0; + for(;;) + { + if( data.writeX86[idx] == RegsX86::invalid ) + { + FollowRead( line, reg, limit - 1 ); + return; + } + if( data.writeX86[idx] == reg ) + { + idx = 0; + for(;;) + { + if( data.regData[idx] == 0 ) + { + data.regData[idx] = ReuseBit | (int)reg; + return; + } + if( ( data.regData[idx] & RegMask ) == (int)reg ) + { + data.regData[idx] |= ReuseBit; + return; + } + idx++; + } + } + idx++; + } + } + if( data.readX86[idx] == reg ) + { + idx = 0; + for(;;) + { + if( data.regData[idx] == 0 ) + { + data.regData[idx] = ReadBit | (int)reg; + return; + } + if( ( data.regData[idx] & RegMask ) == (int)reg ) + { + data.regData[idx] |= ReadBit; + return; + } + idx++; + } + } + idx++; + } +} + +void SourceView::CheckWrite( int line, RegsX86 reg, int limit ) +{ + auto& data = m_asm[line]; + int idx = 0; + for(;;) + { + if( data.writeX86[idx] == RegsX86::invalid ) + { + idx = 0; + for(;;) + { + if( data.readX86[idx] == RegsX86::invalid ) + { + FollowWrite( line, reg, limit - 1 ); + return; + } + if( data.readX86[idx] == reg ) + { + idx = 0; + for(;;) + { + if( data.regData[idx] == 0 ) + { + data.regData[idx] = ReuseBit | (int)reg; + return; + } + if( ( data.regData[idx] & RegMask ) == (int)reg ) + { + data.regData[idx] |= ReuseBit; + return; + } + idx++; + } + } + idx++; + } + + } + if( data.writeX86[idx] == reg ) + { + idx = 0; + for(;;) + { + if( data.regData[idx] == 0 ) + { + data.regData[idx] = WriteBit | (int)reg; + return; + } + else if( ( data.regData[idx] & RegMask ) == (int)reg ) + { + data.regData[idx] |= WriteBit; + return; + } + idx++; + } + } + idx++; + } +} + } diff --git a/server/TracySourceView.hpp b/server/TracySourceView.hpp index 9d41870f..733dd956 100644 --- a/server/TracySourceView.hpp +++ b/server/TracySourceView.hpp @@ -145,7 +145,7 @@ private: uint64_t RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map ipcount, uint32_t ipmax, const Worker& worker, const View& view ); void RenderLine( const Line& line, int lineNum, uint32_t ipcnt, uint32_t iptotal, uint32_t ipmax, const Worker* worker ); - void RenderAsmLine( const AsmLine& line, uint32_t ipcnt, uint32_t iptotal, uint32_t ipmax, const Worker& worker, uint64_t& jumpOut, int maxAddrLen, const View& view ); + void RenderAsmLine( AsmLine& line, uint32_t ipcnt, uint32_t iptotal, uint32_t ipmax, const Worker& worker, uint64_t& jumpOut, int maxAddrLen, const View& view ); void SelectLine( uint32_t line, const Worker* worker, bool changeAsmLine = true, uint64_t targetAddr = 0 ); void SelectAsmLines( uint32_t file, uint32_t line, const Worker& worker, bool changeAsmLine = true, uint64_t targetAddr = 0 ); @@ -159,6 +159,10 @@ private: std::vector Tokenize( const char* begin, const char* end ); void ResetAsm(); + void FollowRead( int line, RegsX86 reg, int limit ); + void FollowWrite( int line, RegsX86 reg, int limit ); + void CheckRead( int line, RegsX86 reg, int limit ); + void CheckWrite( int line, RegsX86 reg, int limit ); struct TokenizerState {