Getting ppc tests building again (big surprise: they are failing).

This commit is contained in:
Ben Vanik
2014-09-09 20:25:38 -07:00
parent 437ec45d66
commit a337ce33ed
63 changed files with 471 additions and 453 deletions

View File

@@ -24,4 +24,7 @@
'ppc_translator.cc',
'ppc_translator.h',
],
'includes': [
],
}

View File

@@ -0,0 +1,38 @@
BINUTILS=../../../third_party/binutils/bin/
PPC_AS=$(BINUTILS)/powerpc-none-elf-as
PPC_LD=$(BINUTILS)/powerpc-none-elf-ld
PPC_OBJDUMP=$(BINUTILS)/powerpc-none-elf-objdump
SRCS=$(wildcard *.s)
BINS=$(SRCS:.s=.bin)
DISASMS=$(SRCS:.s=.dis)
%.o: %.s
$(PPC_AS) \
-a64 \
-be \
-mregnames \
-mpower7 \
-maltivec \
-mvsx \
-mvmx128 \
-R \
-o $@ \
$<
%.dis: %.o
$(PPC_OBJDUMP) --adjust-vma=0x100000 -Mpower7 -Mvmx128 -D -EB $< > $@
%.bin: %.o
$(PPC_LD) \
-A powerpc:common64 \
-melf64ppc \
-EB \
-nostdlib \
--oformat binary \
-Ttext 0x100000 \
-e 0x100000 \
-o $@ \
$<
all: $(BINS) $(DISASMS)

View File

@@ -0,0 +1,61 @@
# Codegen Tests
This directory contains the test assets used by the automated codegen test
runner.
Each test is structured as a source `[name].s` PPC assembly file and the
generated outputs. The outputs are made using the custom build of binutils
setup when `xenia-build setup` is called and are checked in to make it easier
to run the tests on Windows.
Tests are run using the `xenia-test` app or via `xenia-build test`.
## Execution
The test binary is placed into memory at `0x82010000` and all other memory is
zeroed.
All registers are reset to zero. In order to provide useful inputs tests can
specify `# REGISTER_IN` values.
The code is jumped into at the starting address and executed until the last
instruction in the input file is reached.
After all instructions complete any `# REGISTER_OUT` values are checked and if
they do not match the test is failed.
## Annotations
Annotations can appear at any line in a file. If a number is required it can
be in either hex or decimal form, or IEEE if floating-point.
### REGISTER_IN
```
# REGISTER_IN [register name] [register value]
```
Sets the value of a register prior to executing the instructions.
Examples:
```
# REGISTER_IN r4 0x1234
# REGISTER_IN r4 5678
```
### REGISTER_OUT
```
# REGISTER_OUT [register name] [register value]
```
Defines the expected register value when the instructions have executed.
If after all instructions have completed the register value does not match
the value given here the test will fail.
Examples:
```
# REGISTER_OUT r3 123
```
TODO: memory setup/assertions

View File

@@ -0,0 +1,340 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <alloy/alloy.h>
#include <alloy/backend/ivm/ivm_backend.h>
#include <alloy/backend/x64/x64_backend.h>
#include <alloy/frontend/ppc/ppc_context.h>
#include <alloy/frontend/ppc/ppc_frontend.h>
#include <alloy/runtime/raw_module.h>
#include <poly/main.h>
#include <poly/poly.h>
#if !XE_LIKE_WIN32
#include <dirent.h>
#endif // !WIN32
#include <gflags/gflags.h>
DEFINE_string(test_path, "src/alloy/frontend/ppc/test/",
"Directory scanned for test files.");
namespace alloy {
namespace test {
using alloy::frontend::ppc::PPCContext;
using alloy::runtime::Runtime;
typedef std::vector<std::pair<std::string, std::string>> AnnotationList;
const uint32_t START_ADDRESS = 0x100000;
class ThreadState : public alloy::runtime::ThreadState {
public:
ThreadState(Runtime* runtime, uint32_t thread_id, uint64_t stack_address,
size_t stack_size, uint64_t thread_state_address)
: alloy::runtime::ThreadState(runtime, thread_id),
stack_address_(stack_address),
stack_size_(stack_size),
thread_state_address_(thread_state_address) {
memset(memory_->Translate(stack_address_), 0, stack_size_);
// Allocate with 64b alignment.
context_ = (PPCContext*)calloc(1, sizeof(PPCContext));
assert_true((reinterpret_cast<uint64_t>(context_) & 0xF) == 0);
// Stash pointers to common structures that callbacks may need.
context_->reserve_address = memory_->reserve_address();
context_->membase = memory_->membase();
context_->runtime = runtime;
context_->thread_state = this;
// Set initial registers.
context_->r[1] = stack_address_ + stack_size;
context_->r[13] = thread_state_address_;
// Pad out stack a bit, as some games seem to overwrite the caller by about
// 16 to 32b.
context_->r[1] -= 64;
raw_context_ = context_;
runtime_->debugger()->OnThreadCreated(this);
}
~ThreadState() override {
runtime_->debugger()->OnThreadDestroyed(this);
free(context_);
}
PPCContext* context() const { return context_; }
private:
uint64_t stack_address_;
size_t stack_size_;
uint64_t thread_state_address_;
// NOTE: must be 64b aligned for SSE ops.
PPCContext* context_;
};
bool ReadAnnotations(std::wstring& src_file_path, AnnotationList& annotations) {
// TODO(benvanik): use PAL instead of this
FILE* f = fopen(poly::to_string(src_file_path).c_str(), "r");
char line_buffer[BUFSIZ];
while (fgets(line_buffer, sizeof(line_buffer), f)) {
if (strlen(line_buffer) > 3 && line_buffer[0] == '#' &&
line_buffer[1] == ' ') {
// Comment - check if formed like an annotation.
// We don't actually verify anything here.
char* next_space = strchr(line_buffer + 3, ' ');
if (next_space) {
// Looks legit.
std::string key(line_buffer + 2, next_space);
std::string value(next_space + 1);
while (value.find_last_of(" \t\n") == value.size() - 1) {
value.erase(value.end() - 1);
}
annotations.emplace_back(key, value);
}
}
}
fclose(f);
return true;
}
class TestRunner {
public:
TestRunner() {
memory_size = 64 * 1024 * 1024;
memory.reset(new SimpleMemory(memory_size));
runtime.reset(new Runtime(memory.get()));
auto frontend =
std::make_unique<alloy::frontend::ppc::PPCFrontend>(runtime.get());
runtime->Initialize(std::move(frontend), nullptr);
}
~TestRunner() {
thread_state.reset();
runtime.reset();
memory.reset();
}
bool Setup(std::wstring& src_file_path) {
// test.s -> test.bin
std::wstring bin_file_path;
size_t dot = src_file_path.find_last_of(L".s");
bin_file_path = src_file_path;
bin_file_path.replace(dot - 1, 2, L".bin");
// Read annotations so we can setup state/etc.
if (!ReadAnnotations(src_file_path, annotations)) {
PLOGE("Unable to read annotations for test %ls", src_file_path.c_str());
return false;
}
// Load the binary module.
auto module = std::make_unique<alloy::runtime::RawModule>(runtime.get());
if (module->LoadFile(START_ADDRESS, bin_file_path)) {
PLOGE("Unable to load test binary %ls", bin_file_path.c_str());
return false;
}
runtime->AddModule(std::move(module));
// Simulate a thread.
uint64_t stack_size = 64 * 1024;
uint64_t stack_address = START_ADDRESS - stack_size;
uint64_t thread_state_address = stack_address - 0x1000;
thread_state.reset(new ThreadState(runtime.get(), 0x100, stack_address,
stack_size, thread_state_address));
return true;
}
bool Run() {
// Setup test state from annotations.
if (!SetupTestState()) {
PLOGE("Test setup failed");
return false;
}
// Execute test.
alloy::runtime::Function* fn;
runtime->ResolveFunction(START_ADDRESS, &fn);
if (!fn) {
PLOGE("Entry function not found");
return false;
}
auto ctx = thread_state->context();
ctx->lr = 0xBEBEBEBE;
fn->Call(thread_state.get(), ctx->lr);
// Assert test state expectations.
bool result = CheckTestResults();
return result;
}
bool SetupTestState() {
auto ppc_state = thread_state->context();
for (AnnotationList::iterator it = annotations.begin();
it != annotations.end(); ++it) {
if (it->first == "REGISTER_IN") {
size_t space_pos = it->second.find(" ");
auto reg_name = it->second.substr(0, space_pos);
auto reg_value = it->second.substr(space_pos + 1);
ppc_state->SetRegFromString(reg_name.c_str(), reg_value.c_str());
}
}
return true;
}
bool CheckTestResults() {
auto ppc_state = thread_state->context();
char actual_value[2048];
bool any_failed = false;
for (AnnotationList::iterator it = annotations.begin();
it != annotations.end(); ++it) {
if (it->first == "REGISTER_OUT") {
size_t space_pos = it->second.find(" ");
auto reg_name = it->second.substr(0, space_pos);
auto reg_value = it->second.substr(space_pos + 1);
if (!ppc_state->CompareRegWithString(reg_name.c_str(),
reg_value.c_str(), actual_value,
poly::countof(actual_value))) {
any_failed = true;
printf("Register %s assert failed:\n", reg_name.c_str());
printf(" Expected: %s == %s\n", reg_name.c_str(), reg_value.c_str());
printf(" Actual: %s == %s\n", reg_name.c_str(), actual_value);
}
}
}
return !any_failed;
}
size_t memory_size;
std::unique_ptr<Memory> memory;
std::unique_ptr<Runtime> runtime;
std::unique_ptr<ThreadState> thread_state;
AnnotationList annotations;
};
bool DiscoverTests(std::wstring& test_path,
std::vector<std::wstring>& test_files) {
// TODO(benvanik): use PAL instead of this.
#if XE_LIKE_WIN32
std::wstring search_path = test_path;
search_path.append(L"\\*.s");
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile(search_path.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
PLOGE("Unable to find test path %s", test_path.c_str());
return false;
}
do {
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
std::wstring file_name(ffd.cFileName);
std::wstring file_path = test_path;
if (*(test_path.end() - 1) != '\\') {
file_path += '\\';
}
file_path += file_name;
test_files.push_back(file_path);
}
} while (FindNextFile(hFind, &ffd));
FindClose(hFind);
#else
DIR* d = opendir(test_path.c_str());
if (!d) {
PLOGE("Unable to find test path %s", test_path.c_str());
return false;
}
struct dirent* dir;
while ((dir = readdir(d))) {
if (dir->d_type == DT_REG) {
// Only return .s files.
string file_name = string(dir->d_name);
if (file_name.rfind(".s") != string::npos) {
string file_path = test_path;
if (*(test_path.end() - 1) != '/') {
file_path += "/";
}
file_path += file_name;
test_files.push_back(file_path);
}
}
}
closedir(d);
#endif // WIN32
return true;
}
bool RunTests(const std::wstring& test_name) {
int result_code = 1;
int failed_count = 0;
int passed_count = 0;
auto test_path = poly::fix_path_separators(poly::to_wstring(FLAGS_test_path));
std::vector<std::wstring> test_files;
if (!DiscoverTests(test_path, test_files)) {
return false;
}
if (!test_files.size()) {
PLOGE("No tests discovered - invalid path?");
return false;
}
PLOGI("%d tests discovered.", (int)test_files.size());
PLOGI("");
for (auto& test_path : test_files) {
if (!test_name.empty() && test_path != test_name) {
continue;
}
PLOGI("Running %ls...", test_path.c_str());
TestRunner runner;
if (!runner.Setup(test_path)) {
PLOGE("TEST FAILED SETUP");
++failed_count;
}
if (runner.Run()) {
PLOGI("Passed");
++passed_count;
} else {
PLOGE("TEST FAILED");
++failed_count;
}
}
PLOGI("");
PLOGI("Total tests: %d", failed_count + passed_count);
PLOGI("Passed: %d", passed_count);
PLOGI("Failed: %d", failed_count);
return failed_count ? false : true;
}
int main(std::vector<std::wstring>& args) {
// Grab test name, if present.
std::wstring test_name;
if (args.size() >= 2) {
test_name = args[1];
}
return RunTests(test_name) ? 0 : 1;
}
} // namespace test
} // namespace alloy
DEFINE_ENTRY_POINT(L"alloy-ppc-test", L"alloy-ppc-test [test name]",
alloy::test::main);

