From patchwork Fri Mar 30 16:37:43 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Matz X-Patchwork-Id: 149682 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 64D3CB6EF4 for ; Sat, 31 Mar 2012 03:38:15 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1333730295; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Date: From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type: Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:Sender:Delivered-To; bh=o/20RajrtgrBqiniayfy +3sLKr0=; b=kYKSAQIYMcZlKr08oM/ZZ7VftjMugTLCnOu8IJmcfSuhYVyKuDq7 ppXpNcZ4ANKQC5InH6skCyiTbXCvO665O05yeh2t+y+edpAnwUE+BFS+5rumdT7o Cf/l1FDADx75FNGVCfrGuI03lPnmvAKt2tCzz+NCEBD9MDU0vOykaMs= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Date:From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=P3F6wk2y88Lx1zF91zJgBaYyMt6WWsxnm9PMeE6O9qd3osygANq0axp+nSfHfQ JLY2dwyYoiqGErTyjsWbJgjLC1mS8MR4FCc0mA056lr2o1V62aarNgDyzHGyxMoh 4ki2A6ZRzRj0H90aiIoqilhv2mRgyyvIIgTF4Bnw0Zj7I=; Received: (qmail 6781 invoked by alias); 30 Mar 2012 16:38:08 -0000 Received: (qmail 5947 invoked by uid 22791); 30 Mar 2012 16:38:01 -0000 X-SWARE-Spam-Status: No, hits=-5.0 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, TW_TM, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from cantor2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 30 Mar 2012 16:37:46 +0000 Received: from relay1.suse.de (unknown [195.135.220.254]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx2.suse.de (Postfix) with ESMTP id 1783E8FE2D; Fri, 30 Mar 2012 18:37:44 +0200 (CEST) Date: Fri, 30 Mar 2012 18:37:43 +0200 (CEST) From: Michael Matz To: gcc-patches@gcc.gnu.org Cc: rth@redhat.com Subject: [rfc] Fix PR52770 (supoport throwing asms) Message-ID: MIME-Version: 1.0 X-IsSubscribed: yes 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 Hi, So here's an extended variant of my hack that implements throwing asms. Like rth proposed I've added a new pseudo clobber, "throw": int f (void) { int x, y; x = 1; y = 2; try { __asm__ ("" : "=r"(x), "=r"(y) : : "throw"); } catch (...) { return 2+x+y; } return x+y; } The patch handles multiple output arguments by doing the same we do for calls, i.e. introducing new temporaries. For gimple this clobber is retained and hence a throwing asm can be simply recognized by searching for it. For RTL I've added a new flag to mark the ASM_OPERANDS rtx. Without such marking we would have to treat every asm as potentially throwing in insn_could_throw_p, and rely on the REG_EH_REGION notes to mark them as non-throwing. Instead of auditing all MEM_VOLATILE_P uses on asms to see if they require handling throwing I've settled on simply implying the volatile bit for throwing asms. Not yet regstrapped, so no rfa, but does this seem sane? Ciao, Michael. Index: tree-eh.c =================================================================== --- tree-eh.c (revision 183716) +++ tree-eh.c (working copy) @@ -1990,6 +1990,44 @@ lower_eh_constructs_2 (struct leh_state } break; + case GIMPLE_ASM: + /* Similar to normal LHS handling above, replace outputs + with new temporaries. */ + if (stmt_could_throw_p (stmt) + && gimple_code (stmt) == GIMPLE_ASM) + { + unsigned noutputs; + unsigned i; + + noutputs = gimple_asm_noutputs (stmt); + for (i = 0; i < noutputs; i++) + { + tree link, op; + link = gimple_asm_output_op (stmt, i); + op = TREE_VALUE (link); + if (!tree_could_throw_p (op) + && is_gimple_reg_type (TREE_TYPE (op))) + { + tree tmp = create_tmp_var (TREE_TYPE (op), NULL); + gimple s = gimple_build_assign (op, tmp); + gimple_set_location (s, gimple_location (stmt)); + gimple_set_block (s, gimple_block (stmt)); + TREE_VALUE (link) = tmp; + if (TREE_CODE (TREE_TYPE (tmp)) == COMPLEX_TYPE + || TREE_CODE (TREE_TYPE (tmp)) == VECTOR_TYPE) + DECL_GIMPLE_REG_P (tmp) = 1; + gsi_insert_after (gsi, s, GSI_SAME_STMT); + } + } + } + /* Look for things that can throw exceptions, and record them. */ + if (state->cur_region && stmt_could_throw_p (stmt)) + { + record_stmt_eh_region (state->cur_region, stmt); + note_eh_region_may_contain_throw (state->cur_region); + } + break; + case GIMPLE_COND: case GIMPLE_GOTO: case GIMPLE_RETURN: @@ -2639,6 +2677,8 @@ stmt_could_throw_p (gimple stmt) return stmt_could_throw_1_p (stmt); case GIMPLE_ASM: + if (gimple_asm_can_throw_p (stmt)) + return true; if (!cfun->can_throw_non_call_exceptions) return false; return gimple_asm_volatile_p (stmt); Index: varasm.c =================================================================== --- varasm.c (revision 183716) +++ varasm.c (working copy) @@ -834,9 +834,10 @@ set_user_assembler_name (tree decl, cons /* Decode an `asm' spec for a declaration as a register name. Return the register number, or -1 if nothing specified, - or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized, + or -2 if the ASMSPEC is not `cc', `memory' or `throw' and is not recognized, or -3 if ASMSPEC is `cc' and is not recognized, - or -4 if ASMSPEC is `memory' and is not recognized. + or -4 if ASMSPEC is `memory' and is not recognized, + or -5 if ASMSPEC is `throw' and is not recognized. Accept an exact spelling or a decimal number. Prefixes such as % are optional. */ @@ -902,6 +903,9 @@ decode_reg_name_and_count (const char *a } #endif /* ADDITIONAL_REGISTER_NAMES */ + if (!strcmp (asmspec, "throw")) + return -5; + if (!strcmp (asmspec, "memory")) return -4; Index: rtl.h =================================================================== --- rtl.h (revision 183716) +++ rtl.h (working copy) @@ -266,7 +266,8 @@ struct GTY((chain_next ("RTX_NEXT (&%h)" 1 in a CALL_INSN if it is a sibling call. 1 in a SET that is for a return. In a CODE_LABEL, part of the two-bit alternate entry field. - 1 in a CONCAT is VAL_EXPR_IS_COPIED in var-tracking.c. */ + 1 in a CONCAT is VAL_EXPR_IS_COPIED in var-tracking.c. + 1 in an ASM_OPERANDS is ASM_OPERANDS_THROW_P. */ unsigned int jump : 1; /* In a CODE_LABEL, part of the two-bit alternate entry field. 1 in a MEM if it cannot trap. @@ -1317,6 +1318,8 @@ do { \ #define ASM_OPERANDS_LABEL_LENGTH(RTX) XCVECLEN (RTX, 5, ASM_OPERANDS) #define ASM_OPERANDS_LABEL(RTX, N) XCVECEXP (RTX, 5, N, ASM_OPERANDS) #define ASM_OPERANDS_SOURCE_LOCATION(RTX) XCUINT (RTX, 6, ASM_OPERANDS) +#define ASM_OPERANDS_THROW_P(RTX) \ + (RTL_FLAG_CHECK1("ASM_OPERANDS_THROW_P", (RTX), ASM_OPERANDS)->jump) #define ASM_INPUT_SOURCE_LOCATION(RTX) XCUINT (RTX, 1, ASM_INPUT) /* 1 if RTX is a mem that is statically allocated in read-only memory. */ Index: gimple.c =================================================================== --- gimple.c (revision 183716) +++ gimple.c (working copy) @@ -5513,4 +5513,21 @@ gimple_asm_clobbers_memory_p (const_gimp return false; } + +/* Return true if the GIMPLE_ASM STMT can throw. */ + +bool +gimple_asm_can_throw_p (const_gimple stmt) +{ + unsigned i; + + for (i = 0; i < gimple_asm_nclobbers (stmt); i++) + { + tree op = gimple_asm_clobber_op (stmt, i); + if (strcmp (TREE_STRING_POINTER (TREE_VALUE (op)), "throw") == 0) + return true; + } + + return false; +} #include "gt-gimple.h" Index: gimple.h =================================================================== --- gimple.h (revision 183716) +++ gimple.h (working copy) @@ -1030,6 +1030,7 @@ extern bool walk_stmt_load_store_ops (gi extern bool gimple_ior_addresses_taken (bitmap, gimple); extern bool gimple_call_builtin_p (gimple, enum built_in_function); extern bool gimple_asm_clobbers_memory_p (const_gimple); +extern bool gimple_asm_can_throw_p (const_gimple); /* In gimplify.c */ extern tree create_tmp_var_raw (tree, const char *); Index: tree-cfg.c =================================================================== --- tree-cfg.c (revision 183716) +++ tree-cfg.c (working copy) @@ -580,6 +580,8 @@ make_edges (void) case GIMPLE_ASM: make_gimple_asm_edges (bb); + if (is_ctrl_altering_stmt (last)) + make_eh_edges (last); fallthru = true; break; Index: stmt.c =================================================================== --- stmt.c (revision 183716) +++ stmt.c (working copy) @@ -657,6 +657,7 @@ expand_asm_operands (tree string, tree o enum machine_mode *inout_mode = XALLOCAVEC (enum machine_mode, noutputs); const char **constraints = XALLOCAVEC (const char *, noutputs + ninputs); int old_generating_concat_p = generating_concat_p; + bool throw_p = false; /* An ASM with no outputs needs to be treated as volatile, for now. */ if (noutputs == 0) @@ -696,6 +697,11 @@ expand_asm_operands (tree string, tree o i = decode_reg_name_and_count (regname, &nregs); if (i == -4) ++nclobbers; + else if (i == -5) + { + throw_p = true; + vol = 1; + } else if (i == -2) error ("unknown register name %qs in %", regname); @@ -872,6 +878,7 @@ expand_asm_operands (tree string, tree o labelvec, locus); MEM_VOLATILE_P (body) = vol; + ASM_OPERANDS_THROW_P (body) = throw_p; /* Eval the inputs and put them into ARGVEC. Put their constraints into ASM_INPUTs and store in CONSTRAINTS. */ @@ -1028,6 +1035,7 @@ expand_asm_operands (tree string, tree o i, argvec, constraintvec, labelvec, locus)); MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol; + ASM_OPERANDS_THROW_P (SET_SRC (XVECEXP (body, 0, i))) = throw_p; } /* If there are no outputs (but there are some clobbers) Index: except.c =================================================================== --- except.c (revision 183716) +++ except.c (working copy) @@ -1622,12 +1622,16 @@ make_reg_eh_region_note_nothrow_nononloc bool insn_could_throw_p (const_rtx insn) { + rtx tmp; if (!flag_exceptions) return false; if (CALL_P (insn)) return true; if (INSN_P (insn) && cfun->can_throw_non_call_exceptions) return may_trap_p (PATTERN (insn)); + if (INSN_P (insn) + && (tmp = extract_asm_operands (PATTERN (insn))) != NULL) + return ASM_OPERANDS_THROW_P (tmp); return false; } Index: cfgbuild.c =================================================================== --- cfgbuild.c (revision 183716) +++ cfgbuild.c (working copy) @@ -82,6 +82,7 @@ inside_basic_block_p (const_rtx insn) bool control_flow_insn_p (const_rtx insn) { + rtx tmp; switch (GET_CODE (insn)) { case NOTE: @@ -112,6 +113,8 @@ control_flow_insn_p (const_rtx insn) if (GET_CODE (PATTERN (insn)) == TRAP_IF && XEXP (PATTERN (insn), 0) == const1_rtx) return true; + if ((tmp = extract_asm_operands (PATTERN (insn))) != NULL) + return can_throw_internal (insn); if (!cfun->can_throw_non_call_exceptions) return false; break; @@ -364,6 +367,8 @@ make_edges (basic_block min, basic_block } } } + else if (code == INSN && extract_asm_operands (PATTERN (insn))) + rtl_make_eh_edge (edge_cache, bb, insn); /* Find out if we can drop through to the next block. */ insn = NEXT_INSN (insn); Index: testsuite/g++.dg/eh/pr52770.C =================================================================== --- testsuite/g++.dg/eh/pr52770.C (revision 0) +++ testsuite/g++.dg/eh/pr52770.C (revision 0) @@ -0,0 +1,16 @@ +// PR c++/52770 +// { dg-do compile } +// { dg-final { scan-assembler "EHB" } } +// { dg-options "-O2" } +int f (void) +{ + int x, y; + x = 1; + y = 2; + try { + __asm__ ("" : "=r"(x), "=r"(y) : : "throw"); + } catch (...) { + return 2+x+y; + } + return x+y; +}