[AArch64, ILP32] 2/6 More backend changes and support for small absolute and
authorYufeng Zhang <yufeng.zhang@arm.com>
Tue, 23 Jul 2013 12:20:05 +0000 (12:20 +0000)
committerYufeng Zhang <yufeng@gcc.gnu.org>
Tue, 23 Jul 2013 12:20:05 +0000 (12:20 +0000)
small PIC addressing models

gcc/

* config/aarch64/aarch64.c (POINTER_BYTES): New define.
(aarch64_load_symref_appropriately): In the case of
SYMBOL_SMALL_ABSOLUTE, use the mode of 'dest' instead of Pmode
to generate new rtx; likewise to the case of SYMBOL_SMALL_GOT.
(aarch64_expand_mov_immediate): In the case of SYMBOL_FORCE_TO_MEM,
change to pass 'ptr_mode' to force_const_mem and zero-extend 'mem'
if 'mode' doesn't equal to 'ptr_mode'.
(aarch64_output_mi_thunk): Add an assertion on the alignment of
'vcall_offset'; change to call aarch64_emit_move differently depending
on whether 'Pmode' equals to 'ptr_mode' or not; use 'POINTER_BYTES'
to calculate the upper bound of 'vcall_offset'.
(aarch64_cannot_force_const_mem): Change to also return true if
mode != ptr_mode.
(aarch64_legitimize_reload_address): In the case of large
displacements, add new local variable 'xmode' and an assertion
based on it; change to use 'xmode' to generate the new rtx and
reload.
(aarch64_asm_trampoline_template): Change to generate the template
differently depending on TARGET_ILP32 or not; change to use
'POINTER_BYTES' in the argument passed to assemble_aligned_integer.
(aarch64_trampoline_size): Removed.
(aarch64_trampoline_init): Add new local constant 'tramp_code_sz'
and replace immediate literals with it.  Change to use 'ptr_mode'
instead of 'DImode' and call convert_memory_address if the mode
of 'fnaddr' doesn't equal to 'ptr_mode'.
(aarch64_elf_asm_constructor): Change to use assemble_aligned_integer
to output symbol.
(aarch64_elf_asm_destructor): Likewise.
* config/aarch64/aarch64.h (TRAMPOLINE_SIZE): Change to be dependent
on TARGET_ILP32 instead of aarch64_trampoline_size.
* config/aarch64/aarch64.md (movsi_aarch64): Add new alternatives
of 'mov' between WSP and W registers as well as 'adr' and 'adrp'.
(loadwb_pair<GPI:mode>_<PTR:mode>): Rename to ...
(loadwb_pair<GPI:mode>_<P:mode>): ... this.  Replace PTR with P.
(storewb_pair<GPI:mode>_<PTR:mode>): Likewise; rename to ...
(storewb_pair<GPI:mode>_<P:mode>): ... this.
(add_losym): Change to 'define_expand' and call gen_add_losym_<mode>
depending on the value of 'mode'.
(add_losym_<mode>): New.
(ldr_got_small_<mode>): New, based on ldr_got_small.
(ldr_got_small): Remove.
(ldr_got_small_sidi): New.
* config/aarch64/iterators.md (P): New.
(PTR): Change to 'ptr_mode' in the condition.

From-SVN: r201165

gcc/ChangeLog
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/aarch64.h
gcc/config/aarch64/aarch64.md
gcc/config/aarch64/iterators.md