Binary file not shown.

View File

@@ -0,0 +1,9 @@
instr_add.o: file format elf64-powerpc
Disassembly of section .text:
0000000000100000 <.text>:
100000: 7d 65 ca 14 add r11,r5,r25
100004: 4e 80 00 20 blr

View File

@@ -0,0 +1,9 @@
# REGISTER_IN r5 0x00100000
# REGISTER_IN r25 0x0000FFFF
add r11, r5, r25
blr
# REGISTER_OUT r5 0x00100000
# REGISTER_OUT r25 0x0000FFFF
# REGISTER_OUT r11 0x0010FFFF

Binary file not shown.

View File

@@ -0,0 +1,9 @@
instr_extrwi.o: file format elf64-powerpc
Disassembly of section .text:
0000000000100000 <.text>:
100000: 54 a7 ef 3e rlwinm r7,r5,29,28,31
100004: 4e 80 00 20 blr

View File

@@ -0,0 +1,11 @@
# This is a variant of rlwinmx:
# extrwi ra,rs,n,b (n > 0) == rlwinm ra,rs,b+n,32-n,31
# REGISTER_IN r5 0x30
# rlwinm r7, r5, 29, 28, 31
extrwi r7, r5, 4, 25
blr
# REGISTER_OUT r5 0x30
# REGISTER_OUT r7 0x06

Binary file not shown.

View File

@@ -0,0 +1,9 @@
instr_ori.o: file format elf64-powerpc
Disassembly of section .text:
0000000000100000 <.text>:
100000: 60 83 fe dc ori r3,r4,65244
100004: 4e 80 00 20 blr

View File

@@ -0,0 +1,7 @@
# REGISTER_IN r4 0xDEADBEEF00000000
ori r3, r4, 0xFEDC
blr
# REGISTER_OUT r3 0xDEADBEEF0000FEDC
# REGISTER_OUT r4 0xDEADBEEF00000000

Binary file not shown.

View File

@@ -0,0 +1,9 @@
instr_rlwimi.o: file format elf64-powerpc
Disassembly of section .text:
0000000000100000 <.text>:
100000: 50 86 10 3a rlwimi r6,r4,2,0,29
100004: 4e 80 00 20 blr

View File

@@ -0,0 +1,8 @@
# REGISTER_IN r4 0xCAFEBABE90003000
# REGISTER_IN r6 0xDEADBEEF00000003
rlwimi r6, r4, 2, 0, 0x1D
blr
# REGISTER_OUT r4 0xCAFEBABE90003000
# REGISTER_OUT r6 0xDEADBEEF4000C003

Binary file not shown.

View File

@@ -0,0 +1,9 @@
instr_subfe.o: file format elf64-powerpc
Disassembly of section .text:
0000000000100000 <.text>:
100000: 7c 6a 59 10 subfe r3,r10,r11
100004: 4e 80 00 20 blr

View File

@@ -0,0 +1,9 @@
# REGISTER_IN r10 0x00000000000103BF
# REGISTER_IN r11 0x00000000000103C0
subfe r3, r10, r11
blr
# REGISTER_OUT r10 0x00000000000103BF
# REGISTER_OUT r11 0x00000000000103C0
# REGISTER_OUT r3 0x1

Binary file not shown.

View File

@@ -0,0 +1,10 @@
instr_x.o: file format elf64-powerpc
Disassembly of section .text:
0000000000100000 <.text>:
100000: 10 01 12 46 vcmpgtuh v0,v1,v2
100004: 10 03 20 83 lvewx128 v0,r3,r4
100008: 4e 80 00 20 blr

View File

@@ -0,0 +1,4 @@
vcmpgtuh v0, v1, v2
lvewx128 v0, r3, r4
blr

View File

@@ -0,0 +1,28 @@
# Copyright 2014 Ben Vanik. All Rights Reserved.
{
'targets': [
{
'target_name': 'alloy-ppc-test',
'type': 'executable',
'msvs_settings': {
'VCLinkerTool': {
'SubSystem': '1',
},
},
'dependencies': [
'alloy',
'xenia',
],
'include_dirs': [
'.',
],
'sources': [
'alloy-ppc-test.cc',
],
},
],
}

View File

@@ -0,0 +1,132 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <alloy/alloy.h>
#include <alloy/backend/ivm/ivm_backend.h>
#include <alloy/backend/x64/x64_backend.h>
#include <alloy/frontend/ppc/ppc_context.h>
#include <alloy/frontend/ppc/ppc_frontend.h>
#include <alloy/runtime/raw_module.h>
#include <poly/main.h>
#include <poly/poly.h>
#include <gflags/gflags.h>
namespace alloy {
namespace sandbox {
using alloy::frontend::ppc::PPCContext;
using alloy::runtime::Runtime;
class ThreadState : public alloy::runtime::ThreadState {
public:
ThreadState(Runtime* runtime, uint32_t thread_id, uint64_t stack_address,
size_t stack_size, uint64_t thread_state_address)
: alloy::runtime::ThreadState(runtime, thread_id),
stack_address_(stack_address),
stack_size_(stack_size),
thread_state_address_(thread_state_address) {
memset(memory_->Translate(stack_address_), 0, stack_size_);
// Allocate with 64b alignment.
context_ = (PPCContext*)calloc(1, sizeof(PPCContext));
assert_true((reinterpret_cast<uint64_t>(context_) & 0xF) == 0);
// Stash pointers to common structures that callbacks may need.
context_->reserve_address = memory_->reserve_address();
context_->membase = memory_->membase();
context_->runtime = runtime;
context_->thread_state = this;
// Set initial registers.
context_->r[1] = stack_address_ + stack_size;
context_->r[13] = thread_state_address_;
// Pad out stack a bit, as some games seem to overwrite the caller by about
// 16 to 32b.
context_->r[1] -= 64;
raw_context_ = context_;
runtime_->debugger()->OnThreadCreated(this);
}
~ThreadState() override {
runtime_->debugger()->OnThreadDestroyed(this);
free(context_);
}
PPCContext* context() const { return context_; }
private:
uint64_t stack_address_;
size_t stack_size_;
uint64_t thread_state_address_;
// NOTE: must be 64b aligned for SSE ops.
PPCContext* context_;
};
// TODO(benvanik): simple memory? move more into core?
int main(std::vector<std::wstring>& args) {
#if XE_OPTION_PROFILING
xe::Profiler::Initialize();
xe::Profiler::ThreadEnter("main");
#endif // XE_OPTION_PROFILING
size_t memory_size = 16 * 1024 * 1024;
auto memory = std::make_unique<SimpleMemory>(memory_size);
auto runtime = std::make_unique<Runtime>(memory.get());
auto frontend =
std::make_unique<alloy::frontend::ppc::PPCFrontend>(runtime.get());
std::unique_ptr<alloy::backend::Backend> backend;
// backend =
// std::make_unique<alloy::backend::ivm::IVMBackend>(runtime.get());
// backend =
// std::make_unique<alloy::backend::x64::X64Backend>(runtime.get());
runtime->Initialize(std::move(frontend), std::move(backend));
auto module = std::make_unique<alloy::runtime::RawModule>(runtime.get());
module->LoadFile(0x00001000, L"test\\codegen\\instr_add.bin");
runtime->AddModule(std::move(module));
{
uint64_t stack_size = 64 * 1024;
uint64_t stack_address = memory_size - stack_size;
uint64_t thread_state_address = stack_address - 0x1000;
auto thread_state = std::make_unique<ThreadState>(
runtime.get(), 100, stack_address, stack_size, thread_state_address);
alloy::runtime::Function* fn;
runtime->ResolveFunction(0x1000, &fn);
auto ctx = thread_state->context();
ctx->lr = 0xBEBEBEBE;
ctx->r[5] = 10;
ctx->r[25] = 25;
fn->Call(thread_state.get(), ctx->lr);
auto result = ctx->r[11];
printf("%llu", result);
}
runtime.reset();
memory.reset();
#if XE_OPTION_PROFILING
xe::Profiler::Dump();
xe::Profiler::ThreadExit();
#endif // XE_OPTION_PROFILING
return 0;
}
} // namespace sandbox
} // namespace alloy
DEFINE_ENTRY_POINT(L"alloy-sandbox", L"?", alloy::sandbox::main);

