about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--Makerules18
-rw-r--r--scripts/gen-as-const.awk63
-rw-r--r--scripts/gen-as-const.py159
4 files changed, 174 insertions, 74 deletions
diff --git a/ChangeLog b/ChangeLog
index f912f8c58c..f478eeed45 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2018-11-30  Joseph Myers  <joseph@codesourcery.com>
+
+	* scripts/gen-as-const.py: New file.
+	* scripts/gen-as-const.awk: Remove.
+	* Makerules ($(common-objpfx)%.h $(common-objpfx)%.h.d): Use
+	gen-as-const.py.
+	($(objpfx)test-as-const-%.c): Likewise.
+
 2018-11-29  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* elf/dl-exception.c: Include <_itoa.h>.
diff --git a/Makerules b/Makerules
index 07bfe8abcb..8e49a73342 100644
--- a/Makerules
+++ b/Makerules
@@ -282,15 +282,12 @@ ifdef gen-as-const-headers
 # may include <tcb-offsets.h>.  Target header files can check if
 # GEN_AS_CONST_HEADERS is defined to avoid circular dependency which
 # may lead to build hang on a many-core machine.
-$(common-objpfx)%.h $(common-objpfx)%.h.d: $(..)scripts/gen-as-const.awk \
+$(common-objpfx)%.h $(common-objpfx)%.h.d: $(..)scripts/gen-as-const.py \
 					   %.sym $(common-before-compile)
-	$(AWK) -f $< $(filter %.sym,$^) \
-	| $(CC) -S -o $(@:.h.d=.h)T3 $(CFLAGS) $(CPPFLAGS) \
-		-DGEN_AS_CONST_HEADERS -x c - \
-		-MD -MP -MF $(@:.h=.h.d)T -MT '$(@:.h=.h.d) $(@:.h.d=.h)'
-	sed -n 's/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$$/#define \1 \2/p' \
-		$(@:.h.d=.h)T3 > $(@:.h.d=.h)T
-	rm -f $(@:.h.d=.h)T3
+	$(PYTHON) $< --cc="$(CC) $(CFLAGS) $(CPPFLAGS) -DGEN_AS_CONST_HEADERS \
+			   -MD -MP -MF $(@:.h=.h.d)T \
+			   -MT '$(@:.h=.h.d) $(@:.h.d=.h)'" \
+		  $(filter %.sym,$^) > $(@:.h.d=.h)T
 	sed $(sed-remove-objpfx) $(sed-remove-dotdot) \
 	    $(@:.h=.h.d)T > $(@:.h=.h.d)T2
 	rm -f $(@:.h=.h.d)T
@@ -301,11 +298,10 @@ before-compile += $(gen-as-const-headers:%.sym=$(common-objpfx)%.h)
 
 tests-internal += $(gen-as-const-headers:%.sym=test-as-const-%)
 generated += $(gen-as-const-headers:%.sym=test-as-const-%.c)
-$(objpfx)test-as-const-%.c: $(..)scripts/gen-as-const.awk $(..)Makerules \
+$(objpfx)test-as-const-%.c: $(..)scripts/gen-as-const.py $(..)Makerules \
 			    %.sym $(common-objpfx)%.h
 	($(AWK) '{ sub(/^/, "asconst_", $$2); print; }' $(filter %.h,$^); \
-	 $(AWK) -v test=1 -f $< $(filter %.sym,$^); \
-	 echo '#include "$(..)test-skeleton.c"') > $@T
+	 $(PYTHON) $< --test $(filter %.sym,$^)) > $@T
 	mv -f $@T $@
 endif
 
