From 4bfb5282bcf861add019d2c6133ecfe01a7dd319 Mon Sep 17 00:00:00 2001 From: fxcoudert Date: Tue, 7 Sep 2010 22:25:08 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@163976 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/fortran/ChangeLog | 13 ++++- gcc/fortran/trans-decl.c | 18 ------- gcc/fortran/trans-intrinsic.c | 122 ++++++++++++++++++++++++++++++++++++++---- gcc/fortran/trans.h | 2 - 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 + + * 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 - * 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 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; -- 2.7.4