index 32e20902dc7b510dea2d657594c203f0a3cbdf24..963320cec731996bc153b3b3906e2083fcdd57c2 100644 (file)
@@ -1,3 +1,50 @@
+2013-07-23  Yufeng Zhang  <yufeng.zhang@arm.com>
+
+       * config/aarch64/aarch64.c (POINTER_BYTES): New define.
+       (aarch64_load_symref_appropriately): In the case of
+       SYMBOL_SMALL_ABSOLUTE, use the mode of 'dest' instead of Pmode
+       to generate new rtx; likewise to the case of SYMBOL_SMALL_GOT.
+       (aarch64_expand_mov_immediate): In the case of SYMBOL_FORCE_TO_MEM,
+       change to pass 'ptr_mode' to force_const_mem and zero-extend 'mem'
+       if 'mode' doesn't equal to 'ptr_mode'.
+       (aarch64_output_mi_thunk): Add an assertion on the alignment of
+       'vcall_offset'; change to call aarch64_emit_move differently depending
+       on whether 'Pmode' equals to 'ptr_mode' or not; use 'POINTER_BYTES'
+       to calculate the upper bound of 'vcall_offset'.
+       (aarch64_cannot_force_const_mem): Change to also return true if
+       mode != ptr_mode.
+       (aarch64_legitimize_reload_address): In the case of large
+       displacements, add new local variable 'xmode' and an assertion
+       based on it; change to use 'xmode' to generate the new rtx and
+       reload.
+       (aarch64_asm_trampoline_template): Change to generate the template
+       differently depending on TARGET_ILP32 or not; change to use
+       'POINTER_BYTES' in the argument passed to assemble_aligned_integer.
+       (aarch64_trampoline_size): Removed.
+       (aarch64_trampoline_init): Add new local constant 'tramp_code_sz'
+       and replace immediate literals with it.  Change to use 'ptr_mode'
+       instead of 'DImode' and call convert_memory_address if the mode
+       of 'fnaddr' doesn't equal to 'ptr_mode'.
+       (aarch64_elf_asm_constructor): Change to use assemble_aligned_integer
+       to output symbol.
+       (aarch64_elf_asm_destructor): Likewise.
+       * config/aarch64/aarch64.h (TRAMPOLINE_SIZE): Change to be dependent
+       on TARGET_ILP32 instead of aarch64_trampoline_size.
+       * config/aarch64/aarch64.md (movsi_aarch64): Add new alternatives
+       of 'mov' between WSP and W registers as well as 'adr' and 'adrp'.
+       (loadwb_pair<GPI:mode>_<PTR:mode>): Rename to ...
+       (loadwb_pair<GPI:mode>_<P:mode>): ... this.  Replace PTR with P.
+       (storewb_pair<GPI:mode>_<PTR:mode>): Likewise; rename to ...
+       (storewb_pair<GPI:mode>_<P:mode>): ... this.
+       (add_losym): Change to 'define_expand' and call gen_add_losym_<mode>
+       depending on the value of 'mode'.
+       (add_losym_<mode>): New.
+       (ldr_got_small_<mode>): New, based on ldr_got_small.
+       (ldr_got_small): Remove.
+       (ldr_got_small_sidi): New.
+       * config/aarch64/iterators.md (P): New.
+       (PTR): Change to 'ptr_mode' in the condition.
+
 2013-07-23  Yufeng Zhang  <yufeng.zhang@arm.com>
 
        * config.gcc (aarch64*-*-*): Support --with-abi.
index 9a38ed7b48fd774c8737000e3aef2288e5f9fa95..da041f8e3f89c86ad7b43d6cfc82bdc2b263ef4a 100644 (file)
@@ -48,6 +48,9 @@
 #include "cfgloop.h"
 #include "tree-vectorizer.h"
 
+/* Defined for convenience.  */
+#define POINTER_BYTES (POINTER_SIZE / BITS_PER_UNIT)
+
 /* Classifies an address.
 
    ADDRESS_REG_IMM
@@ -543,13 +546,16 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm,
     {
     case SYMBOL_SMALL_ABSOLUTE:
       {
+       /* In ILP32, the mode of dest can be either SImode or DImode.  */
        rtx tmp_reg = dest;
+       enum machine_mode mode = GET_MODE (dest);
+
+       gcc_assert (mode == Pmode || mode == ptr_mode);
+
        if (can_create_pseudo_p ())
-         {
-           tmp_reg =  gen_reg_rtx (Pmode);
-         }
+         tmp_reg = gen_reg_rtx (mode);
 
