b/gcc/config/aarch64/aarch64-protos.h
@@ -247,6 +247,7 @@ void aarch64_print_operand (FILE *, rtx, char);
void aarch64_print_operand_address (FILE *, rtx);
bool aarch64_uimm5 (HOST_WIDE_INT);
+const char* aarch64_output_ccmp (rtx *, bool, int);
/* Initialize builtins for SIMD intrinsics. */
void init_aarch64_simd_builtins (void);
@@ -9602,6 +9602,137 @@ aarch64_uimm5 (HOST_WIDE_INT val)
return (val & (HOST_WIDE_INT) 0x1f) == val;
}
+/* N Z C V. */
+#define AARCH64_CC_V 1
+#define AARCH64_CC_C (1 << 1)
+#define AARCH64_CC_Z (1 << 2)
+#define AARCH64_CC_N (1 << 3)
+
+static unsigned int
+aarch64_code_to_nzcv (enum rtx_code code, bool inverse)
+{
+ switch (code)
+ {
+ case NE: /* NE, Z == 0. */
+ return inverse ? AARCH64_CC_Z : 0;
+ case EQ: /* EQ, Z == 1. */
+ return inverse ? 0 : AARCH64_CC_Z;
+ case LE: /* LE, !(Z == 0 && N == V). */
+ return inverse ? AARCH64_CC_N | AARCH64_CC_V : AARCH64_CC_Z;
+ case GT: /* GT, Z == 0 && N == V. */
+ return inverse ? AARCH64_CC_Z : AARCH64_CC_N | AARCH64_CC_V;
+ case LT: /* LT, N != V. */
+ return inverse ? AARCH64_CC_N | AARCH64_CC_V : AARCH64_CC_N;
+ case GE: /* GE, N == V. */
+ return inverse ? AARCH64_CC_N : AARCH64_CC_N | AARCH64_CC_V;
+ case LEU: /* LS, !(C == 1 && Z == 0). */
+ return inverse ? AARCH64_CC_C: AARCH64_CC_Z;
+ case GTU: /* HI, C ==1 && Z == 0. */
+ return inverse ? AARCH64_CC_Z : AARCH64_CC_C;
+ case LTU: /* CC, C == 0. */
+ return inverse ? AARCH64_CC_C : 0;
+ case GEU: /* CS, C == 1. */
+ return inverse ? 0 : AARCH64_CC_C;
+ default:
+ gcc_unreachable ();
+ return 0;
+ }
+}
+
+static unsigned
+aarch64_mode_to_condition_code (enum machine_mode mode, bool inverse)
+{
+ switch (mode)
+ {
+ case CC_DNEmode:
+ return inverse ? aarch64_get_condition_code_1 (CCmode, EQ)
+ : aarch64_get_condition_code_1 (CCmode, NE);
+ case CC_DEQmode:
+ return inverse ? aarch64_get_condition_code_1 (CCmode, NE)
+ : aarch64_get_condition_code_1 (CCmode, EQ);
+ case CC_DLEmode:
+ return inverse ? aarch64_get_condition_code_1 (CCmode, GT)
+ : aarch64_get_condition_code_1 (CCmode, LE);
+ case CC_DGTmode:
+ return inverse ? aarch64_get_condition_code_1 (CCmode, LE)
+ : aarch64_get_condition_code_1 (CCmode, GT);
+ case CC_DLTmode:
+ return inverse ? aarch64_get_condition_code_1 (CCmode, GE)
+ : aarch64_get_condition_code_1 (CCmode, LT);
+ case CC_DGEmode:
+ return inverse ? aarch64_get_condition_code_1 (CCmode, LT)
+ : aarch64_get_condition_code_1 (CCmode, GE);
+ case CC_DLEUmode:
+ return inverse ? aarch64_get_condition_code_1 (CCmode, GTU)
+ : aarch64_get_condition_code_1 (CCmode, LEU);
+ case CC_DGTUmode:
+ return inverse ? aarch64_get_condition_code_1 (CCmode, LEU)
+ : aarch64_get_condition_code_1 (CCmode, GTU);
+ case CC_DLTUmode:
+ return inverse ? aarch64_get_condition_code_1 (CCmode, GEU)
+ : aarch64_get_condition_code_1 (CCmode, LTU);
+ case CC_DGEUmode:
+ return inverse ? aarch64_get_condition_code_1 (CCmode, LTU)
+ : aarch64_get_condition_code_1 (CCmode, GEU);
+ default:
+ gcc_unreachable ();
+ }
+}
+
+const char *
+aarch64_output_ccmp (rtx *operands, bool is_and, int which_alternative)
+{
+ char buf[32];
+ rtx cc = operands[0];
+ enum rtx_code code = GET_CODE (operands[5]);
+ unsigned char nzcv = aarch64_code_to_nzcv (code, is_and);
+ enum machine_mode mode = GET_MODE (cc);
+ unsigned int cond_code = aarch64_mode_to_condition_code (mode, !is_and);
+
+ gcc_assert (GET_MODE (operands[2]) == SImode
+ || GET_MODE (operands[2]) == DImode);
+
+ if (GET_MODE (operands[2]) == SImode)
+ switch (which_alternative)
+ {
+ case 0:
+ snprintf (buf, sizeof (buf), "ccmp\t%%w2, %%w3, #%u, %s",
+ nzcv, aarch64_condition_codes[cond_code]);
+ break;
+ case 1:
+ snprintf (buf, sizeof (buf), "ccmp\t%%w2, #%%3, #%u, %s",
+ nzcv, aarch64_condition_codes[cond_code]);
+ break;
+ case 2:
+ snprintf (buf, sizeof (buf), "ccmn\t%%w2, #%%n3, #%u, %s",
+ nzcv, aarch64_condition_codes[cond_code]);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ else
+ switch (which_alternative)
+ {
+ case 0:
+ snprintf (buf, sizeof (buf), "ccmp\t%%x2, %%x3, #%u, %s",
+ nzcv, aarch64_condition_codes[cond_code]);
+ break;
+ case 1:
+ snprintf (buf, sizeof (buf), "ccmp\t%%x2, #%%3, #%u, %s",
+ nzcv, aarch64_condition_codes[cond_code]);
+ break;
+ case 2:
+ snprintf (buf, sizeof (buf), "ccmn\t%%x2, #%%n3, #%u, %s",
+ nzcv, aarch64_condition_codes[cond_code]);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ output_asm_insn (buf, operands);
+ return "";
+}
+
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST aarch64_address_cost