ART: Assembler_arm_test
Add some generic test infrastructure, and update the arm32 test.
Supports many of the GPR instructions.
Change-Id: I8a270ec377f3266d6ab486e636abb50c56b87823
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index 9d3fa01..1fadb91 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -38,14 +38,14 @@
// temp directory.
static std::string tmpnam_;
+enum class RegisterView { // private
+ kUsePrimaryName,
+ kUseSecondaryName
+};
+
template<typename Ass, typename Reg, typename FPReg, typename Imm>
class AssemblerTest : public testing::Test {
public:
- enum class RegisterView { // private
- kUsePrimaryName,
- kUseSecondaryName
- };
-
Ass* GetAssembler() {
return assembler_.get();
}
@@ -159,6 +159,9 @@
bool as_uint = false) {
std::string str;
std::vector<int64_t> imms = CreateImmediateValues(imm_bytes, as_uint);
+
+ WarnOnCombinations(imms.size());
+
for (int64_t imm : imms) {
Imm new_imm = CreateImmediate(imm);
(assembler_.get()->*f)(new_imm);
@@ -184,12 +187,12 @@
// This is intended to be run as a test.
bool CheckTools() {
- if (!FileExists(GetAssemblerCommand())) {
+ if (!FileExists(FindTool(GetAssemblerCmdName()))) {
return false;
}
LOG(INFO) << "Chosen assembler command: " << GetAssemblerCommand();
- if (!FileExists(GetObjdumpCommand())) {
+ if (!FileExists(FindTool(GetObjdumpCmdName()))) {
return false;
}
LOG(INFO) << "Chosen objdump command: " << GetObjdumpCommand();
@@ -197,7 +200,7 @@
// Disassembly is optional.
std::string disassembler = GetDisassembleCommand();
if (disassembler.length() != 0) {
- if (!FileExists(disassembler)) {
+ if (!FileExists(FindTool(GetDisassembleCmdName()))) {
return false;
}
LOG(INFO) << "Chosen disassemble command: " << GetDisassembleCommand();
@@ -271,7 +274,7 @@
resolved_assembler_cmd_ = line + GetAssemblerParameters();
- return line;
+ return resolved_assembler_cmd_;
}
// Get the name of the objdump, e.g., "objdump" by default.
@@ -298,7 +301,7 @@
resolved_objdump_cmd_ = line + GetObjdumpParameters();
- return line;
+ return resolved_objdump_cmd_;
}
// Get the name of the objdump, e.g., "objdump" by default.
@@ -324,7 +327,7 @@
resolved_disassemble_cmd_ = line + GetDisassembleParameters();
- return line;
+ return resolved_disassemble_cmd_;
}
// Create a couple of immediate values up to the number of bytes given.
@@ -406,6 +409,8 @@
std::string (AssemblerTest::*GetName1)(const Reg1&),
std::string (AssemblerTest::*GetName2)(const Reg2&),
std::string fmt) {
+ WarnOnCombinations(reg1_registers.size() * reg2_registers.size());
+
std::string str;
for (auto reg1 : reg1_registers) {
for (auto reg2 : reg2_registers) {
@@ -435,7 +440,6 @@
return str;
}
- private:
template <RegisterView kRegView>
std::string GetRegName(const Reg& reg) {
std::ostringstream sreg;
@@ -457,12 +461,32 @@
return sreg.str();
}
+ // If the assembly file needs a header, return it in a sub-class.
+ virtual const char* GetAssemblyHeader() {
+ return nullptr;
+ }
+
+ void WarnOnCombinations(size_t count) {
+ if (count > kWarnManyCombinationsThreshold) {
+ GTEST_LOG_(WARNING) << "Many combinations (" << count << "), test generation might be slow.";
+ }
+ }
+
+ static constexpr const char* REG_TOKEN = "{reg}";
+ static constexpr const char* REG1_TOKEN = "{reg1}";
+ static constexpr const char* REG2_TOKEN = "{reg2}";
+ static constexpr const char* IMM_TOKEN = "{imm}";
+
+ private:
template <RegisterView kRegView>
std::string RepeatRegisterImm(void (Ass::*f)(Reg, const Imm&), size_t imm_bytes,
std::string fmt) {
const std::vector<Reg*> registers = GetRegisters();
std::string str;
std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
+
+ WarnOnCombinations(registers.size() * imms.size());
+
for (auto reg : registers) {
for (int64_t imm : imms) {
Imm new_imm = CreateImmediate(imm);
@@ -547,7 +571,7 @@
// Compile the assembly file from_file to a binary file to_file. Returns true on success.
bool Assemble(const char* from_file, const char* to_file, std::string* error_msg) {
- bool have_assembler = FileExists(GetAssemblerCommand());
+ bool have_assembler = FileExists(FindTool(GetAssemblerCmdName()));
EXPECT_TRUE(have_assembler) << "Cannot find assembler:" << GetAssemblerCommand();
if (!have_assembler) {
return false;
@@ -569,13 +593,20 @@
args.push_back("-c");
args.push_back(cmd);
- return Exec(args, error_msg);
+ bool success = Exec(args, error_msg);
+ if (!success) {
+ LOG(INFO) << "Assembler command line:";
+ for (std::string arg : args) {
+ LOG(INFO) << arg;
+ }
+ }
+ return success;
}
// Runs objdump -h on the binary file and extracts the first line with .text.
// Returns "" on failure.
std::string Objdump(std::string file) {
- bool have_objdump = FileExists(GetObjdumpCommand());
+ bool have_objdump = FileExists(FindTool(GetObjdumpCmdName()));
EXPECT_TRUE(have_objdump) << "Cannot find objdump: " << GetObjdumpCommand();
if (!have_objdump) {
return "";
@@ -652,10 +683,10 @@
// If you want to take a look at the differences between the ART assembler and GCC, comment
// out the removal code.
- std::remove(data_name.c_str());
- std::remove(as_name.c_str());
- std::remove((data_name + ".dis").c_str());
- std::remove((as_name + ".dis").c_str());
+// std::remove(data_name.c_str());
+// std::remove(as_name.c_str());
+// std::remove((data_name + ".dis").c_str());
+// std::remove((as_name + ".dis").c_str());
return result;
}
@@ -714,6 +745,10 @@
// TODO: Lots of error checking.
std::ofstream s_out(res->base_name + ".S");
+ const char* header = GetAssemblyHeader();
+ if (header != nullptr) {
+ s_out << header;
+ }
s_out << assembly_code;
s_out.close();
@@ -862,13 +897,9 @@
return tmpnam_;
}
+ static constexpr size_t kWarnManyCombinationsThreshold = 500;
static constexpr size_t OBJDUMP_SECTION_LINE_MIN_TOKENS = 6;
- static constexpr const char* REG_TOKEN = "{reg}";
- static constexpr const char* REG1_TOKEN = "{reg1}";
- static constexpr const char* REG2_TOKEN = "{reg2}";
- static constexpr const char* IMM_TOKEN = "{imm}";
-
std::unique_ptr<Ass> assembler_;
std::string resolved_assembler_cmd_;