-       emit_move_insn (tmp_reg, gen_rtx_HIGH (Pmode, imm));
+       emit_move_insn (tmp_reg, gen_rtx_HIGH (mode, imm));
        emit_insn (gen_add_losym (dest, tmp_reg, imm));
        return;
       }
@@ -560,11 +566,33 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm,
 
     case SYMBOL_SMALL_GOT:
       {
+       /* In ILP32, the mode of dest can be either SImode or DImode,
+          while the got entry is always of SImode size.  The mode of
+          dest depends on how dest is used: if dest is assigned to a
+          pointer (e.g. in the memory), it has SImode; it may have
+          DImode if dest is dereferenced to access the memeory.
+          This is why we have to handle three different ldr_got_small
+          patterns here (two patterns for ILP32).  */
        rtx tmp_reg = dest;
+       enum machine_mode mode = GET_MODE (dest);
+
        if (can_create_pseudo_p ())
-         tmp_reg =  gen_reg_rtx (Pmode);
-       emit_move_insn (tmp_reg, gen_rtx_HIGH (Pmode, imm));
-       emit_insn (gen_ldr_got_small (dest, tmp_reg, imm));
+         tmp_reg = gen_reg_rtx (mode);
+
+       emit_move_insn (tmp_reg, gen_rtx_HIGH (mode, imm));
+       if (mode == ptr_mode)
+         {
+           if (mode == DImode)
+             emit_insn (gen_ldr_got_small_di (dest, tmp_reg, imm));
+           else
+             emit_insn (gen_ldr_got_small_si (dest, tmp_reg, imm));
+         }
+       else
+         {
+           gcc_assert (mode == Pmode);
+           emit_insn (gen_ldr_got_small_sidi (dest, tmp_reg, imm));
+         }
+
        return;
       }
 
@@ -885,8 +913,10 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm)
              aarch64_emit_move (dest, base);
              return;
            }
-         mem = force_const_mem (mode, imm);
+         mem = force_const_mem (ptr_mode, imm);
          gcc_assert (mem);
+         if (mode != ptr_mode)
+           mem = gen_rtx_ZERO_EXTEND (mode, mem);
          emit_insn (gen_rtx_SET (VOIDmode, dest, mem));
          return;
 
@@ -2518,7 +2548,7 @@ aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
     aarch64_add_constant (this_regno, IP1_REGNUM, delta);
   else
     {
-      gcc_assert ((vcall_offset & 0x7) == 0);
+      gcc_assert ((vcall_offset & (POINTER_BYTES - 1)) == 0);
 
       this_rtx = gen_rtx_REG (Pmode, this_regno);
       temp0 = gen_rtx_REG (Pmode, IP0_REGNUM);
@@ -2534,9 +2564,14 @@ aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
            aarch64_add_constant (this_regno, IP1_REGNUM, delta);
        }
 
-      aarch64_emit_move (temp0, gen_rtx_MEM (Pmode, addr));
+      if (Pmode == ptr_mode)
+       aarch64_emit_move (temp0, gen_rtx_MEM (ptr_mode, addr));
+      else
+       aarch64_emit_move (temp0,
+                          gen_rtx_ZERO_EXTEND (Pmode,
+                                               gen_rtx_MEM (ptr_mode, addr)));
 
-      if (vcall_offset >= -256 && vcall_offset < 32768)
+      if (vcall_offset >= -256 && vcall_offset < 4096 * POINTER_BYTES)
          addr = plus_constant (Pmode, temp0, vcall_offset);
       else
        {
@@ -2544,7 +2579,13 @@ aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
          addr = gen_rtx_PLUS (Pmode, temp0, temp1);
        }
 
-      aarch64_emit_move (temp1, gen_rtx_MEM (Pmode,addr));
+      if (Pmode == ptr_mode)
+       aarch64_emit_move (temp1, gen_rtx_MEM (ptr_mode,addr));
+      else
+       aarch64_emit_move (temp1,
+                          gen_rtx_SIGN_EXTEND (Pmode,
+                                               gen_rtx_MEM (ptr_mode, addr)));
+
       emit_insn (gen_add2_insn (this_rtx, temp1));
     }
 
