@@ -2884,26 +2884,18 @@ expand_asm_stmt (gasm *stmt)
int nregs, j;
j = decode_reg_name_and_count (regname, &nregs);
- if (j < 0)
+ if (j == -2)
{
- if (j == -2)
- {
- /* ??? Diagnose during gimplification? */
- error ("unknown register name %qs in %<asm%>", regname);
- }
- else if (j == -4)
- {
- rtx x = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode));
- clobber_rvec.safe_push (x);
- }
- else
- {
- /* Otherwise we should have -1 == empty string
- or -3 == cc, which is not a register. */
- gcc_assert (j == -1 || j == -3);
- }
+ /* ??? Diagnose during gimplification? */
+ error ("unknown register name %qs in %<asm%>", regname);
}
- else
+ else if (j == -4)
+ {
+ rtx x = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode));
+ clobber_rvec.safe_push (x);
+ }
+ else if (j != -1 /* empty string */
+ && j != -3 /* cc, which is not a register */)
for (int reg = j; reg < j + nregs; reg++)
{
/* Clobbering the PIC register is an error. */
@@ -2915,7 +2907,8 @@ expand_asm_stmt (gasm *stmt)
return;
}
- SET_HARD_REG_BIT (clobbered_regs, reg);
+ if (reg >= 0)
+ SET_HARD_REG_BIT (clobbered_regs, reg);
rtx x = gen_rtx_REG (reg_raw_mode[reg], reg);
clobber_rvec.safe_push (x);
}
@@ -4207,6 +4207,7 @@ ix86_target_string (HOST_WIDE_INT isa, i
{ "-minline-stringops-dynamically", MASK_INLINE_STRINGOPS_DYNAMICALLY },
{ "-mms-bitfields", MASK_MS_BITFIELD_LAYOUT },
{ "-mno-align-stringops", MASK_NO_ALIGN_STRINGOPS },
+ { "-mno-default-asm-clobbers", MASK_NO_DEFAULT_ASM_CLOBBERS },
{ "-mno-fancy-math-387", MASK_NO_FANCY_MATH_387 },
{ "-mno-push-args", MASK_NO_PUSH_ARGS },
{ "-mno-red-zone", MASK_NO_RED_ZONE },
@@ -6488,6 +6489,10 @@ ix86_valid_target_attribute_inner_p (tre
OPT_mno_align_stringops,
MASK_NO_ALIGN_STRINGOPS),
+ IX86_ATTR_NO ("default-asm-clobbers",
+ OPT_mno_default_asm_clobbers,
+ MASK_NO_DEFAULT_ASM_CLOBBERS),
+
IX86_ATTR_YES ("recip",
OPT_mrecip,
MASK_RECIP),
@@ -48384,8 +48389,38 @@ ix86_md_asm_adjust (vec<rtx> &outputs, v
vec<const char *> &constraints,
vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs)
{
- clobbers.safe_push (gen_rtx_REG (CCFPmode, FPSR_REG));
- SET_HARD_REG_BIT (clobbered_regs, FPSR_REG);
+ bool noflags_used = false, nofpsr_used = false;
+
+ for (unsigned i = 0; i < clobbers.length (); )
+ {
+ const_rtx clobbered_reg = clobbers[i];
+
+ if (! REG_P (clobbered_reg))
+ {
+ ++i;
+ continue;
+ }
+
+ switch (REGNO (clobbered_reg))
+ {
+ default: ++i; continue;
+ case NOFLAGS_REGNUM: noflags_used = true; break;
+ case NOFPSR_REGNUM: nofpsr_used = true; break;
+ }
+
+ clobbers.unordered_remove (i);
+ }
+
+ if ((noflags_used && TEST_HARD_REG_BIT (clobbered_regs, FLAGS_REG))
+ || (nofpsr_used && TEST_HARD_REG_BIT (clobbered_regs, FPSR_REG)))
+ error ("conflicting clobbers in %<asm%>");
+
+ if (TARGET_DEFAULT_ASM_CLOBBERS && !nofpsr_used
+ && !TEST_HARD_REG_BIT (clobbered_regs, FPSR_REG))
+ {
+ clobbers.safe_push (gen_rtx_REG (CCFPmode, FPSR_REG));
+ SET_HARD_REG_BIT (clobbered_regs, FPSR_REG);
+ }
bool saw_asm_flag = false;
@@ -48395,6 +48430,11 @@ ix86_md_asm_adjust (vec<rtx> &outputs, v
const char *con = constraints[i];
if (strncmp (con, "=@cc", 4) != 0)
continue;
+ if (noflags_used)
+ {
+ error ("%<asm%> flag output conflicts with clobbers");
+ continue;
+ }
con += 4;
if (strchr (con, ',') != NULL)
{
@@ -48530,13 +48570,16 @@ ix86_md_asm_adjust (vec<rtx> &outputs, v
if (saw_asm_flag)
return seq;
- else
+
+ if (TARGET_DEFAULT_ASM_CLOBBERS && !noflags_used
+ && !TEST_HARD_REG_BIT (clobbered_regs, FLAGS_REG))
{
/* If we had no asm flag outputs, clobber the flags. */
clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REG));
SET_HARD_REG_BIT (clobbered_regs, FLAGS_REG);
- return NULL;
}
+
+ return NULL;
}
/* Implements target vector targetm.asm.encode_section_info. */
@@ -1304,6 +1304,11 @@ extern const char *host_detect_local_cpu
: REAL_PIC_OFFSET_TABLE_REGNUM) \
: INVALID_REGNUM)
+/* Fake register numbers to be used as "inverse" asm() clobber specifiers.
+ Any negative numbers below the range used by decode_reg_name () will do. */
+#define NOFLAGS_REGNUM (-127)
+#define NOFPSR_REGNUM (-126)
+
#define GOT_SYMBOL_NAME "_GLOBAL_OFFSET_TABLE_"
/* This is overridden by <cygwin.h>. */
@@ -2141,7 +2146,11 @@ do { \
{ "zmm16", 53}, { "zmm17", 54}, { "zmm18", 55}, { "zmm19", 56}, \
{ "zmm20", 57}, { "zmm21", 58}, { "zmm22", 59}, { "zmm23", 60}, \
{ "zmm24", 61}, { "zmm25", 62}, { "zmm26", 63}, { "zmm27", 64}, \
- { "zmm28", 65}, { "zmm29", 66}, { "zmm30", 67}, { "zmm31", 68} }
+ { "zmm28", 65}, { "zmm29", 66}, { "zmm30", 67}, { "zmm31", 68}, \
+ { "!flags", NOFLAGS_REGNUM }, { "!fpsr", NOFPSR_REGNUM } }
+
+#define OVERLAPPING_REGISTER_NAMES \
+{ { "cc", FLAGS_REG, 2 }, { "!cc", NOFLAGS_REGNUM, 2 } }
/* Note we are omitting these since currently I don't know how
to get gcc to use these, since they want the same but different
@@ -304,6 +304,10 @@ Enum(pmode) String(long) Value(PMODE_DI)
mcpu=
Target RejectNegative Joined Undocumented Alias(mtune=) Warn(%<-mcpu=%> is deprecated; use %<-mtune=%> or %<-march=%> instead)
+mdefault-asm-clobbers
+Target RejectNegative Report InverseMask(NO_DEFAULT_ASM_CLOBBERS, DEFAULT_ASM_CLOBBERS) Undocumented Save
+Attach compatibility clobbers (flags and fpsr) to every asm().
+
mfancy-math-387
Target RejectNegative Report InverseMask(NO_FANCY_MATH_387, USE_FANCY_MATH_387) Save
Generate sin, cos, sqrt for FPU.
@@ -372,6 +376,10 @@ Use native (MS) bitfield layout.
mno-align-stringops
Target RejectNegative Report Mask(NO_ALIGN_STRINGOPS) Undocumented Save
+mno-default-asm-clobbers
+Target RejectNegative Report Mask(NO_DEFAULT_ASM_CLOBBERS) Save
+Don't attach compatibility clobbers (flags and fpsr) to every asm().
+
mno-fancy-math-387
Target RejectNegative Report Mask(NO_FANCY_MATH_387) Undocumented Save
@@ -3,6 +3,6 @@
void
foo (void)
{
- register int cc __asm ("cc"); /* { dg-error "invalid register name" } */
+ register int cc __asm ("cc"); /* { dg-error "register specified .* not general enough" } */
__asm ("" : : "r" (cc) : "cc");
}
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+void test(void)
+{
+ int v;
+
+ asm ("" ::: "cc");
+ asm ("" ::: "!cc");
+ asm ("" ::: "flags");
+ asm ("" ::: "!flags");
+ asm ("" ::: "fpsr");
+ asm ("" ::: "!fpsr");
+
+ asm ("" ::: "cc", "!cc"); /* { dg-error "conflicting clobbers" } */
+ asm ("" ::: "flags", "!flags"); /* { dg-error "conflicting clobbers" } */
+ asm ("" ::: "fpsr", "!fpsr"); /* { dg-error "conflicting clobbers" } */
+ asm ("" ::: "flags", "!cc"); /* { dg-error "conflicting clobbers" } */
+ asm ("" ::: "cc", "!flags"); /* { dg-error "conflicting clobbers" } */
+ asm ("" ::: "fpsr", "!cc"); /* { dg-error "conflicting clobbers" } */
+ asm ("" ::: "cc", "!fpsr"); /* { dg-error "conflicting clobbers" } */
+
+#if 0 /* These right now are internal compiler errors. */
+ asm ("" : "=@ccz" (v) :: "cc"); /* { dg-bogus "clobber conflict with output" } */
+ asm ("" : "=@ccz" (v) :: "flags"); /* { dg-bogus "clobber conflict with output" } */
+#endif
+ asm ("" : "=@ccz" (v) :: "!cc"); /* { dg-error "output conflicts with clobbers" } */
+ asm ("" : "=@ccz" (v) :: "!flags"); /* { dg-error "output conflicts with clobbers" } */
+
+ asm ("" ::: "flags", "!fpsr");
+ asm ("" ::: "fpsr", "!flags");
+}
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-rtl-expand" } */
+
+void test(void)
+{
+ asm ("" ::: "!cc");
+ asm ("" ::: "!fpsr", "!flags");
+}
+
+/* { dg-final { scan-rtl-dump-not "clobber" "expand" } } */
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-rtl-expand" } */
+
+void test(void)
+{
+ asm ("" ::: "!cc");
+ asm ("" ::: "!flags");
+ asm ("" ::: "!fpsr");
+}
+
+/* { dg-final { scan-rtl-dump-times "\\(clobber \\(reg\[^()\]* fpsr\\)\\)" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "\\(clobber \\(reg\[^()\]* flags\\)\\)" 1 "expand" } } */
@@ -943,7 +943,7 @@ decode_reg_name_and_count (const char *a
for (i = 0; i < (int) ARRAY_SIZE (table); i++)
if (table[i].name[0]
&& ! strcmp (asmspec, table[i].name)
- && reg_names[table[i].number][0])
+ && (table[i].number < 0 || reg_names[table[i].number][0]))
return table[i].number;
}
#endif /* ADDITIONAL_REGISTER_NAMES */