You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
8.9 KiB
334 lines
8.9 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
#include <cassert>
|
|
#include <map>
|
|
#include <vector>
|
|
#include "regvalue_test_utils.h"
|
|
#include "regvalues.h"
|
|
using std::endl;
|
|
using std::flush;
|
|
|
|
using std::map;
|
|
using std::vector;
|
|
|
|
// In this file, we refer to the Active Register Set (ARS) as the set of registers being tested in a specific test run.
|
|
// The set is a subset of the TestReg enum (defined in the RegisterDB class below). It is defined by the knobs:
|
|
// KnobTestSt, KnobTestPartial and KnobTestSIMD.
|
|
|
|
|
|
/////////////////////
|
|
// TYPE DEFINITIONS
|
|
/////////////////////
|
|
|
|
class RegisterDB
|
|
{
|
|
public:
|
|
// API FUNCTIONS
|
|
|
|
static inline RegisterDB* Instance();
|
|
inline const vector<REG>& GetTestRegs() const;
|
|
inline const REGSET& GetTestRegset() const;
|
|
void PrintStoredRegisters(ostream& ost) const;
|
|
inline UINT8* GetRegval(REG reg);
|
|
inline const UINT8* GetAppRegisterValue(REG reg) const;
|
|
inline const UINT8* GetToolRegisterValue(REG reg) const;
|
|
|
|
private:
|
|
// TYPE DEFINITIONS
|
|
|
|
// Registers to check:
|
|
//
|
|
// This is an enumeration of the complete set of test registers. The tested subset is defined by the knobs:
|
|
// KnobTestSt, KnobTestPartial and KnobTestSIMD.
|
|
// To obtain the tested subset, use the GetTestRegs() and/or GetTestRegset() functions.
|
|
enum TestReg {
|
|
GPRREG = 0,
|
|
#if defined(TARGET_IA32E)
|
|
GPR32REG,
|
|
#endif
|
|
GPR16REG,
|
|
GPRLREG,
|
|
GPRHREG,
|
|
STREG,
|
|
XMMREG,
|
|
YMMREG,
|
|
ZMMREG,
|
|
OPMASKREG,
|
|
TESTREGSIZE
|
|
};
|
|
|
|
private:
|
|
// DATA FIELDS
|
|
|
|
static RegisterDB* _theInstance;
|
|
|
|
vector<REG> _testRegs; // A vector of all the ARS REGs.
|
|
REGSET _testRegset; // A REGSET of all the ARS REGs.
|
|
int _numOfTestRegs; // The number of registers in the ARS.
|
|
|
|
// REG -> TestReg mapping. Contains only the registers in the ARS.
|
|
map<REG, TestReg> _regToTestReg;
|
|
|
|
// REG -> Value saved by the tool. Contains only the registers in the ARS.
|
|
//
|
|
// Usage:
|
|
// The application register values will be stored in the _regvalMap map by the tools.
|
|
// They will be stored and printed before and after the application changes them.
|
|
// In addition, after the application changes the registers, the values will be
|
|
// compared to the expected values, obtained using the _GetAppRegisterValue() function.
|
|
map<REG, UINT8*> _regvalMap;
|
|
|
|
private:
|
|
inline RegisterDB();
|
|
|
|
// DISABLED FUNCTIONS
|
|
inline RegisterDB(const RegisterDB& src) { assert(false); } // disable copy constructor
|
|
inline void operator=(const RegisterDB& src) { assert(false); } // disable assignment operator
|
|
|
|
// MAPPING FUNCTIONS
|
|
inline REG _GetRegFromTestReg(TestReg testReg) const;
|
|
inline const UINT8* _GetAppRegisterValue(REG reg) const;
|
|
inline const UINT8* _GetToolRegisterValue(REG reg) const;
|
|
|
|
// UTILITY FUNCTIONS
|
|
inline void Verify(REG reg) const;
|
|
inline void PrintRegval(REG reg, ostream& ost) const;
|
|
void DefineActiveRegister(TestReg testReg);
|
|
void InitializeDB();
|
|
};
|
|
|
|
RegisterDB* RegisterDB::_theInstance = NULL;
|
|
|
|
RegisterDB* RegisterDB::Instance()
|
|
{
|
|
if (_theInstance == NULL)
|
|
{
|
|
_theInstance = new RegisterDB;
|
|
}
|
|
return _theInstance;
|
|
}
|
|
|
|
const vector<REG>& RegisterDB::GetTestRegs() const
|
|
{
|
|
return _testRegs;
|
|
}
|
|
|
|
const REGSET& RegisterDB::GetTestRegset() const
|
|
{
|
|
return _testRegset;
|
|
}
|
|
|
|
void RegisterDB::PrintStoredRegisters(ostream& ost) const
|
|
{
|
|
for (int r = 0; r < _numOfTestRegs; ++r)
|
|
{
|
|
PrintRegval(_testRegs[r], ost);
|
|
}
|
|
}
|
|
|
|
UINT8* RegisterDB::GetRegval(REG reg)
|
|
{
|
|
Verify(reg);
|
|
return _regvalMap[reg];
|
|
}
|
|
|
|
const UINT8* RegisterDB::GetAppRegisterValue(REG reg) const
|
|
{
|
|
Verify(reg);
|
|
return _GetAppRegisterValue(reg);
|
|
}
|
|
|
|
const UINT8* RegisterDB::GetToolRegisterValue(REG reg) const
|
|
{
|
|
Verify(reg);
|
|
return _GetToolRegisterValue(reg);
|
|
}
|
|
|
|
RegisterDB::RegisterDB() : _numOfTestRegs(0)
|
|
{
|
|
InitializeDB();
|
|
}
|
|
|
|
REG RegisterDB::_GetRegFromTestReg(TestReg testReg) const
|
|
{
|
|
// TestReg -> REG mapping. Contains all the registers in the TestReg enum.
|
|
static REG const testRegToReg[TESTREGSIZE] =
|
|
{
|
|
REG_GBX,
|
|
#if defined(TARGET_IA32E)
|
|
REG_EBX,
|
|
#endif
|
|
REG_BX,
|
|
REG_BL,
|
|
REG_BH,
|
|
REG_ST2,
|
|
REG_XMM0,
|
|
REG_YMM1,
|
|
REG_ZMM5,
|
|
REG_K3
|
|
};
|
|
return testRegToReg[testReg];
|
|
}
|
|
|
|
const UINT8* RegisterDB::_GetAppRegisterValue(REG reg) const
|
|
{
|
|
// TestReg -> Expected application register value (defined in regvalues.h).
|
|
// Contains all the registers in the TestReg enum.
|
|
static const unsigned char* const appRegisterValues[TESTREGSIZE] =
|
|
{
|
|
gprval,
|
|
#if defined(TARGET_IA32E)
|
|
gpr32val,
|
|
#endif
|
|
gpr16val, gprlval, gprhval, stval,
|
|
xmmval, ymmval, zmmval, opmaskval
|
|
};
|
|
return reinterpret_cast<const UINT8*>(appRegisterValues[_regToTestReg.find(reg)->second]);
|
|
}
|
|
|
|
const UINT8* RegisterDB::_GetToolRegisterValue(REG reg) const
|
|
{
|
|
// TestReg -> Value loaded by the tool (defined in regvalues.h).
|
|
// Contains all the registers in the TestReg enum.
|
|
static const unsigned char* const toolRegisterValues[TESTREGSIZE] =
|
|
{
|
|
tgprval,
|
|
#if defined(TARGET_IA32E)
|
|
tgpr32val,
|
|
#endif
|
|
tgpr16val, tgprlval, tgprhval, tstval,
|
|
txmmval, tymmval, tzmmval, topmaskval
|
|
};
|
|
return reinterpret_cast<const UINT8*>(toolRegisterValues[_regToTestReg.find(reg)->second]);
|
|
}
|
|
|
|
void RegisterDB::Verify(REG reg) const
|
|
{
|
|
assert(_testRegset.Contains(reg));
|
|
}
|
|
|
|
void RegisterDB::PrintRegval(REG reg, ostream& ost) const
|
|
{
|
|
ost << REG_StringShort(reg) << " = " << Val2Str(_regvalMap.find(reg)->second, REG_Size(reg)) << endl << flush;
|
|
}
|
|
|
|
void RegisterDB::DefineActiveRegister(TestReg testReg)
|
|
{
|
|
REG reg = _GetRegFromTestReg(testReg);
|
|
_testRegs.push_back(reg);
|
|
_regToTestReg[reg] = testReg;
|
|
REGSET_Insert(_testRegset, reg);
|
|
|
|
// This singleton will reside in memory as long as the tool is running. So we don't bother with freeing the
|
|
// memory since the OS will do it when the process terminates.
|
|
_regvalMap[reg] = new UINT8[REG_Size(reg)];
|
|
}
|
|
|
|
void RegisterDB::InitializeDB()
|
|
{
|
|
REGSET_Clear(_testRegset);
|
|
DefineActiveRegister(GPRREG); // Always tested
|
|
if (KnobTestPartial.Value())
|
|
{
|
|
#if defined(TARGET_IA32E)
|
|
DefineActiveRegister(GPR32REG);
|
|
#endif
|
|
DefineActiveRegister(GPR16REG);
|
|
DefineActiveRegister(GPRLREG);
|
|
DefineActiveRegister(GPRHREG);
|
|
}
|
|
if (KnobTestSt.Value())
|
|
{
|
|
DefineActiveRegister(STREG);
|
|
}
|
|
if (KnobTestSIMD.Value())
|
|
{
|
|
DefineActiveRegister(XMMREG);
|
|
if (hasAvxSupport)
|
|
{
|
|
DefineActiveRegister(YMMREG);
|
|
}
|
|
|
|
if (hasAvx512fSupport)
|
|
{
|
|
DefineActiveRegister(ZMMREG);
|
|
DefineActiveRegister(OPMASKREG);
|
|
}
|
|
}
|
|
_numOfTestRegs = _testRegs.size();
|
|
}
|
|
|
|
|
|
/////////////////////
|
|
// GLOBAL VARIABLES
|
|
/////////////////////
|
|
|
|
// A knob for specifying whether x87 fpstate registers should be tested.
|
|
KNOB<bool> KnobTestSt(KNOB_MODE_WRITEONCE, "pintool", "test_st", "1",
|
|
"specify whether x87 fpstate registers should be tested");
|
|
|
|
// A knob for specifying whether partial registers should be tested.
|
|
KNOB<bool> KnobTestPartial(KNOB_MODE_WRITEONCE, "pintool", "test_partial", "1",
|
|
"specify whether partial registers should be tested");
|
|
|
|
// A knob for specifying whether the SIMD registers should be tested.
|
|
KNOB<bool> KnobTestSIMD(KNOB_MODE_WRITEONCE, "pintool", "test_simd", "1",
|
|
"specify whether the SIMD registers should be tested");
|
|
|
|
|
|
/////////////////////
|
|
// API FUNCTIONS IMPLEMENTATION
|
|
/////////////////////
|
|
|
|
const vector<REG>& GetTestRegs()
|
|
{
|
|
return RegisterDB::Instance()->GetTestRegs();
|
|
}
|
|
|
|
const REGSET& GetTestRegset()
|
|
{
|
|
return RegisterDB::Instance()->GetTestRegset();
|
|
}
|
|
|
|
void PrintStoredRegisters(ostream& ost)
|
|
{
|
|
RegisterDB::Instance()->PrintStoredRegisters(ost);
|
|
}
|
|
|
|
UINT8* GetRegval(REG reg)
|
|
{
|
|
return RegisterDB::Instance()->GetRegval(reg);
|
|
}
|
|
|
|
const UINT8* GetAppRegisterValue(REG reg)
|
|
{
|
|
return RegisterDB::Instance()->GetAppRegisterValue(reg);
|
|
}
|
|
|
|
const UINT8* GetToolRegisterValue(REG reg)
|
|
{
|
|
return RegisterDB::Instance()->GetToolRegisterValue(reg);
|
|
}
|
|
|
|
bool CheckAllExpectedValues(ostream& ost)
|
|
{
|
|
bool success = true;
|
|
const vector<REG>& regs = GetTestRegs();
|
|
int numOfRegs = regs.size();
|
|
for (int r = 0; r < numOfRegs; ++r)
|
|
{
|
|
REG reg = regs[r];
|
|
success &= CompareValues(GetRegval(reg), GetAppRegisterValue(reg), REG_Size(reg), ost);
|
|
}
|
|
return success;
|
|
}
|