MIPS64r6 Assembler Tests
Assembler tests for:
- SQRT.fmt - ABS.fmt - ROUND.L.fmt - ROUND.W.fmt
- CEIL.L.fmt - CEIL.W.fmt - FLOOR.L.fmt - FLOOR.W.fmt
- SEL.fmt - RINT.fmt - CLASS.fmt - MIN.fmt
- MAX.fmt - cvt.d.l - BITSWAP - DBITSWAP
- DSBH - DSHD - WSBH - ROTR
- SELEQZ - SELNEZ - CLZ - CLO
- DCLZ - DCLO - SC - SCD
- LL - LLD
These are the assembler instructions which were added to support
intrinsic functions on MIPS64. Tests for additional assembler
instructions will follow.
Support added to the testing infrastructure for:
- Assembler instructions which use three registers; previously
instructions were limited to one, or two, registers.
- Immediate values which have their sizes specified by the number of
bits required to store them rather than the number of bytes, in both
signed and unsigned versions.
Change-Id: I38c07dcbf2539825b25bed13aac05a26fa594b0b
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index 017402d..bd994f4 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -92,6 +92,17 @@
fmt);
}
+ std::string RepeatRRR(void (Ass::*f)(Reg, Reg, Reg), std::string fmt) {
+ return RepeatTemplatedRegisters<Reg, Reg, Reg>(f,
+ GetRegisters(),
+ GetRegisters(),
+ GetRegisters(),
+ &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+ &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+ &AssemblerTest::GetRegName<RegisterView::kUsePrimaryName>,
+ fmt);
+ }
+
std::string Repeatrb(void (Ass::*f)(Reg, Reg), std::string fmt) {
return RepeatTemplatedRegisters<Reg, Reg>(f,
GetRegisters(),
@@ -118,6 +129,66 @@
return RepeatRegisterImm<RegisterView::kUseSecondaryName>(f, imm_bytes, fmt);
}
+ template <typename Reg1Type, typename Reg2Type, typename ImmType,
+ RegisterView Reg1View, RegisterView Reg2View>
+ std::string RepeatRegRegImmBits(void (Ass::*f)(Reg1Type, Reg2Type, ImmType),
+ int imm_bits,
+ std::string fmt) {
+ const std::vector<Reg1Type*> reg1_registers = GetRegisters();
+ const std::vector<Reg2Type*> reg2_registers = GetRegisters();
+ std::string str;
+ std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), imm_bits > 0);
+
+ for (auto reg1 : reg1_registers) {
+ for (auto reg2 : reg2_registers) {
+ for (int64_t imm : imms) {
+ ImmType new_imm = CreateImmediate(imm);
+ (assembler_.get()->*f)(*reg1, *reg2, new_imm);
+ std::string base = fmt;
+
+ std::string reg1_string = GetRegName<Reg1View>(*reg1);
+ size_t reg1_index;
+ while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
+ base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
+ }
+
+ std::string reg2_string = GetRegName<Reg2View>(*reg2);
+ size_t reg2_index;
+ while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
+ base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
+ }
+
+ size_t imm_index = base.find(IMM_TOKEN);
+ if (imm_index != std::string::npos) {
+ std::ostringstream sreg;
+ sreg << imm;
+ std::string imm_string = sreg.str();
+ base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string);
+ }
+
+ if (str.size() > 0) {
+ str += "\n";
+ }
+ str += base;
+ }
+ }
+ }
+ // Add a newline at the end.
+ str += "\n";
+ return str;
+ }
+
+ template <typename Reg1Type, typename Reg2Type, typename ImmType>
+ std::string RepeatRRIb(void (Ass::*f)(Reg1Type, Reg2Type, ImmType),
+ int imm_bits,
+ std::string fmt) {
+ return RepeatRegRegImmBits<Reg1Type,
+ Reg2Type,
+ ImmType,
+ RegisterView::kUsePrimaryName,
+ RegisterView::kUsePrimaryName>(f, imm_bits, fmt);
+ }
+
std::string RepeatFF(void (Ass::*f)(FPReg, FPReg), std::string fmt) {
return RepeatTemplatedRegisters<FPReg, FPReg>(f,
GetFPRegisters(),
@@ -127,14 +198,27 @@
fmt);
}
- std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&), size_t imm_bytes, std::string fmt) {
+ std::string RepeatFFF(void (Ass::*f)(FPReg, FPReg, FPReg), std::string fmt) {
+ return RepeatTemplatedRegisters<FPReg, FPReg, FPReg>(f,
+ GetFPRegisters(),
+ GetFPRegisters(),
+ GetFPRegisters(),
+ &AssemblerTest::GetFPRegName,
+ &AssemblerTest::GetFPRegName,
+ &AssemblerTest::GetFPRegName,
+ fmt);
+ }
+
+ std::string RepeatFFI(void (Ass::*f)(FPReg, FPReg, const Imm&),
+ size_t imm_bytes,
+ std::string fmt) {
return RepeatTemplatedRegistersImm<FPReg, FPReg>(f,
- GetFPRegisters(),
- GetFPRegisters(),
- &AssemblerTest::GetFPRegName,
- &AssemblerTest::GetFPRegName,
- imm_bytes,
- fmt);
+ GetFPRegisters(),
+ GetFPRegisters(),
+ &AssemblerTest::GetFPRegName,
+ &AssemblerTest::GetFPRegName,
+ imm_bytes,
+ fmt);
}
std::string RepeatFR(void (Ass::*f)(FPReg, Reg), std::string fmt) {
@@ -339,6 +423,63 @@
return res;
}
+ const int kMaxBitsExhaustiveTest = 8;
+
+ // Create a couple of immediate values up to the number of bits given.
+ virtual std::vector<int64_t> CreateImmediateValuesBits(const int imm_bits, bool as_uint = false) {
+ CHECK_GT(imm_bits, 0);
+ CHECK_LE(imm_bits, 64);
+ std::vector<int64_t> res;
+
+ if (imm_bits <= kMaxBitsExhaustiveTest) {
+ if (as_uint) {
+ for (uint64_t i = MinInt<uint64_t>(imm_bits); i <= MaxInt<uint64_t>(imm_bits); i++) {
+ res.push_back(static_cast<int64_t>(i));
+ }
+ } else {
+ for (int64_t i = MinInt<int64_t>(imm_bits); i <= MaxInt<int64_t>(imm_bits); i++) {
+ res.push_back(i);
+ }
+ }
+ } else {
+ if (as_uint) {
+ for (uint64_t i = MinInt<uint64_t>(kMaxBitsExhaustiveTest);
+ i <= MaxInt<uint64_t>(kMaxBitsExhaustiveTest);
+ i++) {
+ res.push_back(static_cast<int64_t>(i));
+ }
+ for (int i = 0; i <= imm_bits; i++) {
+ uint64_t j = (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1) +
+ ((MaxInt<uint64_t>(imm_bits) -
+ (MaxInt<uint64_t>(kMaxBitsExhaustiveTest) + 1))
+ * i / imm_bits);
+ res.push_back(static_cast<int64_t>(j));
+ }
+ } else {
+ for (int i = 0; i <= imm_bits; i++) {
+ int64_t j = MinInt<int64_t>(imm_bits) +
+ ((((MinInt<int64_t>(kMaxBitsExhaustiveTest) - 1) -
+ MinInt<int64_t>(imm_bits))
+ * i) / imm_bits);
+ res.push_back(static_cast<int64_t>(j));
+ }
+ for (int64_t i = MinInt<int64_t>(kMaxBitsExhaustiveTest);
+ i <= MaxInt<int64_t>(kMaxBitsExhaustiveTest);
+ i++) {
+ res.push_back(static_cast<int64_t>(i));
+ }
+ for (int i = 0; i <= imm_bits; i++) {
+ int64_t j = (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1) +
+ ((MaxInt<int64_t>(imm_bits) - (MaxInt<int64_t>(kMaxBitsExhaustiveTest) + 1))
+ * i / imm_bits);
+ res.push_back(static_cast<int64_t>(j));
+ }
+ }
+ }
+
+ return res;
+ }
+
// Create an immediate from the specific value.
virtual Imm CreateImmediate(int64_t imm_value) = 0;
@@ -406,6 +547,52 @@
return str;
}
+ template <typename Reg1, typename Reg2, typename Reg3>
+ std::string RepeatTemplatedRegisters(void (Ass::*f)(Reg1, Reg2, Reg3),
+ const std::vector<Reg1*> reg1_registers,
+ const std::vector<Reg2*> reg2_registers,
+ const std::vector<Reg3*> reg3_registers,
+ std::string (AssemblerTest::*GetName1)(const Reg1&),
+ std::string (AssemblerTest::*GetName2)(const Reg2&),
+ std::string (AssemblerTest::*GetName3)(const Reg3&),
+ std::string fmt) {
+ std::string str;
+ for (auto reg1 : reg1_registers) {
+ for (auto reg2 : reg2_registers) {
+ for (auto reg3 : reg3_registers) {
+ (assembler_.get()->*f)(*reg1, *reg2, *reg3);
+ std::string base = fmt;
+
+ std::string reg1_string = (this->*GetName1)(*reg1);
+ size_t reg1_index;
+ while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) {
+ base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string);
+ }
+
+ std::string reg2_string = (this->*GetName2)(*reg2);
+ size_t reg2_index;
+ while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) {
+ base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string);
+ }
+
+ std::string reg3_string = (this->*GetName3)(*reg3);
+ size_t reg3_index;
+ while ((reg3_index = base.find(REG3_TOKEN)) != std::string::npos) {
+ base.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string);
+ }
+
+ if (str.size() > 0) {
+ str += "\n";
+ }
+ str += base;
+ }
+ }
+ }
+ // Add a newline at the end.
+ str += "\n";
+ return str;
+ }
+
template <typename Reg1, typename Reg2>
std::string RepeatTemplatedRegistersImm(void (Ass::*f)(Reg1, Reg2, const Imm&),
const std::vector<Reg1*> reg1_registers,
@@ -500,6 +687,7 @@
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* REG3_TOKEN = "{reg3}";
static constexpr const char* IMM_TOKEN = "{imm}";
private: