Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/CodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,8 @@ namespace
long offset = 0;
if( !evaluateIntegerExpression( i->immediate(), offset ) )
return false;
if( offset + delta < -1024 || offset + delta > 1023 )
return false;

std::stringstream s;
s << (offset + delta);
Expand Down
4 changes: 4 additions & 0 deletions src/CommandLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ CommandLine::CommandLine()
m_knownLoopOptimizations = false;
m_genericSoftwarePipelining = true;
m_strictScheduleSlots = false;
m_warningsAsErrors = false;

m_gasp = "gasp";
m_cpp = "cpp";
Expand Down Expand Up @@ -129,6 +130,7 @@ CommandLine::CommandLine()
m_options.push_back(Option('\0',"enable-generic-software-pipelining",ENABLE_GENERIC_SOFTWARE_PIPELINING,false));
m_options.push_back(Option('\0',"disable-generic-software-pipelining",DISABLE_GENERIC_SOFTWARE_PIPELINING,false));
m_options.push_back(Option('\0',"strict-schedule-slots",STRICT_SCHEDULE_SLOTS,false));
m_options.push_back(Option('\0',"warnings-as-errors",WARNINGS_AS_ERRORS,false));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -243,6 +245,7 @@ bool CommandLine::parse( int argc, char* argv[] )
case ENABLE_GENERIC_SOFTWARE_PIPELINING: m_genericSoftwarePipelining = true; break;
case DISABLE_GENERIC_SOFTWARE_PIPELINING: m_genericSoftwarePipelining = false; break;
case STRICT_SCHEDULE_SLOTS: m_strictScheduleSlots = true; break;
case WARNINGS_AS_ERRORS: m_warningsAsErrors = true; break;
case ANALYZE_VSM_COST_LOOP:
{
std::string::size_type separator = argument.find('=');
Expand Down Expand Up @@ -334,6 +337,7 @@ void CommandLine::showUsage( std::ostream& stream )
stream << " --enable-generic-software-pipelining Enable generic software-pipeline rewrites. (Default)" << std::endl;
stream << " --disable-generic-software-pipelining Disable generic software-pipeline rewrites." << std::endl;
stream << " --strict-schedule-slots Emit from scheduler-selected pairs without legacy lookahead fallbacks. (Default for generic codegen)" << std::endl;
stream << " --warnings-as-errors Fail (non-zero exit status) when any warning is reported." << std::endl;

stream << std::endl << " If no input or output file are specified, standard I/O will be used instead." << std::endl;

Expand Down
3 changes: 3 additions & 0 deletions src/CommandLine.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class CommandLine
bool knownLoopOptimizations() const;
bool genericSoftwarePipelining() const;
bool strictScheduleSlots() const;
bool warningsAsErrors() const;
const std::vector< std::pair<std::string, unsigned int> >& costLoops() const;
const std::string& costCompareBaseline() const;
const std::string& costCompareListCheckMetric() const;
Expand Down Expand Up @@ -134,6 +135,7 @@ class CommandLine
ENABLE_GENERIC_SOFTWARE_PIPELINING,
DISABLE_GENERIC_SOFTWARE_PIPELINING,
STRICT_SCHEDULE_SLOTS,
WARNINGS_AS_ERRORS,

IGNORE
};
Expand Down Expand Up @@ -187,6 +189,7 @@ class CommandLine
bool m_knownLoopOptimizations;
bool m_genericSoftwarePipelining;
bool m_strictScheduleSlots;
bool m_warningsAsErrors;
std::vector< std::pair<std::string, unsigned int> > m_costLoops;
std::string m_costCompareBaseline;
std::string m_costCompareListCheckMetric;
Expand Down
7 changes: 7 additions & 0 deletions src/CommandLine.inl
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ inline bool CommandLine::strictScheduleSlots() const

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

inline bool CommandLine::warningsAsErrors() const
{
return m_warningsAsErrors;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

inline const std::vector< std::pair<std::string, unsigned int> >& CommandLine::costLoops() const
{
return m_costLoops;
Expand Down
15 changes: 11 additions & 4 deletions src/Error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace vcl

std::list<Error> Error::ms_errors;
unsigned int Error::ms_errorCount = 0;
bool Error::ms_warningsAsErrors = false;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -158,10 +159,11 @@ std::string Error::toString() const
void Error::Display( const Error& e )
{
std::cerr << e.toString() << std::endl;
// Track non-warning errors so main() can fail the run with a non-zero
// exit code. Without this, openvcl prints diagnostics and still
// reports success, which lets broken VCL silently produce empty .vsm.
if( !e.m_warning )
// Track non-warning errors (and, with --warnings-as-errors, warnings) so
// main() can fail the run with a non-zero exit code. Without this,
// openvcl prints diagnostics and still reports success, which lets
// broken VCL silently produce empty .vsm.
if( !e.m_warning || ms_warningsAsErrors )
++ms_errorCount;
}

Expand All @@ -175,4 +177,9 @@ void Error::ResetErrorCount()
ms_errorCount = 0;
}

void Error::SetWarningsAsErrors( bool enable )
{
ms_warningsAsErrors = enable;
}

}
5 changes: 5 additions & 0 deletions src/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class Error
static bool HasErrors();
static void ResetErrorCount();

