The behavior of the 'g'-constraint on asm statement operands does not
strictly match that described in the GCC User Manual:
"'g' Any register, memory, or immediate integer operand is allowed,
except for registers that are not general registers."
-- 6.12.3.1 Simple Constraints, Using the GCC (the latest)
Contrary to the quote above, the following example will produce different
results depending on whether TARGET_CONST16 or TARGET_AUTO_LITPOOLS is
enabled:
/* example */
void test(void) {
asm volatile ("# %0"::"g"(65536));
}
;; TARGET_CONST16 || TARGET_AUTO_LITPOOLS
test:
entry sp, 32
# 65536
retw.n
;; !TARGET_CONST16 && !TARGET_AUTO_LITPOOLS
.literal_position
.literal .LC0, 65536
test:
entry sp, 32
# .LC0
retw.n
Indeed, both of the above results satisfy the constraint, but the latter
is not an "any" constant as stated in the manual, and is therefore incon-
sistent with the former.
This is because the behavior of the 'g'-constraint on constants depends
on the general_operand() predicate, and essentially on
TARGET_LEGITIMATE_CONSTANT_P().
This patch resolves that inconsistency by adding an 'n'-constraint imme-
diately before every occurrence of 'g' in each constraint string during
the RTL generation pass, to prioritize being an integer constant for the
alternative to which 'g' belongs.
gcc/ChangeLog:
* config/xtensa/xtensa.cc
(TARGET_MD_ASM_ADJUST): New macro definition.
(xtensa_md_asm_adjust): New function prototype and definition, that
prepends all 'g'-constraints in the "constraints" vector with 'n',
if neither TARGET_CONST16 nor TARGET_AUTO_LITPOOLS is enabled.
---
gcc/config/xtensa/xtensa.cc | 66 +++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index bcb26df2e22..00c36915795 100644
--- a/gcc/config/xtensa/xtensa.cc
+++ b/gcc/config/xtensa/xtensa.cc
@@ -204,6 +204,10 @@ static rtx xtensa_delegitimize_address (rtx);
static reg_class_t xtensa_ira_change_pseudo_allocno_class (int, reg_class_t,
reg_class_t);
static HARD_REG_SET xtensa_zero_call_used_regs (HARD_REG_SET);
+static rtx_insn *xtensa_md_asm_adjust (vec<rtx> &, vec<rtx> &,
+ vec<machine_mode> &, vec<const char *> &,
+ vec<rtx> &, vec<rtx> &, HARD_REG_SET &,
+ location_t);
@@ -377,6 +381,9 @@ static HARD_REG_SET xtensa_zero_call_used_regs (HARD_REG_SET);
#undef TARGET_ZERO_CALL_USED_REGS
#define TARGET_ZERO_CALL_USED_REGS xtensa_zero_call_used_regs
+#undef TARGET_MD_ASM_ADJUST
+#define TARGET_MD_ASM_ADJUST xtensa_md_asm_adjust
+
struct gcc_target targetm = TARGET_INITIALIZER;
@@ -5648,4 +5655,63 @@ xtensa_zero_call_used_regs (HARD_REG_SET selected_regs)
return selected_regs;
}
+/* Implement TARGET_MD_ASM_ADJUST.
+
+ If either TARGET_CONST16 or TARGET_AUTO_LITPOOLS is enabled, the 'g'-
+ constraint (based on general_operand()) accepts any integer constant,
+ but if neither it limits within signed 12 bit by
+ TARGET_LEGITIMATE_CONSTANT_P().
+ This behavior is not reasonable and can be addressed by prepending an
+ 'n'-constraint to the 'g' during the RTL generation, if necessary. */
+
+static rtx_insn *
+xtensa_md_asm_adjust (vec<rtx> &outputs ATTRIBUTE_UNUSED,
+ vec<rtx> &inputs ATTRIBUTE_UNUSED,
+ vec<machine_mode> &input_modes ATTRIBUTE_UNUSED,
+ vec<const char *> &constraints,
+ vec<rtx> &uses ATTRIBUTE_UNUSED,
+ vec<rtx> &clobbers ATTRIBUTE_UNUSED,
+ HARD_REG_SET &clobbered_regs ATTRIBUTE_UNUSED,
+ location_t loc ATTRIBUTE_UNUSED)
+{
+ size_t n, l;
+ const char *p;
+ int c;
+ char *modified, *q;
+
+ if (!TARGET_CONST16 && !TARGET_AUTO_LITPOOLS)
+ for (auto &constraint : constraints)
+ {
+ /* Count the number of 'g'-constraints in each constraint string. */
+ for (n = 0, p = constraint; (c = *p); p += CONSTRAINT_LEN (c, p))
+ if (c == 'g')
+ ++n;
+ if (n == 0)
+ continue;
+
+ /* If the constraint string contains 'g'-constraints, then each
+ 'g' is prefixed with an 'n'-constraint to form a new constraint
+ string. */
+ n += strlen (constraint);
+ modified = (char *)ggc_alloc_atomic (n + 1);
+ for (p = constraint, q = modified; (c = *p); )
+ if (c == 'g')
+ q[0] = 'n', q[1] = 'g', ++p, q += 2;
+ else
+ if ((l = CONSTRAINT_LEN (c, p)) > 1)
+ memcpy (q, p, l), p += l, q += l;
+ else
+ *q++ = *p++;
+ *q = '\0';
+ if (dump_file)
+ fprintf (dump_file,
+ "xtensa_md_asm_adjust: "
+ "The constraint \"%s\" contains 'g's, so modify it to "
+ "\"%s\".\n", constraint, modified);
+ constraint = modified;
+ }
+
+ return NULL;
+}
+
#include "gt-xtensa.h"
--
2.39.5