@@ -2722,8 +2763,15 @@ aarch64_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
 
   split_const (x, &base, &offset);
   if (GET_CODE (base) == SYMBOL_REF || GET_CODE (base) == LABEL_REF)
-    return (aarch64_classify_symbol (base, SYMBOL_CONTEXT_ADR)
-           != SYMBOL_FORCE_TO_MEM);
+    {
+      if (aarch64_classify_symbol (base, SYMBOL_CONTEXT_ADR)
+         != SYMBOL_FORCE_TO_MEM)
+       return true;
+      else
+       /* Avoid generating a 64-bit relocation in ILP32; leave
+          to aarch64_expand_mov_immediate to handle it properly.  */
+       return mode != ptr_mode;
+    }
 
   return aarch64_tls_referenced_p (x);
 }
@@ -3918,6 +3966,10 @@ aarch64_legitimize_reload_address (rtx *x_p,
       HOST_WIDE_INT high = val - low;
       HOST_WIDE_INT offs;
       rtx cst;
+      enum machine_mode xmode = GET_MODE (x);
+
+      /* In ILP32, xmode can be either DImode or SImode.  */
+      gcc_assert (xmode == DImode || xmode == SImode);
 
       /* Reload non-zero BLKmode offsets.  This is because we cannot ascertain
         BLKmode alignment.  */
@@ -3951,16 +4003,16 @@ aarch64_legitimize_reload_address (rtx *x_p,
 
       cst = GEN_INT (high);
       if (!aarch64_uimm12_shift (high))
-       cst = force_const_mem (Pmode, cst);
+       cst = force_const_mem (xmode, cst);
 
       /* Reload high part into base reg, leaving the low part
         in the mem instruction.  */
-      x = gen_rtx_PLUS (Pmode,
-                       gen_rtx_PLUS (Pmode, XEXP (x, 0), cst),
+      x = gen_rtx_PLUS (xmode,
+                       gen_rtx_PLUS (xmode, XEXP (x, 0), cst),
                        GEN_INT (low));
 
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
-                  BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
+                  BASE_REG_CLASS, xmode, VOIDmode, 0, 0,
                   opnum, (enum reload_type) type);
       return x;
     }
@@ -4108,41 +4160,47 @@ aarch64_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
 static void
 aarch64_asm_trampoline_template (FILE *f)
 {
-  asm_fprintf (f, "\tldr\t%s, .+16\n", reg_names [IP1_REGNUM]);
-  asm_fprintf (f, "\tldr\t%s, .+20\n", reg_names [STATIC_CHAIN_REGNUM]);
+  if (TARGET_ILP32)
+    {
+      asm_fprintf (f, "\tldr\tw%d, .+16\n", IP1_REGNUM - R0_REGNUM);
+      asm_fprintf (f, "\tldr\tw%d, .+16\n", STATIC_CHAIN_REGNUM - R0_REGNUM);
+    }
+  else
+    {
+      asm_fprintf (f, "\tldr\t%s, .+16\n", reg_names [IP1_REGNUM]);
+      asm_fprintf (f, "\tldr\t%s, .+20\n", reg_names [STATIC_CHAIN_REGNUM]);
+    }
   asm_fprintf (f, "\tbr\t%s\n", reg_names [IP1_REGNUM]);
   assemble_aligned_integer (4, const0_rtx);
-  assemble_aligned_integer (UNITS_PER_WORD, const0_rtx);
-  assemble_aligned_integer (UNITS_PER_WORD, const0_rtx);
-}
-
-unsigned
-aarch64_trampoline_size (void)
-{
-  return 32;  /* 3 insns + padding + 2 dwords.  */
+  assemble_aligned_integer (POINTER_BYTES, const0_rtx);
+  assemble_aligned_integer (POINTER_BYTES, const0_rtx);
 }
 
 static void
 aarch64_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
 {
   rtx fnaddr, mem, a_tramp;
+  const int tramp_code_sz = 16;
 
   /* Don't need to copy the trailing D-words, we fill those in below.  */
   emit_block_move (m_tramp, assemble_trampoline_template (),
-                  GEN_INT (TRAMPOLINE_SIZE - 16), BLOCK_OP_NORMAL);
-  mem = adjust_address (m_tramp, DImode, 16);
+                  GEN_INT (tramp_code_sz), BLOCK_OP_NORMAL);
+  mem = adjust_address (m_tramp, ptr_mode, tramp_code_sz);
   fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  if (GET_MODE (fnaddr) != ptr_mode)
+    fnaddr = convert_memory_address (ptr_mode, fnaddr);
   emit_move_insn (mem, fnaddr);
 
-  mem = adjust_address (m_tramp, DImode, 24);
+  mem = adjust_address (m_tramp, ptr_mode, tramp_code_sz + POINTER_BYTES);
   emit_move_insn (mem, chain_value);
 
   /* XXX We should really define a "clear_cache" pattern and use
      gen_clear_cache().  */
   a_tramp = XEXP (m_tramp, 0);
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
-                    LCT_NORMAL, VOIDmode, 2, a_tramp, Pmode,
-                    plus_constant (Pmode, a_tramp, TRAMPOLINE_SIZE), Pmode);
+                    LCT_NORMAL, VOIDmode, 2, a_tramp, ptr_mode,
+                    plus_constant (ptr_mode, a_tramp, TRAMPOLINE_SIZE),
+                    ptr_mode);
 }
 
 static unsigned char
