]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
msp430.c (msp430_builtin): Add MSP430_BUILTIN_DELAY_CYCLES.
authorDJ Delorie <dj@redhat.com>
Wed, 14 May 2014 21:27:21 +0000 (17:27 -0400)
committerDJ Delorie <dj@gcc.gnu.org>
Wed, 14 May 2014 21:27:21 +0000 (17:27 -0400)
* config/msp430/msp430.c (msp430_builtin): Add
MSP430_BUILTIN_DELAY_CYCLES.
(msp430_init_builtins): Register void __delay_cycles(long long).
(msp430_builtin_decl): Add it.
(cg_magic_constant): New.
(msp430_expand_delay_cycles): New.
(msp430_expand_builtin): Call it.
(msp430_print_operand_raw): Change integer printing from "int" to
HOST_WIDE_INT.
* config/msp430/msp430.md (define_constants): Add delay_cycles tags.
(delay_cycles_start): New.
(delay_cycles_end): New.
(delay_cycles_32): New.
(delay_cycles_32x): New.
(delay_cycles_16): New.
(delay_cycles_16x): New.
(delay_cycles_2): New.
(delay_cycles_1): New.
* doc/extend.texi: Document __delay_cycles().

From-SVN: r210441

gcc/ChangeLog
gcc/config/msp430/msp430.c
gcc/config/msp430/msp430.md
gcc/doc/extend.texi

index c7fbc1a1ef11c0f60ac171fb05b729b4fe4937d0..228f0e96ba7ba700018ff308dd48a87c3672843d 100644 (file)
@@ -1,3 +1,25 @@
+2014-05-14  DJ Delorie  <dj@redhat.com>
+
+       * config/msp430/msp430.c (msp430_builtin): Add
+       MSP430_BUILTIN_DELAY_CYCLES.
+       (msp430_init_builtins): Register void __delay_cycles(long long).
+       (msp430_builtin_decl): Add it.
+       (cg_magic_constant): New.
+       (msp430_expand_delay_cycles): New.
+       (msp430_expand_builtin): Call it.
+       (msp430_print_operand_raw): Change integer printing from "int" to
+       HOST_WIDE_INT.
+       * config/msp430/msp430.md (define_constants): Add delay_cycles tags.
+       (delay_cycles_start): New.
+       (delay_cycles_end): New.
+       (delay_cycles_32): New.
+       (delay_cycles_32x): New.
+       (delay_cycles_16): New.
+       (delay_cycles_16x): New.
+       (delay_cycles_2): New.
+       (delay_cycles_1): New.
+       * doc/extend.texi: Document __delay_cycles().
+
 2014-05-14  Sandra Loosemore  <sandra@codesourcery.com>
 
        * config/nios2/nios2.md (nios2_cbranch): Fix paste-o in
index 1ec96526efd36344b46037ababe53fb32757e529..55b6f0be6b17e5a552bd0f889b4a57b0eff6c793 100644 (file)
@@ -1194,6 +1194,7 @@ enum msp430_builtin
 {
   MSP430_BUILTIN_BIC_SR,
   MSP430_BUILTIN_BIS_SR,
+  MSP430_BUILTIN_DELAY_CYCLES,
   MSP430_BUILTIN_max
 };
 
@@ -1203,6 +1204,7 @@ static void
 msp430_init_builtins (void)
 {
   tree void_ftype_int = build_function_type_list (void_type_node, integer_type_node, NULL);
+  tree void_ftype_longlong = build_function_type_list (void_type_node, long_long_integer_type_node, NULL);
 
   msp430_builtins[MSP430_BUILTIN_BIC_SR] =
     add_builtin_function ( "__bic_SR_register_on_exit", void_ftype_int,
@@ -1211,6 +1213,10 @@ msp430_init_builtins (void)
   msp430_builtins[MSP430_BUILTIN_BIS_SR] =
     add_builtin_function ( "__bis_SR_register_on_exit", void_ftype_int,
                           MSP430_BUILTIN_BIS_SR, BUILT_IN_MD, NULL, NULL_TREE);
+
+  msp430_builtins[MSP430_BUILTIN_DELAY_CYCLES] =
+    add_builtin_function ( "__delay_cycles", void_ftype_longlong,
+                          MSP430_BUILTIN_DELAY_CYCLES, BUILT_IN_MD, NULL, NULL_TREE);
 }
 
 static tree
@@ -1220,12 +1226,126 @@ msp430_builtin_decl (unsigned code, bool initialize ATTRIBUTE_UNUSED)
     {
     case MSP430_BUILTIN_BIC_SR:
     case MSP430_BUILTIN_BIS_SR:
+    case MSP430_BUILTIN_DELAY_CYCLES:
       return msp430_builtins[code];
     default:
       return error_mark_node;
     }
 }
 
