From patchwork Wed May 14 21:30:15 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 348992 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id C11B8140085 for ; Thu, 15 May 2014 08:23:28 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :message-id:from:to:subject; q=dns; s=default; b=RhnjkvP0DmihT1a oFNNMfl7j4WAdHntTyQB32muDNVwkf7uk6OwivJHOrB/pQ8iNq7tpquD5nLN6BVl rLo6giLvp8OQNlNb2fQwmLRsa0pVWifatpTPk6tSJcUqSkH6iXYP3cr8SsOqsTbG s2e6A0gBJsNGB5ktkCPhk0z7P/CM= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :message-id:from:to:subject; s=default; bh=CvnFGHCujAdhEbeiwkyRr KBLXp0=; b=sO+QQGQjvyegw9zUZPFA1iRejymPv70L6jJJl7ealyTA79h82QuMy VkDrTfk68GUPdDIbgQpLWjErxM6eZPMFL5QJYGpL6tJukKjAKlnotr/QJghMzi4F T9C4aH5tgnPh/5XpCO2GHuNYHMhlJVbuiIqo9luNAUY4RYO7brJmEw= Received: (qmail 10203 invoked by alias); 14 May 2014 22:22:49 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 10117 invoked by uid 89); 14 May 2014 22:22:49 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.2 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 14 May 2014 22:22:47 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s4EMMjCZ002055 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Wed, 14 May 2014 18:22:45 -0400 Received: from greed.delorie.com (ovpn-113-109.phx2.redhat.com [10.3.113.109]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s4ELUGCe029742 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Wed, 14 May 2014 17:30:17 -0400 Received: from greed.delorie.com (greed.delorie.com [127.0.0.1]) by greed.delorie.com (8.14.4/8.14.4) with ESMTP id s4ELUFge008594 for ; Wed, 14 May 2014 17:30:15 -0400 Received: (from dj@localhost) by greed.delorie.com (8.14.4/8.14.4/Submit) id s4ELUFp7008593; Wed, 14 May 2014 17:30:15 -0400 Date: Wed, 14 May 2014 17:30:15 -0400 Message-Id: <201405142130.s4ELUFp7008593@greed.delorie.com> From: DJ Delorie To: gcc-patches@gcc.gnu.org Subject: [msp430] add __delay_cycles() builtin X-IsSubscribed: yes Adds a new __delay_cycles() builtin to the msp430 backend. Committed. * 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(). Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 210437) +++ gcc/doc/extend.texi (working copy) @@ -13191,12 +13191,21 @@ once the handler returns. @item __bis_SR_register_on_exit (int @var{mask}) 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 @subsection NDS32 Built-in Functions These built-in functions are available for the NDS32 target: Index: gcc/config/msp430/msp430.md =================================================================== --- gcc/config/msp430/msp430.md (revision 210437) +++ gcc/config/msp430/msp430.md (working copy) @@ -44,12 +44,21 @@ UNS_PUSH_INTR UNS_POP_INTR UNS_BIC_SR 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") (include "constraints.md") (define_mode_iterator QHI [QI HI PSI]) @@ -1314,12 +1323,96 @@ return \"MOV.W\t%1, %0 { SUB.W\t#0, %0 { AND.W\t%2, %0\"; else return \"SUB.W\t#0, %0 { AND.W\t%2, %0\"; " ) +(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")) (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] "optimize > 2 && msp430_hwmult_type != NONE" "* Index: gcc/config/msp430/msp430.c =================================================================== --- gcc/config/msp430/msp430.c (revision 210437) +++ gcc/config/msp430/msp430.c (working copy) @@ -1191,55 +1191,178 @@ msp430_function_section (tree decl, enum #define TARGET_ASM_FUNCTION_SECTION msp430_function_section enum msp430_builtin { MSP430_BUILTIN_BIC_SR, MSP430_BUILTIN_BIS_SR, + MSP430_BUILTIN_DELAY_CYCLES, MSP430_BUILTIN_max }; static GTY(()) tree msp430_builtins [(int) MSP430_BUILTIN_max]; 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, MSP430_BUILTIN_BIC_SR, BUILT_IN_MD, NULL, NULL_TREE); 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 msp430_builtin_decl (unsigned code, bool initialize ATTRIBUTE_UNUSED) { switch (code) { 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, rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) { tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); 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"); return NULL_RTX; }