// Count warnings as errors from now on (--warnings-as-errors), so they
// fail the run too.
static void SetWarningsAsErrors( bool enable );

private:

enum
Expand All @@ -50,6 +54,7 @@ class Error

static std::list<Error> ms_errors;
static unsigned int ms_errorCount;
static bool ms_warningsAsErrors;
};

}
Expand Down
2 changes: 2 additions & 0 deletions src/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,8 @@ bool Parser::create( int argc, char* argv[] )
return false;
}

Error::SetWarningsAsErrors( m_cmdLine.warningsAsErrors() );

if( m_cmdLine.showVersion() )
setState( SHOW_VERSION );
else if( m_cmdLine.showUsage() )
Expand Down
64 changes: 64 additions & 0 deletions src/Tokenizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "Tokenizer.h"
#include "Error.h"
#include "VuTokenResourceAccess.h"
#include "stlhelp.h"

#include <iostream>
Expand Down Expand Up @@ -371,6 +372,8 @@ bool Tokenizer::handleToken( Token& token )
return false;
}

checkImmediate( token );

// raw VSM mode

if( vsmMode() )
Expand Down Expand Up @@ -523,6 +526,67 @@ bool Tokenizer::handleToken( Token& token )

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Tokenizer::checkImmediate( Token& token )
{
// dvp-as keeps only the low bits of an immediate that doesn't fit its
// instruction's field, without a diagnostic. The token is kept either way,
// so a bad immediate doesn't cascade into errors about its destination.

double value;
long minimum, maximum;
const Token::Argument* immediate = findVuTokenImmediate( token, value, minimum, maximum );
if( !immediate || ((value >= minimum) && (value <= maximum)) )
return;

// an iaddi beyond its 5 bits becomes an isubiu or iaddiu (SCE VCL emits
// every iaddi that way)

if( VU_OP_IADDI == vuInstructionOpcodeForMnemonic( token.operand()->name() ) )
{
minimum = -0x7fff;
maximum = 0x7fff;

if( (value >= minimum) && (value <= maximum) )
{
const char* name = (value < 0) ? "isubiu" : "iaddiu";
for( std::list<Operand>::const_iterator i = m_operands->begin(); i != m_operands->end(); ++i )
{
if( casecompare( (*i).name(), name ) )
continue;

std::stringstream s;
s << static_cast<long>( (value < 0) ? -value : value );
token.arguments().back().setImmediate( s.str() );
token.setOperand( &(*i) );
return;
}
}
}

std::stringstream message;
if( (value > -1e15) && (value < 1e15) )
message << static_cast<long long>( value );
else
message << value;
message << " is outside " << minimum << ".." << maximum;

// an offset only wraps: VU1 data memory is 1024 quadwords and addresses
// wrap, so on VU1 the encoded offset reaches the same address

if( (immediate->flags() & Token::Argument::INDIRECT) && (value > -0x80000000LL) && (value < 0x80000000LL) )
{
const long long range = maximum - minimum + 1;
const long long wrapped = (((static_cast<long long>( value ) - minimum) % range + range) % range) + minimum;
message << " and assembles as " << wrapped;
Error::Display( Error( "Offset " + message.str(), token, *immediate, true ) );
return;
}

Error::Display( Error( "Immediate " + message.str(), token, *immediate ) );
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

const Operand* Tokenizer::identifyToken( Token& token )
{
assert( m_operands );
Expand Down
1 change: 1 addition & 0 deletions src/Tokenizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class Tokenizer

const Operand* identifyToken( Token& token );
bool handleToken( Token& token );
void checkImmediate( Token& token );

void setAvailableFloats( unsigned int floats );
void setAvailableIntegers( unsigned int ints );
Expand Down
49 changes: 49 additions & 0 deletions src/VuInstructionInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,4 +626,53 @@ const char* vuInstructionDescription( const VuInstructionInfo& info )
return "VU instruction.";
}

bool vuInstructionImmediateRange( VuInstructionOpcode opcode, long& minimum, long& maximum )
{
switch( opcode )
{
// 5 bits, signed
case VU_OP_IADDI:
minimum = -16;
maximum = 15;
return true;

// 15 bits, unsigned
case VU_OP_IADDIU:
case VU_OP_ISUBIU:
minimum = 0;
maximum = 0x7fff;
return true;

// 11 bits, signed
case VU_OP_LQ:
case VU_OP_SQ:
case VU_OP_ILW:
case VU_OP_ISW:
minimum = -1024;
maximum = 1023;
return true;

// 24 bits
case VU_OP_FCAND:
case VU_OP_FCEQ:
case VU_OP_FCOR:
case VU_OP_FCSET:
minimum = 0;
maximum = 0xffffff;
return true;

// 12 bits
case VU_OP_FSAND:
case VU_OP_FSEQ:
case VU_OP_FSOR:
case VU_OP_FSSET:
minimum = 0;
maximum = 0xfff;
return true;

default:
return false;
}
}

}
6 changes: 6 additions & 0 deletions src/VuInstructionInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ std::string normalizeVuMnemonic( const std::string& word );
std::string vuInstructionParameterSummary( const VuInstructionInfo& info );
const char* vuInstructionDescription( const VuInstructionInfo& info );

