Add support for CSSC instructions (#69)
Add support for CSSC instructions (abs, cnt, ctz, smax, smin, umax, umin) to all
components, and refactor some of the code nearby.
diff --git a/src/aarch64/assembler-aarch64.cc b/src/aarch64/assembler-aarch64.cc
index df17813..604ec46 100644
--- a/src/aarch64/assembler-aarch64.cc
+++ b/src/aarch64/assembler-aarch64.cc
@@ -2429,6 +2429,52 @@
Emit(0x19c02400 | Rd(rd) | Rn(rn) | Rs(rs));
}
+void Assembler::abs(const Register& rd, const Register& rn) {
+ VIXL_ASSERT(CPUHas(CPUFeatures::kCSSC));
+ VIXL_ASSERT(rd.IsSameSizeAndType(rn));
+
+ Emit(0x5ac02000 | SF(rd) | Rd(rd) | Rn(rn));
+}
+
+void Assembler::cnt(const Register& rd, const Register& rn) {
+ VIXL_ASSERT(CPUHas(CPUFeatures::kCSSC));
+ VIXL_ASSERT(rd.IsSameSizeAndType(rn));
+
+ Emit(0x5ac01c00 | SF(rd) | Rd(rd) | Rn(rn));
+}
+
+void Assembler::ctz(const Register& rd, const Register& rn) {
+ VIXL_ASSERT(CPUHas(CPUFeatures::kCSSC));
+ VIXL_ASSERT(rd.IsSameSizeAndType(rn));
+
+ Emit(0x5ac01800 | SF(rd) | Rd(rd) | Rn(rn));
+}
+
+#define MINMAX(V) \
+ V(smax, 0x11c00000, 0x1ac06000, true) \
+ V(smin, 0x11c80000, 0x1ac06800, true) \
+ V(umax, 0x11c40000, 0x1ac06400, false) \
+ V(umin, 0x11cc0000, 0x1ac06c00, false)
+
+#define VIXL_DEFINE_ASM_FUNC(FN, IMMOP, REGOP, SIGNED) \
+ void Assembler::FN(const Register& rd, \
+ const Register& rn, \
+ const Operand& op) { \
+ VIXL_ASSERT(rd.IsSameSizeAndType(rn)); \
+ Instr i = SF(rd) | Rd(rd) | Rn(rn); \
+ if (op.IsImmediate()) { \
+ int64_t imm = op.GetImmediate(); \
+ i |= SIGNED ? ImmField<17, 10>(imm) : ImmUnsignedField<17, 10>(imm); \
+ Emit(IMMOP | i); \
+ } else { \
+ VIXL_ASSERT(op.IsPlainRegister()); \
+ VIXL_ASSERT(op.GetRegister().IsSameSizeAndType(rd)); \
+ Emit(REGOP | i | Rm(op.GetRegister())); \
+ } \
+ }
+MINMAX(VIXL_DEFINE_ASM_FUNC)
+#undef VIXL_DEFINE_ASM_FUNC
+
// NEON structure loads and stores.
Instr Assembler::LoadStoreStructAddrModeField(const MemOperand& addr) {
Instr addr_field = RnSP(addr.GetBaseRegister());
diff --git a/src/aarch64/assembler-aarch64.h b/src/aarch64/assembler-aarch64.h
index 0d0387f..fbf5a84 100644
--- a/src/aarch64/assembler-aarch64.h
+++ b/src/aarch64/assembler-aarch64.h
@@ -7050,6 +7050,27 @@
// Memory Set, non-temporal.
void setpn(const Register& rd, const Register& rn, const Register& rs);
+ // Absolute value.
+ void abs(const Register& rd, const Register& rn);
+
+ // Count bits.
+ void cnt(const Register& rd, const Register& rn);
+
+ // Count Trailing Zeros.
+ void ctz(const Register& rd, const Register& rn);
+
+ // Signed Maximum.
+ void smax(const Register& rd, const Register& rn, const Operand& op);
+
+ // Signed Minimum.
+ void smin(const Register& rd, const Register& rn, const Operand& op);
+
+ // Unsigned Maximum.
+ void umax(const Register& rd, const Register& rn, const Operand& op);
+
+ // Unsigned Minimum.
+ void umin(const Register& rd, const Register& rn, const Operand& op);
+
// Emit generic instructions.
// Emit raw instructions into the instruction stream.
diff --git a/src/aarch64/cpu-aarch64.cc b/src/aarch64/cpu-aarch64.cc
index fba0dfd..3b70cfc 100644
--- a/src/aarch64/cpu-aarch64.cc
+++ b/src/aarch64/cpu-aarch64.cc
@@ -81,6 +81,8 @@
const IDRegister::Field AA64ISAR2::kWFXT(0);
const IDRegister::Field AA64ISAR2::kRPRES(4);
+const IDRegister::Field AA64ISAR2::kMOPS(16);
+const IDRegister::Field AA64ISAR2::kCSSC(52);
const IDRegister::Field AA64MMFR0::kECV(60);
@@ -195,6 +197,8 @@
CPUFeatures f;
if (Get(kWFXT) >= 2) f.Combine(CPUFeatures::kWFXT);
if (Get(kRPRES) >= 1) f.Combine(CPUFeatures::kRPRES);
+ if (Get(kMOPS) >= 1) f.Combine(CPUFeatures::kMOPS);
+ if (Get(kCSSC) >= 1) f.Combine(CPUFeatures::kCSSC);
return f;
}
diff --git a/src/aarch64/cpu-aarch64.h b/src/aarch64/cpu-aarch64.h
index 7ec3a25..d5a5f8c 100644
--- a/src/aarch64/cpu-aarch64.h
+++ b/src/aarch64/cpu-aarch64.h
@@ -171,6 +171,8 @@
private:
static const Field kWFXT;
static const Field kRPRES;
+ static const Field kMOPS;
+ static const Field kCSSC;
};
class AA64MMFR0 : public IDRegister {
diff --git a/src/aarch64/cpu-features-auditor-aarch64.cc b/src/aarch64/cpu-features-auditor-aarch64.cc
index 1adb37c..e426932 100644
--- a/src/aarch64/cpu-features-auditor-aarch64.cc
+++ b/src/aarch64/cpu-features-auditor-aarch64.cc
@@ -1800,6 +1800,28 @@
{"setm_set_memcms"_h, CPUFeatures::kMOPS},
{"setpn_set_memcms"_h, CPUFeatures::kMOPS},
{"setp_set_memcms"_h, CPUFeatures::kMOPS},
+ {"abs_32_dp_1src"_h, CPUFeatures::kCSSC},
+ {"abs_64_dp_1src"_h, CPUFeatures::kCSSC},
+ {"cnt_32_dp_1src"_h, CPUFeatures::kCSSC},
+ {"cnt_64_dp_1src"_h, CPUFeatures::kCSSC},
+ {"ctz_32_dp_1src"_h, CPUFeatures::kCSSC},
+ {"ctz_64_dp_1src"_h, CPUFeatures::kCSSC},
+ {"smax_32_dp_2src"_h, CPUFeatures::kCSSC},
+ {"smax_64_dp_2src"_h, CPUFeatures::kCSSC},
+ {"smin_32_dp_2src"_h, CPUFeatures::kCSSC},
+ {"smin_64_dp_2src"_h, CPUFeatures::kCSSC},
+ {"umax_32_dp_2src"_h, CPUFeatures::kCSSC},
+ {"umax_64_dp_2src"_h, CPUFeatures::kCSSC},
+ {"umin_32_dp_2src"_h, CPUFeatures::kCSSC},
+ {"umin_64_dp_2src"_h, CPUFeatures::kCSSC},
+ {"smax_32_minmax_imm"_h, CPUFeatures::kCSSC},
+ {"smax_64_minmax_imm"_h, CPUFeatures::kCSSC},
+ {"smin_32_minmax_imm"_h, CPUFeatures::kCSSC},
+ {"smin_64_minmax_imm"_h, CPUFeatures::kCSSC},
+ {"umax_32u_minmax_imm"_h, CPUFeatures::kCSSC},
+ {"umax_64u_minmax_imm"_h, CPUFeatures::kCSSC},
+ {"umin_32u_minmax_imm"_h, CPUFeatures::kCSSC},
+ {"umin_64u_minmax_imm"_h, CPUFeatures::kCSSC},
};
if (features.count(form_hash) > 0) {
diff --git a/src/aarch64/disasm-aarch64.cc b/src/aarch64/disasm-aarch64.cc
index 24d20df..3592752 100644
--- a/src/aarch64/disasm-aarch64.cc
+++ b/src/aarch64/disasm-aarch64.cc
@@ -730,6 +730,28 @@
{"setm_set_memcms"_h, &Disassembler::DisassembleSet},
{"setpn_set_memcms"_h, &Disassembler::DisassembleSet},
{"setp_set_memcms"_h, &Disassembler::DisassembleSet},
+ {"abs_32_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},
+ {"abs_64_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},
+ {"cnt_32_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},
+ {"cnt_64_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},
+ {"ctz_32_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},
+ {"ctz_64_dp_1src"_h, &Disassembler::VisitDataProcessing1Source},
+ {"smax_32_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},
+ {"smax_64_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},
+ {"smin_32_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},
+ {"smin_64_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},
+ {"umax_32_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},
+ {"umax_64_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},
+ {"umin_32_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},
+ {"umin_64_dp_2src"_h, &Disassembler::VisitDataProcessing2Source},
+ {"smax_32_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},
+ {"smax_64_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},
+ {"smin_32_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},
+ {"smin_64_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},
+ {"umax_32u_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},
+ {"umax_64u_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},
+ {"umin_32u_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},
+ {"umin_64u_minmax_imm"_h, &Disassembler::DisassembleMinMaxImm},
};
return &form_to_visitor;
} // NOLINT(readability/fn_size)
@@ -1416,6 +1438,10 @@
Format(instr, mnemonic, form);
}
+void Disassembler::DisassembleMinMaxImm(const Instruction *instr) {
+ const char *suffix = (instr->ExtractBit(18) == 0) ? "'s1710" : "'u1710";
+ FormatWithDecodedMnemonic(instr, "'Rd, 'Rn, #", suffix);
+}
void Disassembler::VisitCompareBranch(const Instruction *instr) {
FormatWithDecodedMnemonic(instr, "'Rt, 'TImmCmpa");
diff --git a/src/aarch64/disasm-aarch64.h b/src/aarch64/disasm-aarch64.h
index 3345174..cc941bb 100644
--- a/src/aarch64/disasm-aarch64.h
+++ b/src/aarch64/disasm-aarch64.h
@@ -186,6 +186,7 @@
void DisassembleCpy(const Instruction* instr);
void DisassembleSet(const Instruction* instr);
+ void DisassembleMinMaxImm(const Instruction* instr);
void DisassembleSVEShiftLeftImm(const Instruction* instr);
void DisassembleSVEShiftRightImm(const Instruction* instr);
diff --git a/src/aarch64/macro-assembler-aarch64.cc b/src/aarch64/macro-assembler-aarch64.cc
index a48931b..94e153a 100644
--- a/src/aarch64/macro-assembler-aarch64.cc
+++ b/src/aarch64/macro-assembler-aarch64.cc
@@ -1411,6 +1411,33 @@
Add(rd, rn, operand, SetFlags);
}
+#define MINMAX(V) \
+ V(Smax, smax, IsInt8) \
+ V(Smin, smin, IsInt8) \
+ V(Umax, umax, IsUint8) \
+ V(Umin, umin, IsUint8)
+
+#define VIXL_DEFINE_MASM_FUNC(MASM, ASM, RANGE) \
+ void MacroAssembler::MASM(const Register& rd, \
+ const Register& rn, \
+ const Operand& op) { \
+ VIXL_ASSERT(allow_macro_instructions_); \
+ if (op.IsImmediate()) { \
+ int64_t imm = op.GetImmediate(); \
+ if (!RANGE(imm)) { \
+ UseScratchRegisterScope temps(this); \
+ Register temp = temps.AcquireSameSizeAs(rd); \
+ Mov(temp, imm); \
+ MASM(rd, rn, temp); \
+ return; \
+ } \
+ } \
+ SingleEmissionCheckScope guard(this); \
+ ASM(rd, rn, op); \
+ }
+MINMAX(VIXL_DEFINE_MASM_FUNC)
+#undef VIXL_DEFINE_MASM_FUNC
+
void MacroAssembler::St2g(const Register& rt, const MemOperand& addr) {
VIXL_ASSERT(allow_macro_instructions_);
SingleEmissionCheckScope guard(this);
diff --git a/src/aarch64/macro-assembler-aarch64.h b/src/aarch64/macro-assembler-aarch64.h
index f0663ee..78c9e9a 100644
--- a/src/aarch64/macro-assembler-aarch64.h
+++ b/src/aarch64/macro-assembler-aarch64.h
@@ -7777,6 +7777,29 @@
MOPS_LIST(DEFINE_MACRO_ASM_FUNC)
#undef DEFINE_MACRO_ASM_FUNC
+ void Abs(const Register& rd, const Register& rn) {
+ VIXL_ASSERT(allow_macro_instructions_);
+ SingleEmissionCheckScope guard(this);
+ abs(rd, rn);
+ }
+
+ void Cnt(const Register& rd, const Register& rn) {
+ VIXL_ASSERT(allow_macro_instructions_);
+ SingleEmissionCheckScope guard(this);
+ cnt(rd, rn);
+ }
+
+ void Ctz(const Register& rd, const Register& rn) {
+ VIXL_ASSERT(allow_macro_instructions_);
+ SingleEmissionCheckScope guard(this);
+ ctz(rd, rn);
+ }
+
+ void Smax(const Register& rd, const Register& rn, const Operand& op);
+ void Smin(const Register& rd, const Register& rn, const Operand& op);
+ void Umax(const Register& rd, const Register& rn, const Operand& op);
+ void Umin(const Register& rd, const Register& rn, const Operand& op);
+
template <typename T>
Literal<T>* CreateLiteralDestroyedWithPool(T value) {
return new Literal<T>(value,
diff --git a/src/aarch64/simulator-aarch64.cc b/src/aarch64/simulator-aarch64.cc
index 275840a..7c7dc1c 100644
--- a/src/aarch64/simulator-aarch64.cc
+++ b/src/aarch64/simulator-aarch64.cc
@@ -468,6 +468,28 @@
{"seten_set_memcms"_h, &Simulator::SimulateSetE},
{"setge_set_memcms"_h, &Simulator::SimulateSetE},
{"setgen_set_memcms"_h, &Simulator::SimulateSetE},
+ {"abs_32_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
+ {"abs_64_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
+ {"cnt_32_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
+ {"cnt_64_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
+ {"ctz_32_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
+ {"ctz_64_dp_1src"_h, &Simulator::VisitDataProcessing1Source},
+ {"smax_32_dp_2src"_h, &Simulator::SimulateSignedMinMax},
+ {"smax_64_dp_2src"_h, &Simulator::SimulateSignedMinMax},
+ {"smin_32_dp_2src"_h, &Simulator::SimulateSignedMinMax},
+ {"smin_64_dp_2src"_h, &Simulator::SimulateSignedMinMax},
+ {"smax_32_minmax_imm"_h, &Simulator::SimulateSignedMinMax},
+ {"smax_64_minmax_imm"_h, &Simulator::SimulateSignedMinMax},
+ {"smin_32_minmax_imm"_h, &Simulator::SimulateSignedMinMax},
+ {"smin_64_minmax_imm"_h, &Simulator::SimulateSignedMinMax},
+ {"umax_32_dp_2src"_h, &Simulator::SimulateUnsignedMinMax},
+ {"umax_64_dp_2src"_h, &Simulator::SimulateUnsignedMinMax},
+ {"umin_32_dp_2src"_h, &Simulator::SimulateUnsignedMinMax},
+ {"umin_64_dp_2src"_h, &Simulator::SimulateUnsignedMinMax},
+ {"umax_32u_minmax_imm"_h, &Simulator::SimulateUnsignedMinMax},
+ {"umax_64u_minmax_imm"_h, &Simulator::SimulateUnsignedMinMax},
+ {"umin_32u_minmax_imm"_h, &Simulator::SimulateUnsignedMinMax},
+ {"umin_64u_minmax_imm"_h, &Simulator::SimulateUnsignedMinMax},
};
return &form_to_visitor;
}
@@ -5225,112 +5247,102 @@
}
-#define PAUTH_MODES_REGISTER_CONTEXT(V) \
- V(IA, kPACKeyIA, kInstructionPointer) \
- V(IB, kPACKeyIB, kInstructionPointer) \
- V(DA, kPACKeyDA, kDataPointer) \
- V(DB, kPACKeyDB, kDataPointer)
-
-#define PAUTH_MODES_ZERO_CONTEXT(V) \
- V(IZA, kPACKeyIA, kInstructionPointer) \
- V(IZB, kPACKeyIB, kInstructionPointer) \
- V(DZA, kPACKeyDA, kDataPointer) \
- V(DZB, kPACKeyDB, kDataPointer)
+#define PAUTH_MODES_REGISTER_CONTEXT(V) \
+ V(i, a, kPACKeyIA, kInstructionPointer) \
+ V(i, b, kPACKeyIB, kInstructionPointer) \
+ V(d, a, kPACKeyDA, kDataPointer) \
+ V(d, b, kPACKeyDB, kDataPointer)
void Simulator::VisitDataProcessing1Source(const Instruction* instr) {
unsigned dst = instr->GetRd();
unsigned src = instr->GetRn();
+ Reg31Mode r31_pac = Reg31IsStackPointer;
- switch (instr->Mask(DataProcessing1SourceMask)) {
-#define DEFINE_PAUTH_FUNCS(SUFFIX, KEY, D) \
- case PAC##SUFFIX: { \
- uint64_t mod = ReadXRegister(src, Reg31IsStackPointer); \
- uint64_t ptr = ReadXRegister(dst); \
- WriteXRegister(dst, AddPAC(ptr, mod, KEY, D)); \
- break; \
- } \
- case AUT##SUFFIX: { \
- uint64_t mod = ReadXRegister(src, Reg31IsStackPointer); \
- uint64_t ptr = ReadXRegister(dst); \
- WriteXRegister(dst, AuthPAC(ptr, mod, KEY, D)); \
- break; \
+ switch (form_hash_) {
+#define DEFINE_PAUTH_FUNCS(SUF0, SUF1, KEY, D) \
+ case "pac" #SUF0 "z" #SUF1 "_64z_dp_1src"_h: \
+ VIXL_ASSERT(src == kZeroRegCode); \
+ r31_pac = Reg31IsZeroRegister; \
+ VIXL_FALLTHROUGH(); \
+ case "pac" #SUF0 #SUF1 "_64p_dp_1src"_h: { \
+ uint64_t mod = ReadXRegister(src, r31_pac); \
+ uint64_t ptr = ReadXRegister(dst); \
+ WriteXRegister(dst, AddPAC(ptr, mod, KEY, D)); \
+ break; \
+ } \
+ case "aut" #SUF0 "z" #SUF1 "_64z_dp_1src"_h: \
+ VIXL_ASSERT(src == kZeroRegCode); \
+ r31_pac = Reg31IsZeroRegister; \
+ VIXL_FALLTHROUGH(); \
+ case "aut" #SUF0 #SUF1 "_64p_dp_1src"_h: { \
+ uint64_t mod = ReadXRegister(src, r31_pac); \
+ uint64_t ptr = ReadXRegister(dst); \
+ WriteXRegister(dst, AuthPAC(ptr, mod, KEY, D)); \
+ break; \
}
-
PAUTH_MODES_REGISTER_CONTEXT(DEFINE_PAUTH_FUNCS)
#undef DEFINE_PAUTH_FUNCS
-#define DEFINE_PAUTH_FUNCS(SUFFIX, KEY, D) \
- case PAC##SUFFIX: { \
- if (src != kZeroRegCode) { \
- VIXL_UNIMPLEMENTED(); \
- } \
- uint64_t ptr = ReadXRegister(dst); \
- WriteXRegister(dst, AddPAC(ptr, 0x0, KEY, D)); \
- break; \
- } \
- case AUT##SUFFIX: { \
- if (src != kZeroRegCode) { \
- VIXL_UNIMPLEMENTED(); \
- } \
- uint64_t ptr = ReadXRegister(dst); \
- WriteXRegister(dst, AuthPAC(ptr, 0x0, KEY, D)); \
- break; \
- }
-
- PAUTH_MODES_ZERO_CONTEXT(DEFINE_PAUTH_FUNCS)
-#undef DEFINE_PAUTH_FUNCS
-
- case XPACI:
- if (src != kZeroRegCode) {
- VIXL_UNIMPLEMENTED();
- }
+ case "xpaci_64z_dp_1src"_h:
WriteXRegister(dst, StripPAC(ReadXRegister(dst), kInstructionPointer));
break;
- case XPACD:
- if (src != kZeroRegCode) {
- VIXL_UNIMPLEMENTED();
- }
+ case "xpacd_64z_dp_1src"_h:
WriteXRegister(dst, StripPAC(ReadXRegister(dst), kDataPointer));
break;
- case RBIT_w:
+ case "rbit_32_dp_1src"_h:
WriteWRegister(dst, ReverseBits(ReadWRegister(src)));
break;
- case RBIT_x:
+ case "rbit_64_dp_1src"_h:
WriteXRegister(dst, ReverseBits(ReadXRegister(src)));
break;
- case REV16_w:
+ case "rev16_32_dp_1src"_h:
WriteWRegister(dst, ReverseBytes(ReadWRegister(src), 1));
break;
- case REV16_x:
+ case "rev16_64_dp_1src"_h:
WriteXRegister(dst, ReverseBytes(ReadXRegister(src), 1));
break;
- case REV_w:
+ case "rev_32_dp_1src"_h:
WriteWRegister(dst, ReverseBytes(ReadWRegister(src), 2));
break;
- case REV32_x:
+ case "rev32_64_dp_1src"_h:
WriteXRegister(dst, ReverseBytes(ReadXRegister(src), 2));
break;
- case REV_x:
+ case "rev_64_dp_1src"_h:
WriteXRegister(dst, ReverseBytes(ReadXRegister(src), 3));
break;
- case CLZ_w:
+ case "clz_32_dp_1src"_h:
WriteWRegister(dst, CountLeadingZeros(ReadWRegister(src)));
break;
- case CLZ_x:
+ case "clz_64_dp_1src"_h:
WriteXRegister(dst, CountLeadingZeros(ReadXRegister(src)));
break;
- case CLS_w:
+ case "cls_32_dp_1src"_h:
WriteWRegister(dst, CountLeadingSignBits(ReadWRegister(src)));
break;
- case CLS_x:
+ case "cls_64_dp_1src"_h:
WriteXRegister(dst, CountLeadingSignBits(ReadXRegister(src)));
break;
- default:
- VIXL_UNIMPLEMENTED();
+ case "abs_32_dp_1src"_h:
+ WriteWRegister(dst, Abs(ReadWRegister(src)));
+ break;
+ case "abs_64_dp_1src"_h:
+ WriteXRegister(dst, Abs(ReadXRegister(src)));
+ break;
+ case "cnt_32_dp_1src"_h:
+ WriteWRegister(dst, CountSetBits(ReadWRegister(src)));
+ break;
+ case "cnt_64_dp_1src"_h:
+ WriteXRegister(dst, CountSetBits(ReadXRegister(src)));
+ break;
+ case "ctz_32_dp_1src"_h:
+ WriteWRegister(dst, CountTrailingZeros(ReadWRegister(src)));
+ break;
+ case "ctz_64_dp_1src"_h:
+ WriteXRegister(dst, CountTrailingZeros(ReadXRegister(src)));
+ break;
}
}
-
uint32_t Simulator::Poly32Mod2(unsigned n, uint64_t data, uint32_t poly) {
VIXL_ASSERT((n > 32) && (n <= 64));
for (unsigned i = (n - 1); i >= 32; i--) {
@@ -5507,6 +5519,81 @@
WriteRegister(reg_size, instr->GetRd(), result);
}
+void Simulator::SimulateSignedMinMax(const Instruction* instr) {
+ int32_t wn = ReadWRegister(instr->GetRn());
+ int32_t wm = ReadWRegister(instr->GetRm());
+ int64_t xn = ReadXRegister(instr->GetRn());
+ int64_t xm = ReadXRegister(instr->GetRm());
+ int32_t imm = instr->ExtractSignedBits(17, 10);
+ int dst = instr->GetRd();
+
+ switch (form_hash_) {
+ case "smax_64_minmax_imm"_h:
+ case "smin_64_minmax_imm"_h:
+ xm = imm;
+ break;
+ case "smax_32_minmax_imm"_h:
+ case "smin_32_minmax_imm"_h:
+ wm = imm;
+ break;
+ }
+
+ switch (form_hash_) {
+ case "smax_32_minmax_imm"_h:
+ case "smax_32_dp_2src"_h:
+ WriteWRegister(dst, std::max(wn, wm));
+ break;
+ case "smax_64_minmax_imm"_h:
+ case "smax_64_dp_2src"_h:
+ WriteXRegister(dst, std::max(xn, xm));
+ break;
+ case "smin_32_minmax_imm"_h:
+ case "smin_32_dp_2src"_h:
+ WriteWRegister(dst, std::min(wn, wm));
+ break;
+ case "smin_64_minmax_imm"_h:
+ case "smin_64_dp_2src"_h:
+ WriteXRegister(dst, std::min(xn, xm));
+ break;
+ }
+}
+
+void Simulator::SimulateUnsignedMinMax(const Instruction* instr) {
+ uint64_t xn = ReadXRegister(instr->GetRn());
+ uint64_t xm = ReadXRegister(instr->GetRm());
+ uint32_t imm = instr->ExtractBits(17, 10);
+ int dst = instr->GetRd();
+
+ switch (form_hash_) {
+ case "umax_64u_minmax_imm"_h:
+ case "umax_32u_minmax_imm"_h:
+ case "umin_64u_minmax_imm"_h:
+ case "umin_32u_minmax_imm"_h:
+ xm = imm;
+ break;
+ }
+
+ switch (form_hash_) {
+ case "umax_32u_minmax_imm"_h:
+ case "umax_32_dp_2src"_h:
+ xn &= 0xffff'ffff;
+ xm &= 0xffff'ffff;
+ VIXL_FALLTHROUGH();
+ case "umax_64u_minmax_imm"_h:
+ case "umax_64_dp_2src"_h:
+ WriteXRegister(dst, std::max(xn, xm));
+ break;
+ case "umin_32u_minmax_imm"_h:
+ case "umin_32_dp_2src"_h:
+ xn &= 0xffff'ffff;
+ xm &= 0xffff'ffff;
+ VIXL_FALLTHROUGH();
+ case "umin_64u_minmax_imm"_h:
+ case "umin_64_dp_2src"_h:
+ WriteXRegister(dst, std::min(xn, xm));
+ break;
+ }
+}
void Simulator::VisitDataProcessing3Source(const Instruction* instr) {
unsigned reg_size = instr->GetSixtyFourBits() ? kXRegSize : kWRegSize;
diff --git a/src/aarch64/simulator-aarch64.h b/src/aarch64/simulator-aarch64.h
index 1321c4b..c5cc894 100644
--- a/src/aarch64/simulator-aarch64.h
+++ b/src/aarch64/simulator-aarch64.h
@@ -1397,6 +1397,8 @@
void SimulateSetE(const Instruction* instr);
void SimulateSetGP(const Instruction* instr);
void SimulateSetGM(const Instruction* instr);
+ void SimulateSignedMinMax(const Instruction* instr);
+ void SimulateUnsignedMinMax(const Instruction* instr);
// Integer register accessors.
diff --git a/src/cpu-features.h b/src/cpu-features.h
index 962ad52..97eb661 100644
--- a/src/cpu-features.h
+++ b/src/cpu-features.h
@@ -200,7 +200,8 @@
V(kWFXT, "WFXT", "wfxt") \
/* Extended BFloat16 instructions */ \
V(kEBF16, "EBF16", "ebf16") \
- V(kSVE_EBF16, "EBF16 (SVE)", "sveebf16")
+ V(kSVE_EBF16, "EBF16 (SVE)", "sveebf16") \
+ V(kCSSC, "CSSC", "cssc")
// clang-format on
diff --git a/src/utils-vixl.h b/src/utils-vixl.h
index b6c8455..7af9483 100644
--- a/src/utils-vixl.h
+++ b/src/utils-vixl.h
@@ -291,6 +291,17 @@
return ~value + 1;
}
+// An absolute operation for signed integers that is defined for results outside
+// the representable range. Specifically, Abs(MIN_INT) is MIN_INT.
+template <typename T>
+T Abs(T val) {
+ // TODO: this static assertion is for signed integer inputs, as that's the
+ // only type tested. However, the code should work for all numeric inputs.
+ // Remove the assertion and this comment when more tests are available.
+ VIXL_STATIC_ASSERT(std::is_signed<T>::value && std::is_integral<T>::value);
+ return ((val >= -std::numeric_limits<T>::max()) && (val < 0)) ? -val : val;
+}
+
// Convert unsigned to signed numbers in a well-defined way (using two's
// complement representations).
inline int64_t RawbitsToInt64(uint64_t bits) {