diff --git a/scripts/gen-as-const.awk b/scripts/gen-as-const.awk
deleted file mode 100644
index 1ffd5f2c1c..0000000000
--- a/scripts/gen-as-const.awk
+++ /dev/null
@@ -1,63 +0,0 @@
-# Script used in producing headers of assembly constants from C expressions.
-# The input to this script looks like:
-#	#cpp-directive ...
-#	NAME1
-#	NAME2 expression ...
-# The output of this script is C code to be run through gcc -S and then
-# massaged to extract the integer constant values of the given C expressions.
-# A line giving just a name implies an expression consisting of just that name.
-
-BEGIN { started = 0 }
-
-# cpp directives go straight through.
-/^#/ { print; next }
-
-NF >= 1 && !started {
-  if (test) {
-    print "\n#include <inttypes.h>";
-    print "\n#include <stdio.h>";
-    print "\n#include <bits/wordsize.h>";
-    print "\n#if __WORDSIZE == 64";
-    print "\ntypedef uint64_t c_t;";
-    print "\n#define U(n) UINT64_C (n)";
-    print "\n#define PRI PRId64";
-    print "\n#else";
-    print "\ntypedef uint32_t c_t;";
-    print "\n#define U(n) UINT32_C (n)";
-    print "\n#define PRI PRId32";
-    print "\n#endif";
-    print "\nstatic int do_test (void)\n{\n  int bad = 0, good = 0;\n";
-    print "#define TEST(name, source, expr) \\\n" \
-      "  if (U (asconst_##name) != (c_t) (expr)) { ++bad;" \
-      " fprintf (stderr, \"%s: %s is %\" PRI \" but %s is %\"PRI \"\\n\"," \
-      " source, #name, U (asconst_##name), #expr, (c_t) (expr));" \
-      " } else ++good;\n";
-  }
-  else
-    print "void dummy(void) {";
-  started = 1;
-}
-
-# Separator.
-$1 == "--" { next }
-
-NF == 1 { sub(/^.*$/, "& &"); }
-
-NF > 1 {
-  name = $1;
-  sub(/^[^ 	]+[ 	]+/, "");
-  if (test)
-    print "  TEST (" name ", \"" FILENAME ":" FNR "\", " $0 ")";
-  else
-    printf "asm (\"@@@name@@@%s@@@value@@@%%0@@@end@@@\" : : \"i\" ((long) %s));\n",
-      name, $0;
-}
-
-END {
-  if (test) {
-    print "  printf (\"%d errors in %d tests\\n\", bad, good + bad);"
-    print "  return bad != 0 || good == 0;\n}\n";
-    print "#define TEST_FUNCTION do_test ()";
-  }
-  else if (started) print "}";
-}
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
new file mode 100644
index 0000000000..b7a5744bb1
--- /dev/null
+++ b/scripts/gen-as-const.py
@@ -0,0 +1,159 @@
+#!/usr/bin/python3
+# Produce headers of assembly constants from C expressions.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+# The input to this script looks like:
+#       #cpp-directive ...
+#       NAME1
+#       NAME2 expression ...
+# A line giving just a name implies an expression consisting of just that name.
+
+import argparse
+import os.path
+import re
+import subprocess
+import tempfile
+
+
+def compute_c_consts(sym_data, cc):
+    """Compute the values of some C constants.
+
+    The first argument is a list whose elements are either strings
+    (preprocessor directives) or pairs of strings (a name and a C
+    expression for the corresponding value).  Preprocessor directives
+    in the middle of the list may be used to select which constants
+    end up being evaluated using which expressions.
+
+    """
+    out_lines = []
+    started = False
+    for arg in sym_data:
+        if isinstance(arg, str):
+            out_lines.append(arg)
+            continue
+        name = arg[0]
+        value = arg[1]
+        if not started:
+            out_lines.append('void\ndummy (void)\n{')
+            started = True
+        out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
+                         ': : \"i\" ((long int) (%s)));'
+                         % (name, value))
+    if started:
+        out_lines.append('}')
+    out_lines.append('')
+    out_text = '\n'.join(out_lines)
+    with tempfile.TemporaryDirectory() as temp_dir:
+        c_file_name = os.path.join(temp_dir, 'test.c')
+        s_file_name = os.path.join(temp_dir, 'test.s')
+        with open(c_file_name, 'w') as c_file:
+            c_file.write(out_text)
+        # Compilation has to be from stdin to avoid the temporary file
+        # name being written into the generated dependencies.
+        cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name))
+        subprocess.check_call(cmd, shell=True)
+        consts = {}
+        with open(s_file_name, 'r') as s_file:
+            for line in s_file:
+                match = re.search('@@@name@@@([^@]*)'
+                                  '@@@value@@@[^0-9Xxa-fA-F-]*'
+                                  '([0-9Xxa-fA-F-]+).*@@@end@@@', line)
+                if match:
+                    if (match.group(1) in consts
+                        and match.group(2) != consts[match.group(1)]):
+                        raise ValueError('duplicate constant %s'
+                                         % match.group(1))
+                    consts[match.group(1)] = match.group(2)
+        return consts
+
+
+def gen_test(sym_data):
+    """Generate a test for the values of some C constants.
+
+    The first argument is as for compute_c_consts.
+
+    """
+    out_lines = []
+    started = False
+    for arg in sym_data:
+        if isinstance(arg, str):
+            out_lines.append(arg)
+            continue
+        name = arg[0]
+        value = arg[1]
+        if not started:
+            out_lines.append('#include <stdint.h>\n'
+                             '#include <stdio.h>\n'
+                             '#include <bits/wordsize.h>\n'
+                             '#if __WORDSIZE == 64\n'
+                             'typedef uint64_t c_t;\n'
+                             '# define U(n) UINT64_C (n)\n'
+                             '#else\n'
+                             'typedef uint32_t c_t;\n'
+                             '# define U(n) UINT32_C (n)\n'
+                             '#endif\n'
+                             'static int\n'
+                             'do_test (void)\n'
+                             '{\n'
+                             # Compilation test only, using static assertions.
+                             '  return 0;\n'
+                             '}\n'
+                             '#include <support/test-driver.c>')
+            started = True
+        out_lines.append('_Static_assert (U (asconst_%s) == (c_t) (%s), '
+                         '"value of %s");'
+                         % (name, value, name))
+    return '\n'.join(out_lines)
+
+
+def main():
+    """The main entry point."""
+    parser = argparse.ArgumentParser(
+        description='Produce headers of assembly constants.')
+    parser.add_argument('--cc', metavar='CC',
+                        help='C compiler (including options) to use')
+    parser.add_argument('--test', action='store_true',
+                        help='Generate test case instead of header')
+    parser.add_argument('sym_file',
+                        help='.sym file to process')
+    args = parser.parse_args()
+    sym_data = []
+    with open(args.sym_file, 'r') as sym_file:
+        for line in sym_file:
+            line = line.strip()
+            if line == '':
+                continue
+            # Pass preprocessor directives through.
+            if line.startswith('#'):
+                sym_data.append(line)
+                continue
+            words = line.split(maxsplit=1)
+            # Separator.
+            if words[0] == '--':
+                continue
+            name = words[0]
+            value = words[1] if len(words) > 1 else words[0]
+            sym_data.append((name, value))
+    if args.test:
+        print(gen_test(sym_data))
+    else:
+        consts = compute_c_consts(sym_data, args.cc)
+        print('\n'.join('#define %s %s' % c for c in sorted(consts.items())))
+
+if __name__ == '__main__':
+    main()