@@ -4197,9 +4255,7 @@ aarch64_elf_asm_constructor (rtx symbol, int priority)
       s = get_section (buf, SECTION_WRITE, NULL);
       switch_to_section (s);
       assemble_align (POINTER_SIZE);
-      fputs ("\t.dword\t", asm_out_file);
-      output_addr_const (asm_out_file, symbol);
-      fputc ('\n', asm_out_file);
+      assemble_aligned_integer (POINTER_BYTES, symbol);
     }
 }
 
@@ -4216,9 +4272,7 @@ aarch64_elf_asm_destructor (rtx symbol, int priority)
       s = get_section (buf, SECTION_WRITE, NULL);
       switch_to_section (s);
       assemble_align (POINTER_SIZE);
-      fputs ("\t.dword\t", asm_out_file);
-      output_addr_const (asm_out_file, symbol);
-      fputc ('\n', asm_out_file);
+      assemble_aligned_integer (POINTER_BYTES, symbol);
     }
 }
 
index 6011ab8026b129047ddde9f7ac717dff430e52e6..413f97de200f8afea74837d9d4775d95b246e0f3 100644 (file)
@@ -740,7 +740,8 @@ do {                                                                             \
 
 #define RETURN_ADDR_RTX aarch64_return_addr
 
-#define TRAMPOLINE_SIZE        aarch64_trampoline_size ()
+/* 3 insns + padding + 2 pointer-sized entries.  */
+#define TRAMPOLINE_SIZE        (TARGET_ILP32 ? 24 : 32)
 
 /* Trampolines contain dwords, so must be dword aligned.  */
 #define TRAMPOLINE_ALIGNMENT 64
index 229564cc96209fca40f0868dd5337cee13aa73c7..233014eb43630eb877e5dcfcccd30191b3909bbb 100644 (file)
 )
 
 (define_insn "*movsi_aarch64"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,*w,m,  m,*w, r,*w")
-       (match_operand:SI 1 "aarch64_mov_operand"  " r,M,m, m,rZ,*w,rZ,*w,*w"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,k,r,r,r,*w,m,  m,r,r  ,*w, r,*w")
+       (match_operand:SI 1 "aarch64_mov_operand"  " r,r,k,M,m, m,rZ,*w,S,Ush,rZ,*w,*w"))]
   "(register_operand (operands[0], SImode)
     || aarch64_reg_or_zero (operands[1], SImode))"
   "@
