DEF(ext16s_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ext16s_i32))
DEF(ext8u_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ext8u_i32))
DEF(ext16u_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ext16u_i32))
-DEF(bswap16_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_bswap16_i32))
-DEF(bswap32_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_bswap32_i32))
+DEF(bswap16_i32, 1, 1, 1, IMPL(TCG_TARGET_HAS_bswap16_i32))
+DEF(bswap32_i32, 1, 1, 1, IMPL(TCG_TARGET_HAS_bswap32_i32))
DEF(not_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_not_i32))
DEF(neg_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_neg_i32))
DEF(andc_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_andc_i32))
DEF(ext8u_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext8u_i64))
DEF(ext16u_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext16u_i64))
DEF(ext32u_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext32u_i64))
-DEF(bswap16_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_bswap16_i64))
-DEF(bswap32_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_bswap32_i64))
-DEF(bswap64_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_bswap64_i64))
+DEF(bswap16_i64, 1, 1, 1, IMPL64 | IMPL(TCG_TARGET_HAS_bswap16_i64))
+DEF(bswap32_i64, 1, 1, 1, IMPL64 | IMPL(TCG_TARGET_HAS_bswap32_i64))
+DEF(bswap64_i64, 1, 1, 1, IMPL64 | IMPL(TCG_TARGET_HAS_bswap64_i64))
DEF(not_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_not_i64))
DEF(neg_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_neg_i64))
DEF(andc_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_andc_i64))
/* Used to align parameters. See the comment before tcgv_i32_temp. */
#define TCG_CALL_DUMMY_ARG ((TCGArg)0)
+/*
+ * Flags for the bswap opcodes.
+ * If IZ, the input is zero-extended, otherwise unknown.
+ * If OZ or OS, the output is zero- or sign-extended respectively,
+ * otherwise the high bits are undefined.
+ */
+enum {
+ TCG_BSWAP_IZ = 1,
+ TCG_BSWAP_OZ = 2,
+ TCG_BSWAP_OS = 4,
+};
+
typedef enum TCGTempVal {
TEMP_VAL_DEAD,
TEMP_VAL_REG,
8, 16 or 32 bit sign/zero extension (both operands must have the same type)
-* bswap16_i32/i64 t0, t1
+* bswap16_i32/i64 t0, t1, flags
-16 bit byte swap on a 32/64 bit value. It assumes that the two/six high order
-bytes are set to zero.
+16 bit byte swap on the low bits of a 32/64 bit input.
+If flags & TCG_BSWAP_IZ, then t1 is known to be zero-extended from bit 15.
+If flags & TCG_BSWAP_OZ, then t0 will be zero-extended from bit 15.
+If flags & TCG_BSWAP_OS, then t0 will be sign-extended from bit 15.
+If neither TCG_BSWAP_OZ nor TCG_BSWAP_OS are set, then the bits of
+t0 above bit 15 may contain any value.
-* bswap32_i32/i64 t0, t1
+* bswap32_i64 t0, t1, flags
-32 bit byte swap on a 32/64 bit value. With a 64 bit value, it assumes that
-the four high order bytes are set to zero.
+32 bit byte swap on a 64-bit value. The flags are the same as for bswap16,
+except they apply from bit 31 instead of bit 15.
-* bswap64_i64 t0, t1
+* bswap32_i32 t0, t1, flags
+* bswap64_i64 t0, t1, flags
-64 bit byte swap
+32/64 bit byte swap. The flags are ignored, but still present
+for consistency with the other bswap opcodes.
* discard_i32/i64 t0
void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg)
{
if (TCG_TARGET_HAS_bswap16_i32) {
- tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg);
+ tcg_gen_op3i_i32(INDEX_op_bswap16_i32, ret, arg,
+ TCG_BSWAP_IZ | TCG_BSWAP_OZ);
} else {
TCGv_i32 t0 = tcg_temp_new_i32();
void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg)
{
if (TCG_TARGET_HAS_bswap32_i32) {
- tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg);
+ tcg_gen_op3i_i32(INDEX_op_bswap32_i32, ret, arg, 0);
} else {
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg));
tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
} else if (TCG_TARGET_HAS_bswap16_i64) {
- tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg);
+ tcg_gen_op3i_i64(INDEX_op_bswap16_i64, ret, arg,
+ TCG_BSWAP_IZ | TCG_BSWAP_OZ);
} else {
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg));
tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
} else if (TCG_TARGET_HAS_bswap32_i64) {
- tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg);
+ tcg_gen_op3i_i64(INDEX_op_bswap32_i64, ret, arg,
+ TCG_BSWAP_IZ | TCG_BSWAP_OZ);
} else {
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_temp_free_i32(t0);
tcg_temp_free_i32(t1);
} else if (TCG_TARGET_HAS_bswap64_i64) {
- tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg);
+ tcg_gen_op3i_i64(INDEX_op_bswap64_i64, ret, arg, 0);
} else {
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
[MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
};
+static const char bswap_flag_name[][6] = {
+ [TCG_BSWAP_IZ] = "iz",
+ [TCG_BSWAP_OZ] = "oz",
+ [TCG_BSWAP_OS] = "os",
+ [TCG_BSWAP_IZ | TCG_BSWAP_OZ] = "iz,oz",
+ [TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
+};
+
static inline bool tcg_regset_single(TCGRegSet d)
{
return (d & (d - 1)) == 0;
i = 1;
}
break;
+ case INDEX_op_bswap16_i32:
+ case INDEX_op_bswap16_i64:
+ case INDEX_op_bswap32_i32:
+ case INDEX_op_bswap32_i64:
+ case INDEX_op_bswap64_i64:
+ {
+ TCGArg flags = op->args[k];
+ const char *name = NULL;
+
+ if (flags < ARRAY_SIZE(bswap_flag_name)) {
+ name = bswap_flag_name[flags];
+ }
+ if (name) {
+ col += qemu_log(",%s", name);
+ } else {
+ col += qemu_log(",$0x%" TCG_PRIlx, flags);
+ }
+ i = k = 1;
+ }
+ break;
default:
i = 0;
break;