// The values an instruction's integer immediate field (the offset, for
// LQ/SQ/ILW/ISW) can encode. dvp-as keeps only the low bits of a value
// outside it, without a diagnostic. Returns false for an instruction
// without such a field.
bool vuInstructionImmediateRange( VuInstructionOpcode opcode, long& minimum, long& maximum );

}

#endif
55 changes: 51 additions & 4 deletions src/VuSchedulerAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2398,7 +2398,10 @@ namespace
access.hasMemoryBase
? findInductionUpdate( opportunity.inductionUpdates, access.memoryBaseRegister )
: NULL;
if( update && update->stepKnown && access.hasMemoryOffset )
// an offset the load can't encode is as good as unknown
if( update && update->stepKnown && access.hasMemoryOffset
&& access.memoryOffset + update->step >= -1024
&& access.memoryOffset + update->step <= 1023 )
{
prefetch.hasNextIterationOffset = true;
prefetch.nextIterationOffset = access.memoryOffset + update->step;
Expand Down Expand Up @@ -2464,8 +2467,14 @@ namespace
tokenIndex,
stepAfterStore ) )
{
suffixStore.hasNextIterationOffset = true;
suffixStore.nextIterationOffset = access.memoryOffset - stepAfterStore;
// an offset the store can't encode is as good as unknown, which
// blocks the drain (store_without_next_offset)
const long nextIterationOffset = access.memoryOffset - stepAfterStore;
if( nextIterationOffset >= -1024 && nextIterationOffset <= 1023 )
{
suffixStore.hasNextIterationOffset = true;
suffixStore.nextIterationOffset = nextIterationOffset;
}
suffixStore.drainCandidate = suffixStore.usesInductionRegister;
}

Expand Down Expand Up @@ -3396,6 +3405,37 @@ namespace
}
}

// True when a cyclic-prefix load or store, its offset shifted as above,
// would no longer fit the instruction's 11-bit offset. The insertion point
// is not settled yet when a candidate is checked, so every known update of
// the base register counts.
bool cyclicPrefixOffsetsLeaveImmediateRange( const VuLoopPipelineOpportunity& candidate,
const std::vector<const Token*>& indexedTokens )
{
for( std::vector<unsigned int>::const_iterator p = candidate.multiQCyclicPrefixTokenIndices.begin();
p != candidate.multiQCyclicPrefixTokenIndices.end(); ++p )
{
VuTokenResourceAccess access;
if( *p >= indexedTokens.size()
|| !buildVuTokenResourceAccess( *indexedTokens[*p], access )
|| access.memoryKind == VU_MEMORY_NONE
|| !access.hasMemoryBase
|| !access.hasMemoryOffset )
continue;

for( std::vector<VuLoopInductionUpdate>::const_iterator i = candidate.inductionUpdates.begin();
i != candidate.inductionUpdates.end(); ++i )
{
if( !i->stepKnown || i->registerName != access.memoryBaseRegister )
continue;
const long adjustedOffset = access.memoryOffset + i->step;
if( adjustedOffset < -1024 || adjustedOffset > 1023 )
return true;
}
}
return false;
}

Token adjustedMultiQCyclicPrefixToken( const Token& token,
const std::vector<VuSoftwarePipelineRotation>& rotations,
const std::vector<VuLoopInductionUpdate>& inductionUpdates,
Expand Down Expand Up @@ -3550,6 +3590,8 @@ namespace
indexedTokens,
allowGuardedPlainStores ) )
return false;
if( cyclicPrefixOffsetsLeaveImmediateRange( candidate, indexedTokens ) )
return false;
if( tokenIndicesContainVisibleLabel( candidate.multiQCyclicPrefixTokenIndices,
indexedTokens,
candidate.labelTokenIndex )
Expand Down Expand Up @@ -10368,7 +10410,12 @@ bool advanceVuStoreBaseUpdates( std::list<Token>& tokens )
long offset = 0;
if( storeUsesBaseWithKnownOffset( *i, induction.registerName, offset ) )
{
(void)offset;
const long adjustedOffset = offset - induction.step;
if( adjustedOffset < -1024 || adjustedOffset > 1023 )
{
canMove = false;
break;
}
continue;
}
if( tokenReadsOrWritesRegisterKey( *i, induction.registerName ) )
Expand Down
Loading
Loading