Commit 100ec60528 for qemu.org
commit 100ec60528d389a20fa5c4323a2b35a6f5b9fd3c
Author: Richard Henderson <richard.henderson@linaro.org>
Date: Tue Aug 11 16:40:17 2026 -0700
tcg/aarch64: Implement min/max with FEAT_CSSC
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/tcg/aarch64/tcg-target-con-set.h b/tcg/aarch64/tcg-target-con-set.h
index d0622e65fb..dd84a9af58 100644
--- a/tcg/aarch64/tcg-target-con-set.h
+++ b/tcg/aarch64/tcg-target-con-set.h
@@ -24,6 +24,8 @@ C_O1_I2(r, r, rAL)
C_O1_I2(r, r, rC)
C_O1_I2(r, r, ri)
C_O1_I2(r, r, rL)
+C_O1_I2(r, r, rS)
+C_O1_I2(r, r, rU)
C_O1_I2(r, rZ, rA)
C_O1_I2(r, rz, rMZ)
C_O1_I2(r, rz, rz)
diff --git a/tcg/aarch64/tcg-target-con-str.h b/tcg/aarch64/tcg-target-con-str.h
index 48e1722c68..fef75e8a76 100644
--- a/tcg/aarch64/tcg-target-con-str.h
+++ b/tcg/aarch64/tcg-target-con-str.h
@@ -21,4 +21,6 @@ CONST('L', TCG_CT_CONST_LIMM)
CONST('M', TCG_CT_CONST_MONE)
CONST('O', TCG_CT_CONST_ORRI)
CONST('N', TCG_CT_CONST_ANDI)
+CONST('S', TCG_CT_CONST_S8)
+CONST('U', TCG_CT_CONST_U8)
CONST('Z', TCG_CT_CONST_ZERO)
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
index f5c185bbf4..55b3be0b96 100644
--- a/tcg/aarch64/tcg-target.c.inc
+++ b/tcg/aarch64/tcg-target.c.inc
@@ -152,6 +152,8 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
#define TCG_CT_CONST_ORRI 0x1000
#define TCG_CT_CONST_ANDI 0x2000
#define TCG_CT_CONST_CMP 0x4000
+#define TCG_CT_CONST_S8 0x8000
+#define TCG_CT_CONST_U8 0x10000
#define ALL_GENERAL_REGS 0xffffffffu
#define ALL_VECTOR_REGS 0xffffffff00000000ull
@@ -320,6 +322,12 @@ static bool tcg_target_const_match(int64_t val, int ct,
if ((ct & TCG_CT_CONST_LIMM) && is_limm(val)) {
return 1;
}
+ if ((ct & TCG_CT_CONST_S8) && val == (int8_t)val) {
+ return 1;
+ }
+ if ((ct & TCG_CT_CONST_U8) && val == (uint8_t)val) {
+ return 1;
+ }
if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
return 1;
}
@@ -472,6 +480,12 @@ typedef enum {
Iaddsub_imm_SUBI = 0x51000000,
Iaddsub_imm_SUBSI = 0x71000000,
+ /* Min/max immediate instructions. */
+ Iminmax_imm_SMAXI = 0x11c00000,
+ Iminmax_imm_UMAXI = 0x11c40000,
+ Iminmax_imm_SMINI = 0x11c80000,
+ Iminmax_imm_UMINI = 0x11cc0000,
+
/* Bitfield instructions. */
Ibitfield_BFM = 0x33000000,
Ibitfield_SBFM = 0x13000000,
@@ -533,6 +547,10 @@ typedef enum {
Irrr_UMULH = 0x9bc07c00,
Irrr_UDIV = 0x1ac00800,
Irrr_SDIV = 0x1ac00c00,
+ Irrr_SMAX = 0x1ac00600,
+ Irrr_UMAX = 0x1ac00640,
+ Irrr_SMIN = 0x1ac00680,
+ Irrr_UMIN = 0x1ac006c0,
/* Data-processing (3 source) instructions. */
Irrrr_MADD = 0x1b000000,
@@ -737,6 +755,13 @@ static void tcg_out_insn_addsub_imm(TCGContext *s, AArch64Insn insn,
tcg_out32(s, insn | ext << 31 | aimm << 10 | rn << 5 | rd);
}
+static void tcg_out_insn_minmax_imm(TCGContext *s, AArch64Insn insn,
+ TCGType ext, TCGReg rd, TCGReg rn,
+ uint8_t imm)
+{
+ tcg_out32(s, insn | ext << 31 | imm << 10 | rn << 5 | rd);
+}
+
/* This function can be used for both 3.4.2 (Bitfield) and 3.4.4
(Logical immediate). Both insn groups have N, IMMR and IMMS fields
that feed the DecodeBitMasks pseudo function. */
@@ -2592,20 +2617,90 @@ static void tcg_out_set_borrow(TCGContext *s)
TCG_REG_XZR, TCG_REG_XZR, TCG_REG_XZR);
}
+static TCGConstraintSetIndex cset_sminmax(TCGType type, unsigned flags)
+{
+ return cpuinfo & CPUINFO_CSSC ? C_O1_I2(r, r, rS) : C_NotImplemented;
+}
+
+static void tgen_smax(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out_insn(s, rrr, SMAX, type, a0, a1, a2);
+}
+
+static void tgen_smaxi(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out_insn(s, minmax_imm, SMAXI, type, a0, a1, a2);
+}
+
static const TCGOutOpBinary outop_smax = {
- .base.static_constraint = C_NotImplemented,
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_sminmax,
+ .out_rrr = tgen_smax,
+ .out_rri = tgen_smaxi,
};
+static void tgen_smin(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out_insn(s, rrr, SMIN, type, a0, a1, a2);
+}
+
+static void tgen_smini(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out_insn(s, minmax_imm, SMINI, type, a0, a1, a2);
+}
+
static const TCGOutOpBinary outop_smin = {
- .base.static_constraint = C_NotImplemented,
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_sminmax,
+ .out_rrr = tgen_smin,
+ .out_rri = tgen_smini,
};
+static TCGConstraintSetIndex cset_uminmax(TCGType type, unsigned flags)
+{
+ return cpuinfo & CPUINFO_CSSC ? C_O1_I2(r, r, rU) : C_NotImplemented;
+}
+
+static void tgen_umax(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out_insn(s, rrr, UMAX, type, a0, a1, a2);
+}
+
+static void tgen_umaxi(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out_insn(s, minmax_imm, UMAXI, type, a0, a1, a2);
+}
+
static const TCGOutOpBinary outop_umax = {
- .base.static_constraint = C_NotImplemented,
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_uminmax,
+ .out_rrr = tgen_umax,
+ .out_rri = tgen_umaxi,
};
+static void tgen_umin(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out_insn(s, rrr, UMIN, type, a0, a1, a2);
+}
+
+static void tgen_umini(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out_insn(s, minmax_imm, UMINI, type, a0, a1, a2);
+}
+
static const TCGOutOpBinary outop_umin = {
- .base.static_constraint = C_NotImplemented,
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_uminmax,
+ .out_rrr = tgen_umin,
+ .out_rri = tgen_umini,
};
static void tgen_xor(TCGContext *s, TCGType type,