View File

@@ -0,0 +1,44 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#define CATCH_CONFIG_RUNNER
#include <third_party/catch/single_include/catch.hpp>
#include <tools/alloy-test/util.h>
namespace alloy {
namespace test {
using alloy::frontend::ppc::PPCContext;
using alloy::runtime::Runtime;
int main(std::vector<std::wstring>& args) {
std::vector<std::string> narrow_args;
auto narrow_argv = new char* [args.size()];
for (size_t i = 0; i < args.size(); ++i) {
auto narrow_arg = poly::to_string(args[i]);
narrow_argv[i] = const_cast<char*>(narrow_arg.data());
narrow_args.push_back(std::move(narrow_arg));
}
int ret = Catch::Session().run(int(args.size()), narrow_argv);
if (ret) {
#if XE_LIKE_WIN32
// Visual Studio kills the console on shutdown, so prevent that.
if (poly::debugging::IsDebuggerAttached()) {
poly::debugging::Break();
}
#endif // XE_LIKE_WIN32
}
return ret;
}
} // namespace test
} // namespace alloy
DEFINE_ENTRY_POINT(L"alloy-test", L"?", alloy::test::main);

118
src/alloy/test/test.gypi Normal file
View File

@@ -0,0 +1,118 @@
# Copyright 2014 Ben Vanik. All Rights Reserved.
{
'targets': [
{
'target_name': 'alloy-sandbox',
'type': 'executable',
'msvs_settings': {
'VCLinkerTool': {
'SubSystem': '1'
},
},
'dependencies': [
'alloy',
'xenia',
],
'include_dirs': [
'.',
],
'sources': [
'alloy-sandbox.cc',
],
},
],
'targets': [
{
'target_name': 'alloy-test',
'type': 'executable',
'msvs_settings': {
'VCLinkerTool': {
'SubSystem': '1'
},
},
'dependencies': [
'alloy',
'xenia',
],
'include_dirs': [
'.',
],
'sources': [
'alloy-test.cc',
#'test_abs.cc',
'test_add.cc',
#'test_add_carry.cc',
#'test_and.cc',
#'test_assign.cc',
#'test_atomic_add.cc',
#'test_atomic_exchange.cc',
#'test_atomic_sub.cc',
#'test_branch.cc',
#'test_byte_swap.cc',
#'test_cast.cc',
#'test_cntlz.cc',
#'test_compare.cc',
#'test_compare_exchange.cc',
#'test_convert.cc',
#'test_did_carry.cc',
#'test_div.cc',
#'test_dot_product_3.cc',
#'test_dot_product_4.cc',
'test_extract.cc',
'test_insert.cc',
#'test_is_true_false.cc',
#'test_load_clock.cc',
'test_load_vector_shl_shr.cc',
#'test_log2.cc',
#'test_max.cc',
#'test_min.cc',
#'test_mul.cc',
#'test_mul_add.cc',
#'test_mul_hi.cc',
#'test_mul_sub.cc',
#'test_neg.cc',
#'test_not.cc',
#'test_or.cc',
'test_pack.cc',
'test_permute.cc',
#'test_pow2.cc',
#'test_rotate_left.cc',
#'test_round.cc',
#'test_rsqrt.cc',
#'test_select.cc',
'test_sha.cc',
'test_shl.cc',
'test_shr.cc',
#'test_sign_extend.cc',
#'test_splat.cc',
#'test_sqrt.cc',
#'test_sub.cc',
'test_swizzle.cc',
#'test_truncate.cc',
'test_unpack.cc',
'test_vector_add.cc',
#'test_vector_compare.cc',
#'test_vector_convert.cc',
'test_vector_max.cc',
'test_vector_min.cc',
'test_vector_rotate_left.cc',
'test_vector_sha.cc',
'test_vector_shl.cc',
'test_vector_shr.cc',
#'test_vector_sub.cc',
#'test_xor.cc',
#'test_zero_extend.cc',
'util.h',
],
},
],
}

552
src/alloy/test/test_add.cc Normal file
View File

@@ -0,0 +1,552 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
#include <cfloat>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("ADD_I8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT8_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<int8_t>(ctx->r[3]);
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 10;
ctx->r[5] = 25;
},
[](PPCContext* ctx) {
auto result = static_cast<int8_t>(ctx->r[3]);
REQUIRE(result == 0x23);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = -10;
ctx->r[5] = -5;
},
[](PPCContext* ctx) {
auto result = static_cast<int8_t>(ctx->r[3]);
REQUIRE(result == -15);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT8_MIN;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<int8_t>(ctx->r[3]);
REQUIRE(result == INT8_MIN);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT8_MAX;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == UINT8_MAX);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT8_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = static_cast<int8_t>(ctx->r[3]);
REQUIRE(result == INT8_MAX);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT8_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<int8_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}
TEST_CASE("ADD_I8_CARRY", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT8_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE), ARITHMETIC_SET_CARRY);
StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT8_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT8_MAX;
ctx->r[5] = UINT8_MAX;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT8_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
}
TEST_CASE("ADD_I16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT16_TYPE),
b.Truncate(LoadGPR(b, 5), INT16_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<int16_t>(ctx->r[3]);
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 10;
ctx->r[5] = 25;
},
[](PPCContext* ctx) {
auto result = static_cast<int16_t>(ctx->r[3]);
REQUIRE(result == 0x23);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = -10;
ctx->r[5] = -5;
},
[](PPCContext* ctx) {
auto result = static_cast<int16_t>(ctx->r[3]);
REQUIRE(result == -15);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT16_MIN;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<int16_t>(ctx->r[3]);
REQUIRE(result == INT16_MIN);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT16_MAX;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == UINT16_MAX);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT16_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = static_cast<int16_t>(ctx->r[3]);
REQUIRE(result == INT16_MAX);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT16_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<int16_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}
TEST_CASE("ADD_I16_CARRY", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT16_TYPE),
b.Truncate(LoadGPR(b, 5), INT16_TYPE), ARITHMETIC_SET_CARRY);
StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT16_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT16_MAX;
ctx->r[5] = UINT16_MAX;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT16_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
}
TEST_CASE("ADD_I32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT32_TYPE),
b.Truncate(LoadGPR(b, 5), INT32_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<int32_t>(ctx->r[3]);
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 10;
ctx->r[5] = 25;
},
[](PPCContext* ctx) {
auto result = static_cast<int32_t>(ctx->r[3]);
REQUIRE(result == 0x23);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = -10;
ctx->r[5] = -5;
},
[](PPCContext* ctx) {
auto result = static_cast<int32_t>(ctx->r[3]);
REQUIRE(result == -15);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT32_MIN;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<int32_t>(ctx->r[3]);
REQUIRE(result == INT32_MIN);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT32_MAX;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == UINT32_MAX);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT32_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = static_cast<int32_t>(ctx->r[3]);
REQUIRE(result == INT32_MAX);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT32_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<int32_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}
TEST_CASE("ADD_I32_CARRY", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT32_TYPE),
b.Truncate(LoadGPR(b, 5), INT32_TYPE), ARITHMETIC_SET_CARRY);
StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT32_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT32_MAX;
ctx->r[5] = UINT32_MAX;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT32_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
}
TEST_CASE("ADD_I64", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.Add(LoadGPR(b, 4), LoadGPR(b, 5)));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 10;
ctx->r[5] = 25;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0x23);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = -10;
ctx->r[5] = -5;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == -15);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT64_MIN;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == INT64_MIN);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT64_MAX;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == UINT64_MAX);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT64_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == INT64_MAX);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT64_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0);
});
}
TEST_CASE("ADD_I64_CARRY", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
auto v = b.Add(b.Truncate(LoadGPR(b, 4), INT64_TYPE),
b.Truncate(LoadGPR(b, 5), INT64_TYPE), ARITHMETIC_SET_CARRY);
StoreGPR(b, 3, b.ZeroExtend(b.DidCarry(v), INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT64_MAX;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = UINT64_MAX;
ctx->r[5] = UINT64_MAX;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = INT64_MIN;
ctx->r[5] = -1;
},
[](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == 1);
});
}
TEST_CASE("ADD_F32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreFPR(b, 3, b.Convert(b.Add(b.Convert(LoadFPR(b, 4), FLOAT32_TYPE),
b.Convert(LoadFPR(b, 5), FLOAT32_TYPE)),
FLOAT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = 0.0;
ctx->f[5] = 0.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == 0.0);
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = 5.0;
ctx->f[5] = 7.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == 12.0);
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = FLT_MAX / 2.0;
ctx->f[5] = FLT_MAX / 2.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == FLT_MAX);
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = -100.0;
ctx->f[5] = -150.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == -250.0);
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = FLT_MIN;
ctx->f[5] = 0.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == FLT_MIN);
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = FLT_MAX;
ctx->f[5] = 0.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == FLT_MAX);
});
}
TEST_CASE("ADD_F64", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreFPR(b, 3, b.Add(LoadFPR(b, 4), LoadFPR(b, 5)));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = 0.0;
ctx->f[5] = 0.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == 0.0);
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = 5.0;
ctx->f[5] = 7.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == 12.0);
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = DBL_MAX / 2.0;
ctx->f[5] = DBL_MAX / 2.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == DBL_MAX);
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = -100.0;
ctx->f[5] = -150.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == -250.0);
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = DBL_MIN;
ctx->f[5] = 0.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == DBL_MIN);
});
test.Run([](PPCContext* ctx) {
ctx->f[4] = DBL_MAX;
ctx->f[5] = 0.0;
},
[](PPCContext* ctx) {
auto result = ctx->f[3];
REQUIRE(result == DBL_MAX);
});
}

