aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorFrançois-Xavier Coudert <fxcoudert@gcc.gnu.org>2010-09-07 22:25:08 +0000
committerFrançois-Xavier Coudert <fxcoudert@gcc.gnu.org>2010-09-07 22:25:08 +0000
commit16c0e295094c8f7721d838378f8b692331576887 (patch)
tree79d5b55ac565ae07c2478c721b8819a796a18229 /gcc
parent237e9c04cd786379d85273faa6fed98119ac0c0d (diff)
downloadgcc-16c0e295094c8f7721d838378f8b692331576887.zip
gcc-16c0e295094c8f7721d838378f8b692331576887.tar.gz
gcc-16c0e295094c8f7721d838378f8b692331576887.tar.bz2
trans.h (gfor_fndecl_clz128, [...]): Remove.
* trans.h (gfor_fndecl_clz128, gfor_fndecl_ctz128): Remove. * trans-decl.c (gfor_fndecl_clz128, gfor_fndecl_ctz128): Remove. (gfc_build_intrinsic_function_decls): Don't build the gfor_fndecl_clz128 and gfor_fndecl_ctz128. * trans-intrinsic.c (gfc_conv_intrinsic_leadz, gfc_conv_intrinsic_trailz): Generate inline arithmetic instead of calling clz128/ctz128 library functions. From-SVN: r163976
Diffstat (limited to 'gcc')
-rw-r--r--gcc/fortran/ChangeLog13
-rw-r--r--gcc/fortran/trans-decl.c18
-rw-r--r--gcc/fortran/trans-intrinsic.c122
-rw-r--r--gcc/fortran/trans.h2
4 files changed, 123 insertions, 32 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 84cf449..7a9f678 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,6 +1,17 @@
+2010-09-08 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
+
+ * trans.h (gfor_fndecl_clz128, gfor_fndecl_ctz128): Remove.
+ * trans-decl.c (gfor_fndecl_clz128, gfor_fndecl_ctz128): Remove.
+ (gfc_build_intrinsic_function_decls): Don't build the
+ gfor_fndecl_clz128 and gfor_fndecl_ctz128.
+ * trans-intrinsic.c (gfc_conv_intrinsic_leadz,
+ gfc_conv_intrinsic_trailz): Generate inline arithmetic instead
+ of calling clz128/ctz128 library functions.
+
2010-09-07 Jan Hubicka <jh@suse.cz>
- * trans-expr.c (gfc_conv_initializer): Set STATIC flags for initializers.
+ * trans-expr.c (gfc_conv_initializer): Set STATIC flags for
+ initializers.
2010-09-07 Tobias Burnus <burnus@net-b.de>
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 3514ada..d3d15db 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -150,12 +150,9 @@ tree gfor_fndecl_convert_char4_to_char1;
/* Other misc. runtime library functions. */
-
tree gfor_fndecl_size0;
tree gfor_fndecl_size1;
tree gfor_fndecl_iargc;
-tree gfor_fndecl_clz128;
-tree gfor_fndecl_ctz128;
/* Intrinsic functions implemented in Fortran. */
tree gfor_fndecl_sc_kind;
@@ -2775,21 +2772,6 @@ gfc_build_intrinsic_function_decls (void)
gfor_fndecl_iargc = gfc_build_library_function_decl (
get_identifier (PREFIX ("iargc")), gfc_int4_type_node, 0);
TREE_NOTHROW (gfor_fndecl_iargc) = 1;
-
- if (gfc_type_for_size (128, true))
- {
- tree uint128 = gfc_type_for_size (128, true);
-
- gfor_fndecl_clz128 = gfc_build_library_function_decl (
- get_identifier (PREFIX ("clz128")), integer_type_node, 1, uint128);
- TREE_READONLY (gfor_fndecl_clz128) = 1;
- TREE_NOTHROW (gfor_fndecl_clz128) = 1;
-
- gfor_fndecl_ctz128 = gfc_build_library_function_decl (
- get_identifier (PREFIX ("ctz128")), integer_type_node, 1, uint128);
- TREE_READONLY (gfor_fndecl_ctz128) = 1;
- TREE_NOTHROW (gfor_fndecl_ctz128) = 1;
- }
}
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index c33b20f..53cbc99 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -3433,6 +3433,7 @@ gfc_conv_intrinsic_ishftc (gfc_se * se, gfc_expr * expr)
rrot);
}
+
/* LEADZ (i) = (i == 0) ? BIT_SIZE (i)
: __builtin_clz(i) - (BIT_SIZE('int') - BIT_SIZE(i))
@@ -3477,9 +3478,9 @@ gfc_conv_intrinsic_leadz (gfc_se * se, gfc_expr * expr)
}
else
{
- gcc_assert (argsize == 128);
+ gcc_assert (argsize == 2 * LONG_LONG_TYPE_SIZE);
arg_type = gfc_build_uint_type (argsize);
- func = gfor_fndecl_clz128;
+ func = NULL_TREE;
}
/* Convert the actual argument twice: first, to the unsigned type of the
@@ -3487,14 +3488,66 @@ gfc_conv_intrinsic_leadz (gfc_se * se, gfc_expr * expr)
function. But the return type is of the default INTEGER kind. */
arg = fold_convert (gfc_build_uint_type (argsize), arg);
arg = fold_convert (arg_type, arg);
+ arg = gfc_evaluate_now (arg, &se->pre);
result_type = gfc_get_int_type (gfc_default_integer_kind);
/* Compute LEADZ for the case i .ne. 0. */
- s = TYPE_PRECISION (arg_type) - argsize;
- tmp = fold_convert (result_type, build_call_expr_loc (input_location, func,
- 1, arg));
- leadz = fold_build2_loc (input_location, MINUS_EXPR, result_type,
- tmp, build_int_cst (result_type, s));
+ if (func)
+ {
+ s = TYPE_PRECISION (arg_type) - argsize;
+ tmp = fold_convert (result_type,
+ build_call_expr_loc (input_location, func,
+ 1, arg));
+ leadz = fold_build2_loc (input_location, MINUS_EXPR, result_type,
+ tmp, build_int_cst (result_type, s));
+ }
+ else
+ {
+ /* We end up here if the argument type is larger than 'long long'.
+ We generate this code:
+
+ if (x & (ULL_MAX << ULL_SIZE) != 0)
+ return clzll ((unsigned long long) (x >> ULLSIZE));
+ else
+ return ULL_SIZE + clzll ((unsigned long long) x);
+
+ where ULL_MAX is the largest value that a ULL_MAX can hold
+ (0xFFFFFFFFFFFFFFFF for a 64-bit long long type), and ULLSIZE
+ is the bit-size of the long long type (64 in this example). */
+ tree ullsize, ullmax, tmp1, tmp2;
+
+ ullsize = build_int_cst (result_type, LONG_LONG_TYPE_SIZE);
+ ullmax = fold_build1_loc (input_location, BIT_NOT_EXPR,
+ long_long_unsigned_type_node,
+ build_int_cst (long_long_unsigned_type_node,
+ 0));
+
+ cond = fold_build2_loc (input_location, LSHIFT_EXPR, arg_type,
+ fold_convert (arg_type, ullmax), ullsize);
+ cond = fold_build2_loc (input_location, BIT_AND_EXPR, arg_type,
+ arg, cond);
+ cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
+ cond, build_int_cst (arg_type, 0));
+
+ tmp1 = fold_build2_loc (input_location, RSHIFT_EXPR, arg_type,
+ arg, ullsize);
+ tmp1 = fold_convert (long_long_unsigned_type_node, tmp1);
+ tmp1 = fold_convert (result_type,
+ build_call_expr_loc (input_location,
+ built_in_decls[BUILT_IN_CLZLL],
+ 1, tmp1));
+
+ tmp2 = fold_convert (long_long_unsigned_type_node, arg);
+ tmp2 = fold_convert (result_type,
+ build_call_expr_loc (input_location,
+ built_in_decls[BUILT_IN_CLZLL],
+ 1, tmp2));
+ tmp2 = fold_build2_loc (input_location, PLUS_EXPR, result_type,
+ tmp2, ullsize);
+
+ leadz = fold_build3_loc (input_location, COND_EXPR, result_type,
+ cond, tmp1, tmp2);
+ }
/* Build BIT_SIZE. */
bit_size = build_int_cst (result_type, argsize);
@@ -3505,6 +3558,7 @@ gfc_conv_intrinsic_leadz (gfc_se * se, gfc_expr * expr)
bit_size, leadz);
}
+
/* TRAILZ(i) = (i == 0) ? BIT_SIZE (i) : __builtin_ctz(i)
The conditional expression is necessary because the result of TRAILZ(0)
@@ -3544,9 +3598,9 @@ gfc_conv_intrinsic_trailz (gfc_se * se, gfc_expr *expr)
}
else
{
- gcc_assert (argsize == 128);
+ gcc_assert (argsize == 2 * LONG_LONG_TYPE_SIZE);
arg_type = gfc_build_uint_type (argsize);
- func = gfor_fndecl_ctz128;
+ func = NULL_TREE;
}
/* Convert the actual argument twice: first, to the unsigned type of the
@@ -3554,11 +3608,57 @@ gfc_conv_intrinsic_trailz (gfc_se * se, gfc_expr *expr)
function. But the return type is of the default INTEGER kind. */
arg = fold_convert (gfc_build_uint_type (argsize), arg);
arg = fold_convert (arg_type, arg);
+ arg = gfc_evaluate_now (arg, &se->pre);
result_type = gfc_get_int_type (gfc_default_integer_kind);
/* Compute TRAILZ for the case i .ne. 0. */
- trailz = fold_convert (result_type, build_call_expr_loc (input_location,
- func, 1, arg));
+ if (func)
+ trailz = fold_convert (result_type, build_call_expr_loc (input_location,
+ func, 1, arg));
+ else
+ {
+ /* We end up here if the argument type is larger than 'long long'.
+ We generate this code:
+
+ if ((x & ULL_MAX) == 0)
+ return ULL_SIZE + ctzll ((unsigned long long) (x >> ULLSIZE));
+ else
+ return ctzll ((unsigned long long) x);
+
+ where ULL_MAX is the largest value that a ULL_MAX can hold
+ (0xFFFFFFFFFFFFFFFF for a 64-bit long long type), and ULLSIZE
+ is the bit-size of the long long type (64 in this example). */
+ tree ullsize, ullmax, tmp1, tmp2;
+
+ ullsize = build_int_cst (result_type, LONG_LONG_TYPE_SIZE);
+ ullmax = fold_build1_loc (input_location, BIT_NOT_EXPR,
+ long_long_unsigned_type_node,
+ build_int_cst (long_long_unsigned_type_node, 0));
+
+ cond = fold_build2_loc (input_location, BIT_AND_EXPR, arg_type, arg,
+ fold_convert (arg_type, ullmax));
+ cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, cond,
+ build_int_cst (arg_type, 0));
+
+ tmp1 = fold_build2_loc (input_location, RSHIFT_EXPR, arg_type,
+ arg, ullsize);
+ tmp1 = fold_convert (long_long_unsigned_type_node, tmp1);
+ tmp1 = fold_convert (result_type,
+ build_call_expr_loc (input_location,
+ built_in_decls[BUILT_IN_CTZLL],
+ 1, tmp1));
+ tmp1 = fold_build2_loc (input_location, PLUS_EXPR, result_type,
+ tmp1, ullsize);
+
+ tmp2 = fold_convert (long_long_unsigned_type_node, arg);
+ tmp2 = fold_convert (result_type,
+ build_call_expr_loc (input_location,
+ built_in_decls[BUILT_IN_CTZLL],
+ 1, tmp2));
+
+ trailz = fold_build3_loc (input_location, COND_EXPR, result_type,
+ cond, tmp1, tmp2);
+ }
/* Build BIT_SIZE. */
bit_size = build_int_cst (result_type, argsize);
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 970ae02..a803b53 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -647,8 +647,6 @@ extern GTY(()) tree gfor_fndecl_convert_char4_to_char1;
extern GTY(()) tree gfor_fndecl_size0;
extern GTY(()) tree gfor_fndecl_size1;
extern GTY(()) tree gfor_fndecl_iargc;
-extern GTY(()) tree gfor_fndecl_clz128;
-extern GTY(()) tree gfor_fndecl_ctz128;
/* Implemented in Fortran. */
extern GTY(()) tree gfor_fndecl_sc_kind;