For aarch64, arm, loongarch64, mips, we can drop rotl.
For ppc, s390x we can drop rotr.
Only x86, riscv, tci have both rotl and rotr.
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
/* optional instructions */
#define TCG_TARGET_HAS_bswap16_i32 1
#define TCG_TARGET_HAS_bswap32_i32 1
-#define TCG_TARGET_HAS_rot_i32 1
#define TCG_TARGET_HAS_clz_i32 1
#define TCG_TARGET_HAS_ctz_i32 1
#define TCG_TARGET_HAS_ctpop_i32 0
#define TCG_TARGET_HAS_bswap16_i64 1
#define TCG_TARGET_HAS_bswap32_i64 1
#define TCG_TARGET_HAS_bswap64_i64 1
-#define TCG_TARGET_HAS_rot_i64 1
#define TCG_TARGET_HAS_clz_i64 1
#define TCG_TARGET_HAS_ctz_i64 1
#define TCG_TARGET_HAS_ctpop_i64 0
tcg_out_insn(s, 3403, EXTR, ext, rd, rn, rm, a);
}
-static inline void tcg_out_rotr(TCGContext *s, TCGType ext,
- TCGReg rd, TCGReg rn, unsigned int m)
-{
- int max = ext ? 63 : 31;
- tcg_out_extr(s, ext, rd, rn, rn, m & max);
-}
-
-static inline void tcg_out_rotl(TCGContext *s, TCGType ext,
- TCGReg rd, TCGReg rn, unsigned int m)
-{
- int max = ext ? 63 : 31;
- tcg_out_extr(s, ext, rd, rn, rn, -m & max);
-}
-
static inline void tcg_out_dep(TCGContext *s, TCGType ext, TCGReg rd,
TCGReg rn, unsigned lsb, unsigned width)
{
.out_rrr = tgen_remu,
};
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_rotr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out_insn(s, 3508, RORV, type, a0, a1, a2);
+}
+
+static void tgen_rotri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int max = type == TCG_TYPE_I32 ? 31 : 63;
+ tcg_out_extr(s, type, a0, a1, a1, a2 & max);
+}
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_O1_I2(r, r, ri),
+ .out_rrr = tgen_rotr,
+ .out_rri = tgen_rotri,
+};
+
static void tgen_sar(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3);
break;
- case INDEX_op_rotr_i64:
- case INDEX_op_rotr_i32:
- if (c2) {
- tcg_out_rotr(s, ext, a0, a1, a2);
- } else {
- tcg_out_insn(s, 3508, RORV, ext, a0, a1, a2);
- }
- break;
-
- case INDEX_op_rotl_i64:
- case INDEX_op_rotl_i32:
- if (c2) {
- tcg_out_rotl(s, ext, a0, a1, a2);
- } else {
- tcg_out_insn(s, 3502, SUB, 0, TCG_REG_TMP0, TCG_REG_XZR, a2);
- tcg_out_insn(s, 3508, RORV, ext, a0, a1, TCG_REG_TMP0);
- }
- break;
-
case INDEX_op_clz_i64:
case INDEX_op_clz_i32:
tcg_out_cltz(s, ext, a0, a1, a2, c2, false);
case INDEX_op_negsetcond_i64:
return C_O1_I2(r, r, rC);
- case INDEX_op_rotl_i32:
- case INDEX_op_rotr_i32:
- case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i64:
- return C_O1_I2(r, r, ri);
-
case INDEX_op_clz_i32:
case INDEX_op_ctz_i32:
case INDEX_op_clz_i64:
/* optional instructions */
#define TCG_TARGET_HAS_bswap16_i32 1
#define TCG_TARGET_HAS_bswap32_i32 1
-#define TCG_TARGET_HAS_rot_i32 1
#define TCG_TARGET_HAS_clz_i32 1
#define TCG_TARGET_HAS_ctz_i32 use_armv7_instructions
#define TCG_TARGET_HAS_ctpop_i32 0
.base.static_constraint = C_NotImplemented,
};
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_rotr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV, a0, 0, a1, SHIFT_REG_ROR(a2));
+}
+
+static void tgen_rotri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV, a0, 0, a1, SHIFT_IMM_ROR(a2 & 0x1f));
+}
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_O1_I2(r, r, ri),
+ .out_rrr = tgen_rotr,
+ .out_rri = tgen_rotri,
+};
+
static void tgen_sar(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
case INDEX_op_muls2_i32:
tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]);
break;
- case INDEX_op_rotr_i32:
- c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ROR(args[2] & 0x1f) :
- SHIFT_IMM_LSL(0) : SHIFT_REG_ROR(args[2]);
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c);
- break;
-
- case INDEX_op_rotl_i32:
- if (const_args[2]) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1],
- ((0x20 - args[2]) & 0x1f) ?
- SHIFT_IMM_ROR((0x20 - args[2]) & 0x1f) :
- SHIFT_IMM_LSL(0));
- } else {
- tcg_out_dat_imm(s, COND_AL, ARITH_RSB, TCG_REG_TMP, args[2], 0x20);
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1],
- SHIFT_REG_ROR(TCG_REG_TMP));
- }
- break;
case INDEX_op_ctz_i32:
tcg_out_dat_reg(s, COND_AL, INSN_RBIT, TCG_REG_TMP, 0, args[1], 0);
case INDEX_op_muls2_i32:
return C_O2_I2(r, r, r, r);
- case INDEX_op_rotl_i32:
- case INDEX_op_rotr_i32:
- return C_O1_I2(r, r, ri);
-
case INDEX_op_brcond_i32:
return C_O0_I2(r, rIN);
case INDEX_op_deposit_i32:
#define have_avx512vbmi2 ((cpuinfo & CPUINFO_AVX512VBMI2) && have_avx512vl)
/* optional instructions */
-#define TCG_TARGET_HAS_rot_i32 1
#define TCG_TARGET_HAS_bswap16_i32 1
#define TCG_TARGET_HAS_bswap32_i32 1
#define TCG_TARGET_HAS_clz_i32 1
#if TCG_TARGET_REG_BITS == 64
/* Keep 32-bit values zero-extended in a register. */
#define TCG_TARGET_HAS_extr_i64_i32 1
-#define TCG_TARGET_HAS_rot_i64 1
#define TCG_TARGET_HAS_bswap16_i64 1
#define TCG_TARGET_HAS_bswap32_i64 1
#define TCG_TARGET_HAS_bswap64_i64 1
.base.static_constraint = C_NotImplemented,
};
+static void tgen_rotl(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_ROL, a0);
+}
+
+static void tgen_rotli(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_shifti(s, SHIFT_ROL + rexw, a0, a2);
+}
+
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_O1_I2(r, 0, ci),
+ .out_rrr = tgen_rotl,
+ .out_rri = tgen_rotli,
+};
+
+static void tgen_rotr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_ROR, a0);
+}
+
+static void tgen_rotri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW;
+ tcg_out_shifti(s, SHIFT_ROR + rexw, a0, a2);
+}
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_O1_I2(r, 0, ci),
+ .out_rrr = tgen_rotr,
+ .out_rri = tgen_rotri,
+};
+
static TCGConstraintSetIndex cset_shift(TCGType type, unsigned flags)
{
return have_bmi2 ? C_O1_I2(r, r, ri) : C_O1_I2(r, 0, ci);
const int const_args[TCG_MAX_OP_ARGS])
{
TCGArg a0, a1, a2;
- int c, const_a2, rexw;
+ int const_a2, rexw;
#if TCG_TARGET_REG_BITS == 64
# define OP_32_64(x) \
}
break;
- OP_32_64(rotl):
- c = SHIFT_ROL;
- goto gen_shift;
- OP_32_64(rotr):
- c = SHIFT_ROR;
- goto gen_shift;
- gen_shift:
- if (const_a2) {
- tcg_out_shifti(s, c + rexw, a0, a2);
- } else {
- tcg_out_modrm(s, OPC_SHIFT_cl + rexw, c, a0);
- }
- break;
-
OP_32_64(ctz):
tcg_out_ctz(s, rexw, args[0], args[1], args[2], const_args[2]);
break;
case INDEX_op_st_i64:
return C_O0_I2(re, r);
- case INDEX_op_rotl_i32:
- case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i32:
- case INDEX_op_rotr_i64:
- return C_O1_I2(r, 0, ci);
-
case INDEX_op_brcond_i32:
case INDEX_op_brcond_i64:
return C_O0_I2(r, reT);
/* optional instructions */
#define TCG_TARGET_HAS_negsetcond_i32 0
-#define TCG_TARGET_HAS_rot_i32 1
#define TCG_TARGET_HAS_extract2_i32 0
#define TCG_TARGET_HAS_add2_i32 0
#define TCG_TARGET_HAS_sub2_i32 0
/* 64-bit operations */
#define TCG_TARGET_HAS_negsetcond_i64 0
-#define TCG_TARGET_HAS_rot_i64 1
#define TCG_TARGET_HAS_extract2_i64 0
#define TCG_TARGET_HAS_extr_i64_i32 1
#define TCG_TARGET_HAS_bswap16_i64 1
.out_rrr = tgen_remu,
};
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static void tgen_rotr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_opc_rotr_w(s, a0, a1, a2);
+ } else {
+ tcg_out_opc_rotr_d(s, a0, a1, a2);
+ }
+}
+
+static void tgen_rotri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_opc_rotri_w(s, a0, a1, a2 & 0x1f);
+ } else {
+ tcg_out_opc_rotri_d(s, a0, a1, a2 & 0x3f);
+ }
+}
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_O1_I2(r, r, ri),
+ .out_rrr = tgen_rotr,
+ .out_rri = tgen_rotri,
+};
+
static void tgen_sar(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_clzctz(s, OPC_CTZ_D, a0, a1, a2, c2, false);
break;
- case INDEX_op_rotl_i32:
- /* transform into equivalent rotr/rotri */
- if (c2) {
- tcg_out_opc_rotri_w(s, a0, a1, (32 - a2) & 0x1f);
- } else {
- tcg_out_opc_sub_w(s, TCG_REG_TMP0, TCG_REG_ZERO, a2);
- tcg_out_opc_rotr_w(s, a0, a1, TCG_REG_TMP0);
- }
- break;
- case INDEX_op_rotl_i64:
- /* transform into equivalent rotr/rotri */
- if (c2) {
- tcg_out_opc_rotri_d(s, a0, a1, (64 - a2) & 0x3f);
- } else {
- tcg_out_opc_sub_w(s, TCG_REG_TMP0, TCG_REG_ZERO, a2);
- tcg_out_opc_rotr_d(s, a0, a1, TCG_REG_TMP0);
- }
- break;
-
- case INDEX_op_rotr_i32:
- if (c2) {
- tcg_out_opc_rotri_w(s, a0, a1, a2 & 0x1f);
- } else {
- tcg_out_opc_rotr_w(s, a0, a1, a2);
- }
- break;
- case INDEX_op_rotr_i64:
- if (c2) {
- tcg_out_opc_rotri_d(s, a0, a1, a2 & 0x3f);
- } else {
- tcg_out_opc_rotr_d(s, a0, a1, a2);
- }
- break;
-
case INDEX_op_setcond_i32:
case INDEX_op_setcond_i64:
tcg_out_setcond(s, args[3], a0, a1, a2, c2);
case INDEX_op_qemu_ld_i64:
return C_O1_I1(r, r);
- case INDEX_op_rotl_i32:
- case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i32:
- case INDEX_op_rotr_i64:
- return C_O1_I2(r, r, ri);
-
case INDEX_op_clz_i32:
case INDEX_op_clz_i64:
case INDEX_op_ctz_i32:
/* optional instructions detected at runtime */
#define TCG_TARGET_HAS_extract2_i32 0
-#define TCG_TARGET_HAS_rot_i32 use_mips32r2_instructions
#define TCG_TARGET_HAS_clz_i32 use_mips32r2_instructions
#define TCG_TARGET_HAS_ctz_i32 0
#define TCG_TARGET_HAS_ctpop_i32 0
#define TCG_TARGET_HAS_bswap32_i64 1
#define TCG_TARGET_HAS_bswap64_i64 1
#define TCG_TARGET_HAS_extract2_i64 0
-#define TCG_TARGET_HAS_rot_i64 use_mips32r2_instructions
#define TCG_TARGET_HAS_clz_i64 use_mips32r2_instructions
#define TCG_TARGET_HAS_ctz_i64 0
#define TCG_TARGET_HAS_ctpop_i64 0
.out_rrr = tgen_remu,
};
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static TCGConstraintSetIndex cset_rotr(TCGType type, unsigned flags)
+{
+ return use_mips32r2_instructions ? C_O1_I2(r, r, ri) : C_NotImplemented;
+}
+
+static void tgen_rotr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_ROTRV : OPC_DROTRV;
+ tcg_out_opc_reg(s, insn, a0, a1, a2);
+}
+
+static void tgen_rotri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_opc_sa(s, OPC_ROTR, a0, a1, a2);
+ } else {
+ tcg_out_opc_sa64(s, OPC_DROTR, OPC_DROTR32, a0, a1, a2);
+ }
+}
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_rotr,
+ .out_rrr = tgen_rotr,
+ .out_rri = tgen_rotri,
+};
+
static void tgen_sar(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
const TCGArg args[TCG_MAX_OP_ARGS],
const int const_args[TCG_MAX_OP_ARGS])
{
- MIPSInsn i1, i2;
+ MIPSInsn i1;
TCGArg a0, a1, a2;
- int c2;
a0 = args[0];
a1 = args[1];
a2 = args[2];
- c2 = const_args[2];
switch (opc) {
case INDEX_op_goto_ptr:
tcg_out_dsra(s, a0, a1, 32);
break;
- case INDEX_op_rotr_i32:
- i1 = OPC_ROTRV, i2 = OPC_ROTR;
- if (c2) {
- tcg_out_opc_sa(s, i2, a0, a1, a2);
- break;
- }
- do_shiftv:
- tcg_out_opc_reg(s, i1, a0, a2, a1);
- break;
- case INDEX_op_rotl_i32:
- if (c2) {
- tcg_out_opc_sa(s, OPC_ROTR, a0, a1, 32 - a2);
- } else {
- tcg_out_opc_reg(s, OPC_SUBU, TCG_TMP0, TCG_REG_ZERO, a2);
- tcg_out_opc_reg(s, OPC_ROTRV, a0, TCG_TMP0, a1);
- }
- break;
- case INDEX_op_rotr_i64:
- if (c2) {
- tcg_out_opc_sa64(s, OPC_DROTR, OPC_DROTR32, a0, a1, a2);
- break;
- }
- i1 = OPC_DROTRV;
- goto do_shiftv;
- case INDEX_op_rotl_i64:
- if (c2) {
- tcg_out_opc_sa64(s, OPC_DROTR, OPC_DROTR32, a0, a1, 64 - a2);
- } else {
- tcg_out_opc_reg(s, OPC_DSUBU, TCG_TMP0, TCG_REG_ZERO, a2);
- tcg_out_opc_reg(s, OPC_DROTRV, a0, TCG_TMP0, a1);
- }
- break;
-
case INDEX_op_clz_i32:
tcg_out_clz(s, OPC_CLZ, OPC_CLZ_R6, 32, a0, a1, a2);
break;
case INDEX_op_muls2_i64:
case INDEX_op_mulu2_i64:
return C_O2_I2(r, r, r, r);
- case INDEX_op_rotr_i32:
- case INDEX_op_rotl_i32:
- case INDEX_op_rotr_i64:
- case INDEX_op_rotl_i64:
- return C_O1_I2(r, r, ri);
case INDEX_op_clz_i32:
case INDEX_op_clz_i64:
return C_O1_I2(r, r, rzW);
#define have_vsx (cpuinfo & CPUINFO_VSX)
/* optional instructions */
-#define TCG_TARGET_HAS_rot_i32 1
#define TCG_TARGET_HAS_bswap16_i32 1
#define TCG_TARGET_HAS_bswap32_i32 1
#define TCG_TARGET_HAS_clz_i32 1
#define TCG_TARGET_HAS_add2_i32 0
#define TCG_TARGET_HAS_sub2_i32 0
#define TCG_TARGET_HAS_extr_i64_i32 0
-#define TCG_TARGET_HAS_rot_i64 1
#define TCG_TARGET_HAS_bswap16_i64 1
#define TCG_TARGET_HAS_bswap32_i64 1
#define TCG_TARGET_HAS_bswap64_i64 1
.out_rrr = tgen_remu,
};
+static void tgen_rotl(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out32(s, RLWNM | SAB(a1, a0, a2) | MB(0) | ME(31));
+ } else {
+ tcg_out32(s, RLDCL | SAB(a1, a0, a2) | MB64(0));
+ }
+}
+
+static void tgen_rotli(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ if (type == TCG_TYPE_I32) {
+ tcg_out_rlw(s, RLWINM, a0, a1, a2, 0, 31);
+ } else {
+ tcg_out_rld(s, RLDICL, a0, a1, a2, 0);
+ }
+}
+
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_O1_I2(r, r, ri),
+ .out_rrr = tgen_rotl,
+ .out_rri = tgen_rotli,
+};
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_NotImplemented,
+};
+
static void tgen_sar(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0));
break;
- case INDEX_op_rotl_i32:
- if (const_args[2]) {
- tcg_out_rlw(s, RLWINM, args[0], args[1], args[2], 0, 31);
- } else {
- tcg_out32(s, RLWNM | SAB(args[1], args[0], args[2])
- | MB(0) | ME(31));
- }
- break;
- case INDEX_op_rotr_i32:
- if (const_args[2]) {
- tcg_out_rlw(s, RLWINM, args[0], args[1], 32 - args[2], 0, 31);
- } else {
- tcg_out32(s, SUBFIC | TAI(TCG_REG_R0, args[2], 32));
- tcg_out32(s, RLWNM | SAB(args[1], args[0], TCG_REG_R0)
- | MB(0) | ME(31));
- }
- break;
-
case INDEX_op_brcond_i32:
tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
arg_label(args[3]), TCG_TYPE_I32);
tcg_out_brcond2(s, args, const_args);
break;
- case INDEX_op_rotl_i64:
- if (const_args[2]) {
- tcg_out_rld(s, RLDICL, args[0], args[1], args[2], 0);
- } else {
- tcg_out32(s, RLDCL | SAB(args[1], args[0], args[2]) | MB64(0));
- }
- break;
- case INDEX_op_rotr_i64:
- if (const_args[2]) {
- tcg_out_rld(s, RLDICL, args[0], args[1], 64 - args[2], 0);
- } else {
- tcg_out32(s, SUBFIC | TAI(TCG_REG_R0, args[2], 64));
- tcg_out32(s, RLDCL | SAB(args[1], args[0], TCG_REG_R0) | MB64(0));
- }
- break;
-
case INDEX_op_qemu_ld_i32:
tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32);
break;
case INDEX_op_st_i64:
return C_O0_I2(r, r);
- case INDEX_op_rotl_i32:
- case INDEX_op_rotr_i32:
- case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i64:
- return C_O1_I2(r, r, ri);
-
case INDEX_op_clz_i32:
case INDEX_op_ctz_i32:
case INDEX_op_clz_i64:
/* optional instructions */
#define TCG_TARGET_HAS_negsetcond_i32 1
-#define TCG_TARGET_HAS_rot_i32 (cpuinfo & CPUINFO_ZBB)
#define TCG_TARGET_HAS_extract2_i32 0
#define TCG_TARGET_HAS_add2_i32 1
#define TCG_TARGET_HAS_sub2_i32 1
#define TCG_TARGET_HAS_qemu_st8_i32 0
#define TCG_TARGET_HAS_negsetcond_i64 1
-#define TCG_TARGET_HAS_rot_i64 (cpuinfo & CPUINFO_ZBB)
#define TCG_TARGET_HAS_extract2_i64 0
#define TCG_TARGET_HAS_extr_i64_i32 1
#define TCG_TARGET_HAS_bswap16_i64 (cpuinfo & CPUINFO_ZBB)
.out_rrr = tgen_remu,
};
+static TCGConstraintSetIndex cset_rot(TCGType type, unsigned flags)
+{
+ return cpuinfo & CPUINFO_ZBB ? C_O1_I2(r, r, ri) : C_NotImplemented;
+}
+
+static void tgen_rotr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_RORW : OPC_ROR;
+ tcg_out_opc_reg(s, insn, a0, a1, a2);
+}
+
+static void tgen_rotri(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_RORIW : OPC_RORI;
+ unsigned mask = type == TCG_TYPE_I32 ? 31 : 63;
+ tcg_out_opc_imm(s, insn, a0, a1, a2 & mask);
+}
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_rot,
+ .out_rrr = tgen_rotr,
+ .out_rri = tgen_rotri,
+};
+
+static void tgen_rotl(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_ROLW : OPC_ROL;
+ tcg_out_opc_reg(s, insn, a0, a1, a2);
+}
+
+static void tgen_rotli(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tgen_rotri(s, type, a0, a1, -a2);
+}
+
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_Dynamic,
+ .base.dynamic_constraint = cset_rot,
+ .out_rrr = tgen_rotl,
+ .out_rri = tgen_rotli,
+};
+
static void tgen_sar(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_ldst(s, OPC_SD, a0, a1, a2);
break;
- case INDEX_op_rotl_i32:
- if (c2) {
- tcg_out_opc_imm(s, OPC_RORIW, a0, a1, -a2 & 0x1f);
- } else {
- tcg_out_opc_reg(s, OPC_ROLW, a0, a1, a2);
- }
- break;
- case INDEX_op_rotl_i64:
- if (c2) {
- tcg_out_opc_imm(s, OPC_RORI, a0, a1, -a2 & 0x3f);
- } else {
- tcg_out_opc_reg(s, OPC_ROL, a0, a1, a2);
- }
- break;
-
- case INDEX_op_rotr_i32:
- if (c2) {
- tcg_out_opc_imm(s, OPC_RORIW, a0, a1, a2 & 0x1f);
- } else {
- tcg_out_opc_reg(s, OPC_RORW, a0, a1, a2);
- }
- break;
- case INDEX_op_rotr_i64:
- if (c2) {
- tcg_out_opc_imm(s, OPC_RORI, a0, a1, a2 & 0x3f);
- } else {
- tcg_out_opc_reg(s, OPC_ROR, a0, a1, a2);
- }
- break;
-
case INDEX_op_bswap64_i64:
tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0);
break;
case INDEX_op_negsetcond_i64:
return C_O1_I2(r, r, rI);
- case INDEX_op_rotl_i32:
- case INDEX_op_rotr_i32:
- case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i64:
- return C_O1_I2(r, r, ri);
-
case INDEX_op_clz_i32:
case INDEX_op_clz_i64:
case INDEX_op_ctz_i32:
((s390_facilities[FACILITY_##X / 64] >> (63 - FACILITY_##X % 64)) & 1)
/* optional instructions */
-#define TCG_TARGET_HAS_rot_i32 1
#define TCG_TARGET_HAS_bswap16_i32 1
#define TCG_TARGET_HAS_bswap32_i32 1
#define TCG_TARGET_HAS_clz_i32 0
#define TCG_TARGET_HAS_extr_i64_i32 0
#define TCG_TARGET_HAS_qemu_st8_i32 0
-#define TCG_TARGET_HAS_rot_i64 1
#define TCG_TARGET_HAS_bswap16_i64 1
#define TCG_TARGET_HAS_bswap32_i64 1
#define TCG_TARGET_HAS_bswap64_i64 1
.base.static_constraint = C_NotImplemented,
};
+static void tgen_rotl_int(TCGContext *s, TCGType type, TCGReg dst,
+ TCGReg src, TCGReg v, tcg_target_long i)
+{
+ S390Opcode insn = type == TCG_TYPE_I32 ? RSY_RLL : RSY_RLLG;
+ tcg_out_sh64(s, insn, dst, src, v, i);
+}
+
+static void tgen_rotl(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tgen_rotl_int(s, type, a0, a1, a2, 0);
+}
+
+static void tgen_rotli(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, tcg_target_long a2)
+{
+ tgen_rotl_int(s, type, a0, a1, TCG_REG_NONE, a2);
+}
+
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_O1_I2(r, r, ri),
+ .out_rrr = tgen_rotl,
+ .out_rri = tgen_rotli,
+};
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_NotImplemented,
+};
+
static void tgen_sar_int(TCGContext *s, TCGType type, TCGReg dst,
TCGReg src, TCGReg v, tcg_target_long i)
{
tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
break;
- case INDEX_op_rotl_i32:
- /* ??? Using tcg_out_sh64 here for the format; it is a 32-bit rol. */
- if (const_args[2]) {
- tcg_out_sh64(s, RSY_RLL, args[0], args[1], TCG_REG_NONE, args[2]);
- } else {
- tcg_out_sh64(s, RSY_RLL, args[0], args[1], args[2], 0);
- }
- break;
- case INDEX_op_rotr_i32:
- if (const_args[2]) {
- tcg_out_sh64(s, RSY_RLL, args[0], args[1],
- TCG_REG_NONE, (32 - args[2]) & 31);
- } else {
- tcg_out_insn(s, RR, LCR, TCG_TMP0, args[2]);
- tcg_out_sh64(s, RSY_RLL, args[0], args[1], TCG_TMP0, 0);
- }
- break;
-
case INDEX_op_bswap16_i32:
a0 = args[0], a1 = args[1], a2 = args[2];
tcg_out_insn(s, RRE, LRVR, a0, a1);
tcg_out_insn(s, RRFa, MGRK, args[1], args[2], args[3]);
break;
- case INDEX_op_rotl_i64:
- if (const_args[2]) {
- tcg_out_sh64(s, RSY_RLLG, args[0], args[1],
- TCG_REG_NONE, args[2]);
- } else {
- tcg_out_sh64(s, RSY_RLLG, args[0], args[1], args[2], 0);
- }
- break;
- case INDEX_op_rotr_i64:
- if (const_args[2]) {
- tcg_out_sh64(s, RSY_RLLG, args[0], args[1],
- TCG_REG_NONE, (64 - args[2]) & 63);
- } else {
- /* We can use the smaller 32-bit negate because only the
- low 6 bits are examined for the rotate. */
- tcg_out_insn(s, RR, LCR, TCG_TMP0, args[2]);
- tcg_out_sh64(s, RSY_RLLG, args[0], args[1], TCG_TMP0, 0);
- }
- break;
-
case INDEX_op_add2_i64:
if (const_args[4]) {
if ((int64_t)args[4] >= 0) {
case INDEX_op_st_i64:
return C_O0_I2(r, r);
- case INDEX_op_rotl_i32:
- case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i32:
- case INDEX_op_rotr_i64:
- return C_O1_I2(r, r, ri);
case INDEX_op_setcond_i32:
case INDEX_op_negsetcond_i32:
case INDEX_op_setcond_i64:
#endif
/* optional instructions */
-#define TCG_TARGET_HAS_rot_i32 0
#define TCG_TARGET_HAS_bswap16_i32 0
#define TCG_TARGET_HAS_bswap32_i32 0
#define TCG_TARGET_HAS_clz_i32 0
#define TCG_TARGET_HAS_qemu_st8_i32 0
#define TCG_TARGET_HAS_extr_i64_i32 0
-#define TCG_TARGET_HAS_rot_i64 0
#define TCG_TARGET_HAS_bswap16_i64 0
#define TCG_TARGET_HAS_bswap32_i64 0
#define TCG_TARGET_HAS_bswap64_i64 0
.base.static_constraint = C_NotImplemented,
};
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_NotImplemented,
+};
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_NotImplemented,
+};
+
static void tgen_sar(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
#if TCG_TARGET_REG_BITS == 32
/* Turn some undef macros into false macros. */
#define TCG_TARGET_HAS_extr_i64_i32 0
-#define TCG_TARGET_HAS_rot_i64 0
#define TCG_TARGET_HAS_bswap16_i64 0
#define TCG_TARGET_HAS_bswap32_i64 0
#define TCG_TARGET_HAS_bswap64_i64 0
OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc),
OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems),
OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu),
+ OUTOP(INDEX_op_rotl_i32, TCGOutOpBinary, outop_rotl),
+ OUTOP(INDEX_op_rotl_i64, TCGOutOpBinary, outop_rotl),
+ OUTOP(INDEX_op_rotr_i32, TCGOutOpBinary, outop_rotr),
+ OUTOP(INDEX_op_rotr_i64, TCGOutOpBinary, outop_rotr),
OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar),
OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl),
OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr),
case INDEX_op_negsetcond_i32:
return TCG_TARGET_HAS_negsetcond_i32;
- case INDEX_op_rotl_i32:
- case INDEX_op_rotr_i32:
- return TCG_TARGET_HAS_rot_i32;
case INDEX_op_extract2_i32:
return TCG_TARGET_HAS_extract2_i32;
case INDEX_op_add2_i32:
case INDEX_op_negsetcond_i64:
return TCG_TARGET_HAS_negsetcond_i64;
- case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i64:
- return TCG_TARGET_HAS_rot_i64;
case INDEX_op_extract2_i64:
return TCG_TARGET_HAS_extract2_i64;
case INDEX_op_extrl_i64_i32:
case INDEX_op_orc:
case INDEX_op_rems:
case INDEX_op_remu:
+ case INDEX_op_rotl_i32:
+ case INDEX_op_rotl_i64:
+ case INDEX_op_rotr_i32:
+ case INDEX_op_rotr_i64:
case INDEX_op_sar:
case INDEX_op_shl:
case INDEX_op_shr:
regs[r0] = ((tcg_target_long)regs[r1]
>> (regs[r2] % TCG_TARGET_REG_BITS));
break;
-#if TCG_TARGET_HAS_rot_i32
- case INDEX_op_rotl_i32:
+ case INDEX_op_tci_rotl32:
tci_args_rrr(insn, &r0, &r1, &r2);
regs[r0] = rol32(regs[r1], regs[r2] & 31);
break;
- case INDEX_op_rotr_i32:
+ case INDEX_op_tci_rotr32:
tci_args_rrr(insn, &r0, &r1, &r2);
regs[r0] = ror32(regs[r1], regs[r2] & 31);
break;
-#endif
case INDEX_op_deposit_i32:
tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len);
regs[r0] = deposit32(regs[r1], pos, len, regs[r2]);
/* Shift/rotate operations (64 bit). */
-#if TCG_TARGET_HAS_rot_i64
case INDEX_op_rotl_i64:
tci_args_rrr(insn, &r0, &r1, &r2);
regs[r0] = rol64(regs[r1], regs[r2] & 63);
tci_args_rrr(insn, &r0, &r1, &r2);
regs[r0] = ror64(regs[r1], regs[r2] & 63);
break;
-#endif
case INDEX_op_deposit_i64:
tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len);
regs[r0] = deposit64(regs[r1], pos, len, regs[r2]);
case INDEX_op_shr:
case INDEX_op_sub:
case INDEX_op_xor:
- case INDEX_op_rotl_i32:
case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i32:
case INDEX_op_rotr_i64:
case INDEX_op_clz_i32:
case INDEX_op_clz_i64:
case INDEX_op_tci_divu32:
case INDEX_op_tci_rems32:
case INDEX_op_tci_remu32:
+ case INDEX_op_tci_rotl32:
+ case INDEX_op_tci_rotr32:
tci_args_rrr(insn, &r0, &r1, &r2);
info->fprintf_func(info->stream, "%-12s %s, %s, %s",
op_name, str_r(r0), str_r(r1), str_r(r2));
#define TCG_TARGET_HAS_clz_i32 1
#define TCG_TARGET_HAS_ctz_i32 1
#define TCG_TARGET_HAS_ctpop_i32 1
-#define TCG_TARGET_HAS_rot_i32 1
#define TCG_TARGET_HAS_negsetcond_i32 0
#define TCG_TARGET_HAS_muls2_i32 1
#define TCG_TARGET_HAS_qemu_st8_i32 0
#define TCG_TARGET_HAS_clz_i64 1
#define TCG_TARGET_HAS_ctz_i64 1
#define TCG_TARGET_HAS_ctpop_i64 1
-#define TCG_TARGET_HAS_rot_i64 1
#define TCG_TARGET_HAS_negsetcond_i64 0
#define TCG_TARGET_HAS_muls2_i64 1
#define TCG_TARGET_HAS_add2_i32 1
DEF(tci_divu32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
DEF(tci_rems32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
DEF(tci_remu32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
+DEF(tci_rotl32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
+DEF(tci_rotr32, 1, 2, 0, TCG_OPF_NOT_PRESENT)
case INDEX_op_st_i64:
return C_O0_I2(r, r);
- case INDEX_op_rotl_i32:
- case INDEX_op_rotl_i64:
- case INDEX_op_rotr_i32:
- case INDEX_op_rotr_i64:
case INDEX_op_setcond_i32:
case INDEX_op_setcond_i64:
case INDEX_op_deposit_i32:
.out_rrr = tgen_remu,
};
+static void tgen_rotl(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ TCGOpcode opc = (type == TCG_TYPE_I32
+ ? INDEX_op_tci_rotl32
+ : INDEX_op_rotl_i64);
+ tcg_out_op_rrr(s, opc, a0, a1, a2);
+}
+
+static const TCGOutOpBinary outop_rotl = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_rotl,
+};
+
+static void tgen_rotr(TCGContext *s, TCGType type,
+ TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ TCGOpcode opc = (type == TCG_TYPE_I32
+ ? INDEX_op_tci_rotr32
+ : INDEX_op_rotr_i64);
+ tcg_out_op_rrr(s, opc, a0, a1, a2);
+}
+
+static const TCGOutOpBinary outop_rotr = {
+ .base.static_constraint = C_O1_I2(r, r, r),
+ .out_rrr = tgen_rotr,
+};
+
static void tgen_sar(TCGContext *s, TCGType type,
TCGReg a0, TCGReg a1, TCGReg a2)
{
tcg_out_ldst(s, opc, args[0], args[1], args[2]);
break;
- CASE_32_64(rotl) /* Optional (TCG_TARGET_HAS_rot_*). */
- CASE_32_64(rotr) /* Optional (TCG_TARGET_HAS_rot_*). */
CASE_32_64(clz) /* Optional (TCG_TARGET_HAS_clz_*). */
CASE_32_64(ctz) /* Optional (TCG_TARGET_HAS_ctz_*). */
tcg_out_op_rrr(s, opc, args[0], args[1], args[2]);