View File

@@ -0,0 +1,141 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
#include <cfloat>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("EXTRACT_INT8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Extract(LoadVR(b, 4),
b.Truncate(LoadGPR(b, 4), INT8_TYPE),
INT8_TYPE),
INT64_TYPE));
b.Return();
});
for (int i = 0; i < 16; ++i) {
test.Run([i](PPCContext* ctx) {
ctx->r[4] = i;
ctx->v[4] = vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15);
},
[i](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == i);
});
}
}
TEST_CASE("EXTRACT_INT8_CONSTANT", "[instr]") {
for (int i = 0; i < 16; ++i) {
TestFunction([i](hir::HIRBuilder& b) {
StoreGPR(b, 3,
b.ZeroExtend(
b.Extract(LoadVR(b, 4),
b.LoadConstant(int8_t(i)), INT8_TYPE),
INT64_TYPE));
b.Return();
}).Run([i](PPCContext* ctx) {
ctx->r[4] = i;
ctx->v[4] = vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15);
},
[i](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == i);
});
}
}
TEST_CASE("EXTRACT_INT16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Extract(LoadVR(b, 4),
b.Truncate(LoadGPR(b, 4), INT8_TYPE),
INT16_TYPE),
INT64_TYPE));
b.Return();
});
for (int i = 0; i < 8; ++i) {
test.Run([i](PPCContext* ctx) {
ctx->r[4] = i;
ctx->v[4] = vec128s(0x0000, 0x1001, 0x2002, 0x3003, 0x4004,
0x5005, 0x6006, 0x7007);
},
[i](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == (i | (i << 12)));
});
}
}
TEST_CASE("EXTRACT_INT16_CONSTANT", "[instr]") {
for (int i = 0; i < 8; ++i) {
TestFunction([i](hir::HIRBuilder& b) {
StoreGPR(b, 3,
b.ZeroExtend(b.Extract(LoadVR(b, 4),
b.LoadConstant(int8_t(i)),
INT16_TYPE),
INT64_TYPE));
b.Return();
}).Run([i](PPCContext* ctx) {
ctx->r[4] = i;
ctx->v[4] = vec128s(0, 1, 2, 3, 4, 5, 6, 7);
},
[i](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == i);
});
}
}
TEST_CASE("EXTRACT_INT32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Extract(LoadVR(b, 4),
b.Truncate(LoadGPR(b, 4), INT8_TYPE),
INT32_TYPE),
INT64_TYPE));
b.Return();
});
for (int i = 0; i < 4; ++i) {
test.Run([i](PPCContext* ctx) {
ctx->r[4] = i;
ctx->v[4] = vec128i(0, 1, 2, 3);
},
[i](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == i);
});
}
}
TEST_CASE("EXTRACT_INT32_CONSTANT", "[instr]") {
for (int i = 0; i < 4; ++i) {
TestFunction([i](hir::HIRBuilder& b) {
StoreGPR(b, 3,
b.ZeroExtend(b.Extract(LoadVR(b, 4),
b.LoadConstant(int8_t(i)),
INT32_TYPE),
INT64_TYPE));
b.Return();
}).Run([i](PPCContext* ctx) {
ctx->r[4] = i;
ctx->v[4] = vec128i(0, 1, 2, 3);
},
[i](PPCContext* ctx) {
auto result = ctx->r[3];
REQUIRE(result == i);
});
}
}

View File

@@ -0,0 +1,83 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
#include <cfloat>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("INSERT_INT8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Insert(LoadVR(b, 4), LoadGPR(b, 4),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)));
b.Return();
});
for (int i = 0; i < 16; ++i) {
test.Run([i](PPCContext* ctx) {
ctx->v[4] = vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15);
ctx->r[4] = i;
ctx->r[5] = 100 + i;
},
[i](PPCContext* ctx) {
auto result = ctx->v[3];
auto expected = vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15);
expected.i8[i ^ 0x3] = 100 + i;
REQUIRE(result == expected);
});
}
}
TEST_CASE("INSERT_INT16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Insert(LoadVR(b, 4), LoadGPR(b, 4),
b.Truncate(LoadGPR(b, 5), INT16_TYPE)));
b.Return();
});
for (int i = 0; i < 8; ++i) {
test.Run([i](PPCContext* ctx) {
ctx->v[4] = vec128s(0, 1, 2, 3, 4, 5, 6, 7);
ctx->r[4] = i;
ctx->r[5] = 100 + i;
},
[i](PPCContext* ctx) {
auto result = ctx->v[3];
auto expected = vec128s(0, 1, 2, 3, 4, 5, 6, 7);
expected.i16[i ^ 0x1] = 100 + i;
REQUIRE(result == expected);
});
}
}
TEST_CASE("INSERT_INT32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Insert(LoadVR(b, 4), LoadGPR(b, 4),
b.Truncate(LoadGPR(b, 5), INT32_TYPE)));
b.Return();
});
for (int i = 0; i < 4; ++i) {
test.Run([i](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 1, 2, 3);
ctx->r[4] = i;
ctx->r[5] = 100 + i;
},
[i](PPCContext* ctx) {
auto result = ctx->v[3];
auto expected = vec128i(0, 1, 2, 3);
expected.i32[i] = 100 + i;
REQUIRE(result == expected);
});
}
}

View File

@@ -0,0 +1,78 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("LOAD_VECTOR_SHL", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.LoadVectorShl(b.Truncate(LoadGPR(b, 4), INT8_TYPE)));
b.Return();
});
test.Run([](PPCContext* ctx) { ctx->r[4] = 0; },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15));
});
test.Run([](PPCContext* ctx) { ctx->r[4] = 7; },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22));
});
test.Run([](PPCContext* ctx) { ctx->r[4] = 15; },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30));
});
test.Run([](PPCContext* ctx) { ctx->r[4] = 16; },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15));
});
}
TEST_CASE("LOAD_VECTOR_SHR", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.LoadVectorShr(b.Truncate(LoadGPR(b, 4), INT8_TYPE)));
b.Return();
});
test.Run([](PPCContext* ctx) { ctx->r[4] = 0; },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31));
});
test.Run([](PPCContext* ctx) { ctx->r[4] = 7; },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24));
});
test.Run([](PPCContext* ctx) { ctx->r[4] = 15; },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16));
});
test.Run([](PPCContext* ctx) { ctx->r[4] = 16; },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31));
});
}

111
src/alloy/test/test_pack.cc Normal file
View File

@@ -0,0 +1,111 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("PACK_D3DCOLOR", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Pack(LoadVR(b, 4), PACK_TYPE_D3DCOLOR));
b.Return();
});
test.Run([](PPCContext* ctx) { ctx->v[4] = vec128f(1.0f); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x3F800050, 0x3F800060, 0x3F800070, 0x3F800080);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0, 0, 0, 0x80506070));
});
}
TEST_CASE("PACK_FLOAT16_2", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Pack(LoadVR(b, 4), PACK_TYPE_FLOAT16_2));
b.Return();
});
test.Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0, 0, 0, 0x3F800000); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x47FFE000, 0xC7FFE000, 0x00000000, 0x3F800000);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0, 0, 0, 0x7FFFFFFF));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x42AAA000, 0x44CCC000, 0x00000000, 0x3F800000);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0, 0, 0, 0x55556666));
});
}
TEST_CASE("PACK_FLOAT16_4", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Pack(LoadVR(b, 4), PACK_TYPE_FLOAT16_4));
b.Return();
});
test.Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0, 0, 0, 0); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x449A4000, 0x45B17000, 0x41103261, 0x40922B6B);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x00000000, 0x00000000, 0x64D26D8C, 0x48824491));
});
}
TEST_CASE("PACK_SHORT_2", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Pack(LoadVR(b, 4), PACK_TYPE_SHORT_2));
b.Return();
});
test.Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0x43817E00, 0xC37CFC00, 0, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0, 0, 0, 0x7FFF8001));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0xC0D47D97, 0xC2256E9D, 0, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0, 0, 0, 0x80018001));
});
}

View File

