https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70162

            Bug ID: 70162
           Summary: [RX] const_int printing causes wrong code on 32 bit
                    host
           Product: gcc
           Version: 5.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: olegendo at gcc dot gnu.org
                CC: dj at redhat dot com
  Target Milestone: ---
              Host: i686
            Target: rx-elf

It seems the rx-elf toolchain (incl. binutils) has some issues on 32 bit hosts. 

The following C++ program exposes 3 issues.

typedef unsigned char uint8_t;

void send_1 (unsigned int, const void*, unsigned int);

signed char fail (void)
{
  static const uint8_t cmd42[] = { 0x98, 0x00, 0x00, 0x00, 0x00, 0xFF };
  send_1 (0x42, cmd42, 6);

  static const uint8_t cmd40[] = { 0x98, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  send_1 (0x40, cmd40, 6);

  uint8_t wr_data[] = { 0x88, 0x00, 0x00, 0x00 };
  send_1 (0x42, wr_data, 4);

  return -80;
}

Compiled with -O2 will result in:

        ...
        mov.L   r0, r2
        mov.B   #0xffffffffffffff88, [r0]  <<<<< (*1)
        mov.B   #0, 1[r0]
        mov.B   #0, 2[r0]
        mov.B   #0, 3[r0]
        jsr     r7
        mov.L   #0xffffffffffffffb0, r1    <<<<< (*2)
        rtsd    #8, r7-r7


In (*1) GAS will misinterpret the 64 bit value and the resulting code becomes:

  2b:   f8 04 88                        mov.b   #136, [r0]
  2e:   ff ff                           *unknown*

Which results in an illegal instruction exception.


In (*2) GAS will select a longer instruction than necessary:

  3c:   fb 12 b0 ff ff ff               mov.l   #-80, r1


Another issue (*3) is GAS issuing the warning:

main.s: Assembler messages:
main.s:33: Warning: bignum truncated to 1 bytes
main.s:42: Warning: bignum truncated to 1 bytes

which comes from things like

__ZZ4failvE5cmd40:
        .byte   0xffffffffffffff98
        .byte   -1
        ....


The following patch fixes issues (*1) and (*2):

Index: gcc/config/rx/rx.md
===================================================================
--- gcc/config/rx/rx.md (revision 234073)
+++ gcc/config/rx/rx.md (working copy)
@@ -588,7 +588,21 @@
        (match_operand:register_modes
         1 "general_operand"
"Int08,Sint16,Sint24,i,r,m,r,Int08,Sint16,Sint24,i,RpdaRpid"))]
   ""
-  { return rx_gen_move_template (operands, false); }
+  {
+    if (CONST_INT_P (operands[1]))
+      {
+       /* Truncate constants to the size of the move insn to avoid printing
+          64 bit constants which might be misinterpreted by the assembler.  */
+       if (<MODE>mode == QImode)
+         operands[1] = GEN_INT (INTVAL (operands[1]) & 0xFF);
+       else if (<MODE>mode == HImode)
+         operands[1] = GEN_INT (INTVAL (operands[1]) & 0xFFFF);
+       else
+         operands[1] = GEN_INT (INTVAL (operands[1]) & 0xFFFFFFFF);
+      }
+
+    return rx_gen_move_template (operands, false);
+  }
   [(set_attr "length" "3,4,5,6,2,4,6,5,6,7,8,8")
    (set_attr "timings" "11,11,11,11,11,12,11,11,11,11,11,11")]
 )


Issue (*3) can be avoided by this:

Index: gcc/config/rx/rx.c
===================================================================
--- gcc/config/rx/rx.c  (revision 234073)
+++ gcc/config/rx/rx.c  (working copy)
@@ -513,6 +513,9 @@
 static bool
 rx_assemble_integer (rtx x, unsigned int size, int is_aligned)
 {
+  if (!TARGET_AS100_SYNTAX)
+    return default_assemble_integer (x, size, is_aligned);
+
   const char *  op = integer_asm_op (size, is_aligned);

   if (! CONST_INT_P (x))

Reply via email to