+/* These constants are really register reads, which are faster than
+   regular constants.  */
+static int
+cg_magic_constant (HOST_WIDE_INT c)
+{
+  switch (c)
+    {
+    case 0xffff:
+    case -1:
+    case 0:
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+static rtx
+msp430_expand_delay_cycles (rtx arg)
+{
+  HOST_WIDE_INT i, c, n;
+  /* extra cycles for MSP430X instructions */
+#define CYCX(M,X) (msp430x ? (X) : (M))
+
+  if (GET_CODE (arg) != CONST_INT)
+    {
+      error ("__delay_cycles() only takes constant arguments");
+      return NULL_RTX;
+    }
+
+  c = INTVAL (arg);
+
+  if (HOST_BITS_PER_WIDE_INT > 32)
+    {
+      if (c < 0)
+       {
+         error ("__delay_cycles only takes non-negative cycle counts.");
+         return NULL_RTX;
+       }
+    }
+
+  emit_insn (gen_delay_cycles_start (arg));
+
+  /* For 32-bit loops, there's 13(16) + 5(min(x,0x10000) + 6x cycles.  */
+  if (c > 3 * 0xffff + CYCX (7, 10))
+    {
+      n = c;
+      /* There's 4 cycles in the short (i>0xffff) loop and 7 in the long (x<=0xffff) loop */
+      if (c >= 0x10000 * 7 + CYCX (14, 16))
+       {
+         i = 0x10000;
+         c -= CYCX (14, 16) + 7 * 0x10000;
+         i += c / 4;
+         c %= 4;
+         if ((unsigned long long) i > 0xffffffffULL)
+           {
+             error ("__delay_cycles is limited to 32-bit loop counts.");
+             return NULL_RTX;
+           }
+       }
+      else
+       {
+         i = (c - CYCX (14, 16)) / 7;
+         c -= CYCX (14, 16) + i * 7;
+       }
+
+      if (cg_magic_constant (i & 0xffff))
+       c ++;
+      if (cg_magic_constant ((i >> 16) & 0xffff))
+       c ++;
+
+      if (msp430x)
+       emit_insn (gen_delay_cycles_32x (GEN_INT (i), GEN_INT (n - c)));
+      else
+       emit_insn (gen_delay_cycles_32 (GEN_INT (i), GEN_INT (n - c)));
+    }
+
+  /* For 16-bit loops, there's 7(10) + 3x cycles - so the max cycles is 0x30004(7).  */
+  if (c > 12)
+    {
+      n = c;
+      i = (c - CYCX (7, 10)) / 3;
+      c -= CYCX (7, 10) + i * 3;
+
+      if (cg_magic_constant (i))
+       c ++;
+
+      if (msp430x)
+       emit_insn (gen_delay_cycles_16x (GEN_INT (i), GEN_INT (n - c)));
+      else
+       emit_insn (gen_delay_cycles_16 (GEN_INT (i), GEN_INT (n - c)));
+    }
+
+  while (c > 1)
+    {
+      emit_insn (gen_delay_cycles_2 ());
+      c -= 2;
+    }
+
+  if (c)
+    {
+      emit_insn (gen_delay_cycles_1 ());
+      c -= 1;
+    }
+
+  emit_insn (gen_delay_cycles_end (arg));
+
+  return NULL_RTX;
+}
+
 static rtx
 msp430_expand_builtin (tree exp,
                       rtx target ATTRIBUTE_UNUSED,
@@ -1237,6 +1357,9 @@ msp430_expand_builtin (tree exp,
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
   rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0));
 
+  if (fcode == MSP430_BUILTIN_DELAY_CYCLES)
+    return msp430_expand_delay_cycles (arg1);
+
   if (! msp430_is_interrupt_func ())
     {
       error ("MSP430 builtin functions only work inside interrupt handlers");
index 74a98b48019ae9fa83f1c29097b448cb797c1824..ceff537c31db7401fecd39f005ec7a6652eee265 100644 (file)
    UNS_BIS_SR
 
    UNS_REFSYM_NEED_EXIT
+
+   UNS_DELAY_32
+   UNS_DELAY_32X
+   UNS_DELAY_16
+   UNS_DELAY_16X
+   UNS_DELAY_2
+   UNS_DELAY_1
+   UNS_DELAY_START
+   UNS_DELAY_END
   ])
 
 (include "predicates.md")
   "
   )
 