@@ -0,0 +1,139 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("PERMUTE_V128_BY_INT32_CONSTANT", "[instr]") {
{
uint32_t mask = PERMUTE_MASK(0, 0, 0, 1, 0, 2, 0, 3);
TestFunction([mask](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Permute(b.LoadConstant(mask), LoadVR(b, 4),
LoadVR(b, 5), INT32_TYPE));
b.Return();
}).Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 1, 2, 3);
ctx->v[5] = vec128i(4, 5, 6, 7);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0, 1, 2, 3));
});
}
{
uint32_t mask = PERMUTE_MASK(1, 0, 1, 1, 1, 2, 1, 3);
TestFunction([mask](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Permute(b.LoadConstant(mask), LoadVR(b, 4),
LoadVR(b, 5), INT32_TYPE));
b.Return();
}).Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 1, 2, 3);
ctx->v[5] = vec128i(4, 5, 6, 7);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(4, 5, 6, 7));
});
}
{
uint32_t mask = PERMUTE_MASK(0, 3, 0, 2, 0, 1, 0, 0);
TestFunction([mask](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Permute(b.LoadConstant(mask), LoadVR(b, 4),
LoadVR(b, 5), INT32_TYPE));
b.Return();
}).Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 1, 2, 3);
ctx->v[5] = vec128i(4, 5, 6, 7);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(3, 2, 1, 0));
});
}
{
uint32_t mask = PERMUTE_MASK(1, 3, 1, 2, 1, 1, 1, 0);
TestFunction([mask](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Permute(b.LoadConstant(mask), LoadVR(b, 4),
LoadVR(b, 5), INT32_TYPE));
b.Return();
}).Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 1, 2, 3);
ctx->v[5] = vec128i(4, 5, 6, 7);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(7, 6, 5, 4));
});
}
}
TEST_CASE("PERMUTE_V128_BY_V128", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3,
b.Permute(LoadVR(b, 3), LoadVR(b, 4), LoadVR(b, 5), VEC128_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[3] =
vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
ctx->v[4] = vec128b(100, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15);
ctx->v[5] = vec128b(16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(100, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15));
});
test.Run([](PPCContext* ctx) {
ctx->v[3] = vec128b(16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31);
ctx->v[4] =
vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
ctx->v[5] = vec128b(116, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(116, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31));
});
test.Run([](PPCContext* ctx) {
ctx->v[3] =
vec128b(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
ctx->v[4] = vec128b(100, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15);
ctx->v[5] = vec128b(16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4,
3, 2, 1, 100));
});
test.Run([](PPCContext* ctx) {
ctx->v[3] = vec128b(31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20,
19, 18, 17, 16);
ctx->v[4] =
vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
ctx->v[5] = vec128b(16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 131);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(131, 30, 29, 28, 27, 26, 25, 24, 23, 22,
21, 20, 19, 18, 17, 16));
});
}

211
src/alloy/test/test_sha.cc Normal file
View File

@@ -0,0 +1,211 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("SHA_I8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Sha(b.Truncate(LoadGPR(b, 4), INT8_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xF0;
ctx->r[5] = 4;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0xFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFF;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0xFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFF;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0xFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x80;
ctx->r[5] = 8;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0xFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7F;
ctx->r[5] = 7;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}
TEST_CASE("SHA_I16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Sha(b.Truncate(LoadGPR(b, 4), INT16_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFF00;
ctx->r[5] = 8;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0xFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFF;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0xFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFE;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0xFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x8000;
ctx->r[5] = 16;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0xFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFF;
ctx->r[5] = 15;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}
TEST_CASE("SHA_I32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Sha(b.Truncate(LoadGPR(b, 4), INT32_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFF0000;
ctx->r[5] = 16;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFF;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFE;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x80000000;
ctx->r[5] = 32;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0x80000000);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFFFFFF;
ctx->r[5] = 31;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}
TEST_CASE("SHA_I64", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.Sha(b.Truncate(LoadGPR(b, 4), INT64_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFF00000000ull;
ctx->r[5] = 32;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFFFFFFFFFFull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFFFFFFFFFFull;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFFFFFFFFFFull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFFFFFFFFFEull;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFFFFFFFFFFull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x8000000000000000ull;
ctx->r[5] = 64;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0x8000000000000000ull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFFFFFFFFFFFFFFull;
ctx->r[5] = 63;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}

211
src/alloy/test/test_shl.cc Normal file
View File

@@ -0,0 +1,211 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("SHL_I8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Shl(b.Truncate(LoadGPR(b, 4), INT8_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x0F;
ctx->r[5] = 4;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0xF0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFF;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0xFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFF;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0xFE);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x80;
ctx->r[5] = 8;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7F;
ctx->r[5] = 7;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0x80);
});
}
TEST_CASE("SHL_I16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Shl(b.Truncate(LoadGPR(b, 4), INT16_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x00FF;
ctx->r[5] = 8;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0xFF00);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFF;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0xFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFF;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0xFFFE);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x8000;
ctx->r[5] = 16;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFF;
ctx->r[5] = 15;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0x8000);
});
}
TEST_CASE("SHL_I32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Shl(b.Truncate(LoadGPR(b, 4), INT32_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x0000FFFF;
ctx->r[5] = 16;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0xFFFF0000);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFF;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFFFFFF;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFE);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x80000000;
ctx->r[5] = 32;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0x80000000);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFFFFFF;
ctx->r[5] = 31;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0x80000000);
});
}
TEST_CASE("SHL_I64", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.Shl(b.Truncate(LoadGPR(b, 4), INT64_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x00000000FFFFFFFFull;
ctx->r[5] = 32;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFF00000000ull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFFFFFFFFFFull;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFFFFFFFFFFull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFFFFFFFFFFFFFFull;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFFFFFFFFFEull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x8000000000000000ull;
ctx->r[5] = 64;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0x8000000000000000ull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFFFFFFFFFFFFFFull;
ctx->r[5] = 63;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0x8000000000000000ull);
});
}

211
src/alloy/test/test_shr.cc Normal file
View File

@@ -0,0 +1,211 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("SHR_I8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Shr(b.Truncate(LoadGPR(b, 4), INT8_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xF0;
ctx->r[5] = 4;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0x0F);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFF;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0xFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFF;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0x7F);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x80;
ctx->r[5] = 8;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7F;
ctx->r[5] = 7;
},
[](PPCContext* ctx) {
auto result = static_cast<uint8_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}
TEST_CASE("SHR_I16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Shr(b.Truncate(LoadGPR(b, 4), INT16_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFF00;
ctx->r[5] = 8;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0x00FF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFF;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0xFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFE;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0x7FFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x8000;
ctx->r[5] = 16;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFF;
ctx->r[5] = 15;
},
[](PPCContext* ctx) {
auto result = static_cast<uint16_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}
TEST_CASE("SHR_I32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.ZeroExtend(b.Shr(b.Truncate(LoadGPR(b, 4), INT32_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)),
INT64_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFF0000;
ctx->r[5] = 16;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0x0000FFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFF;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFE;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0x7FFFFFFF);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x80000000;
ctx->r[5] = 32;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0x80000000);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFFFFFF;
ctx->r[5] = 31;
},
[](PPCContext* ctx) {
auto result = static_cast<uint32_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}
TEST_CASE("SHR_I64", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreGPR(b, 3, b.Shr(b.Truncate(LoadGPR(b, 4), INT64_TYPE),
b.Truncate(LoadGPR(b, 5), INT8_TYPE)));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFF00000000ull;
ctx->r[5] = 32;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0x00000000FFFFFFFFull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFFFFFFFFFFull;
ctx->r[5] = 0;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0xFFFFFFFFFFFFFFFFull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0xFFFFFFFFFFFFFFFEull;
ctx->r[5] = 1;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0x7FFFFFFFFFFFFFFFull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x8000000000000000ull;
ctx->r[5] = 64;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0x8000000000000000ull);
});
test.Run([](PPCContext* ctx) {
ctx->r[4] = 0x7FFFFFFFFFFFFFFFull;
ctx->r[5] = 63;
},
[](PPCContext* ctx) {
auto result = static_cast<uint64_t>(ctx->r[3]);
REQUIRE(result == 0);
});
}

View File

@@ -0,0 +1,46 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("SWIZZLE_V128", "[instr]") {
TestFunction([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Swizzle(LoadVR(b, 4), INT32_TYPE,
SWIZZLE_MASK(0, 1, 2, 3)));
b.Return();
}).Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0, 1, 2, 3); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0, 1, 2, 3));
});
TestFunction([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Swizzle(LoadVR(b, 4), INT32_TYPE,
SWIZZLE_MASK(3, 2, 1, 0)));
b.Return();
}).Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0, 1, 2, 3); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(3, 2, 1, 0));
});
TestFunction([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Swizzle(LoadVR(b, 4), INT32_TYPE,
SWIZZLE_MASK(1, 1, 2, 2)));
b.Return();
}).Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0, 1, 2, 3); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(1, 1, 2, 2));
});
}

View File

