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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/lib/arch/aarch64/InstructionMetadata.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1798,6 +1798,7 @@ void InstructionMetadata::revertAliasing() {
case ARM64_INS_AT:
return aliasNYI();
case ARM64_INS_BFI:
// TODO no tests of alias
if (opcode == Opcode::AArch64_BFMWri) {
// bfi wd, wn, #lsb, #width; alias for
// bfm wd, wn, #(-lsb MOD 32), #(width - 1)
Expand All @@ -1814,6 +1815,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_BFXIL:
// TODO no tests for alias
if (opcode == Opcode::AArch64_BFMWri ||
opcode == Opcode::AArch64_BFMXri) {
// bfxil rd, rn, #lsb, #width; alias for
Expand Down Expand Up @@ -1896,6 +1898,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_CSET:
// TODO no usage in regression tests
if (opcode == Opcode::AArch64_CSINCWr ||
opcode == Opcode::AArch64_CSINCXr) {
// cset rd, cc; alias for: csinc rd, zr, zr, invert(cc)
Expand Down Expand Up @@ -1952,6 +1955,7 @@ void InstructionMetadata::revertAliasing() {
case ARM64_INS_IC:
return aliasNYI();
case ARM64_INS_LSL:
// TODO no usage in regression tests
if (opcode == Opcode::AArch64_UBFMWri ||
opcode == Opcode::AArch64_UBFMXri) {
// lsl rd, rn, #shift; alias for:
Expand Down Expand Up @@ -1998,6 +2002,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_MNEG:
// TODO no test
if (opcode == Opcode::AArch64_MSUBXrrr) {
// mneg xd, xn, xm; alias for msub xd, xn, xm, xzr
operandCount = 4;
Expand All @@ -2016,6 +2021,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_MOV:
// TODO no specific tests
if (opcode == Opcode::AArch64_AND_PPzPP) {
// mov pd.b, pg/z, pn.b; alias for: and pd.b, pg/z, pn.b, pn.b
operandCount = 4;
Expand Down Expand Up @@ -2272,6 +2278,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_MUL:
// TODO add comment
if (opcode == Opcode::AArch64_MADDXrrr ||
opcode == Opcode::AArch64_MADDWrrr) {
operandCount = 4;
Expand Down Expand Up @@ -2310,13 +2317,15 @@ void InstructionMetadata::revertAliasing() {
}
if (opcode == Opcode::AArch64_NOTv16i8 ||
opcode == Opcode::AArch64_NOTv8i8) {
// TODO needs tests
// mvn vd.t, vn.t; alias for : not vd.t, vn.t
// Blank entry was for a legitimate alias, however operands were
// identical so nothing to alter between the instructions.
return;
}
return aliasNYI();
case ARM64_INS_NEG:
// TODO needs tests
if (opcode == Opcode::AArch64_SUBWrs ||
opcode == Opcode::AArch64_SUBXrs) {
// neg rd, rm{, shift #amount}; alias for:
Expand Down Expand Up @@ -2364,7 +2373,7 @@ void InstructionMetadata::revertAliasing() {
return aliasNYI();
case ARM64_INS_NOT:
if (opcode == Opcode::AArch64_EOR_PPzPP) {
// not pd.b, pg/z, pn.b; alisas for: eor pd.b, pg/z, pn.b, pg.b
// not pd.b, pg/z, pn.b; alias for: eor pd.b, pg/z, pn.b, pg.b
operandCount = 4;
operands[0].access = CS_AC_WRITE;
operands[1].access = CS_AC_READ;
Expand All @@ -2388,6 +2397,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_ROR:
// TODO needs test
if (opcode == Opcode::AArch64_RORVWr ||
opcode == Opcode::AArch64_RORVXr) {
// ror wd, wn, wm; alias for : rorv wd, wn, wm
Expand All @@ -2398,6 +2408,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_SBFIZ:
// TODO needs test
if (opcode == Opcode::AArch64_SBFMWri ||
opcode == Opcode::AArch64_SBFMXri) {
operands[3].imm -= 1;
Expand All @@ -2412,6 +2423,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_SBFX:
// TODO needs test
if (opcode == Opcode::AArch64_SBFMWri ||
opcode == Opcode::AArch64_SBFMXri) {
// sbfx rd, rn, #lsb, #width; alias for
Expand Down Expand Up @@ -2482,6 +2494,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_SYS: {
// TODO no test
// Extract IC/DC/AT/TLBI operation
if (std::string(mnemonic) == "dc") {
if (operandStr.substr(0, 3) == "zva") {
Expand All @@ -2502,6 +2515,7 @@ void InstructionMetadata::revertAliasing() {
case ARM64_INS_TLBI:
return aliasNYI();
case ARM64_INS_TST:
// TODO needs test for register case
if (opcode == Opcode::AArch64_ANDSWrs ||
opcode == Opcode::AArch64_ANDSXrs ||
opcode == Opcode::AArch64_ANDSWri ||
Expand All @@ -2525,6 +2539,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_UBFIZ:
// TODO needs test and comment
if (opcode == Opcode::AArch64_UBFMWri ||
opcode == Opcode::AArch64_UBFMXri) {
operands[3].imm -= 1;
Expand All @@ -2539,6 +2554,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_UBFX:
// TODO needs test
if (opcode == Opcode::AArch64_UBFMWri ||
opcode == Opcode::AArch64_UBFMXri) {
// ubfx rd, rn, #lsb, #width; alias for
Expand All @@ -2560,6 +2576,7 @@ void InstructionMetadata::revertAliasing() {
}
return aliasNYI();
case ARM64_INS_UXTB:
// TODO needs test
// uxtb wd, wn; alias for: ubfm wd, wn, #0, #7
if (opcode == Opcode::AArch64_UBFMWri) {
operandCount = 4;
Expand Down
123 changes: 77 additions & 46 deletions test/regression/RegressionTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ void RegressionTest::TearDown() {
}
}

void RegressionTest::run(const char* source, const char* triple,
const char* extensions) {
testing::internal::CaptureStdout();

void RegressionTest::createArchitecture(const char* source, const char* triple,
const char* extensions) {
// Zero-out process memory from any prior runs
if (processMemory_ != nullptr)
std::memset(processMemory_, '\0', processMemorySize_);
Expand All @@ -47,56 +45,44 @@ void RegressionTest::run(const char* source, const char* triple,
// The process image is finalised by the createStack method
// which creates and populates the initial process stack.
// The created process image can be accessed via a shared_ptr
// returned by the getProcessImage method.
// returned by the getProcessImage method
process_ = std::make_unique<simeng::kernel::LinuxProcess>(
simeng::span(reinterpret_cast<const uint8_t*>(code_), codeSize_));

ASSERT_TRUE(process_->isValid());
uint64_t entryPoint = process_->getEntryPoint();
entryPoint_ = process_->getEntryPoint();
processMemorySize_ = process_->getProcessImageSize();

// This instance of procImgPtr pointer needs to be shared because
// getMemoryValue in RegressionTest.hh uses reference to the class
// member processMemory_.
// member processMemory_
std::shared_ptr<char> procImgPtr = process_->getProcessImage();
processMemory_ = procImgPtr.get();

// Create memory interfaces for instruction and data access.
// For each memory interface, a dereferenced shared_ptr to the
// processImage is passed as argument.
simeng::memory::FlatMemoryInterface instructionMemory(processMemory_,
processMemorySize_);

std::unique_ptr<simeng::memory::FlatMemoryInterface> flatDataMemory =
std::make_unique<simeng::memory::FlatMemoryInterface>(processMemory_,
processMemorySize_);
// Populate the heap with initial data (specified by the test being run)
ASSERT_LT(process_->getHeapStart() + initialHeapData_.size(),
process_->getInitialStackPointer());
std::copy(initialHeapData_.begin(), initialHeapData_.end(),
processMemory_ + process_->getHeapStart());

std::unique_ptr<simeng::memory::FixedLatencyMemoryInterface>
fixedLatencyDataMemory =
std::make_unique<simeng::memory::FixedLatencyMemoryInterface>(
processMemory_, processMemorySize_, 4);
std::unique_ptr<simeng::memory::MemoryInterface> dataMemory;
ASSERT_TRUE(process_ != nullptr);

// Create the OS kernel and the process
simeng::kernel::Linux kernel(
kernel_ = std::make_unique<simeng::kernel::Linux>(
simeng::config::SimInfo::getConfig()["CPU-Info"]["Special-File-Dir-Path"]
.as<std::string>());
kernel.createProcess(*process_);

// Populate the heap with initial data (specified by the test being run).
ASSERT_LT(process_->getHeapStart() + initialHeapData_.size(),
process_->getInitialStackPointer());
std::copy(initialHeapData_.begin(), initialHeapData_.end(),
processMemory_ + process_->getHeapStart());
kernel_->createProcess(*process_);

// Create the architecture
architecture_ = createArchitecture(kernel);
architecture_ = instantiateArchitecture(*kernel_);
}

// Create a port allocator for an out-of-order core
std::unique_ptr<simeng::pipeline::PortAllocator> portAllocator =
createPortAllocator();
void RegressionTest::createCore(const char* source, const char* triple,
const char* extensions) {
// Create the architecture, kernel and process
createArchitecture(source, triple, extensions);

// Create a branch predictor for a pipelined core
std::unique_ptr<simeng::BranchPredictor> predictor_ = nullptr;
std::string predictorType =
simeng::config::SimInfo::getConfig()["Branch-Predictor"]["Type"]
.as<std::string>();
Expand All @@ -106,34 +92,61 @@ void RegressionTest::run(const char* source, const char* triple,
predictor_ = std::make_unique<simeng::PerceptronPredictor>();
}

// Create memory interfaces for instruction and data access.
Comment thread
dANW34V3R marked this conversation as resolved.
// For each memory interface, a dereferenced shared_ptr to the
// processImage is passed as an argument

ASSERT_TRUE(processMemory_ != nullptr);

instructionMemory_ = std::make_unique<simeng::memory::FlatMemoryInterface>(
processMemory_, processMemorySize_);

flatDataMemory_ = std::make_unique<simeng::memory::FlatMemoryInterface>(
processMemory_, processMemorySize_);

fixedLatencyDataMemory_ =
std::make_unique<simeng::memory::FixedLatencyMemoryInterface>(
processMemory_, processMemorySize_, 4);

// Create the core model
switch (std::get<0>(GetParam())) {
case EMULATION:
core_ = std::make_unique<simeng::models::emulation::Core>(
instructionMemory, *flatDataMemory, entryPoint, processMemorySize_,
*architecture_);
dataMemory = std::move(flatDataMemory);
*instructionMemory_, *flatDataMemory_, entryPoint_,
processMemorySize_, *architecture_);
dataMemory_ = std::move(flatDataMemory_);
break;
case INORDER:
core_ = std::make_unique<simeng::models::inorder::Core>(
instructionMemory, *flatDataMemory, processMemorySize_, entryPoint,
*architecture_, *predictor_);
dataMemory = std::move(flatDataMemory);
*instructionMemory_, *flatDataMemory_, processMemorySize_,
entryPoint_, *architecture_, *predictor_);
dataMemory_ = std::move(flatDataMemory_);
break;
case OUTOFORDER:
// Create a port allocator for an out-of-order core
portAllocator_ = createPortAllocator();

core_ = std::make_unique<simeng::models::outoforder::Core>(
instructionMemory, *fixedLatencyDataMemory, processMemorySize_,
entryPoint, *architecture_, *predictor_, *portAllocator);
dataMemory = std::move(fixedLatencyDataMemory);
*instructionMemory_, *fixedLatencyDataMemory_, processMemorySize_,
entryPoint_, *architecture_, *predictor_, *portAllocator_);
dataMemory_ = std::move(fixedLatencyDataMemory_);
break;
}
}

void RegressionTest::run(const char* source, const char* triple,
const char* extensions) {
testing::internal::CaptureStdout();

// Create the core, memory interfaces, kernel and process
createCore(source, triple, extensions);

// Run the core model until the program is complete
while (!core_->hasHalted() || dataMemory->hasPendingRequests()) {
while (!core_->hasHalted() || dataMemory_->hasPendingRequests()) {
ASSERT_LT(numTicks_, maxTicks_) << "Maximum tick count exceeded.";
core_->tick();
instructionMemory.tick();
dataMemory->tick();
instructionMemory_->tick();
dataMemory_->tick();
numTicks_++;
}

Expand All @@ -143,6 +156,24 @@ void RegressionTest::run(const char* source, const char* triple,
programFinished_ = true;
}

void RegressionTest::checkGroup(const char* source, const char* triple,
const char* extensions,
const std::vector<uint16_t>& expectedGroups) {
createArchitecture(source, triple, extensions);

std::vector<std::shared_ptr<simeng::Instruction>> macroOp;
architecture_->predecode(code_, 4, 0, macroOp);

// Check that there is one expectation group per micro-op
EXPECT_EQ(macroOp.size(), expectedGroups.size());

// Check the assigned and expected group for each micro-op match
for (size_t i = 0; i < macroOp.size(); i++) {
auto group = macroOp[i]->getGroup();
EXPECT_EQ(group, expectedGroups[i]);
}
}

void RegressionTest::assemble(const char* source, const char* triple,
const char* extensions) {
// Get LLVM target
Expand Down
Loading