From patchwork Fri Dec 16 23:37:43 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Botcazou X-Patchwork-Id: 131940 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]) by ozlabs.org (Postfix) with SMTP id 57F9F1007D7 for ; Sat, 17 Dec 2011 10:39:57 +1100 (EST) Received: (qmail 10607 invoked by alias); 16 Dec 2011 23:39:55 -0000 Received: (qmail 10596 invoked by uid 22791); 16 Dec 2011 23:39:54 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from mel.act-europe.fr (HELO mel.act-europe.fr) (194.98.77.210) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 16 Dec 2011 23:39:38 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id E0D17CB1B6E for ; Sat, 17 Dec 2011 00:39:38 +0100 (CET) Received: from mel.act-europe.fr ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id JfdzF0gaBfFu for ; Sat, 17 Dec 2011 00:39:38 +0100 (CET) Received: from [192.168.1.2] (bon31-6-88-161-99-133.fbx.proxad.net [88.161.99.133]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mel.act-europe.fr (Postfix) with ESMTP id A2EEFCB1B6B for ; Sat, 17 Dec 2011 00:39:38 +0100 (CET) From: Eric Botcazou To: gcc-patches@gcc.gnu.org Subject: [SPARC] Emit memory blockage for non-atomic %sp decrement Date: Sat, 17 Dec 2011 00:37:43 +0100 User-Agent: KMail/1.9.9 MIME-Version: 1.0 Message-Id: <201112170037.43781.ebotcazou@adacore.com> 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 In regular mode (with register windows), the compiler can make use of three sequences to establish the frame: 1. a single 'save' instruction taking an immediate as decrement, 2. a 'save' instruction taking an immediate followed by an 'add' instruction taking another immediate as decrement, 3. a single 'save' instruction taking a register as decrement. The first and third sequences are atomic, whereas the second isn't. Therefore it might possible for a %fp-based store instruction to be scheduled between the two frame instructions in the second sequence; if, additionally, the offset is close to the frame size, then the store might access the register window save area, which is volatile. The net effect might be as though the store wasn't issued at all (because it is quickly overwritten). The adverse effect seems to be a very rare event in practice, as I observed it for the first time a couple of days ago and AFAIK it was never reported to us for the SPARC. But the x86 port has a counter-measure for something similar. The attached patch implements a 'frame blockage', which is a memory blockage with a dependency on the stack pointer. This is sufficient to order the stack pointer decrement instructions and the subsequent stores. Tested on SPARC/Solaris, applied on mainline, 4.6 and 4.5 branches. 2011-12-16 Eric Botcazou * config/sparc/sparc.md (UNSPEC_FRAME_BLOCKAGE): New constant. (frame_blockage): New expander. (frame_blockage): New instruction. * config/sparc/sparc.c (sparc_expand_prologue): When the sequence of instructions establishing the frame isn't atomic, emit frame blockage. Index: config/sparc/sparc.md =================================================================== --- config/sparc/sparc.md (revision 182398) +++ config/sparc/sparc.md (working copy) @@ -28,6 +28,7 @@ (define_constants [(UNSPEC_MOVE_PIC 0) (UNSPEC_UPDATE_RETURN 1) (UNSPEC_LOAD_PCREL_SYM 2) + (UNSPEC_FRAME_BLOCKAGE 3) (UNSPEC_MOVE_PIC_LABEL 5) (UNSPEC_SETH44 6) (UNSPEC_SETM44 7) @@ -6374,6 +6375,25 @@ (define_insn "blockage" "" "" [(set_attr "length" "0")]) + +;; Do not schedule instructions accessing memory before this point. + +(define_expand "frame_blockage" + [(set (match_dup 0) + (unspec:BLK [(match_dup 1)] UNSPEC_FRAME_BLOCKAGE))] + "" +{ + operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); + MEM_VOLATILE_P (operands[0]) = 1; + operands[1] = stack_pointer_rtx; +}) + +(define_insn "*frame_blockage" + [(set (match_operand:BLK 0 "" "") + (unspec:BLK [(match_operand:P 1 "" "")] UNSPEC_FRAME_BLOCKAGE))] + "" + "" + [(set_attr "length" "0")]) (define_expand "probe_stack" [(set (match_operand 0 "memory_operand" "") (const_int 0))] Index: config/sparc/sparc.c =================================================================== --- config/sparc/sparc.c (revision 182398) +++ config/sparc/sparc.c (working copy) @@ -4972,8 +4972,9 @@ sparc_expand_prologue (void) else if (size <= 8192) { insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096))); - /* %sp is still the CFA register. */ RTX_FRAME_RELATED_P (insn) = 1; + + /* %sp is still the CFA register. */ insn = emit_insn (gen_stack_pointer_inc (GEN_INT (4096 - size))); } else @@ -4996,8 +4997,18 @@ sparc_expand_prologue (void) else if (size <= 8192) { emit_window_save (GEN_INT (-4096)); + /* %sp is not the CFA register anymore. */ emit_insn (gen_stack_pointer_inc (GEN_INT (4096 - size))); + + /* Make sure no %fp-based store is issued until after the frame is + established. The offset between the frame pointer and the stack + pointer is calculated relative to the value of the stack pointer + at the end of the function prologue, and moving instructions that + access the stack via the frame pointer between the instructions + that decrement the stack pointer could result in accessing the + register window save area, which is volatile. */ + emit_insn (gen_frame_blockage ()); } else {