@@ -0,0 +1,162 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("UNPACK_D3DCOLOR", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Unpack(LoadVR(b, 4), PACK_TYPE_D3DCOLOR));
b.Return();
});
test.Run([](PPCContext* ctx) {
uint32_t value = 0;
ctx->v[4] = vec128i(0, 0, 0, value);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128f(1.0f, 1.0f, 1.0f, 1.0f));
});
test.Run([](PPCContext* ctx) {
uint32_t value = 0x80506070;
ctx->v[4] = vec128i(0, 0, 0, value);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x3F800050, 0x3F800060, 0x3F800070, 0x3F800080));
});
}
TEST_CASE("UNPACK_FLOAT16_2", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Unpack(LoadVR(b, 4), PACK_TYPE_FLOAT16_2));
b.Return();
});
test.Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0, 0, 0, 0x3F800000));
});
test.Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0, 0, 0, 0x7FFFFFFF); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x47FFE000, 0xC7FFE000, 0x00000000, 0x3F800000));
});
test.Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0, 0, 0, 0x55556666); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x42AAA000, 0x44CCC000, 0x00000000, 0x3F800000));
});
}
TEST_CASE("UNPACK_FLOAT16_4", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Unpack(LoadVR(b, 4), PACK_TYPE_FLOAT16_4));
b.Return();
});
test.Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0, 0, 0, 0, 0x64D2, 0x6D8B, 0x4881, 0x4491);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x449A4000, 0x45B16000, 0x41102000, 0x40922000));
});
}
TEST_CASE("UNPACK_SHORT_2", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.Unpack(LoadVR(b, 4), PACK_TYPE_SHORT_2));
b.Return();
});
test.Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0); },
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x40400000, 0x40400000, 0x00000000, 0x3F800000));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x7004FD60, 0x8201C990, 0x00000000, 0x7FFF8001);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x40407FFF, 0x403F8001, 0x00000000, 0x3F800000));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 0, 0, (0x1234u << 16) | 0x5678u);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x40401234, 0x40405678, 0x00000000, 0x3F800000));
});
}
// TEST_CASE("UNPACK_S8_IN_16_LO", "[instr]") {
// TestFunction test([](hir::HIRBuilder& b) {
// StoreVR(b, 3, b.Unpack(LoadVR(b, 4), PACK_TYPE_S8_IN_16_LO));
// b.Return();
// });
// test.Run([](PPCContext* ctx) { ctx->v[4] = vec128b(0); },
// [](PPCContext* ctx) {
// auto result = ctx->v[3];
// REQUIRE(result == vec128b(0));
// });
//}
//
// TEST_CASE("UNPACK_S8_IN_16_HI", "[instr]") {
// TestFunction test([](hir::HIRBuilder& b) {
// StoreVR(b, 3, b.Unpack(LoadVR(b, 4), PACK_TYPE_S8_IN_16_HI));
// b.Return();
// });
// test.Run([](PPCContext* ctx) { ctx->v[4] = vec128b(0); },
// [](PPCContext* ctx) {
// auto result = ctx->v[3];
// REQUIRE(result == vec128b(0));
// });
//}
//
// TEST_CASE("UNPACK_S16_IN_32_LO", "[instr]") {
// TestFunction test([](hir::HIRBuilder& b) {
// StoreVR(b, 3, b.Unpack(LoadVR(b, 4), PACK_TYPE_S16_IN_32_LO));
// b.Return();
// });
// test.Run([](PPCContext* ctx) { ctx->v[4] = vec128b(0); },
// [](PPCContext* ctx) {
// auto result = ctx->v[3];
// REQUIRE(result == vec128b(0));
// });
//}
//
// TEST_CASE("UNPACK_S16_IN_32_HI", "[instr]") {
// TestFunction test([](hir::HIRBuilder& b) {
// StoreVR(b, 3, b.Unpack(LoadVR(b, 4), PACK_TYPE_S16_IN_32_HI));
// b.Return();
// });
// test.Run([](PPCContext* ctx) { ctx->v[4] = vec128b(0); },
// [](PPCContext* ctx) {
// auto result = ctx->v[3];
// REQUIRE(result == vec128b(0));
// });
//}

View File

@@ -0,0 +1,282 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
#include <cfloat>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("VECTOR_ADD_I8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
ctx->v[5] = vec128b(100, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(100, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
22, 24, 26, 28, 30));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128b(UINT8_MAX);
ctx->v[5] = vec128b(1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0));
});
}
TEST_CASE("VECTOR_ADD_I8_SAT_SIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE,
ARITHMETIC_SATURATE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128b(INT8_MAX);
ctx->v[5] = vec128b(1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(INT8_MAX));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128b(INT8_MIN);
ctx->v[5] = vec128b(-1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(INT8_MIN));
});
}
TEST_CASE("VECTOR_ADD_I8_SAT_UNSIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE,
ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128b(UINT8_MAX);
ctx->v[5] = vec128b(1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(UINT8_MAX));
});
}
TEST_CASE("VECTOR_ADD_I16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0, 1, 2, 3, 4, 5, 6, 7);
ctx->v[5] = vec128s(100, 1, 2, 3, 4, 5, 6, 7);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(100, 2, 4, 6, 8, 10, 12, 14));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(UINT16_MAX);
ctx->v[5] = vec128s(1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(0));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0);
ctx->v[5] = vec128s(-1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(UINT16_MAX));
});
}
TEST_CASE("VECTOR_ADD_I16_SAT_SIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE,
ARITHMETIC_SATURATE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(INT16_MAX);
ctx->v[5] = vec128s(1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(INT16_MAX));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(INT16_MIN);
ctx->v[5] = vec128s(-1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(INT16_MIN));
});
}
TEST_CASE("VECTOR_ADD_I16_SAT_UNSIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE,
ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(UINT16_MAX);
ctx->v[5] = vec128s(1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(UINT16_MAX));
});
}
TEST_CASE("VECTOR_ADD_I32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 1, 2, 3);
ctx->v[5] = vec128i(100, 1, 2, 3);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(100, 2, 4, 6));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(UINT32_MAX);
ctx->v[5] = vec128i(1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0);
ctx->v[5] = vec128i(-1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(UINT32_MAX));
});
}
TEST_CASE("VECTOR_ADD_I32_SAT_SIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE,
ARITHMETIC_SATURATE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(5);
ctx->v[5] = vec128i(5);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(10));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(INT32_MAX);
ctx->v[5] = vec128i(1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(INT32_MAX));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(INT32_MIN);
ctx->v[5] = vec128i(-1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(INT32_MIN));
});
}
TEST_CASE("VECTOR_ADD_I32_SAT_UNSIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE,
ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(5);
ctx->v[5] = vec128i(5);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(10));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(UINT32_MAX);
ctx->v[5] = vec128i(1);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(UINT32_MAX));
});
}
TEST_CASE("VECTOR_ADD_F32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), FLOAT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128f(0.12f, 0.34f, 0.56f, 0.78f);
ctx->v[5] = vec128f(0.12f, 0.34f, 0.56f, 0.78f);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x3E75C28F, 0x3F2E147B, 0x3F8F5C29, 0x3FC7AE14));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128f(FLT_MAX);
ctx->v[5] = vec128f(FLT_MAX);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0x7F800000));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128f(-FLT_MIN);
ctx->v[5] = vec128f(-1.0f);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0xBF800000));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128f(FLT_MAX);
ctx->v[5] = vec128f(1.0f);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0x7F7FFFFF));
});
}

View File

@@ -0,0 +1,118 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
#include <cfloat>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("VECTOR_MAX_I8_SIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
ctx->v[5] = vec128b(-100, 1, 100, -3, 4, -5, 60, 7, -80, 9, 10,
INT8_MIN, INT8_MAX, 13, 2, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0, 1, 100, 3, 4, 5, 60, 7, 8, 9, 10, 11,
INT8_MAX, 13, 14, 15));
});
}
TEST_CASE("VECTOR_MAX_I8_UNSIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE,
ARITHMETIC_UNSIGNED));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
ctx->v[5] = vec128b(-100, 1, 100, -3, 4, -5, 60, 7, -80, 9, 10,
INT8_MIN, INT8_MAX, 13, 2, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(-100, 1, 100, -3, 4, -5, 60, 7, -80, 9,
10, INT8_MIN, INT8_MAX, 13, 14, 15));
});
}
TEST_CASE("VECTOR_MAX_I16_SIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0, 1, 2, 3, 4, 5, -6000, 7);
ctx->v[5] = vec128s(-1000, 1, -2000, 3, 4, SHRT_MAX, 6, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(0, 1, 2, 3, 4, SHRT_MAX, 6, 7));
});
}
TEST_CASE("VECTOR_MAX_I16_UNSIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE,
ARITHMETIC_UNSIGNED));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0, 1, 2, 3, 4, 5, -6000, 7);
ctx->v[5] = vec128s(-1000, 1, -2000, 3, 4, USHRT_MAX, 6, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128s(-1000, 1, -2000, 3, 4, USHRT_MAX, -6000, 7));
});
}
TEST_CASE("VECTOR_MAX_I32_SIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 1, 123, 3);
ctx->v[5] = vec128i(-1000000, 0, INT_MAX, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0, 1, INT_MAX, 3));
});
}
TEST_CASE("VECTOR_MAX_I32_UNSIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE,
ARITHMETIC_UNSIGNED));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 1, 123, 3);
ctx->v[5] = vec128i(-1000000, 0, UINT_MAX, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(-1000000, 1, UINT_MAX, 3));
});
}

View File

@@ -0,0 +1,117 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
#include <cfloat>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("VECTOR_MIN_I8_SIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
ctx->v[5] = vec128b(-100, 1, 100, -3, 4, -5, 60, 7, -80, 9, 10,
INT8_MIN, INT8_MAX, 13, 2, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(-100, 1, 2, -3, 4, -5, 6, 7, -80, 9, 10,
INT8_MIN, 12, 13, 2, 0));
});
}
TEST_CASE("VECTOR_MIN_I8_UNSIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE,
ARITHMETIC_UNSIGNED));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
ctx->v[5] = vec128b(255, 1, 200, -3, 4, -5, 60, 7, -80, 9, 10, 11,
12, 13, 2, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 2, 0));
});
}
TEST_CASE("VECTOR_MIN_I16_SIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0, 1, 2, 3, 4, 5, -6000, 7);
ctx->v[5] = vec128s(-1000, 1, -2000, 3, 4, SHRT_MAX, 6, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(-1000, 1, -2000, 3, 4, 5, -6000, 0));
});
}
TEST_CASE("VECTOR_MIN_I16_UNSIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE,
ARITHMETIC_UNSIGNED));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0, 1, 2, 3, 4, 5, -6000, 7);
ctx->v[5] = vec128s(-1000, 1, -2000, 3, 4, USHRT_MAX, 6, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(0, 1, 2, 3, 4, 5, 6, 0));
});
}
TEST_CASE("VECTOR_MIN_I32_SIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 1, 123, 3);
ctx->v[5] = vec128i(-1000000, 0, INT_MAX, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(-1000000, 0, 123, 0));
});
}
TEST_CASE("VECTOR_MIN_I32_UNSIGNED", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE,
ARITHMETIC_UNSIGNED));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128i(0, 1, 123, 3);
ctx->v[5] = vec128i(-1000000, 0, UINT_MAX, 0);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128i(0, 0, 123, 0));
});
}

