From patchwork Wed Jan 13 00:53:12 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Jesper_Broge_J=C3=B8rgensen?= X-Patchwork-Id: 566777 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 A4762140BA1 for ; Wed, 13 Jan 2016 11:53:31 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=sJPzZ6PQ; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type :content-transfer-encoding; q=dns; s=default; b=J7kGcxrHVomtx9LY OQe6+PH+kgXxunm8rk35tyrkX0dOKtzsHAuKXxoJaQ2EZ7TEyLjuXk724DbjLXTZ 10g+wylyN05GHHTgSKyErCYAqSeIdPcaQ8jczZOOF/kil7tbXgTAAD4UytaffuPv SsfO2UlP5TkarRWStODkeZGzfhg= 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 :message-id:date:from:mime-version:to:subject:content-type :content-transfer-encoding; s=default; bh=AdZaEOytCduandzlJhokgg Gum4g=; b=sJPzZ6PQBDjh0ppbdq1dozd7BHUU+s1mAJJnZW5djhN9dcW2FWYJ0H O/2Sj9mt+xLftfMBcc949Gp/C9sBr6Dj+AjeDurFL3Sic5ju8hm5g4bvwcftCXpc MC2H7CCaNx0+fCYxTASIzGSy2PB01alHwbLcyPGCNajTkGkR4cvLk= Received: (qmail 42334 invoked by alias); 13 Jan 2016 00:53:19 -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 41668 invoked by uid 89); 13 Jan 2016 00:53:18 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 spammy=attr, is_const, sk:check_a, 2758 X-HELO: mail-wm0-f47.google.com Received: from mail-wm0-f47.google.com (HELO mail-wm0-f47.google.com) (74.125.82.47) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Wed, 13 Jan 2016 00:53:16 +0000 Received: by mail-wm0-f47.google.com with SMTP id b14so347508738wmb.1 for ; Tue, 12 Jan 2016 16:53:16 -0800 (PST) X-Received: by 10.28.47.213 with SMTP id v204mr21422197wmv.69.1452646393445; Tue, 12 Jan 2016 16:53:13 -0800 (PST) Received: from Jespers-MacBook-Pro.local ([178.157.250.38]) by smtp.googlemail.com with ESMTPSA id cs4sm126974482wjc.10.2016.01.12.16.53.12 for (version=TLSv1/SSLv3 cipher=OTHER); Tue, 12 Jan 2016 16:53:12 -0800 (PST) Message-ID: <56959FF8.9070908@gmail.com> Date: Wed, 13 Jan 2016 01:53:12 +0100 From: =?ISO-8859-1?Q?Jesper_Broge_J=F8rgensen?= User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:24.0) Gecko/20100101 Thunderbird/24.6.0 MIME-Version: 1.0 To: gcc-patches@gcc.gnu.org Subject: genattrab.c generate switch Hello genattrab.c can generate if statements that have very deep bracket nesting causing clang to produce errors (when target=arm-none-eabi) as explained at https://gcc.gnu.org/ml/gcc/2014-05/msg00032.html At the above link it was suggested that genattrab.c generated a switch statement instead. I have made a patch that does just that. gcc/ChangeLog: 2016-01-13 Jesper Broge Jørgensen * genattrtab.c (check_attr_set_switch): implemented the function (write_attr_set): Check if expression can be written as a switch const char *, const char *, rtx, int, int, unsigned int); @@ -4113,6 +4115,102 @@ eliminate_known_true (rtx known_true, rtx exp, int insn_code, int insn_index) return exp; } +/* Check if exp contains a series of IOR conditions on the same attr_name. + If it does it can be turned into a switch statement and returns true. + If write_cases is true it will write the cases of the switch to outf. */ + +static int +check_attr_set_switch (FILE *outf, rtx exp, unsigned int attrs_cached, + int write_cases, int indent) +{ + if (GET_CODE (exp) != IOR) + return 0; + if (GET_CODE (XEXP (exp, 0)) != EQ_ATTR) + return 0; + + rtx next = exp; + int ior_depth = 0; + int is_first = 1; + + const char *attr_name_cmp = XSTR (XEXP (exp, 0), 0); + + while (1) + { + rtx op1 = XEXP (next, 0); + rtx op2 = XEXP (next, 1); + + if (GET_CODE (op1) != EQ_ATTR) + return 0; + + const char *attr_name = XSTR (op1, 0); + const char *cmp_val = XSTR (op1, 1); + + /* pointer compare is enough. */ + if (attr_name_cmp != attr_name) + return 0; + + if (write_cases) + { + struct attr_desc *attr = find_attr (&attr_name, 0); + gcc_assert (attr); + if (is_first) + { + fprintf (outf, "("); + is_first = 0; + int i; + for (i = 0; i < cached_attr_count; i++) + if (attr->name == cached_attrs[i]) + break; + + if (i < cached_attr_count && (attrs_cached & (1U << i)) != 0) + fprintf (outf, "cached_%s", attr->name); + else if (i < cached_attr_count && (attrs_to_cache & (1U << i)) != 0) + fprintf (outf, "(cached_%s = get_attr_%s (insn))", attr->name, + attr->name); + else + fprintf (outf, "get_attr_%s (insn)", attr->name); + fprintf (outf, ")\n"); + write_indent (outf, indent); + fprintf (outf, "{\n"); + } + write_indent (outf, indent); + fprintf (outf, "case "); + write_attr_valueq (outf, attr, cmp_val); + fprintf (outf, ":\n"); + } + + const int code = GET_CODE (op2); + if (code != IOR) + { + if (code == EQ_ATTR) + { + const char *attr_name = XSTR (op2, 0); + const char *cmp_val = XSTR (op2, 1); + + if (attr_name == alternative_name) + return 0; + + struct attr_desc *attr = find_attr (&attr_name, 0); + gcc_assert (attr); + + if (attr->is_const) + return 0; + else if (write_cases) + { + write_indent (outf, indent); + fprintf (outf, "case "); + write_attr_valueq (outf, attr, cmp_val); + fprintf (outf, ":\n"); + } + } + break; + } + next = op2; + ior_depth++; + } + return ior_depth > 2; +} + /* Write out a series of tests and assignment statements to perform tests and sets of an attribute value. We are passed an indentation amount and prefix and suffix strings to write around each attribute value (e.g., "return" @@ -4123,6 +4221,7 @@ write_attr_set (FILE *outf, struct attr_desc *attr, int indent, rtx value, const char *prefix, const char *suffix, rtx known_true, int insn_code, int insn_index, unsigned int attrs_cached) { + int n_switches = 0; if (GET_CODE (value) == COND) { /* Assume the default value will be the default of the COND unless we @@ -4132,6 +4231,7 @@ write_attr_set (FILE *outf, struct attr_desc *attr, int indent, rtx value, rtx newexp; int first_if = 1; int i; + int is_switch = 0; if (cached_attr_count) { @@ -4176,40 +4276,68 @@ write_attr_set (FILE *outf, struct attr_desc *attr, int indent, rtx value, if (inner_true == false_rtx) continue; + is_switch = check_attr_set_switch (outf, testexp, attrs_cached, 0, + indent); + attrs_cached_inside = attrs_cached; attrs_cached_after = attrs_cached; write_indent (outf, indent); - fprintf (outf, "%sif ", first_if ? "" : "else "); - first_if = 0; - write_test_expr (outf, testexp, attrs_cached, - (FLG_AFTER | FLG_INSIDE | FLG_OUTSIDE_AND)); - attrs_cached = attrs_cached_after; - fprintf (outf, "\n"); - write_indent (outf, indent + 2); - fprintf (outf, "{\n"); + if (is_switch) + { + fprintf (outf, "switch "); + n_switches++; + first_if = 1; + check_attr_set_switch (outf, testexp, attrs_cached, 1, indent); + indent += 4; + } + else + { + fprintf (outf, "%sif ", first_if ? "" : "else "); + first_if = 0; + write_test_expr (outf, testexp, attrs_cached, + (FLG_AFTER | FLG_INSIDE | FLG_OUTSIDE_AND)); + attrs_cached = attrs_cached_after; + fprintf (outf, "\n"); + } + if (! is_switch) + { + write_indent (outf, indent + 2); + fprintf (outf, "{\n"); + } + write_attr_set (outf, attr, indent + 4, XVECEXP (value, 0, i + 1), prefix, suffix, inner_true, insn_code, insn_index, attrs_cached_inside); write_indent (outf, indent + 2); - fprintf (outf, "}\n"); + if (is_switch) + { + fprintf (outf, "break;\n"); + write_indent (outf, indent); + fprintf (outf, "default:\n"); + indent += 4; + } + else + fprintf (outf, "}\n"); our_known_true = newexp; } - if (! first_if) + if (! first_if && ! is_switch) { write_indent (outf, indent); fprintf (outf, "else\n"); write_indent (outf, indent + 2); fprintf (outf, "{\n"); } + else if (is_switch) + write_indent (outf, indent); - write_attr_set (outf, attr, first_if ? indent : indent + 4, default_val, + write_attr_set (outf, attr, (first_if || is_switch) ? indent : indent + 4, default_val, prefix, suffix, our_known_true, insn_code, insn_index, attrs_cached); - if (! first_if) + if (! first_if && ! is_switch) { write_indent (outf, indent + 2); fprintf (outf, "}\n"); @@ -4222,6 +4350,12 @@ write_attr_set (FILE *outf, struct attr_desc *attr, int indent, rtx value, write_attr_value (outf, attr, value); fprintf (outf, "%s\n", suffix); } + while (n_switches--) + { + indent -= 2; + write_indent (outf, indent); + fprintf (outf, "}\n"); + } } /* Write a series of case statements for every instruction in list IE. diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c index 2caf8f6..b6de642 100644 --- a/gcc/genattrtab.c +++ b/gcc/genattrtab.c @@ -275,6 +275,8 @@ static bool attr_alt_subset_of_compl_p (rtx, rtx); static void clear_struct_flag (rtx); static void write_attr_valueq (FILE *, struct attr_desc *, const char *); static struct attr_value *find_most_used (struct attr_desc *); +static int check_attr_set_switch (FILE *outf, rtx exp, + unsigned int attrs_cached, int write_cases, int indent); static void write_attr_set (FILE *, struct attr_desc *, int, rtx,