msp430.c (msp430_builtin): Add MSP430_BUILTIN_DELAY_CYCLES.

* 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
This commit is contained in:
DJ Delorie 2014-05-14 17:27:21 -04:00 committed by DJ Delorie
parent 5d40b20f6e
commit 5f35dde552
4 changed files with 247 additions and 0 deletions

View 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

View 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");

View File

@ -47,6 +47,15 @@
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")
@ -1317,6 +1326,90 @@
"
)
(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"))

View 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