View File

@@ -0,0 +1,71 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <third_party/xbyak/xbyak/xbyak_bin2hex.h>
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("VECTOR_ROTATE_LEFT_I8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorRotateLeft(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128b(B00000001);
ctx->v[5] =
vec128b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128b(B00000001, B00000010, B00000100, B00001000,
B00010000, B00100000, B01000000, B10000000,
B00000001, B00000010, B00000100, B00001000,
B00010000, B00100000, B01000000, B10000000));
});
}
TEST_CASE("VECTOR_ROTATE_LEFT_I16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorRotateLeft(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0x0001, 0x0001, 0x0001, 0x0001, 0x1000, 0x1000,
0x1000, 0x1000);
ctx->v[5] = vec128s(0, 1, 2, 3, 14, 15, 16, 17);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(0x0001, 0x0002, 0x0004, 0x0008, 0x0400,
0x0800, 0x1000, 0x2000));
});
}
TEST_CASE("VECTOR_ROTATE_LEFT_I32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorRotateLeft(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x00000001, 0x00000001, 0x80000000, 0x80000000);
ctx->v[5] = vec128i(0, 1, 1, 2);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x00000001, 0x00000002, 0x00000001, 0x00000002));
});
}

View File

@@ -0,0 +1,145 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("VECTOR_SHA_I8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorSha(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0x7E, 0x7E, 0x7E, 0x7F, 0x80, 0xFF, 0x01, 0x12, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
ctx->v[5] =
vec128b(0, 1, 2, 8, 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0x7E, 0x3F, 0x1F, 0x7F, 0xF8, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00));
});
}
TEST_CASE("VECTOR_SHA_I8_CONSTANT", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorSha(LoadVR(b, 4), b.LoadConstant(vec128b(
0, 1, 2, 8, 4, 4, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15)),
INT8_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0x7E, 0x7E, 0x7E, 0x7F, 0x80, 0xFF, 0x01, 0x12, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0x7E, 0x3F, 0x1F, 0x7F, 0xF8, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00));
});
}
TEST_CASE("VECTOR_SHA_I16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorSha(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0x7FFE, 0x7FFE, 0x7FFE, 0x7FFF, 0x8000, 0xFFFF,
0x0001, 0x1234);
ctx->v[5] = vec128s(0, 1, 8, 15, 15, 8, 1, 16);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(0x7FFE, 0x3FFF, 0x007F, 0x0000, 0xFFFF,
0xFFFF, 0x0000, 0x1234));
});
}
TEST_CASE("VECTOR_SHA_I16_CONSTANT", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorSha(LoadVR(b, 4), b.LoadConstant(vec128s(
0, 1, 8, 15, 15, 8, 1, 16)),
INT16_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0x7FFE, 0x7FFE, 0x7FFE, 0x7FFF, 0x8000, 0xFFFF,
0x0001, 0x1234);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(0x7FFE, 0x3FFF, 0x007F, 0x0000, 0xFFFF,
0xFFFF, 0x0000, 0x1234));
});
}
TEST_CASE("VECTOR_SHA_I32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorSha(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFF);
ctx->v[5] = vec128i(0, 1, 16, 31);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x7FFFFFFE, 0x3FFFFFFF, 0x00007FFF, 0x00000000));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x80000000, 0xFFFFFFFF, 0x00000001, 0x12345678);
ctx->v[5] = vec128i(31, 16, 1, 32);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x12345678));
});
}
TEST_CASE("VECTOR_SHA_I32_CONSTANT", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3,
b.VectorSha(LoadVR(b, 4), b.LoadConstant(vec128i(0, 1, 16, 31)),
INT32_TYPE));
StoreVR(b, 4,
b.VectorSha(LoadVR(b, 5), b.LoadConstant(vec128i(31, 16, 1, 32)),
INT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFF);
ctx->v[5] =
vec128i(0x80000000, 0xFFFFFFFF, 0x00000001, 0x12345678);
},
[](PPCContext* ctx) {
auto result1 = ctx->v[3];
REQUIRE(result1 ==
vec128i(0x7FFFFFFE, 0x3FFFFFFF, 0x00007FFF, 0x00000000));
auto result2 = ctx->v[4];
REQUIRE(result2 ==
vec128i(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x12345678));
});
}

View File

@@ -0,0 +1,145 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("VECTOR_SHL_I8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorShl(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0x7E, 0x7E, 0x7E, 0x7F, 0x80, 0xFF, 0x01, 0x12, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
ctx->v[5] =
vec128b(0, 1, 2, 8, 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0x7E, 0xFC, 0xF8, 0x7F, 0x00, 0xF0, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00));
});
}
TEST_CASE("VECTOR_SHL_I8_CONSTANT", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorShl(LoadVR(b, 4), b.LoadConstant(vec128b(
0, 1, 2, 8, 4, 4, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15)),
INT8_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0x7E, 0x7E, 0x7E, 0x7F, 0x80, 0xFF, 0x01, 0x12, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0x7E, 0xFC, 0xF8, 0x7F, 0x00, 0xF0, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00));
});
}
TEST_CASE("VECTOR_SHL_I16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorShl(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0x7FFE, 0x7FFE, 0x7FFE, 0x7FFF, 0x8000, 0xFFFF,
0x0001, 0x1234);
ctx->v[5] = vec128s(0, 1, 8, 15, 15, 8, 1, 16);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(0x7FFE, 0xFFFC, 0xFE00, 0x8000, 0x0000,
0xFF00, 0x0002, 0x1234));
});
}
TEST_CASE("VECTOR_SHL_I16_CONSTANT", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorShl(LoadVR(b, 4), b.LoadConstant(vec128s(
0, 1, 8, 15, 15, 8, 1, 16)),
INT16_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0x7FFE, 0x7FFE, 0x7FFE, 0x7FFF, 0x8000, 0xFFFF,
0x0001, 0x1234);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(0x7FFE, 0xFFFC, 0xFE00, 0x8000, 0x0000,
0xFF00, 0x0002, 0x1234));
});
}
TEST_CASE("VECTOR_SHL_I32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorShl(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFF);
ctx->v[5] = vec128i(0, 1, 16, 31);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x7FFFFFFE, 0xFFFFFFFC, 0xFFFE0000, 0x80000000));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x80000000, 0xFFFFFFFF, 0x00000001, 0x12345678);
ctx->v[5] = vec128i(31, 16, 1, 32);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x00000000, 0xFFFF0000, 0x00000002, 0x12345678));
});
}
TEST_CASE("VECTOR_SHL_I32_CONSTANT", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3,
b.VectorShl(LoadVR(b, 4), b.LoadConstant(vec128i(0, 1, 16, 31)),
INT32_TYPE));
StoreVR(b, 4,
b.VectorShl(LoadVR(b, 5), b.LoadConstant(vec128i(31, 16, 1, 32)),
INT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFF);
ctx->v[5] =
vec128i(0x80000000, 0xFFFFFFFF, 0x00000001, 0x12345678);
},
[](PPCContext* ctx) {
auto result1 = ctx->v[3];
REQUIRE(result1 ==
vec128i(0x7FFFFFFE, 0xFFFFFFFC, 0xFFFE0000, 0x80000000));
auto result2 = ctx->v[4];
REQUIRE(result2 ==
vec128i(0x00000000, 0xFFFF0000, 0x00000002, 0x12345678));
});
}

View File

