Skip to content
Open
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
15 changes: 11 additions & 4 deletions src/Token.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@ bool Token::processOperand( const Operand* operand, bool newSyntax, Token::Argum
{
if( 1 != countFields( fields ) )
match = false;

if( hasModifier( WCOMP, modifiers ) && (W != fields) )
match = false;
}
else if( hasModifier( DEST, modifiers ) )
{
Expand Down Expand Up @@ -367,9 +370,12 @@ bool Token::processOperand( const Operand* operand, bool newSyntax, Token::Argum

(*i).setFields( fields );

// if flag hasn't been specified, fail
// if flag hasn't been specified, fail (a W component
// defaults to W instead)

if( hasModifier( FLAG, modifiers ) )
if( hasModifier( WCOMP, modifiers ) )
(*i).setFields( W );
else if( hasModifier( FLAG, modifiers ) )
match = false;

if( hasModifier( BROADCAST, modifiers ) && !activeBroadcast )
Expand Down Expand Up @@ -547,8 +553,9 @@ unsigned int Token::extractModifiers( const std::string& list )
else if( name == "bc" )
modifiers |= (1<<BROADCAST);
else if( name == "wcomp" )
// treat 'wcomp' like a single-component selector requirement
modifiers |= (1<<FLAG);
// a single-component selector that can only be W, and that
// defaults to W when the operand has no field (as SCE VCL does)
modifiers |= (1<<FLAG)|(1<<WCOMP);
else if( name == "noalias" )
modifiers |= (1<<NOALIAS);
else if( name == "write" )
Expand Down
3 changes: 2 additions & 1 deletion src/Token.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ class Token
EVALUATE,
ROTATE,
RAW,
RANGE // operand template accepts a register-range (e.g. vf01-vf04)
RANGE, // operand template accepts a register-range (e.g. vf01-vf04)
WCOMP // operand is a W component (CLIPw's second operand): [w] or no field
};

enum
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ set(OPENVCL_TEST_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/integration/test_cli.cpp
${CMAKE_CURRENT_SOURCE_DIR}/integration/test_init_vf_range.cpp
${CMAKE_CURRENT_SOURCE_DIR}/integration/test_clip_validation.cpp
${CMAKE_CURRENT_SOURCE_DIR}/integration/test_clip_implicit_w.cpp
${CMAKE_CURRENT_SOURCE_DIR}/integration/test_loi_hex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/integration/test_parser_families.cpp
${CMAKE_CURRENT_SOURCE_DIR}/integration/test_instruction_info_dump.cpp
Expand Down
69 changes: 69 additions & 0 deletions test/integration/test_clip_implicit_w.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Regression tests: CLIPw's second operand is always the W component.
//
// SCE VCL accepts `clipw.xyz a, b` and reads b's W, the only component the
// instruction can encode. openvcl required an explicit `b[w]`, so sources
// written for SCE VCL failed with "Invalid argument" (9 of the Tyra engine's
// 15 microprograms do this). The bare form must now compile to exactly the
// same instruction as `b[w]`, and a field other than W, which dvp-as would
// reject, is still an error.

#include "test_harness.h"
#include "openvcl_runner.h"

#include <string>
#include <vector>

namespace
{
std::string program(const std::string& clip)
{
return
"\t.init_vf_all\n"
"\t.init_vi_all\n"
"\t.syntax new\n"
"\t.name vsmClipImplicitW\n"
"\t--enter\n"
"\t--endenter\n"
"\tlq fA, 1(vi00)\n"
"\t" + clip + "\n"
"\tfcand vi01, 0x3f\n"
"\tisw.x vi01, 2(vi00)\n"
"\t--exit\n"
"\t--endexit\n";
}

::test::RunResult compile(const std::string& clip)
{
std::vector<std::string> args;
args.push_back("-o");
args.push_back("-");
return ::test::run_openvcl(args, program(clip));
}
}

TEST_CASE("openvcl: clipw without a field reads the W component")
{
::test::RunResult bare = compile("clipw.xyz fA, fA");
::test::RunResult explicitW = compile("clipw.xyz fA, fA[w]");

CHECK(bare.exit_code == 0);
CHECK(explicitW.exit_code == 0);
CHECK(bare.stdout_data.find("clipw.xyz VF01, VF01w") != std::string::npos);
CHECK(bare.stdout_data == explicitW.stdout_data);
}

TEST_CASE("openvcl: clipw without a dest field or a source field is .xyz and W")
{
::test::RunResult bare = compile("clipw fA, fA");

CHECK(bare.exit_code == 0);
CHECK(bare.stdout_data.find("clipw.xyz VF01, VF01w") != std::string::npos);
}

TEST_CASE("openvcl: clipw rejects a source field other than W")
{
::test::RunResult r = compile("clipw.xyz fA, fA[x]");

CHECK(r.exit_code != 0);
CHECK(r.stderr_data.find("Invalid argument") != std::string::npos);
}