+   mov\\t%w0, %w1
+   mov\\t%w0, %w1
    mov\\t%w0, %w1
    mov\\t%w0, %1
    ldr\\t%w0, %1
    ldr\\t%s0, %1
    str\\t%w1, %0
    str\\t%s1, %0
+   adr\\t%x0, %a1
+   adrp\\t%x0, %A1
    fmov\\t%s0, %w1
    fmov\\t%w0, %s1
    fmov\\t%s0, %s1"
-  [(set_attr "v8type" "move,alu,load1,load1,store1,store1,fmov,fmov,fmov")
+  [(set_attr "v8type" "move,move,move,alu,load1,load1,store1,store1,adr,adr,fmov,fmov,fmov")
    (set_attr "mode" "SI")
-   (set_attr "fp" "*,*,*,yes,*,yes,yes,yes,yes")]
+   (set_attr "fp" "*,*,*,*,*,yes,*,yes,*,*,yes,yes,yes")]
 )
 
 (define_insn "*movdi_aarch64"
 
 ;; Load pair with writeback.  This is primarily used in function epilogues
 ;; when restoring [fp,lr]
-(define_insn "loadwb_pair<GPI:mode>_<PTR:mode>"
+(define_insn "loadwb_pair<GPI:mode>_<P:mode>"
   [(parallel
-    [(set (match_operand:PTR 0 "register_operand" "=k")
-          (plus:PTR (match_operand:PTR 1 "register_operand" "0")
-                  (match_operand:PTR 4 "const_int_operand" "n")))
+    [(set (match_operand:P 0 "register_operand" "=k")
+          (plus:P (match_operand:P 1 "register_operand" "0")
+                  (match_operand:P 4 "const_int_operand" "n")))
      (set (match_operand:GPI 2 "register_operand" "=r")
-          (mem:GPI (plus:PTR (match_dup 1)
+          (mem:GPI (plus:P (match_dup 1)
                    (match_dup 4))))
      (set (match_operand:GPI 3 "register_operand" "=r")
-          (mem:GPI (plus:PTR (match_dup 1)
-                   (match_operand:PTR 5 "const_int_operand" "n"))))])]
+          (mem:GPI (plus:P (match_dup 1)
+                   (match_operand:P 5 "const_int_operand" "n"))))])]
   "INTVAL (operands[5]) == INTVAL (operands[4]) + GET_MODE_SIZE (<GPI:MODE>mode)"
   "ldp\\t%<w>2, %<w>3, [%1], %4"
   [(set_attr "v8type" "load2")
 
 ;; Store pair with writeback.  This is primarily used in function prologues
 ;; when saving [fp,lr]
-(define_insn "storewb_pair<GPI:mode>_<PTR:mode>"
+(define_insn "storewb_pair<GPI:mode>_<P:mode>"
   [(parallel
-    [(set (match_operand:PTR 0 "register_operand" "=&k")
-          (plus:PTR (match_operand:PTR 1 "register_operand" "0")
-                  (match_operand:PTR 4 "const_int_operand" "n")))
-     (set (mem:GPI (plus:PTR (match_dup 0)
+    [(set (match_operand:P 0 "register_operand" "=&k")
+          (plus:P (match_operand:P 1 "register_operand" "0")
+                  (match_operand:P 4 "const_int_operand" "n")))
+     (set (mem:GPI (plus:P (match_dup 0)
                    (match_dup 4)))
           (match_operand:GPI 2 "register_operand" "r"))
-     (set (mem:GPI (plus:PTR (match_dup 0)
-                   (match_operand:PTR 5 "const_int_operand" "n")))
+     (set (mem:GPI (plus:P (match_dup 0)
+                   (match_operand:P 5 "const_int_operand" "n")))
           (match_operand:GPI 3 "register_operand" "r"))])]
   "INTVAL (operands[5]) == INTVAL (operands[4]) + GET_MODE_SIZE (<GPI:MODE>mode)"
   "stp\\t%<w>2, %<w>3, [%0, %4]!"
 ;; and lo_sum's to be used with the labels defining the jump tables in
 ;; rodata section.
 
-(define_insn "add_losym"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-       (lo_sum:DI (match_operand:DI 1 "register_operand" "r")
-                  (match_operand 2 "aarch64_valid_symref" "S")))]
+(define_expand "add_losym"
+  [(set (match_operand 0 "register_operand" "=r")
+       (lo_sum (match_operand 1 "register_operand" "r")
+               (match_operand 2 "aarch64_valid_symref" "S")))]
   ""
-  "add\\t%0, %1, :lo12:%a2"
+{
+  enum machine_mode mode = GET_MODE (operands[0]);
+
+  emit_insn ((mode == DImode
+             ? gen_add_losym_di
+             : gen_add_losym_si) (operands[0],
+                                  operands[1],
+                                  operands[2]));
+  DONE;
+})
+
+(define_insn "add_losym_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=r")
+       (lo_sum:P (match_operand:P 1 "register_operand" "r")
+                 (match_operand 2 "aarch64_valid_symref" "S")))]
+  ""
+  "add\\t%<w>0, %<w>1, :lo12:%a2"
   [(set_attr "v8type" "alu")
-   (set_attr "mode" "DI")]
+   (set_attr "mode" "<MODE>")]
+)
 
+(define_insn "ldr_got_small_<mode>"
+  [(set (match_operand:PTR 0 "register_operand" "=r")
+       (unspec:PTR [(mem:PTR (lo_sum:PTR
+                             (match_operand:PTR 1 "register_operand" "r")
+                             (match_operand:PTR 2 "aarch64_valid_symref" "S")))]
+                   UNSPEC_GOTSMALLPIC))]
+  ""
+  "ldr\\t%<w>0, [%1, #:got_lo12:%a2]"
+  [(set_attr "v8type" "load1")
+   (set_attr "mode" "<MODE>")]
 )
 
-(define_insn "ldr_got_small"
+(define_insn "ldr_got_small_sidi"
   [(set (match_operand:DI 0 "register_operand" "=r")
-       (unspec:DI [(mem:DI (lo_sum:DI
-                             (match_operand:DI 1 "register_operand" "r")
-                             (match_operand:DI 2 "aarch64_valid_symref" "S")))]
-                  UNSPEC_GOTSMALLPIC))]
-  ""
-  "ldr\\t%0, [%1, #:got_lo12:%a2]"
+       (zero_extend:DI
+        (unspec:SI [(mem:SI (lo_sum:DI
+                            (match_operand:DI 1 "register_operand" "r")
+                            (match_operand:DI 2 "aarch64_valid_symref" "S")))]
+                   UNSPEC_GOTSMALLPIC)))]
+  "TARGET_ILP32"
+  "ldr\\t%w0, [%1, #:got_lo12:%a2]"
   [(set_attr "v8type" "load1")
    (set_attr "mode" "DI")]
 )
index 8e40c5de5d4ed121f0be57ad5a589df0a1561ce2..76ff15d9a01dfdc0cd544ca6d3f828f77fda49b2 100644 (file)
 ;; Vector modes for moves.
 (define_mode_iterator VDQM [V8QI V16QI V4HI V8HI V2SI V4SI])
 
+;; This mode iterator allows :P to be used for patterns that operate on
+;; addresses in different modes.  In LP64, only DI will match, while in
+;; ILP32, either can match.
+(define_mode_iterator P [(SI "ptr_mode == SImode || Pmode == SImode")
+                        (DI "ptr_mode == DImode || Pmode == DImode")])
+
 ;; This mode iterator allows :PTR to be used for patterns that operate on
 ;; pointer-sized quantities.  Exactly one of the two alternatives will match.
-(define_mode_iterator PTR [(SI "Pmode == SImode") (DI "Pmode == DImode")])
+(define_mode_iterator PTR [(SI "ptr_mode == SImode") (DI "ptr_mode == DImode")])
 
 ;; Vector Float modes.
 (define_mode_iterator VDQF [V2SF V4SF V2DF])