@@ -0,0 +1,145 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <tools/alloy-test/util.h>
using namespace alloy;
using namespace alloy::hir;
using namespace alloy::runtime;
using namespace alloy::test;
using alloy::frontend::ppc::PPCContext;
TEST_CASE("VECTOR_SHR_I8", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorShr(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0x7E, 0x7E, 0x7E, 0x7F, 0x80, 0xFF, 0x01, 0x12, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
ctx->v[5] =
vec128b(0, 1, 2, 8, 4, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0x7E, 0x3F, 0x1F, 0x7F, 0x08, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00));
});
}
TEST_CASE("VECTOR_SHR_I8_CONSTANT", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorShr(LoadVR(b, 4), b.LoadConstant(vec128b(
0, 1, 2, 8, 4, 4, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15)),
INT8_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128b(0x7E, 0x7E, 0x7E, 0x7F, 0x80, 0xFF, 0x01, 0x12, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128b(0x7E, 0x3F, 0x1F, 0x7F, 0x08, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00));
});
}
TEST_CASE("VECTOR_SHR_I16", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorShr(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0x7FFE, 0x7FFE, 0x7FFE, 0x7FFF, 0x8000, 0xFFFF,
0x0001, 0x1234);
ctx->v[5] = vec128s(0, 1, 8, 15, 15, 8, 1, 16);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(0x7FFE, 0x3FFF, 0x007F, 0x0000, 0x0001,
0x00FF, 0x0000, 0x1234));
});
}
TEST_CASE("VECTOR_SHR_I16_CONSTANT", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorShr(LoadVR(b, 4), b.LoadConstant(vec128s(
0, 1, 8, 15, 15, 8, 1, 16)),
INT16_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] = vec128s(0x7FFE, 0x7FFE, 0x7FFE, 0x7FFF, 0x8000, 0xFFFF,
0x0001, 0x1234);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result == vec128s(0x7FFE, 0x3FFF, 0x007F, 0x0000, 0x0001,
0x00FF, 0x0000, 0x1234));
});
}
TEST_CASE("VECTOR_SHR_I32", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3, b.VectorShr(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFF);
ctx->v[5] = vec128i(0, 1, 16, 31);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x7FFFFFFE, 0x3FFFFFFF, 0x00007FFF, 0x00000000));
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x80000000, 0xFFFFFFFF, 0x00000001, 0x12345678);
ctx->v[5] = vec128i(31, 16, 1, 32);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x00000001, 0x0000FFFF, 0x00000000, 0x12345678));
});
}
TEST_CASE("VECTOR_SHR_I32_CONSTANT", "[instr]") {
TestFunction test([](hir::HIRBuilder& b) {
StoreVR(b, 3,
b.VectorShr(LoadVR(b, 4), b.LoadConstant(vec128i(0, 1, 16, 31)),
INT32_TYPE));
StoreVR(b, 4,
b.VectorShr(LoadVR(b, 5), b.LoadConstant(vec128i(31, 16, 1, 32)),
INT32_TYPE));
b.Return();
});
test.Run([](PPCContext* ctx) {
ctx->v[4] =
vec128i(0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFE, 0x7FFFFFFF);
ctx->v[5] =
vec128i(0x80000000, 0xFFFFFFFF, 0x00000001, 0x12345678);
},
[](PPCContext* ctx) {
auto result1 = ctx->v[3];
REQUIRE(result1 ==
vec128i(0x7FFFFFFE, 0x3FFFFFFF, 0x00007FFF, 0x00000000));
auto result2 = ctx->v[4];
REQUIRE(result2 ==
vec128i(0x00000001, 0x0000FFFF, 0x00000000, 0x12345678));
});
}

181
src/alloy/test/util.h Normal file
View File

@@ -0,0 +1,181 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef ALLOY_TEST_UTIL_H_
#define ALLOY_TEST_UTIL_H_
#include <alloy/alloy.h>
#include <alloy/backend/ivm/ivm_backend.h>
#include <alloy/backend/x64/x64_backend.h>
#include <alloy/frontend/ppc/ppc_context.h>
#include <alloy/frontend/ppc/ppc_frontend.h>
#include <alloy/hir/hir_builder.h>
#include <alloy/runtime/test_module.h>
#include <poly/main.h>
#include <poly/poly.h>
#include <third_party/catch/single_include/catch.hpp>
#define ALLOY_TEST_IVM 1
#define ALLOY_TEST_X64 1
namespace alloy {
namespace test {
using alloy::frontend::ppc::PPCContext;
using alloy::runtime::Runtime;
class ThreadState : public alloy::runtime::ThreadState {
public:
ThreadState(Runtime* runtime, uint32_t thread_id, uint64_t stack_address,
size_t stack_size, uint64_t thread_state_address)
: alloy::runtime::ThreadState(runtime, thread_id),
stack_address_(stack_address),
stack_size_(stack_size),
thread_state_address_(thread_state_address) {
memset(memory_->Translate(stack_address_), 0, stack_size_);
// Allocate with 64b alignment.
context_ = (PPCContext*)calloc(1, sizeof(PPCContext));
assert_true((reinterpret_cast<uint64_t>(context_) & 0xF) == 0);
// Stash pointers to common structures that callbacks may need.
context_->reserve_address = memory_->reserve_address();
context_->membase = memory_->membase();
context_->runtime = runtime;
context_->thread_state = this;
// Set initial registers.
context_->r[1] = stack_address_ + stack_size;
context_->r[13] = thread_state_address_;
// Pad out stack a bit, as some games seem to overwrite the caller by about
// 16 to 32b.
context_->r[1] -= 64;
raw_context_ = context_;
runtime_->debugger()->OnThreadCreated(this);
}
~ThreadState() override {
runtime_->debugger()->OnThreadDestroyed(this);
free(context_);
}
PPCContext* context() const { return context_; }
private:
uint64_t stack_address_;
size_t stack_size_;
uint64_t thread_state_address_;
// NOTE: must be 64b aligned for SSE ops.
PPCContext* context_;
};
class TestFunction {
public:
TestFunction(std::function<void(hir::HIRBuilder& b)> generator) {
memory_size = 16 * 1024 * 1024;
memory.reset(new SimpleMemory(memory_size));
#if ALLOY_TEST_IVM
{
auto runtime = std::make_unique<Runtime>(memory.get());
auto frontend =
std::make_unique<alloy::frontend::ppc::PPCFrontend>(runtime.get());
auto backend =
std::make_unique<alloy::backend::ivm::IVMBackend>(runtime.get());
runtime->Initialize(std::move(frontend), std::move(backend));
runtimes.emplace_back(std::move(runtime));
}
#endif // ALLOY_TEST_IVM
#ifdef ALLOY_TEST_X64
{
auto runtime = std::make_unique<Runtime>(memory.get());
auto frontend =
std::make_unique<alloy::frontend::ppc::PPCFrontend>(runtime.get());
auto backend =
std::make_unique<alloy::backend::x64::X64Backend>(runtime.get());
runtime->Initialize(std::move(frontend), std::move(backend));
runtimes.emplace_back(std::move(runtime));
}
#endif // ALLOY_TEST_X64
for (auto& runtime : runtimes) {
auto module = std::make_unique<alloy::runtime::TestModule>(
runtime.get(), "Test",
[](uint64_t address) { return address == 0x1000; },
[generator](hir::HIRBuilder& b) {
generator(b);
return true;
});
runtime->AddModule(std::move(module));
}
}
~TestFunction() {
runtimes.clear();
memory.reset();
}
void Run(std::function<void(PPCContext*)> pre_call,
std::function<void(PPCContext*)> post_call) {
for (auto& runtime : runtimes) {
memory->Zero(0, memory_size);
alloy::runtime::Function* fn;
runtime->ResolveFunction(0x1000, &fn);
uint64_t stack_size = 64 * 1024;
uint64_t stack_address = memory_size - stack_size;
uint64_t thread_state_address = stack_address - 0x1000;
auto thread_state = std::make_unique<ThreadState>(
runtime.get(), 0x100, stack_address, stack_size, thread_state_address);
auto ctx = thread_state->context();
ctx->lr = 0xBEBEBEBE;
pre_call(ctx);
fn->Call(thread_state.get(), ctx->lr);
post_call(ctx);
}
}
size_t memory_size;
std::unique_ptr<Memory> memory;
std::vector<std::unique_ptr<Runtime>> runtimes;
};
inline hir::Value* LoadGPR(hir::HIRBuilder& b, int reg) {
return b.LoadContext(offsetof(PPCContext, r) + reg * 8, hir::INT64_TYPE);
}
inline void StoreGPR(hir::HIRBuilder& b, int reg, hir::Value* value) {
b.StoreContext(offsetof(PPCContext, r) + reg * 8, value);
}
inline hir::Value* LoadFPR(hir::HIRBuilder& b, int reg) {
return b.LoadContext(offsetof(PPCContext, f) + reg * 8, hir::FLOAT64_TYPE);
}
inline void StoreFPR(hir::HIRBuilder& b, int reg, hir::Value* value) {
b.StoreContext(offsetof(PPCContext, f) + reg * 8, value);
}
inline hir::Value* LoadVR(hir::HIRBuilder& b, int reg) {
return b.LoadContext(offsetof(PPCContext, v) + reg * 16, hir::VEC128_TYPE);
}
inline void StoreVR(hir::HIRBuilder& b, int reg, hir::Value* value) {
b.StoreContext(offsetof(PPCContext, v) + reg * 16, value);
}
} // namespace test
} // namespace alloy
#endif // ALLOY_TEST_UTIL_H_

View File

@@ -9,7 +9,6 @@
#include <xenia/cpu/processor.h>
#include <xenia/emulator.h>
#include <xenia/export_resolver.h>
#include <xenia/cpu/cpu-private.h>
#include <xenia/cpu/xenon_runtime.h>
@@ -45,10 +44,10 @@ void InitializeIfNeeded() {
void CleanupOnShutdown() {}
}
Processor::Processor(Emulator* emulator)
: export_resolver_(emulator->export_resolver()),
Processor::Processor(xe::Memory* memory, ExportResolver* export_resolver)
: export_resolver_(export_resolver),
runtime_(0),
memory_(emulator->memory()),
memory_(memory),
interrupt_thread_state_(NULL),
interrupt_thread_block_(0) {
InitializeIfNeeded();

View File

@@ -14,12 +14,11 @@
#include <vector>
#include <xenia/core.h>
#include <xenia/emulator.h>
#include <xenia/export_resolver.h>
namespace xe {
namespace cpu {
class XenonMemory;
class XenonRuntime;
class XenonThreadState;
class XexModule;
@@ -33,7 +32,7 @@ enum class Irql : uint32_t {
class Processor {
public:
Processor(Emulator* emulator);
Processor(Memory* memory, ExportResolver* export_resolver);
~Processor();
ExportResolver* export_resolver() const { return export_resolver_; }

View File

@@ -89,7 +89,8 @@ X_STATUS Emulator::Setup() {
export_resolver_ = std::make_unique<ExportResolver>();
// Initialize the CPU.
processor_ = std::make_unique<Processor>(this);
processor_ =
std::make_unique<Processor>(memory_.get(), export_resolver_.get());
// Initialize the APU.
audio_system_ = std::move(xe::apu::Create(this));