+(define_insn "delay_cycles_start"
+  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
+                   UNS_DELAY_START)]
+  ""
+  "; Begin %J0 cycle delay"
+  )
+
+(define_insn "delay_cycles_end"
+  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
+                   UNS_DELAY_END)]
+  ""
+  "; End %J0 cycle delay"
+  )
+
+(define_insn "delay_cycles_32"
+  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
+                    (match_operand 1 "immediate_operand" "i")
+                    ] UNS_DELAY_32)]
+  ""
+  "PUSH        r13
+       PUSH    r14
+       MOV.W   %A0, r13
+       MOV.W   %B0, r14
+1:     SUB.W   #1, r13
+       SUBC.W  #0, r14
+       JNE     1b
+       TST.W   r13
+       JNE     1b
+       POP     r14
+       POP     r13"
+  )
+
+(define_insn "delay_cycles_32x"
+  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
+                    (match_operand 1 "immediate_operand" "i")
+                    ] UNS_DELAY_32X)]
+  ""
+  "PUSHM.A     #2,r13
+       MOV.W   %A0, r13
+       MOV.W   %B0, r14
+1:     SUB.W   #1, r13
+       SUBC.W  #0, r14
+       JNE     1b
+       TST.W   r13
+       JNE     1b
+       POPM.A  #2,r13"
+  )
+
+(define_insn "delay_cycles_16"
+  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
+                    (match_operand 1 "immediate_operand" "i")
+                    ] UNS_DELAY_16)]
+  ""
+  "PUSH        r13
+       MOV.W   %0, r13
+1:     SUB.W   #1, r13
+       JNE     1b
+       POP     r13"
+  )
+
+(define_insn "delay_cycles_16x"
+  [(unspec_volatile [(match_operand 0 "immediate_operand" "i")
+                    (match_operand 1 "immediate_operand" "i")
+                    ] UNS_DELAY_16X)]
+  ""
+  "PUSHM.A     #1,r13
+       MOV.W   %0, r13
+1:     SUB.W   #1, r13
+       JNE     1b
+       POPM.A  #1,r13"
+  )
+
+(define_insn "delay_cycles_2"
+  [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)]
+  ""
+  "JMP .+2"
+  )
+
+(define_insn "delay_cycles_1"
+  [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)]
+  ""
+  "NOP"
+  )
+
 (define_insn "mulhisi3"
   [(set (match_operand:SI                          0 "register_operand" "=r")
        (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
index 3dee5cb8e794a48eac6641780e2efd834da28ccd..6e99d81f509a67ca36e94fac29a64b098118acfe 100644 (file)
@@ -13194,6 +13194,15 @@ This sets the indicated bits in the saved copy of the status register
 currently residing on the stack.  This only works inside interrupt
 handlers and the changes to the status register will only take affect
 once the handler returns.
+
+@item __delay_cycles (long long @var{cycles})
+This inserts an instruction sequence that takes exactly @var{cycles}
+cycles (between 0 and about 17E9) to complete.  The inserted sequence
+may use jumps, loops, or no-ops, and does not interfere with any other
+instructions.  Note that @var{cycles} must be a compile-time constant
+integer - that is, you must pass a number, not a variable that may be
+optimized to a constant later.  The number of cycles delayed by this
+builtin is exact.
 @end table
 
 @node NDS32 Built-in Functions