diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-12-02 10:40:41 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-12-02 10:40:41 +0000 |
commit | a634a685a892b0ef270b2ce7454290f4d83cc715 (patch) | |
tree | 46788ae87e00f56ecc4ee43355d56869b303f7a9 | |
parent | 52a88d12a0ae93c5e474f2c897876b0dc3f2e1e1 (diff) | |
download | gcc-a634a685a892b0ef270b2ce7454290f4d83cc715.tar.gz |
2011-12-02 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 181902 using svnmerge
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@181903 138bc75d-0d04-0410-961f-82ee72b054a4
82 files changed, 2251 insertions, 3082 deletions
diff --git a/ChangeLog.MELT b/ChangeLog.MELT index 7e066f0f450..061b238c568 100644 --- a/ChangeLog.MELT +++ b/ChangeLog.MELT @@ -1,4 +1,8 @@ +2011-12-02 Basile Starynkevitch <basile@starynkevitch.net> + + MELT branch merged with trunk rev 181902 using svnmerge + 2011-12-01 Basile Starynkevitch <basile@starynkevitch.net> MELT branch merged with trunk rev 181872 using svnmerge diff --git a/gcc/ChangeLog b/gcc/ChangeLog index addee392384..0a15c038954 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,87 @@ +2011-12-01 Kaz Kojima <kkojima@gcc.gnu.org> + + PR target/50814. + * config/sh/sh.c (expand_ashiftrt): Handle TARGET_SH2A same as + TARGET_SH3. + (shl_sext_kind): Likewise. + * config/sh/sh.h (SH_DYNAMIC_SHIFT_COST): Likewise. + * config/sh/sh.md (ashlsi3_sh2a, ashrsi3_sh2a, lshrsi3_sh2a): + Remove. + (ashlsi3_std): Handle TARGET_SH2A same as TARGET_SH3. + (ashlsi3): Likewise. + (ashrsi3_d): Likewise. + (lshrsi3_d): Likewise. + (lshrsi3): Likewise. + +2011-12-01 Diego Novillo <dnovillo@google.com> + + PR bootstrap/51346 + * ipa-inline.c (can_inline_edge_p): If the edge E has a + statement, use the statement's inline indicator instead + of E's. + Remove consistency check. + +2011-12-01 Diego Novillo <dnovillo@google.com> + + PR bootstrap/51346 + Revert + + 2011-11-29 Diego Novillo <dnovillo@google.com> + + * gimple.c (gimple_call_set_cannot_inline): Move from gimple.h. + Update field call_stmt_cannot_inline_p from call + graph edge, if needed. + * gimple.h (gimple_call_set_cannot_inline): Move to gimple.c. + +2011-12-01 Nathan Sidwell <nathan@acm.org> + + PR gcov-profile/51113 + * coverage.c (build_var): Keep coverage variables static. + +2011-12-01 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/51356 + * tree-vect-patterns.c (vect_recog_bool_pattern): Give up if + vectype doesn't have VECTOR_MODE_P. + + PR debug/50317 + * tree-ssa-dce.c (remove_dead_stmt): Add a debug stmt when removing + as unnecessary a store to a variable with gimple reg type. + * tree-ssa-live.c (remove_unused_locals): Clear TREE_ADDRESSABLE bit + on local unreferenced variables. + * cfgexpand.c (expand_gimple_basic_block): Don't emit DEBUG_INSNs + for !target_for_debug_bind variables. + +2011-12-01 Patrick Marlier <patrick.marlier@gmail.com> + + PR middle-end/51273 + * cgraph.h (cgraph_call_node_duplication_hooks): Declare. + * cgraph.c (cgraph_call_node_duplication_hooks): Make global. + * cgraphunit.c (cgraph_copy_node_for_versioning): Call it. + +2011-12-01 Andrew Pinski <apinski@cavium.com> + + PR lto/51198 + * tree.c (free_lang_data_in_decl): Clear FIELD_DECL's + DECL_INITIAL also. + +2011-12-01 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/51246 + * tree-predcom.c (replace_ref_with): Handle also clobber on the + rhs. + + PR rtl-optimization/51014 + * loop-unroll.c (apply_opt_in_copies): Ignore label DEBUG_INSNs + both from bb and orig_bb. + +2011-12-01 Joern Rennecke <joern.rennecke@embecosm.com> + + PR tree-optimization/50802 + * tree-vrp.c (simplify_conversion_using_ranges): Rewrite test + considering what happens to ranges during sign changes and/or + intermediate narrowing conversions. + 2011-11-30 John David Anglin <dave.anglin@nrc-cnrc.gc.ca> PR middle-end/50283 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 1678f2f93ab..c30346e372a 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20111201 +20111202 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 77fd4bf15d1..9a8a4ed3fab 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2011-12-01 Jakub Jelinek <jakub@redhat.com> + + PR bootstrap/51201 + * gcc-interface/Make-lang.in: Initialize RTS_DIR with = instead of :=. + 2011-11-24 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> * s-taprop-tru64.adb (Create_Task): Use Unrestricted_Access. diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in index 44d75154779..e375796ec8e 100644 --- a/gcc/ada/gcc-interface/Make-lang.in +++ b/gcc/ada/gcc-interface/Make-lang.in @@ -118,7 +118,7 @@ ifeq ($(build), $(host)) # put the host RTS dir first in the PATH to hide the default runtime # files that are among the sources - RTS_DIR:=$(strip $(subst \,/,$(shell gnatls -v | grep adalib ))) + RTS_DIR=$(strip $(subst \,/,$(shell gnatls -v | grep adalib ))) ADA_TOOLS_FLAGS_TO_PASS=\ CC="$(CC)" \ @@ -153,7 +153,7 @@ else else # This is a canadian cross. We should use a toolchain running on the # build platform and targeting the host platform. - RTS_DIR:=$(strip $(subst \,/,$(shell $(GNATLS_FOR_HOST) -v | grep adalib ))) + RTS_DIR=$(strip $(subst \,/,$(shell $(GNATLS_FOR_HOST) -v | grep adalib ))) ADA_TOOLS_FLAGS_TO_PASS=\ CC="$(CC)" \ $(COMMON_FLAGS_TO_PASS) $(ADA_FLAGS_TO_PASS) \ diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 2a82b032f5d..e5a7a392eb4 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -3903,6 +3903,11 @@ expand_gimple_basic_block (basic_block bb) rtx val; enum machine_mode mode; + if (TREE_CODE (var) != DEBUG_EXPR_DECL + && TREE_CODE (var) != LABEL_DECL + && !target_for_debug_bind (var)) + goto delink_debug_stmt; + if (gimple_debug_bind_has_value_p (stmt)) value = gimple_debug_bind_get_value (stmt); else @@ -3932,6 +3937,7 @@ expand_gimple_basic_block (basic_block bb) PAT_VAR_LOCATION_LOC (val) = (rtx)value; } + delink_debug_stmt: /* In order not to generate too many debug temporaries, we delink all uses of debug statements we already expanded. Therefore debug statements between definition and real diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 44a950ca743..ac516abefba 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -412,7 +412,7 @@ cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *entry) } /* Call all node duplication hooks. */ -static void +void cgraph_call_node_duplication_hooks (struct cgraph_node *node1, struct cgraph_node *node2) { diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 834d3d4a443..0efce347261 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -513,6 +513,8 @@ struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type, int, bool, VEC(cgraph_edge_p,heap) *, bool); struct cgraph_node *cgraph_create_function_alias (tree, tree); +void cgraph_call_node_duplication_hooks (struct cgraph_node *node1, + struct cgraph_node *node2); void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *); void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 40bcf8fc9ef..251b5554725 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -2318,6 +2318,8 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version, cgraph_redirect_edge_callee (e, new_version); } + cgraph_call_node_duplication_hooks (old_version, new_version); + return new_version; } diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 870c39f2602..b9834fb5c9f 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -3266,7 +3266,7 @@ expand_ashiftrt (rtx *operands) char func[18]; int value; - if (TARGET_SH3) + if (TARGET_SH3 || TARGET_SH2A) { if (!CONST_INT_P (operands[2])) { @@ -3715,7 +3715,7 @@ shl_sext_kind (rtx left_rtx, rtx size_rtx, int *costp) } } } - if (TARGET_SH3) + if (TARGET_SH3 || TARGET_SH2A) { /* Try to use a dynamic shift. */ cost = shift_insns[32 - insize] + 1 + SH_DYNAMIC_SHIFT_COST; diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 8ab1f10e31e..f873b9d72a3 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -2394,7 +2394,8 @@ extern int current_function_interrupt; #define ACCUMULATE_OUTGOING_ARGS TARGET_ACCUMULATE_OUTGOING_ARGS #define SH_DYNAMIC_SHIFT_COST \ - (TARGET_HARD_SH4 ? 1 : TARGET_SH3 ? (optimize_size ? 1 : 2) : 20) + (TARGET_HARD_SH4 ? 1 \ + : (TARGET_SH3 || TARGET_SH2A) ? (optimize_size ? 1 : 2) : 20) #define NUM_MODES_FOR_MODE_SWITCHING { FP_MODE_NONE } diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index ce660185dd3..b63c8572d74 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -1,6 +1,6 @@ ;;- Machine description for Renesas / SuperH SH. ;; Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -;; 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +;; 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 ;; Free Software Foundation, Inc. ;; Contributed by Steve Chamberlain (sac@cygnus.com). ;; Improved by Jim Wilson (wilson@cygnus.com). @@ -3568,15 +3568,6 @@ label: ;; ;; shift left -(define_insn "ashlsi3_sh2a" - [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (ashift:SI (match_operand:SI 1 "arith_reg_operand" "0") - (match_operand:SI 2 "arith_reg_operand" "r")))] - "TARGET_SH2A" - "shad %2,%0" - [(set_attr "type" "arith") - (set_attr "length" "4")]) - ;; This pattern is used by init_expmed for computing the costs of shift ;; insns. @@ -3585,14 +3576,14 @@ label: (ashift:SI (match_operand:SI 1 "arith_reg_operand" "0,0,0,0") (match_operand:SI 2 "nonmemory_operand" "r,M,P27,?ri"))) (clobber (match_scratch:SI 3 "=X,X,X,&r"))] - "TARGET_SH3 + "(TARGET_SH3 || TARGET_SH2A) || (TARGET_SH1 && satisfies_constraint_P27 (operands[2]))" "@ shld %2,%0 add %0,%0 shll%O2 %0 #" - "TARGET_SH3 + "(TARGET_SH3 || TARGET_SH2A) && reload_completed && CONST_INT_P (operands[2]) && ! satisfies_constraint_P27 (operands[2])" @@ -3671,7 +3662,7 @@ label: if (CONST_INT_P (operands[2]) && sh_dynamicalize_shift_p (operands[2])) operands[2] = force_reg (SImode, operands[2]); - if (TARGET_SH3) + if (TARGET_SH3 || TARGET_SH2A) { emit_insn (gen_ashlsi3_std (operands[0], operands[1], operands[2])); DONE; @@ -3728,15 +3719,6 @@ label: ; arithmetic shift right ; -(define_insn "ashrsi3_sh2a" - [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") - (neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))] - "TARGET_SH2A" - "shad %2,%0" - [(set_attr "type" "dyn_shift") - (set_attr "length" "4")]) - (define_insn "ashrsi3_k" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") @@ -3831,7 +3813,7 @@ label: [(set (match_operand:SI 0 "arith_reg_dest" "=r") (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") (neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))] - "TARGET_SH3" + "TARGET_SH3 || TARGET_SH2A" "shad %2,%0" [(set_attr "type" "dyn_shift")]) @@ -3879,20 +3861,11 @@ label: ;; logical shift right -(define_insn "lshrsi3_sh2a" - [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") - (neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))] - "TARGET_SH2A" - "shld %2,%0" - [(set_attr "type" "dyn_shift") - (set_attr "length" "4")]) - (define_insn "lshrsi3_d" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") (neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))] - "TARGET_SH3" + "TARGET_SH3 || TARGET_SH2A" "shld %2,%0" [(set_attr "type" "dyn_shift")]) @@ -3973,7 +3946,8 @@ label: if (CONST_INT_P (operands[2]) && sh_dynamicalize_shift_p (operands[2])) operands[2] = force_reg (SImode, operands[2]); - if (TARGET_SH3 && arith_reg_operand (operands[2], GET_MODE (operands[2]))) + if ((TARGET_SH3 || TARGET_SH2A) + && arith_reg_operand (operands[2], GET_MODE (operands[2]))) { rtx count = copy_to_mode_reg (SImode, operands[2]); emit_insn (gen_negsi2 (count, count)); diff --git a/gcc/coverage.c b/gcc/coverage.c index 65ceba22783..23cb2f8cf55 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -657,8 +657,7 @@ coverage_end_function (unsigned lineno_checksum, unsigned cfg_checksum) } /* Build a coverage variable of TYPE for function FN_DECL. If COUNTER - >= 0 it is a counter array, otherwise it is the function structure. - Propagate appropriate linkage and visibility from the function decl. */ + >= 0 it is a counter array, otherwise it is the function structure. */ static tree build_var (tree fn_decl, tree type, int counter) @@ -675,21 +674,6 @@ build_var (tree fn_decl, tree type, int counter) TREE_STATIC (var) = 1; TREE_ADDRESSABLE (var) = 1; DECL_ALIGN (var) = TYPE_ALIGN (type); - DECL_WEAK (var) = DECL_WEAK (fn_decl); - TREE_PUBLIC (var) - = TREE_PUBLIC (fn_decl) && (counter < 0 || DECL_WEAK (fn_decl)); - if (DECL_ONE_ONLY (fn_decl)) - make_decl_one_only (var, DECL_COMDAT_GROUP (fn_decl)); - - if (TREE_PUBLIC (var)) - { - DECL_VISIBILITY (var) = DECL_VISIBILITY (fn_decl); - DECL_VISIBILITY_SPECIFIED (var) - = DECL_VISIBILITY_SPECIFIED (fn_decl); - - /* Initialize assembler name so we can stream out. */ - DECL_ASSEMBLER_NAME (var); - } return var; } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 55addacfe46..201f5efb603 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +2011-12-01 Jason Merrill <jason@redhat.com> + + * call.c (build_new_method_call_1): Handle aggregate initialization. + * tree.c (stabilize_init): Handle CONSTRUCTOR. + +2011-12-01 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/51326 + * call.c (build_user_type_conversion_1): Early return NULL if + expr is NULL_TREE. + +2011-12-01 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/51367 + * pt.c (unify_inconsistency): Use either %qT or %qE depending on + whether parm is a type or non-type parameter. + 2011-11-30 Jason Merrill <jason@redhat.com> PR c++/51009 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index ab0654273a3..548a36bf8e5 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -3373,7 +3373,7 @@ static struct z_candidate * build_user_type_conversion_1 (tree totype, tree expr, int flags) { struct z_candidate *candidates, *cand; - tree fromtype = TREE_TYPE (expr); + tree fromtype; tree ctors = NULL_TREE; tree conv_fns = NULL_TREE; conversion *conv = NULL; @@ -3382,6 +3382,11 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) bool any_viable_p; int convflags; + if (!expr) + return NULL; + + fromtype = TREE_TYPE (expr); + /* We represent conversion within a hierarchy using RVALUE_CONV and BASE_CONV, as specified by [over.best.ics]; these become plain constructor calls, as specified in [dcl.init]. */ @@ -7193,6 +7198,7 @@ build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args, && CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0))) { tree init_list = VEC_index (tree, *args, 0); + tree init = NULL_TREE; gcc_assert (VEC_length (tree, *args) == 1 && !(flags & LOOKUP_ONLYCONVERTING)); @@ -7204,8 +7210,16 @@ build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args, if (CONSTRUCTOR_NELTS (init_list) == 0 && TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype) && !processing_template_decl) + init = build_value_init (basetype, complain); + + /* If BASETYPE is an aggregate, we need to do aggregate + initialization. */ + else if (CP_AGGREGATE_TYPE_P (basetype)) + init = digest_init (basetype, init_list, complain); + + if (init) { - tree ob, init = build_value_init (basetype, complain); + tree ob; if (integer_zerop (instance_ptr)) return get_target_expr_sfinae (init, complain); ob = build_fold_indirect_ref (instance_ptr); @@ -7214,6 +7228,7 @@ build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args, return init; } + /* Otherwise go ahead with overload resolution. */ add_list_candidates (fns, first_mem_arg, init_list, basetype, explicit_targs, template_only, conversion_path, access_binfo, flags, &candidates); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 47250807577..15ef7a0caea 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5501,9 +5501,16 @@ static int unify_inconsistency (bool explain_p, tree parm, tree first, tree second) { if (explain_p) - inform (input_location, - " conflicting deductions for parameter %qE (%qE and %qE)", - parm, first, second); + { + if (TYPE_P (parm)) + inform (input_location, + " deduced conflicting types for parameter %qT (%qT and %qT)", + parm, first, second); + else + inform (input_location, + " deduced conflicting values for non-type parameter " + "%qE (%qE and %qE)", parm, first, second); + } return 1; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index d206fd2ec24..8d179d8d2a0 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3337,6 +3337,7 @@ stabilize_init (tree init, tree *initp) if (TREE_CODE (t) == INIT_EXPR && TREE_CODE (TREE_OPERAND (t, 1)) != TARGET_EXPR + && TREE_CODE (TREE_OPERAND (t, 1)) != CONSTRUCTOR && TREE_CODE (TREE_OPERAND (t, 1)) != AGGR_INIT_EXPR) { TREE_OPERAND (t, 1) = stabilize_expr (TREE_OPERAND (t, 1), initp); diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 170c6fbdeff..3fee56d891f 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,21 @@ +2011-12-01 Janne Blomqvist <jb@gcc.gnu.org> + + * module.c (dt_lower_string): Make static. + (dt_upper_string): Likewise. + +2011-12-01 Janne Blomqvist <jb@gcc.gnu.org> + + PR fortran/25708 + * module.c (parse_string): Read string into resizable array + instead of parsing twice and seeking. + (peek_atom): New implementation avoiding seeks. + (require_atom): Save and set column and line explicitly for error + handling. + +2011-12-01 Janne Blomqvist <jb@gcc.gnu.org> + + * misc.c (gfc_open_file): Don't call stat. + 2011-11-29 Thomas Koenig <tkoenig@gcc.gnu.org> PR fortran/40958 diff --git a/gcc/fortran/misc.c b/gcc/fortran/misc.c index 12740478257..05aef9f02ea 100644 --- a/gcc/fortran/misc.c +++ b/gcc/fortran/misc.c @@ -58,17 +58,9 @@ gfc_clear_ts (gfc_typespec *ts) FILE * gfc_open_file (const char *name) { - struct stat statbuf; - if (!*name) return stdin; - if (stat (name, &statbuf) < 0) - return NULL; - - if (!S_ISREG (statbuf.st_mode)) - return NULL; - return fopen (name, "r"); } diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c index 70f8565c150..1ab08ae2cdf 100644 --- a/gcc/fortran/module.c +++ b/gcc/fortran/module.c @@ -435,7 +435,7 @@ resolve_fixups (fixup_t *f, void *gp) to convert the symtree name of a derived-type to the symbol name or to the name of the associated generic function. */ -const char * +static const char * dt_lower_string (const char *name) { if (name[0] != (char) TOLOWER ((unsigned char) name[0])) @@ -450,7 +450,7 @@ dt_lower_string (const char *name) symtree/symbol name of the associated generic function start with a lower- case character. */ -const char * +static const char * dt_upper_string (const char *name) { if (name[0] != (char) TOUPPER ((unsigned char) name[0])) @@ -1069,51 +1069,37 @@ module_unget_char (void) static void parse_string (void) { - module_locus start; - int len, c; - char *p; - - get_module_locus (&start); + int c; + size_t cursz = 30; + size_t len = 0; - len = 0; + atom_string = XNEWVEC (char, cursz); - /* See how long the string is. */ for ( ; ; ) { c = module_char (); - if (c == EOF) - bad_module ("Unexpected end of module in string constant"); - if (c != '\'') + if (c == '\'') { - len++; - continue; + int c2 = module_char (); + if (c2 != '\'') + { + module_unget_char (); + break; + } } - c = module_char (); - if (c == '\'') + if (len >= cursz) { - len++; - continue; + cursz *= 2; + atom_string = XRESIZEVEC (char, atom_string, cursz); } - - break; - } - - set_module_locus (&start); - - atom_string = p = XCNEWVEC (char, len + 1); - - for (; len > 0; len--) - { - c = module_char (); - if (c == '\'') - module_char (); /* Guaranteed to be another \'. */ - *p++ = c; + atom_string[len] = c; + len++; } - module_char (); /* Terminating \'. */ - *p = '\0'; /* C-style string for debug purposes. */ + atom_string = XRESIZEVEC (char, atom_string, len + 1); + atom_string[len] = '\0'; /* C-style string for debug purposes. */ } @@ -1279,17 +1265,99 @@ parse_atom (void) static atom_type peek_atom (void) { - module_locus m; - atom_type a; + int c; - get_module_locus (&m); + do + { + c = module_char (); + } + while (c == ' ' || c == '\r' || c == '\n'); + + switch (c) + { + case '(': + module_unget_char (); + return ATOM_LPAREN; - a = parse_atom (); - if (a == ATOM_STRING) - free (atom_string); + case ')': + module_unget_char (); + return ATOM_RPAREN; + + case '\'': + module_unget_char (); + return ATOM_STRING; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + module_unget_char (); + return ATOM_INTEGER; + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + module_unget_char (); + return ATOM_NAME; - set_module_locus (&m); - return a; + default: + bad_module ("Bad name"); + } } @@ -1299,11 +1367,12 @@ peek_atom (void) static void require_atom (atom_type type) { - module_locus m; atom_type t; const char *p; + int column, line; - get_module_locus (&m); + column = module_column; + line = module_line; t = parse_atom (); if (t != type) @@ -1329,7 +1398,8 @@ require_atom (atom_type type) gfc_internal_error ("require_atom(): bad atom type required"); } - set_module_locus (&m); + module_column = column; + module_line = line; bad_module (p); } } diff --git a/gcc/gimple.c b/gcc/gimple.c index d27e94b218c..071c6515b4c 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -5558,34 +5558,4 @@ gimple_asm_clobbers_memory_p (const_gimple stmt) return false; } - - -/* Set the inlinable status of GIMPLE_CALL S to INLINABLE_P. */ - -void -gimple_call_set_cannot_inline (gimple s, bool inlinable_p) -{ - bool prev_inlinable_p; - - GIMPLE_CHECK (s, GIMPLE_CALL); - - prev_inlinable_p = gimple_call_cannot_inline_p (s); - - if (inlinable_p) - s->gsbase.subcode |= GF_CALL_CANNOT_INLINE; - else - s->gsbase.subcode &= ~GF_CALL_CANNOT_INLINE; - - /* If we have changed the inlinable attribute, and there is a call - graph edge going out of this statement, update its inlinable - attribute as well. */ - if (current_function_decl && prev_inlinable_p != inlinable_p) - { - struct cgraph_node *n = cgraph_get_node (current_function_decl); - struct cgraph_edge *e = cgraph_edge (n, s); - if (e) - e->call_stmt_cannot_inline_p = inlinable_p; - } -} - #include "gt-gimple.h" diff --git a/gcc/gimple.h b/gcc/gimple.h index df31bf3c23a..8536c70e87e 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -1035,7 +1035,6 @@ extern bool walk_stmt_load_store_ops (gimple, void *, 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 void gimple_call_set_cannot_inline (gimple, bool); /* In gimplify.c */ extern tree create_tmp_var_raw (tree, const char *); @@ -2344,6 +2343,19 @@ gimple_call_tail_p (gimple s) } +/* Set the inlinable status of GIMPLE_CALL S to INLINABLE_P. */ + +static inline void +gimple_call_set_cannot_inline (gimple s, bool inlinable_p) +{ + GIMPLE_CHECK (s, GIMPLE_CALL); + if (inlinable_p) + s->gsbase.subcode |= GF_CALL_CANNOT_INLINE; + else + s->gsbase.subcode &= ~GF_CALL_CANNOT_INLINE; +} + + /* Return true if GIMPLE_CALL S cannot be inlined. */ static inline bool diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc index 0832055510c..3fb7089cc7c 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -337,6 +337,7 @@ Export::register_builtin_types(Gogo* gogo) this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR); this->register_builtin_type(gogo, "bool", BUILTIN_BOOL); this->register_builtin_type(gogo, "string", BUILTIN_STRING); + this->register_builtin_type(gogo, "error", BUILTIN_ERROR); } // Register one builtin type in the export table. diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h index 1f8278f419a..a06b549b609 100644 --- a/gcc/go/gofrontend/export.h +++ b/gcc/go/gofrontend/export.h @@ -39,8 +39,9 @@ enum Builtin_code BUILTIN_STRING = -16, BUILTIN_COMPLEX64 = -17, BUILTIN_COMPLEX128 = -18, + BUILTIN_ERROR = -19, - SMALLEST_BUILTIN_CODE = -18 + SMALLEST_BUILTIN_CODE = -19 }; // This class manages exporting Go declarations. It handles the main diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index a2cf33eb67b..a80c82375ce 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -13493,12 +13493,18 @@ Receive_expression::do_check_types(Gogo*) tree Receive_expression::do_get_tree(Translate_context* context) { + Location loc = this->location(); + Channel_type* channel_type = this->channel_->type()->channel_type(); if (channel_type == NULL) { go_assert(this->channel_->type()->is_error()); return error_mark_node; } + + Expression* td = Expression::make_type_descriptor(channel_type, loc); + tree td_tree = td->get_tree(context); + Type* element_type = channel_type->element_type(); Btype* element_type_btype = element_type->get_backend(context->gogo()); tree element_type_tree = type_to_tree(element_type_btype); @@ -13507,8 +13513,7 @@ Receive_expression::do_get_tree(Translate_context* context) if (element_type_tree == error_mark_node || channel == error_mark_node) return error_mark_node; - return Gogo::receive_from_channel(element_type_tree, channel, - this->for_select_, this->location()); + return Gogo::receive_from_channel(element_type_tree, td_tree, channel, loc); } // Dump ast representation for a receive expression. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 74d1281e17c..6da507b57ca 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1947,7 +1947,7 @@ class Receive_expression : public Expression public: Receive_expression(Expression* channel, Location location) : Expression(EXPRESSION_RECEIVE, location), - channel_(channel), for_select_(false) + channel_(channel) { } // Return the channel. @@ -1955,11 +1955,6 @@ class Receive_expression : public Expression channel() { return this->channel_; } - // Note that this is for a select statement. - void - set_for_select() - { this->for_select_ = true; } - protected: int do_traverse(Traverse* traverse) @@ -1998,8 +1993,6 @@ class Receive_expression : public Expression private: // The channel from which we are receiving. Expression* channel_; - // Whether this is for a select statement. - bool for_select_; }; #endif // !defined(GO_EXPRESSIONS_H) diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index 0e77f5dcd61..dd66a7f6832 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -2201,13 +2201,12 @@ Gogo::runtime_error(int code, Location location) } // Return a tree for receiving a value of type TYPE_TREE on CHANNEL. -// This does a blocking receive and returns the value read from the -// channel. If FOR_SELECT is true, this is being done because it was -// chosen in a select statement. +// TYPE_DESCRIPTOR_TREE is the channel's type descriptor. This does a +// blocking receive and returns the value read from the channel. tree -Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select, - Location location) +Gogo::receive_from_channel(tree type_tree, tree type_descriptor_tree, + tree channel, Location location) { if (type_tree == error_mark_node || channel == error_mark_node) return error_mark_node; @@ -2222,12 +2221,10 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select, "__go_receive_small", 2, uint64_type_node, + TREE_TYPE(type_descriptor_tree), + type_descriptor_tree, ptr_type_node, - channel, - boolean_type_node, - (for_select - ? boolean_true_node - : boolean_false_node)); + channel); if (call == error_mark_node) return error_mark_node; // This can panic if there are too many operations on a closed @@ -2253,15 +2250,13 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select, location, "__go_receive_big", 3, - boolean_type_node, + void_type_node, + TREE_TYPE(type_descriptor_tree), + type_descriptor_tree, ptr_type_node, channel, ptr_type_node, - tmpaddr, - boolean_type_node, - (for_select - ? boolean_true_node - : boolean_false_node)); + tmpaddr); if (call == error_mark_node) return error_mark_node; // This can panic if there are too many operations on a closed diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 9d3b37ae857..6efce18cfac 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -527,14 +527,9 @@ class Gogo // Receive a value from a channel. static tree - receive_from_channel(tree type_tree, tree channel, bool for_select, + receive_from_channel(tree type_tree, tree type_descriptor_tree, tree channel, Location); - // Return a tree for receiving an integer on a channel. - static tree - receive_as_64bit_integer(tree type, tree channel, bool blocking, - bool for_select); - // Make a trampoline which calls FNADDR passing CLOSURE. tree make_trampoline(tree fnaddr, tree closure, Location); diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index d3405c191c9..075109c0c04 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -706,6 +706,7 @@ Import::register_builtin_types(Gogo* gogo) this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR); this->register_builtin_type(gogo, "bool", BUILTIN_BOOL); this->register_builtin_type(gogo, "string", BUILTIN_STRING); + this->register_builtin_type(gogo, "error", BUILTIN_ERROR); } // Register a single builtin type. diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 62288687662..37a97825bcd 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -1780,7 +1780,6 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type, Statement* s = Statement::make_tuple_receive_assignment(val_var, received_var, receive->channel(), - false, location); if (!this->gogo_->in_global_scope()) @@ -3769,7 +3768,6 @@ Parse::tuple_assignment(Expression_list* lhs, Range_clause* p_range_clause) Expression* channel = receive->channel(); Statement* s = Statement::make_tuple_receive_assignment(val, success, channel, - false, location); this->gogo_->add_statement(s); } diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc index 42f1e787a8f..bffefbb0513 100644 --- a/gcc/go/gofrontend/runtime.cc +++ b/gcc/go/gofrontend/runtime.cc @@ -54,8 +54,6 @@ enum Runtime_function_type RFT_MAPITER, // Go type chan any, C type struct __go_channel *. RFT_CHAN, - // Go type *chan any, C type struct __go_channel **. - RFT_CHANPTR, // Go type non-empty interface, C type struct __go_interface. RFT_IFACE, // Go type interface{}, C type struct __go_empty_interface. @@ -148,10 +146,6 @@ runtime_function_type(Runtime_function_type bft) t = Type::make_channel_type(true, true, Type::make_void_type()); break; - case RFT_CHANPTR: - t = Type::make_pointer_type(runtime_function_type(RFT_CHAN)); - break; - case RFT_IFACE: { Typed_identifier_list* methods = new Typed_identifier_list(); @@ -223,7 +217,6 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, case RFT_SLICE: case RFT_MAP: case RFT_CHAN: - case RFT_CHANPTR: case RFT_IFACE: case RFT_EFACE: return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc); @@ -393,12 +386,3 @@ Runtime::map_iteration_type() return Type::make_array_type(runtime_function_type(RFT_POINTER), iexpr); } - -// Return the type used to pass a list of general channels to the -// select runtime function. - -Type* -Runtime::chanptr_type() -{ - return runtime_function_type(RFT_CHANPTR); -} diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index d742e5b0c79..fe842c93b9b 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -121,31 +121,44 @@ DEF_GO_RUNTIME(CHAN_LEN, "__go_chan_len", P1(CHAN), R1(INT)) DEF_GO_RUNTIME(CHAN_CAP, "__go_chan_cap", P1(CHAN), R1(INT)) // Send a small value on a channel. -DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(CHAN, UINT64, BOOL), R0()) - -// Send a small value on a channel without blocking. -DEF_GO_RUNTIME(SEND_NONBLOCKING_SMALL, "__go_send_nonblocking_small", - P2(CHAN, UINT64), R1(BOOL)) +DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(TYPE, CHAN, UINT64), R0()) // Send a big value on a channel. -DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(CHAN, POINTER, BOOL), R0()) - -// Send a big value on a channel without blocking. -DEF_GO_RUNTIME(SEND_NONBLOCKING_BIG, "__go_send_nonblocking_big", - P2(CHAN, POINTER), R1(BOOL)) +DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(TYPE, CHAN, POINTER), R0()) // Receive a small value from a channel. -DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(CHAN, BOOL), R1(UINT64)) +DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(TYPE, CHAN), R1(UINT64)) // Receive a big value from a channel. -DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(CHAN, POINTER, BOOL), - R1(BOOL)) +DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(TYPE, CHAN, POINTER), R0()) // Receive a value from a channel returning whether it is closed. -DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL)) +DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER), + R1(BOOL)) + + +// Start building a select statement. +DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P1(INT), R1(POINTER)) -// Receive a value from a channel returning whether it is closed, for select. -DEF_GO_RUNTIME(CHANRECV3, "runtime.chanrecv3", P2(CHAN, POINTER), R1(BOOL)) +// Add a default clause to a select statement. +DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault", P2(POINTER, INT), R0()) + +// Add a send clause to a select statement. +DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend", + P4(POINTER, CHAN, POINTER, INT), R0()) + +// Add a receive clause to a select statement, for a clause which does +// not check whether the channel is closed. +DEF_GO_RUNTIME(SELECTRECV, "runtime.selectrecv", + P4(POINTER, CHAN, POINTER, INT), R0()) + +// Add a receive clause to a select statement, for a clause which does +// check whether the channel is closed. +DEF_GO_RUNTIME(SELECTRECV2, "runtime.selectrecv2", + P5(POINTER, CHAN, POINTER, BOOLPTR, INT), R0()) + +// Run a select, returning the index of the selected clause. +DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P1(POINTER), R1(INT)) // Panic. @@ -213,11 +226,6 @@ DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0()) DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0()) -// Run a select statement. -DEF_GO_RUNTIME(SELECT, "__go_select", P4(UINTPTR, BOOL, CHANPTR, BOOLPTR), - R1(UINTPTR)) - - // Convert an empty interface to an empty interface, returning ok. DEF_GO_RUNTIME(IFACEE2E2, "runtime.ifaceE2E2", P1(EFACE), R2(EFACE, BOOL)) diff --git a/gcc/go/gofrontend/runtime.h b/gcc/go/gofrontend/runtime.h index 3cd40348cbe..be5dcbe25d0 100644 --- a/gcc/go/gofrontend/runtime.h +++ b/gcc/go/gofrontend/runtime.h @@ -43,11 +43,6 @@ class Runtime static Type* map_iteration_type(); - // Return the type used to pass a list of general channels to the - // select runtime function. - static Type* - chanptr_type(); - private: static Named_object* runtime_declaration(Function); diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 835a0cca239..964b394c3bd 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -1329,10 +1329,9 @@ class Tuple_receive_assignment_statement : public Statement { public: Tuple_receive_assignment_statement(Expression* val, Expression* closed, - Expression* channel, bool for_select, - Location location) + Expression* channel, Location location) : Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location), - val_(val), closed_(closed), channel_(channel), for_select_(for_select) + val_(val), closed_(closed), channel_(channel) { } protected: @@ -1360,8 +1359,6 @@ class Tuple_receive_assignment_statement : public Statement Expression* closed_; // The channel on which we receive the value. Expression* channel_; - // Whether this is for a select statement. - bool for_select_; }; // Traversal. @@ -1414,14 +1411,14 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*, Statement::make_temporary(Type::lookup_bool_type(), NULL, loc); b->add_statement(closed_temp); - // closed_temp = chanrecv[23](channel, &val_temp) + // closed_temp = chanrecv2(type, channel, &val_temp) + Expression* td = Expression::make_type_descriptor(this->channel_->type(), + loc); Temporary_reference_expression* ref = Expression::make_temporary_reference(val_temp, loc); Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc); - Expression* call = Runtime::make_call((this->for_select_ - ? Runtime::CHANRECV3 - : Runtime::CHANRECV2), - loc, 2, this->channel_, p2); + Expression* call = Runtime::make_call(Runtime::CHANRECV2, + loc, 3, td, this->channel_, p2); ref = Expression::make_temporary_reference(closed_temp, loc); ref->set_is_lvalue(); Statement* s = Statement::make_assignment(ref, call, loc); @@ -1460,11 +1457,10 @@ Tuple_receive_assignment_statement::do_dump_statement( Statement* Statement::make_tuple_receive_assignment(Expression* val, Expression* closed, Expression* channel, - bool for_select, Location location) { return new Tuple_receive_assignment_statement(val, closed, channel, - for_select, location); + location); } // An assignment to a pair of values from a type guard. This is a @@ -4391,9 +4387,11 @@ Send_statement::do_get_backend(Translate_context* context) && val->temporary_reference_expression() == NULL) can_take_address = false; + Expression* td = Expression::make_type_descriptor(this->channel_->type(), + loc); + Runtime::Function code; Bstatement* btemp = NULL; - Expression* call; if (is_small) { // Type is small enough to handle as uint64. @@ -4421,8 +4419,7 @@ Send_statement::do_get_backend(Translate_context* context) btemp = temp->get_backend(context); } - call = Runtime::make_call(code, loc, 3, this->channel_, val, - Expression::make_boolean(this->for_select_, loc)); + Expression* call = Runtime::make_call(code, loc, 3, td, this->channel_, val); context->gogo()->lower_expression(context->function(), NULL, &call); Bexpression* bcall = tree_to_expr(call->get_tree(context)); @@ -4490,134 +4487,178 @@ Select_clauses::Select_clause::traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Lowering. Here we pull out the channel and the send values, to -// enforce the order of evaluation. We also add explicit send and -// receive statements to the clauses. +// Lowering. We call a function to register this clause, and arrange +// to set any variables in any receive clause. void Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, - Block* b) + Block* b, Temporary_statement* sel) { + Location loc = this->location_; + + Expression* selref = Expression::make_temporary_reference(sel, loc); + + mpz_t ival; + mpz_init_set_ui(ival, this->index_); + Expression* index_expr = Expression::make_integer(&ival, NULL, loc); + mpz_clear(ival); + if (this->is_default_) { go_assert(this->channel_ == NULL && this->val_ == NULL); + this->lower_default(b, selref, index_expr); this->is_lowered_ = true; return; } - Location loc = this->location_; - // Evaluate the channel before the select statement. Temporary_statement* channel_temp = Statement::make_temporary(NULL, this->channel_, loc); b->add_statement(channel_temp); - this->channel_ = Expression::make_temporary_reference(channel_temp, loc); - - // If this is a send clause, evaluate the value to send before the - // select statement. - Temporary_statement* val_temp = NULL; - if (this->is_send_ && !this->val_->is_constant()) - { - val_temp = Statement::make_temporary(NULL, this->val_, loc); - b->add_statement(val_temp); - } + Expression* chanref = Expression::make_temporary_reference(channel_temp, + loc); - // Add the send or receive before the rest of the statements if any. - Block *init = new Block(b, loc); - Expression* ref = Expression::make_temporary_reference(channel_temp, loc); if (this->is_send_) - { - Expression* ref2; - if (val_temp == NULL) - ref2 = this->val_; - else - ref2 = Expression::make_temporary_reference(val_temp, loc); - Send_statement* send = Statement::make_send_statement(ref, ref2, loc); - send->set_for_select(); - init->add_statement(send); - } - else if (this->closed_ != NULL && !this->closed_->is_sink_expression()) - { - go_assert(this->var_ == NULL && this->closedvar_ == NULL); - if (this->val_ == NULL) - this->val_ = Expression::make_sink(loc); - Statement* s = Statement::make_tuple_receive_assignment(this->val_, - this->closed_, - ref, true, loc); - init->add_statement(s); - } - else if (this->closedvar_ != NULL) - { - go_assert(this->val_ == NULL); - Expression* val; - if (this->var_ == NULL) - val = Expression::make_sink(loc); - else - val = Expression::make_var_reference(this->var_, loc); - Expression* closed = Expression::make_var_reference(this->closedvar_, - loc); - Statement* s = Statement::make_tuple_receive_assignment(val, closed, ref, - true, loc); + this->lower_send(b, selref, chanref, index_expr); + else + this->lower_recv(gogo, function, b, selref, chanref, index_expr); - // We have to put S in STATEMENTS_, because that is where the - // variables are declared. + // Now all references should be handled through the statements, not + // through here. + this->is_lowered_ = true; + this->val_ = NULL; + this->var_ = NULL; +} - go_assert(this->statements_ != NULL); +// Lower a default clause in a select statement. - // Skip the variable declaration statements themselves. - size_t skip = 1; - if (this->var_ != NULL) - skip = 2; +void +Select_clauses::Select_clause::lower_default(Block* b, Expression* selref, + Expression* index_expr) +{ + Location loc = this->location_; + Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref, + index_expr); + b->add_statement(Statement::make_statement(call, true)); +} - // Verify that we are only skipping variable declarations. - size_t i = 0; - for (Block::iterator p = this->statements_->begin(); - i < skip && p != this->statements_->end(); - ++p, ++i) - go_assert((*p)->variable_declaration_statement() != NULL); +// Lower a send clause in a select statement. - this->statements_->insert_statement_before(skip, s); +void +Select_clauses::Select_clause::lower_send(Block* b, Expression* selref, + Expression* chanref, + Expression* index_expr) +{ + Location loc = this->location_; - // We have to lower STATEMENTS_ again, to lower the tuple - // receive assignment we just added. - gogo->lower_block(function, this->statements_); - } + Channel_type* ct = this->channel_->type()->channel_type(); + if (ct == NULL) + return; + + Type* valtype = ct->element_type(); + + // Note that copying the value to a temporary here means that we + // evaluate the send values in the required order. + Temporary_statement* val = Statement::make_temporary(valtype, this->val_, + loc); + b->add_statement(val); + + Expression* valref = Expression::make_temporary_reference(val, loc); + Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc); + + Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref, + chanref, valaddr, index_expr); + b->add_statement(Statement::make_statement(call, true)); +} + +// Lower a receive clause in a select statement. + +void +Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, + Block* b, Expression* selref, + Expression* chanref, + Expression* index_expr) +{ + Location loc = this->location_; + + Channel_type* ct = this->channel_->type()->channel_type(); + if (ct == NULL) + return; + + Type* valtype = ct->element_type(); + Temporary_statement* val = Statement::make_temporary(valtype, NULL, loc); + b->add_statement(val); + + Expression* valref = Expression::make_temporary_reference(val, loc); + Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc); + + Temporary_statement* closed_temp = NULL; + + Expression* call; + if (this->closed_ == NULL && this->closedvar_ == NULL) + call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref, + valaddr, index_expr); else { - Receive_expression* recv = Expression::make_receive(ref, loc); - recv->set_for_select(); - if (this->val_ != NULL) - { - go_assert(this->var_ == NULL); - init->add_statement(Statement::make_assignment(this->val_, recv, - loc)); - } - else if (this->var_ != NULL) - { - this->var_->var_value()->set_init(recv); - this->var_->var_value()->clear_type_from_chan_element(); - } - else - { - init->add_statement(Statement::make_statement(recv, true)); - } + closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL, + loc); + b->add_statement(closed_temp); + Expression* cref = Expression::make_temporary_reference(closed_temp, + loc); + Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc); + call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref, + valaddr, caddr, index_expr); } - // Lower any statements we just created. - gogo->lower_block(function, init); + b->add_statement(Statement::make_statement(call, true)); - if (this->statements_ != NULL) - init->add_statement(Statement::make_block_statement(this->statements_, - loc)); + // If the block of statements is executed, arrange for the received + // value to move from VAL to the place where the statements expect + // it. - this->statements_ = init; + Block* init = NULL; - // Now all references should be handled through the statements, not - // through here. - this->is_lowered_ = true; - this->val_ = NULL; - this->var_ = NULL; + if (this->var_ != NULL) + { + go_assert(this->val_ == NULL); + valref = Expression::make_temporary_reference(val, loc); + this->var_->var_value()->set_init(valref); + this->var_->var_value()->clear_type_from_chan_element(); + } + else if (this->val_ != NULL && !this->val_->is_sink_expression()) + { + init = new Block(b, loc); + valref = Expression::make_temporary_reference(val, loc); + init->add_statement(Statement::make_assignment(this->val_, valref, loc)); + } + + if (this->closedvar_ != NULL) + { + go_assert(this->closed_ == NULL); + Expression* cref = Expression::make_temporary_reference(closed_temp, + loc); + this->closedvar_->var_value()->set_init(cref); + } + else if (this->closed_ != NULL && !this->closed_->is_sink_expression()) + { + if (init == NULL) + init = new Block(b, loc); + Expression* cref = Expression::make_temporary_reference(closed_temp, + loc); + init->add_statement(Statement::make_assignment(this->closed_, cref, + loc)); + } + + if (init != NULL) + { + gogo->lower_block(function, init); + + if (this->statements_ != NULL) + init->add_statement(Statement::make_block_statement(this->statements_, + loc)); + this->statements_ = init; + } } // Determine types. @@ -4630,6 +4671,27 @@ Select_clauses::Select_clause::determine_types() this->statements_->determine_types(); } +// Check types. + +void +Select_clauses::Select_clause::check_types() +{ + if (this->is_default_) + return; + + Channel_type* ct = this->channel_->type()->channel_type(); + if (ct == NULL) + { + error_at(this->channel_->location(), "expected channel"); + return; + } + + if (this->is_send_ && !ct->may_send()) + error_at(this->location(), "invalid send on receive-only channel"); + else if (!this->is_send_ && !ct->may_receive()) + error_at(this->location(), "invalid receive on send-only channel"); +} + // Whether this clause may fall through to the statement which follows // the overall select statement. @@ -4717,12 +4779,13 @@ Select_clauses::traverse(Traverse* traverse) // receive statements to the clauses. void -Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b) +Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b, + Temporary_statement* sel) { for (Clauses::iterator p = this->clauses_.begin(); p != this->clauses_.end(); ++p) - p->lower(gogo, function, b); + p->lower(gogo, function, b, sel); } // Determine types. @@ -4736,6 +4799,17 @@ Select_clauses::determine_types() p->determine_types(); } +// Check types. + +void +Select_clauses::check_types() +{ + for (Clauses::iterator p = this->clauses_.begin(); + p != this->clauses_.end(); + ++p) + p->check_types(); +} + // Return whether these select clauses fall through to the statement // following the overall select statement. @@ -4750,179 +4824,55 @@ Select_clauses::may_fall_through() const return false; } -// Convert to the backend representation. We build a call to -// size_t __go_select(size_t count, _Bool has_default, -// channel* channels, _Bool* is_send) -// -// There are COUNT entries in the CHANNELS and IS_SEND arrays. The -// value in the IS_SEND array is true for send, false for receive. -// __go_select returns an integer from 0 to COUNT, inclusive. A -// return of 0 means that the default case should be run; this only -// happens if HAS_DEFAULT is non-zero. Otherwise the number indicates -// the case to run. - -// FIXME: This doesn't handle channels which send interface types -// where the receiver has a static type which matches that interface. +// Convert to the backend representation. We have already accumulated +// all the select information. Now we call selectgo, which will +// return the index of the clause to execute. Bstatement* Select_clauses::get_backend(Translate_context* context, + Temporary_statement* sel, Unnamed_label *break_label, Location location) { size_t count = this->clauses_.size(); + std::vector<std::vector<Bexpression*> > cases(count); + std::vector<Bstatement*> clauses(count); - Expression_list* chan_init = new Expression_list(); - chan_init->reserve(count); - - Expression_list* is_send_init = new Expression_list(); - is_send_init->reserve(count); - - Select_clause *default_clause = NULL; - - Type* runtime_chanptr_type = Runtime::chanptr_type(); - Type* runtime_chan_type = runtime_chanptr_type->points_to(); - + int i = 0; for (Clauses::iterator p = this->clauses_.begin(); p != this->clauses_.end(); - ++p) + ++p, ++i) { - if (p->is_default()) - { - default_clause = &*p; - --count; - continue; - } - - if (p->channel()->type()->channel_type() == NULL) - { - // We should have given an error in the send or receive - // statement we created via lowering. - go_assert(saw_errors()); - return context->backend()->error_statement(); - } - - Expression* c = p->channel(); - c = Expression::make_unsafe_cast(runtime_chan_type, c, p->location()); - chan_init->push_back(c); + int index = p->index(); + mpz_t ival; + mpz_init_set_ui(ival, index); + Expression* index_expr = Expression::make_integer(&ival, NULL, location); + mpz_clear(ival); + cases[i].push_back(tree_to_expr(index_expr->get_tree(context))); - is_send_init->push_back(Expression::make_boolean(p->is_send(), - p->location())); - } + Bstatement* s = p->get_statements_backend(context); + Location gloc = (p->statements() == NULL + ? p->location() + : p->statements()->end_location()); + Bstatement* g = break_label->get_goto(context, gloc); - if (chan_init->empty()) - { - go_assert(count == 0); - Bstatement* s; - Bstatement* ldef = break_label->get_definition(context); - if (default_clause != NULL) - { - // There is a default clause and no cases. Just execute the - // default clause. - s = default_clause->get_statements_backend(context); - } - else - { - // There isn't even a default clause. In this case select - // pauses forever. Call the runtime function with nils. - mpz_t zval; - mpz_init_set_ui(zval, 0); - Expression* zero = Expression::make_integer(&zval, NULL, location); - mpz_clear(zval); - Expression* default_arg = Expression::make_boolean(false, location); - Expression* nil1 = Expression::make_nil(location); - Expression* nil2 = nil1->copy(); - Expression* call = Runtime::make_call(Runtime::SELECT, location, 4, - zero, default_arg, nil1, nil2); - context->gogo()->lower_expression(context->function(), NULL, &call); - Bexpression* bcall = tree_to_expr(call->get_tree(context)); - s = context->backend()->expression_statement(bcall); - } if (s == NULL) - return ldef; - return context->backend()->compound_statement(s, ldef); + clauses[i] = g; + else + clauses[i] = context->backend()->compound_statement(s, g); } - go_assert(count > 0); - - std::vector<Bstatement*> statements; - mpz_t ival; - mpz_init_set_ui(ival, count); - Expression* ecount = Expression::make_integer(&ival, NULL, location); - mpz_clear(ival); - - Type* chan_array_type = Type::make_array_type(runtime_chan_type, ecount); - Expression* chans = Expression::make_composite_literal(chan_array_type, 0, - false, chan_init, - location); - context->gogo()->lower_expression(context->function(), NULL, &chans); - Temporary_statement* chan_temp = Statement::make_temporary(chan_array_type, - chans, - location); - statements.push_back(chan_temp->get_backend(context)); - - Type* is_send_array_type = Type::make_array_type(Type::lookup_bool_type(), - ecount->copy()); - Expression* is_sends = Expression::make_composite_literal(is_send_array_type, - 0, false, - is_send_init, - location); - context->gogo()->lower_expression(context->function(), NULL, &is_sends); - Temporary_statement* is_send_temp = - Statement::make_temporary(is_send_array_type, is_sends, location); - statements.push_back(is_send_temp->get_backend(context)); - - mpz_init_set_ui(ival, 0); - Expression* zero = Expression::make_integer(&ival, NULL, location); - mpz_clear(ival); - - Expression* ref = Expression::make_temporary_reference(chan_temp, location); - Expression* chan_arg = Expression::make_array_index(ref, zero, NULL, - location); - chan_arg = Expression::make_unary(OPERATOR_AND, chan_arg, location); - chan_arg = Expression::make_unsafe_cast(runtime_chanptr_type, chan_arg, - location); - - ref = Expression::make_temporary_reference(is_send_temp, location); - Expression* is_send_arg = Expression::make_array_index(ref, zero->copy(), - NULL, location); - is_send_arg = Expression::make_unary(OPERATOR_AND, is_send_arg, location); - - Expression* default_arg = Expression::make_boolean(default_clause != NULL, - location); - Expression* call = Runtime::make_call(Runtime::SELECT, location, 4, - ecount->copy(), default_arg, - chan_arg, is_send_arg); + Expression* selref = Expression::make_temporary_reference(sel, location); + Expression* call = Runtime::make_call(Runtime::SELECTGO, location, 1, + selref); context->gogo()->lower_expression(context->function(), NULL, &call); Bexpression* bcall = tree_to_expr(call->get_tree(context)); - std::vector<std::vector<Bexpression*> > cases; - std::vector<Bstatement*> clauses; + if (count == 0) + return context->backend()->expression_statement(bcall); - cases.resize(count + (default_clause != NULL ? 1 : 0)); - clauses.resize(count + (default_clause != NULL ? 1 : 0)); - - int index = 0; - - if (default_clause != NULL) - { - this->add_clause_backend(context, location, index, 0, default_clause, - break_label, &cases, &clauses); - ++index; - } - - int i = 1; - for (Clauses::iterator p = this->clauses_.begin(); - p != this->clauses_.end(); - ++p) - { - if (!p->is_default()) - { - this->add_clause_backend(context, location, index, i, &*p, - break_label, &cases, &clauses); - ++i; - ++index; - } - } + std::vector<Bstatement*> statements; + statements.reserve(2); Bstatement* switch_stmt = context->backend()->switch_statement(bcall, cases, @@ -4935,39 +4885,6 @@ Select_clauses::get_backend(Translate_context* context, return context->backend()->statement_list(statements); } - -// Add CLAUSE to CASES/CLAUSES at INDEX. - -void -Select_clauses::add_clause_backend( - Translate_context* context, - Location location, - int index, - int case_value, - Select_clause* clause, - Unnamed_label* bottom_label, - std::vector<std::vector<Bexpression*> > *cases, - std::vector<Bstatement*>* clauses) -{ - mpz_t ival; - mpz_init_set_ui(ival, case_value); - Expression* e = Expression::make_integer(&ival, NULL, location); - mpz_clear(ival); - (*cases)[index].push_back(tree_to_expr(e->get_tree(context))); - - Bstatement* s = clause->get_statements_backend(context); - - Location gloc = (clause->statements() == NULL - ? clause->location() - : clause->statements()->end_location()); - Bstatement* g = bottom_label->get_goto(context, gloc); - - if (s == NULL) - (*clauses)[index] = g; - else - (*clauses)[index] = context->backend()->compound_statement(s, g); -} - // Dump the AST representation for select clauses. void @@ -5003,11 +4920,28 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, { if (this->is_lowered_) return this; - Block* b = new Block(enclosing, this->location()); - this->clauses_->lower(gogo, function, b); + + Location loc = this->location(); + + Block* b = new Block(enclosing, loc); + + go_assert(this->sel_ == NULL); + + mpz_t ival; + mpz_init_set_ui(ival, this->clauses_->size()); + Expression* size_expr = Expression::make_integer(&ival, NULL, loc); + mpz_clear(ival); + + Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 1, size_expr); + + this->sel_ = Statement::make_temporary(NULL, call, loc); + b->add_statement(this->sel_); + + this->clauses_->lower(gogo, function, b, this->sel_); this->is_lowered_ = true; b->add_statement(this); - return Statement::make_block_statement(b, this->location()); + + return Statement::make_block_statement(b, loc); } // Return the backend representation for a select statement. @@ -5015,7 +4949,7 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, Bstatement* Select_statement::do_get_backend(Translate_context* context) { - return this->clauses_->get_backend(context, this->break_label(), + return this->clauses_->get_backend(context, this->sel_, this->break_label(), this->location()); } @@ -5790,7 +5724,7 @@ For_range_statement::lower_range_channel(Gogo*, Expression::make_temporary_reference(ok_temp, loc); oref->set_is_lvalue(); Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref, - false, loc); + loc); iter_init->add_statement(s); Block* then_block = new Block(iter_init, loc); diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 16914f16c37..4548ba6f56c 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -165,12 +165,10 @@ class Statement Expression* should_set, Location); // Make an assignment from a nonblocking receive to a pair of - // variables. FOR_SELECT is true is this is being created for a - // case x, ok := <-c in a select statement. + // variables. static Statement* make_tuple_receive_assignment(Expression* val, Expression* closed, - Expression* channel, bool for_select, - Location); + Expression* channel, Location); // Make an assignment from a type guard to a pair of variables. static Statement* @@ -634,14 +632,9 @@ class Send_statement : public Statement Send_statement(Expression* channel, Expression* val, Location location) : Statement(STATEMENT_SEND, location), - channel_(channel), val_(val), for_select_(false) + channel_(channel), val_(val) { } - // Note that this is for a select statement. - void - set_for_select() - { this->for_select_ = true; } - protected: int do_traverse(Traverse* traverse); @@ -663,8 +656,6 @@ class Send_statement : public Statement Expression* channel_; // The value to send. Expression* val_; - // Whether this is for a select statement. - bool for_select_; }; // Select_clauses holds the clauses of a select statement. This is @@ -693,23 +684,32 @@ class Select_clauses Named_object* var, Named_object* closedvar, bool is_default, Block* statements, Location location) { - this->clauses_.push_back(Select_clause(is_send, channel, val, closed, var, - closedvar, is_default, statements, - location)); + int index = static_cast<int>(this->clauses_.size()); + this->clauses_.push_back(Select_clause(index, is_send, channel, val, + closed, var, closedvar, is_default, + statements, location)); } + size_t + size() const + { return this->clauses_.size(); } + // Traverse the select clauses. int traverse(Traverse*); // Lower statements. void - lower(Gogo*, Named_object*, Block*); + lower(Gogo*, Named_object*, Block*, Temporary_statement*); // Determine types. void determine_types(); + // Check types. + void + check_types(); + // Whether the select clauses may fall through to the statement // which follows the overall select statement. bool @@ -717,7 +717,8 @@ class Select_clauses // Convert to the backend representation. Bstatement* - get_backend(Translate_context*, Unnamed_label* break_label, Location); + get_backend(Translate_context*, Temporary_statement* sel, + Unnamed_label* break_label, Location); // Dump AST representation. void @@ -734,27 +735,37 @@ class Select_clauses is_default_(false) { } - Select_clause(bool is_send, Expression* channel, Expression* val, - Expression* closed, Named_object* var, + Select_clause(int index, bool is_send, Expression* channel, + Expression* val, Expression* closed, Named_object* var, Named_object* closedvar, bool is_default, Block* statements, Location location) - : channel_(channel), val_(val), closed_(closed), var_(var), - closedvar_(closedvar), statements_(statements), location_(location), - is_send_(is_send), is_default_(is_default), is_lowered_(false) + : index_(index), channel_(channel), val_(val), closed_(closed), + var_(var), closedvar_(closedvar), statements_(statements), + location_(location), is_send_(is_send), is_default_(is_default), + is_lowered_(false) { go_assert(is_default ? channel == NULL : channel != NULL); } + // Return the index of this clause. + int + index() const + { return this->index_; } + // Traverse the select clause. int traverse(Traverse*); // Lower statements. void - lower(Gogo*, Named_object*, Block*); + lower(Gogo*, Named_object*, Block*, Temporary_statement*); // Determine types. void determine_types(); + // Check types. + void + check_types(); + // Return true if this is the default clause. bool is_default() const @@ -798,6 +809,18 @@ class Select_clauses dump_clause(Ast_dump_context*) const; private: + void + lower_default(Block*, Expression*, Expression*); + + void + lower_send(Block*, Expression*, Expression*, Expression*); + + void + lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*, + Expression*); + + // The index of this case in the generated switch statement. + int index_; // The channel. Expression* channel_; // The value to send or the lvalue to receive into. @@ -822,12 +845,6 @@ class Select_clauses bool is_lowered_; }; - void - add_clause_backend(Translate_context*, Location, int index, - int case_value, Select_clause*, Unnamed_label*, - std::vector<std::vector<Bexpression*> >* cases, - std::vector<Bstatement*>* clauses); - typedef std::vector<Select_clause> Clauses; Clauses clauses_; @@ -840,7 +857,7 @@ class Select_statement : public Statement public: Select_statement(Location location) : Statement(STATEMENT_SELECT, location), - clauses_(NULL), break_label_(NULL), is_lowered_(false) + clauses_(NULL), sel_(NULL), break_label_(NULL), is_lowered_(false) { } // Add the clauses. @@ -867,6 +884,10 @@ class Select_statement : public Statement do_determine_types() { this->clauses_->determine_types(); } + void + do_check_types(Gogo*) + { this->clauses_->check_types(); } + bool do_may_fall_through() const { return this->clauses_->may_fall_through(); } @@ -880,6 +901,8 @@ class Select_statement : public Statement private: // The select clauses. Select_clauses* clauses_; + // A temporary which holds the select structure we build up at runtime. + Temporary_statement* sel_; // The break label. Unnamed_label* break_label_; // Whether this statement has been lowered. diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 3dadf8d12d7..e3c6b3ce824 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -246,6 +246,14 @@ can_inline_edge_p (struct cgraph_edge *e, bool report) struct function *caller_cfun = DECL_STRUCT_FUNCTION (e->caller->decl); struct function *callee_cfun = callee ? DECL_STRUCT_FUNCTION (callee->decl) : NULL; + bool call_stmt_cannot_inline_p; + + /* If E has a call statement in it, use the inline attribute from + the statement, otherwise use the inline attribute in E. Edges + will not have statements when working in WPA mode. */ + call_stmt_cannot_inline_p = (e->call_stmt) + ? gimple_call_cannot_inline_p (e->call_stmt) + : e->call_stmt_cannot_inline_p; if (!caller_cfun && e->caller->clone_of) caller_cfun = DECL_STRUCT_FUNCTION (e->caller->clone_of->decl); @@ -270,7 +278,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report) e->inline_failed = CIF_OVERWRITABLE; return false; } - else if (e->call_stmt_cannot_inline_p) + else if (call_stmt_cannot_inline_p) { e->inline_failed = CIF_MISMATCHED_ARGUMENTS; inlinable = false; @@ -343,14 +351,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report) } } - /* Be sure that the cannot_inline_p flag is up to date. */ - gcc_checking_assert (!e->call_stmt - || (gimple_call_cannot_inline_p (e->call_stmt) - == e->call_stmt_cannot_inline_p) - /* In -flto-partition=none mode we really keep things out of - sync because call_stmt_cannot_inline_p is set at cgraph - merging when function bodies are not there yet. */ - || (in_lto_p && !gimple_call_cannot_inline_p (e->call_stmt))); if (!inlinable && report) report_inline_failed_reason (e); return inlinable; diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c index 6deff4141a3..378b933baf0 100644 --- a/gcc/loop-unroll.c +++ b/gcc/loop-unroll.c @@ -1,5 +1,5 @@ /* Loop unrolling and peeling. - Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2010 + Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2010, 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -2262,10 +2262,15 @@ apply_opt_in_copies (struct opt_info *opt_info, for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); insn = next) { next = NEXT_INSN (insn); - if (!INSN_P (insn)) + if (!INSN_P (insn) + || (DEBUG_INSN_P (insn) + && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)) continue; - while (!INSN_P (orig_insn)) + while (!INSN_P (orig_insn) + || (DEBUG_INSN_P (orig_insn) + && (TREE_CODE (INSN_VAR_LOCATION_DECL (orig_insn)) + == LABEL_DECL))) orig_insn = NEXT_INSN (orig_insn); ivts_templ.insn = orig_insn; diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index af849540ea8..6f13e04220e 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,8 @@ +2011-12-01 Uros Bizjak <ubizjak@gmail.com> + + * lto-lang.c (lto_attribute_table): Handle *tm regparm. + (ignore_attribute): New. + 2011-11-21 Aldy Hernandez <aldyh@redhat.com> * lto-lang.c (lto_attribute_table): Handle transaction_pure. diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 2536f26ebf0..0d230eeddca 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -47,6 +47,8 @@ static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); +static tree ignore_attribute (tree *, tree, tree, int, bool *); + static tree handle_format_attribute (tree *, tree, tree, int, bool *); static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); @@ -78,6 +80,10 @@ const struct attribute_spec lto_attribute_table[] = handle_type_generic_attribute, false }, { "transaction_pure", 0, 0, false, true, true, handle_transaction_pure_attribute, false }, + /* For internal use only. The leading '*' both prevents its usage in + source code and signals that it may be overridden by machine tables. */ + { "*tm regparm", 0, 0, false, true, true, + ignore_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -419,6 +425,18 @@ handle_transaction_pure_attribute (tree *node, tree ARG_UNUSED (name), return NULL_TREE; } +/* Ignore the given attribute. Used when this attribute may be usefully + overridden by the target, but is not used generically. */ + +static tree +ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + *no_add_attrs = true; + return NULL_TREE; +} + /* Handle a "format" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8e29dab0ade..cd9e27e77f8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,43 @@ +2011-12-01 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp0x/initlist61.C: New. + +2011-12-01 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/51326 + * g++.dg/inherit/crash3.C: New. + +2011-12-01 Nathan Sidwell <nathan@acm.org> + + PR gcov-profile/51113 + * lib/gcov.exp (verify-lines): Add support for xfailing. + (run-gcov): Likewise. + * gcc.misc-tests/gcov-13.c: Xfail weak function. + * gcc.misc-tests/gcov-16.c: Remove. + * gcc.misc-tests/gcov-17.c: Remove. + * g++.dg/gcov-8.C: Remove. + * g++.dg/gcov-9.C: Remove. + * g++.dg/gcovpart-12b.C: New. + * g++.dg/gcov-12.C: New. + +2011-12-01 Andrew Pinski <apinski@cavium.com> + + PR lto/51198 + * g++.dg/torture/pr51198.C: New testcase. + +2011-12-01 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/51246 + * gcc.c-torture/compile/pr51246.c: New test. + + PR rtl-optimization/51014 + * g++.dg/opt/pr51014.C: New test. + +2011-12-01 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/51367 + * g++.dg/template/error47.C: New. + 2011-11-30 Jason Merrill <jason@redhat.com> PR c++/51009 diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist61.C b/gcc/testsuite/g++.dg/cpp0x/initlist61.C new file mode 100644 index 00000000000..28eccc2637d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist61.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } + +struct N { N(int); }; +struct A { N i,j; }; + +int main() +{ + A* ap = new A{1,2}; +} diff --git a/gcc/testsuite/g++.dg/gcov/gcov-12.C b/gcc/testsuite/g++.dg/gcov/gcov-12.C new file mode 100644 index 00000000000..c4708e40726 --- /dev/null +++ b/gcc/testsuite/g++.dg/gcov/gcov-12.C @@ -0,0 +1,21 @@ +/* PR 51113 */ +/* { dg-options "-fprofile-arcs -ftest-coverage -fpic" } */ +/* { dg-do run { target native } } */ +/* { dg-additional-sources "gcovpart-12b.C" } */ + +struct Foo { + Foo () + {} /* count(1) */ + virtual void Func () /* count(#####) */ + {} /* count(#####) */ +}; + +int main () +{ + Foo b; + + return 0; /* count (1) */ +} + +/* { dg-final { run-gcov gcov-12.C } } */ +/* { dg-final { run-gcov gcovpart-12b.C { xfail *-*-* } } } */ diff --git a/gcc/testsuite/g++.dg/gcov/gcov-8.C b/gcc/testsuite/g++.dg/gcov/gcov-8.C deleted file mode 100644 index 272cefc373b..00000000000 --- a/gcc/testsuite/g++.dg/gcov/gcov-8.C +++ /dev/null @@ -1,14 +0,0 @@ -/* { dg-options "-fprofile-arcs -fvisibility=hidden" } */ -/* { dg-require-visibility "" } */ - -struct __attribute__((visibility ("hidden"))) X -{ - void Fink (); -}; - -void X::Fink () -{ -} - -/* { dg-final { scan-assembler "\\.hidden\t__gcov___ZN1X4FinkEv" { target { ! *-*-darwin* } } } } */ -/* { dg-final { scan-assembler "\\.private_extern ___gcov___ZN1X4FinkEv" { target *-*-darwin* } } } */ diff --git a/gcc/testsuite/g++.dg/gcov/gcov-9.C b/gcc/testsuite/g++.dg/gcov/gcov-9.C deleted file mode 100644 index b9c64d22e56..00000000000 --- a/gcc/testsuite/g++.dg/gcov/gcov-9.C +++ /dev/null @@ -1,17 +0,0 @@ -/* { dg-options "-fprofile-arcs -fvisibility-inlines-hidden" } */ -/* { dg-require-visibility "" } */ - -inline void Boo () -{ -} - -extern "C" void (*Foo ()) () -{ - return Boo; -} - -/* { dg-final { scan-assembler "\\.hidden\t__gcov___Z3Boov" { target { ! *-*-darwin* } } } } */ -/* { dg-final { scan-assembler "\\.private_extern ___gcov___Z3Boov" { target *-*-darwin* } } } */ -/* { dg-final { scan-assembler "__gcov__Foo:" } } */ -/* { dg-final { scan-assembler-not "\\.hidden\t__gcov__Foo" { target { ! *-*-darwin* } } } } */ -/* { dg-final { scan-assembler-not "\\.private_extern ___gcov__Foo" { target *-*-darwin* } } } */ diff --git a/gcc/testsuite/g++.dg/gcov/gcovpart-12b.C b/gcc/testsuite/g++.dg/gcov/gcovpart-12b.C new file mode 100644 index 00000000000..6a1f981f0df --- /dev/null +++ b/gcc/testsuite/g++.dg/gcov/gcovpart-12b.C @@ -0,0 +1,5 @@ +struct Foo { + Foo () {} + virtual void Func () /* count(-) { xfail *-*-* } */ + {} /* count(-) { xfail *-*-* } */ +}; diff --git a/gcc/testsuite/g++.dg/inherit/crash3.C b/gcc/testsuite/g++.dg/inherit/crash3.C new file mode 100644 index 00000000000..e6094b04a64 --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/crash3.C @@ -0,0 +1,11 @@ +// PR c++/51326 + +struct A +{ + virtual int& foo(); // { dg-error "overriding" } +}; + +struct B : A +{ + B& foo(); // { dg-error "conflicting return type" } +}; diff --git a/gcc/testsuite/g++.dg/opt/pr51014.C b/gcc/testsuite/g++.dg/opt/pr51014.C new file mode 100644 index 00000000000..1e5bb9f0f14 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr51014.C @@ -0,0 +1,16 @@ +// PR rtl-optimization/51014 +// { dg-do compile } +// { dg-options "-O2 -funroll-loops -fcompare-debug" } + +struct S +{ + ~S() { delete s; } + int *s; +}; + +void +f (S *x, S *y) +{ + for (; x != y; ++x) + x->~S(); +} diff --git a/gcc/testsuite/g++.dg/template/error47.C b/gcc/testsuite/g++.dg/template/error47.C new file mode 100644 index 00000000000..7e360fe69a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/error47.C @@ -0,0 +1,9 @@ +// PR c++/51367 + +template<typename T> void foo(T, T); // { dg-message "template" } + +void bar(void* p) +{ + foo(0, p); // { dg-error "no matching" } +} +// { dg-message "candidate|parameter 'T' ('int' and 'void*')" { target *-*-* } 7 } diff --git a/gcc/testsuite/g++.dg/torture/pr51198.C b/gcc/testsuite/g++.dg/torture/pr51198.C new file mode 100644 index 00000000000..65009ff5458 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr51198.C @@ -0,0 +1,29 @@ +/* { dg-options "-std=gnu++0x" } */ + +struct A +{ + int i = 0 ? 0 : throw 1; +}; + + +struct B +{ + int f(); + int i = f(); +}; + +struct C +{ + C(int); +}; + +struct D +{ + C a = 0; +}; + +A a; +B b; +D d; + + diff --git a/gcc/testsuite/gcc.c-torture/compile/pr51246.c b/gcc/testsuite/gcc.c-torture/compile/pr51246.c new file mode 100644 index 00000000000..c206d8689f1 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr51246.c @@ -0,0 +1,14 @@ +/* PR tree-optimization/51246 */ + +int a, *b; + +void +test (void) +{ + while (1) + { + int c; + a = c; + b = &c; + } +} diff --git a/gcc/testsuite/gcc.misc-tests/gcov-13.c b/gcc/testsuite/gcc.misc-tests/gcov-13.c index 14be8f9e103..fa9680b2544 100644 --- a/gcc/testsuite/gcc.misc-tests/gcov-13.c +++ b/gcc/testsuite/gcc.misc-tests/gcov-13.c @@ -7,7 +7,7 @@ int __attribute__ ((weak)) weak () { - return 1; /* count(-) */ + return 1; /* count(-) { xfail *-*-* } */ } int main () @@ -15,5 +15,5 @@ int main () return weak (); /* count(1) */ } -/* { dg-final { run-gcov { -a gcov-13.c } } } */ +/* { dg-final { run-gcov { -a gcov-13.c } { xfail *-*-* } } } */ /* { dg-final { run-gcov { -a gcovpart-13b.c } } } */ diff --git a/gcc/testsuite/gcc.misc-tests/gcov-16.c b/gcc/testsuite/gcc.misc-tests/gcov-16.c deleted file mode 100644 index 478f44a367d..00000000000 --- a/gcc/testsuite/gcc.misc-tests/gcov-16.c +++ /dev/null @@ -1,12 +0,0 @@ -/* Test visibility is copied */ - -/* { dg-options "-fprofile-arcs -fvisibility=hidden" } */ -/* { dg-require-visibility "" } */ -/* { dg-require-weak "" } */ - -void Foo () -{ -} - - /* { dg-final { scan-assembler "\\.hidden\t__gcov__Foo" { target { ! *-*-darwin* } } } } */ - /* { dg-final { scan-assembler "\\.private_extern ___gcov__Foo" { target *-*-darwin* } } } */ diff --git a/gcc/testsuite/gcc.misc-tests/gcov-17.c b/gcc/testsuite/gcc.misc-tests/gcov-17.c deleted file mode 100644 index f8ff794215c..00000000000 --- a/gcc/testsuite/gcc.misc-tests/gcov-17.c +++ /dev/null @@ -1,12 +0,0 @@ -/* Test visibility is copied */ - -/* { dg-options "-fprofile-arcs" } */ -/* { dg-require-visibility "" } */ -/* { dg-require-weak "" } */ - -void __attribute__ ((visibility ("hidden"), weak)) Foo () -{ -} - -/* { dg-final { scan-assembler "\\.hidden\t__gcov__Foo" { target { ! *-*-darwin* } } } } */ -/* { dg-final { scan-assembler "\\.private_extern ___gcov__Foo" { target *-*-darwin* } } } */ diff --git a/gcc/testsuite/lib/gcov.exp b/gcc/testsuite/lib/gcov.exp index 1c7484785db..081b3ceb14c 100644 --- a/gcc/testsuite/lib/gcov.exp +++ b/gcc/testsuite/lib/gcov.exp @@ -39,19 +39,28 @@ proc clean-gcov { testcase } { # proc verify-lines { testcase file } { #send_user "verify-lines\n" + global subdir set failed 0 set fd [open $file r] while { [gets $fd line] >= 0 } { # We want to match both "-" and "#####" as count as well as numbers, # since we want to detect lines that shouldn't be marked as covered. - if [regexp "^ *(\[^:]*): *(\[0-9\\-#]+):.*count\\((\[0-9\\-#]+)\\)" \ - "$line" all is n shouldbe] { + if [regexp "^ *(\[^:]*): *(\[0-9\\-#]+):.*count\\((\[0-9\\-#]+)\\)(.*)" \ + "$line" all is n shouldbe rest] { + if [regexp "^ *{(.*)}" $rest all xfailed] { + switch [dg-process-target $xfailed] { + "N" { continue } + "F" { setup_xfail "*-*-*" } + } + } if { $is == "" } { - fail "$n:no data available for this line" + fail "$subdir/$testcase:$n:no data available for this line" incr failed } elseif { $is != $shouldbe } { - fail "$n:is $is:should be $shouldbe" + fail "$subdir/$testcase:$n:is $is:should be $shouldbe" incr failed + } else { + pass "$subdir/$testcase:$n line count" } } } @@ -230,32 +239,36 @@ proc run-gcov { args } { global GCOV global srcdir subdir - set gcov_args [lindex $args end] - + set gcov_args "" set gcov_verify_calls 0 set gcov_verify_branches 0 - set gcov_execute_xfail "" - set gcov_verify_xfail "" + set xfailed 0 foreach a $args { if { $a == "calls" } { set gcov_verify_calls 1 } elseif { $a == "branches" } { set gcov_verify_branches 1 + } elseif { $gcov_args == "" } { + set gcov_args $a + } else { + switch [dg-process-target $a] { + "N" { return } + "F" { set xfailed 1 } + } } } # Extract the test name from the arguments. set testcase [lindex $gcov_args end] - if { $gcov_execute_xfail != "" } { - eval setup_xfail [split $gcov_execute_xfail] - } - verbose "Running $GCOV $testcase" 2 set testcase [remote_download host $testcase] set result [remote_exec host $GCOV $gcov_args] if { [lindex $result 0] != 0 } { + if { $xfailed } { + setup_xfail "*-*-*" + } fail "$subdir/$testcase gcov failed: [lindex $result 1]" clean-gcov $testcase return @@ -264,16 +277,15 @@ proc run-gcov { args } { # Get the gcov output file after making sure it exists. set files [glob -nocomplain $testcase.gcov] if { $files == "" } { + if { $xfailed } { + setup_xfail "*-*-*" + } fail "$subdir/$testcase gcov failed: $testcase.gcov does not exist" clean-gcov $testcase return } remote_upload host $testcase.gcov $testcase.gcov - if { $gcov_verify_xfail != "" } { - eval setup_xfail [split $gcov_verify_xfail] - } - # Check that line execution counts are as expected. set lfailed [verify-lines $testcase $testcase.gcov] @@ -293,6 +305,9 @@ proc run-gcov { args } { # Report whether the gcov test passed or failed. If there were # multiple failures then the message is a summary. set tfailed [expr $lfailed + $bfailed + $cfailed] + if { $xfailed } { + setup_xfail "*-*-*" + } if { $tfailed > 0 } { fail "$subdir/$testcase gcov: $lfailed failures in line counts, $bfailed in branch percentages, $cfailed in return percentages" } else { diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c index c55c89e9b71..751bdebfa8a 100644 --- a/gcc/tree-predcom.c +++ b/gcc/tree-predcom.c @@ -1306,8 +1306,20 @@ replace_ref_with (gimple stmt, tree new_tree, bool set, bool in_lhs) val = gimple_assign_lhs (stmt); if (TREE_CODE (val) != SSA_NAME) { - gcc_assert (gimple_assign_copy_p (stmt)); val = gimple_assign_rhs1 (stmt); + gcc_assert (gimple_assign_single_p (stmt)); + if (TREE_CLOBBER_P (val)) + { + val = gimple_default_def (cfun, SSA_NAME_VAR (new_tree)); + if (val == NULL_TREE) + { + val = make_ssa_name (SSA_NAME_VAR (new_tree), + gimple_build_nop ()); + set_default_def (SSA_NAME_VAR (new_tree), val); + } + } + else + gcc_assert (gimple_assign_copy_p (stmt)); } } else diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index d6fbe622df0..a710de620df 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -1215,6 +1215,26 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb) ei_next (&ei); } + /* If this is a store into a variable that is being optimized away, + add a debug bind stmt if possible. */ + if (MAY_HAVE_DEBUG_STMTS + && gimple_assign_single_p (stmt) + && is_gimple_val (gimple_assign_rhs1 (stmt))) + { + tree lhs = gimple_assign_lhs (stmt); + if ((TREE_CODE (lhs) == VAR_DECL || TREE_CODE (lhs) == PARM_DECL) + && !DECL_IGNORED_P (lhs) + && is_gimple_reg_type (TREE_TYPE (lhs)) + && !is_global_var (lhs) + && !DECL_HAS_VALUE_EXPR_P (lhs)) + { + tree rhs = gimple_assign_rhs1 (stmt); + gimple note + = gimple_build_debug_bind (lhs, unshare_expr (rhs), stmt); + gsi_insert_after (i, note, GSI_SAME_STMT); + } + } + unlink_stmt_vdef (stmt); gsi_remove (i, true); release_defs (stmt); diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c index b8a056ebdac..103e4f7155a 100644 --- a/gcc/tree-ssa-live.c +++ b/gcc/tree-ssa-live.c @@ -1,5 +1,5 @@ /* Liveness for SSA trees. - Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010 + Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Andrew MacLeod <amacleod@redhat.com> @@ -814,7 +814,15 @@ remove_unused_locals (void) bitmap_set_bit (global_unused_vars, DECL_UID (var)); } else - continue; + { + /* For unreferenced local vars drop TREE_ADDRESSABLE + bit in case it is referenced from debug stmts. */ + if (DECL_CONTEXT (var) == current_function_decl + && TREE_ADDRESSABLE (var) + && is_gimple_reg_type (TREE_TYPE (var))) + TREE_ADDRESSABLE (var) = 0; + continue; + } } else if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var) diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 22414475f6f..306bac28c18 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -2074,6 +2074,8 @@ vect_recog_bool_pattern (VEC (gimple, heap) **stmts, tree *type_in, stmt_vec_info pattern_stmt_info; vectype = STMT_VINFO_VECTYPE (stmt_vinfo); gcc_assert (vectype != NULL_TREE); + if (!VECTOR_MODE_P (TYPE_MODE (vectype))) + return NULL; if (!check_bool_pattern (var, loop_vinfo)) return NULL; diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 5cbc25fcb1e..494cdd3e030 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -7284,7 +7284,9 @@ simplify_conversion_using_ranges (gimple stmt) tree innerop, middleop, finaltype; gimple def_stmt; value_range_t *innervr; - double_int innermin, innermax, middlemin, middlemax; + bool inner_unsigned_p, middle_unsigned_p, final_unsigned_p; + unsigned inner_prec, middle_prec, final_prec; + double_int innermin, innermed, innermax, middlemin, middlemed, middlemax; finaltype = TREE_TYPE (gimple_assign_lhs (stmt)); if (!INTEGRAL_TYPE_P (finaltype)) @@ -7309,33 +7311,49 @@ simplify_conversion_using_ranges (gimple stmt) the middle conversion is removed. */ innermin = tree_to_double_int (innervr->min); innermax = tree_to_double_int (innervr->max); - middlemin = double_int_ext (innermin, TYPE_PRECISION (TREE_TYPE (middleop)), - TYPE_UNSIGNED (TREE_TYPE (middleop))); - middlemax = double_int_ext (innermax, TYPE_PRECISION (TREE_TYPE (middleop)), - TYPE_UNSIGNED (TREE_TYPE (middleop))); - /* If the middle values are not equal to the original values fail. - But only if the inner cast truncates (thus we ignore differences - in extension to handle the case going from a range to an anti-range - and back). */ - if ((TYPE_PRECISION (TREE_TYPE (innerop)) - > TYPE_PRECISION (TREE_TYPE (middleop))) - && (!double_int_equal_p (innermin, middlemin) - || !double_int_equal_p (innermax, middlemax))) + + inner_prec = TYPE_PRECISION (TREE_TYPE (innerop)); + middle_prec = TYPE_PRECISION (TREE_TYPE (middleop)); + final_prec = TYPE_PRECISION (finaltype); + + /* If the first conversion is not injective, the second must not + be widening. */ + if (double_int_cmp (double_int_sub (innermax, innermin), + double_int_mask (middle_prec), true) > 0 + && middle_prec < final_prec) return false; + /* We also want a medium value so that we can track the effect that + narrowing conversions with sign change have. */ + inner_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (innerop)); + if (inner_unsigned_p) + innermed = double_int_rshift (double_int_mask (inner_prec), + 1, inner_prec, false); + else + innermed = double_int_zero; + if (double_int_cmp (innermin, innermed, inner_unsigned_p) >= 0 + || double_int_cmp (innermed, innermax, inner_unsigned_p) >= 0) + innermed = innermin; + + middle_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (middleop)); + middlemin = double_int_ext (innermin, middle_prec, middle_unsigned_p); + middlemed = double_int_ext (innermed, middle_prec, middle_unsigned_p); + middlemax = double_int_ext (innermax, middle_prec, middle_unsigned_p); + /* Require that the final conversion applied to both the original and the intermediate range produces the same result. */ + final_unsigned_p = TYPE_UNSIGNED (finaltype); if (!double_int_equal_p (double_int_ext (middlemin, - TYPE_PRECISION (finaltype), - TYPE_UNSIGNED (finaltype)), + final_prec, final_unsigned_p), double_int_ext (innermin, - TYPE_PRECISION (finaltype), - TYPE_UNSIGNED (finaltype))) + final_prec, final_unsigned_p)) + || !double_int_equal_p (double_int_ext (middlemed, + final_prec, final_unsigned_p), + double_int_ext (innermed, + final_prec, final_unsigned_p)) || !double_int_equal_p (double_int_ext (middlemax, - TYPE_PRECISION (finaltype), - TYPE_UNSIGNED (finaltype)), + final_prec, final_unsigned_p), double_int_ext (innermax, - TYPE_PRECISION (finaltype), - TYPE_UNSIGNED (finaltype)))) + final_prec, final_unsigned_p))) return false; gimple_assign_set_rhs1 (stmt, innerop); diff --git a/gcc/tree.c b/gcc/tree.c index 72603b59945..4cadc7ef8c4 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -4651,7 +4651,8 @@ free_lang_data_in_decl (tree decl) || (decl_function_context (decl) && !TREE_STATIC (decl))) DECL_INITIAL (decl) = NULL_TREE; } - else if (TREE_CODE (decl) == TYPE_DECL) + else if (TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == FIELD_DECL) DECL_INITIAL (decl) = NULL_TREE; else if (TREE_CODE (decl) == TRANSLATION_UNIT_DECL && DECL_INITIAL (decl) diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 5ab10a61f3d..19ce7152cf1 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -409,10 +409,7 @@ runtime_files = \ runtime/go-caller.c \ runtime/go-can-convert-interface.c \ runtime/go-cgo.c \ - runtime/go-chan-cap.c \ - runtime/go-chan-len.c \ runtime/go-check-interface.c \ - runtime/go-close.c \ runtime/go-construct-map.c \ runtime/go-convert-interface.c \ runtime/go-copy.c \ @@ -432,27 +429,16 @@ runtime_files = \ runtime/go-map-len.c \ runtime/go-map-range.c \ runtime/go-nanotime.c \ - runtime/go-new-channel.c \ runtime/go-new-map.c \ runtime/go-new.c \ runtime/go-panic.c \ runtime/go-print.c \ - runtime/go-rec-big.c \ - runtime/go-rec-nb-big.c \ - runtime/go-rec-nb-small.c \ - runtime/go-rec-small.c \ runtime/go-recover.c \ runtime/go-reflect.c \ runtime/go-reflect-call.c \ - runtime/go-reflect-chan.c \ runtime/go-reflect-map.c \ runtime/go-rune.c \ runtime/go-runtime-error.c \ - runtime/go-select.c \ - runtime/go-send-big.c \ - runtime/go-send-nb-big.c \ - runtime/go-send-nb-small.c \ - runtime/go-send-small.c \ runtime/go-setenv.c \ runtime/go-signal.c \ runtime/go-strcmp.c \ @@ -473,6 +459,7 @@ runtime_files = \ runtime/go-unsafe-newarray.c \ runtime/go-unsafe-pointer.c \ runtime/go-unwind.c \ + runtime/chan.c \ runtime/cpuprof.c \ $(runtime_lock_files) \ runtime/mcache.c \ @@ -488,7 +475,6 @@ runtime_files = \ runtime/thread.c \ runtime/yield.c \ $(rtems_task_variable_add_file) \ - chan.c \ iface.c \ malloc.c \ map.c \ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index f7c293a66cc..1a76f0b5a20 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -183,8 +183,7 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ runtime/go-assert-interface.c \ runtime/go-byte-array-to-string.c runtime/go-breakpoint.c \ runtime/go-caller.c runtime/go-can-convert-interface.c \ - runtime/go-cgo.c runtime/go-chan-cap.c runtime/go-chan-len.c \ - runtime/go-check-interface.c runtime/go-close.c \ + runtime/go-cgo.c runtime/go-check-interface.c \ runtime/go-construct-map.c runtime/go-convert-interface.c \ runtime/go-copy.c runtime/go-defer.c \ runtime/go-deferred-recover.c runtime/go-eface-compare.c \ @@ -195,17 +194,11 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ runtime/go-interface-val-compare.c runtime/go-make-slice.c \ runtime/go-map-delete.c runtime/go-map-index.c \ runtime/go-map-len.c runtime/go-map-range.c \ - runtime/go-nanotime.c runtime/go-new-channel.c \ - runtime/go-new-map.c runtime/go-new.c runtime/go-panic.c \ - runtime/go-print.c runtime/go-rec-big.c \ - runtime/go-rec-nb-big.c runtime/go-rec-nb-small.c \ - runtime/go-rec-small.c runtime/go-recover.c \ + runtime/go-nanotime.c runtime/go-new-map.c runtime/go-new.c \ + runtime/go-panic.c runtime/go-print.c runtime/go-recover.c \ runtime/go-reflect.c runtime/go-reflect-call.c \ - runtime/go-reflect-chan.c runtime/go-reflect-map.c \ - runtime/go-rune.c runtime/go-runtime-error.c \ - runtime/go-select.c runtime/go-send-big.c \ - runtime/go-send-nb-big.c runtime/go-send-nb-small.c \ - runtime/go-send-small.c runtime/go-setenv.c \ + runtime/go-reflect-map.c runtime/go-rune.c \ + runtime/go-runtime-error.c runtime/go-setenv.c \ runtime/go-signal.c runtime/go-strcmp.c \ runtime/go-string-to-byte-array.c \ runtime/go-string-to-int-array.c runtime/go-strplus.c \ @@ -215,15 +208,15 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ runtime/go-type-string.c runtime/go-typedesc-equal.c \ runtime/go-typestring.c runtime/go-unreflect.c \ runtime/go-unsafe-new.c runtime/go-unsafe-newarray.c \ - runtime/go-unsafe-pointer.c runtime/go-unwind.c \ + runtime/go-unsafe-pointer.c runtime/go-unwind.c runtime/chan.c \ runtime/cpuprof.c runtime/lock_sema.c runtime/thread-sema.c \ runtime/lock_futex.c runtime/thread-linux.c runtime/mcache.c \ runtime/mcentral.c runtime/mem_posix_memalign.c runtime/mem.c \ runtime/mfinal.c runtime/mfixalloc.c runtime/mgc0.c \ runtime/mheap.c runtime/msize.c runtime/proc.c \ runtime/runtime.c runtime/thread.c runtime/yield.c \ - runtime/rtems-task-variable-add.c chan.c iface.c malloc.c \ - map.c mprof.c reflect.c runtime1.c sema.c sigqueue.c string.c + runtime/rtems-task-variable-add.c iface.c malloc.c map.c \ + mprof.c reflect.c runtime1.c sema.c sigqueue.c string.c @LIBGO_IS_LINUX_FALSE@am__objects_1 = lock_sema.lo thread-sema.lo @LIBGO_IS_LINUX_TRUE@am__objects_1 = lock_futex.lo thread-linux.lo @HAVE_SYS_MMAN_H_FALSE@am__objects_2 = mem_posix_memalign.lo @@ -231,8 +224,7 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ @LIBGO_IS_RTEMS_TRUE@am__objects_3 = rtems-task-variable-add.lo am__objects_4 = go-append.lo go-assert.lo go-assert-interface.lo \ go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \ - go-can-convert-interface.lo go-cgo.lo go-chan-cap.lo \ - go-chan-len.lo go-check-interface.lo go-close.lo \ + go-can-convert-interface.lo go-cgo.lo go-check-interface.lo \ go-construct-map.lo go-convert-interface.lo go-copy.lo \ go-defer.lo go-deferred-recover.lo go-eface-compare.lo \ go-eface-val-compare.lo go-getgoroot.lo \ @@ -240,23 +232,20 @@ am__objects_4 = go-append.lo go-assert.lo go-assert-interface.lo \ go-interface-compare.lo go-interface-eface-compare.lo \ go-interface-val-compare.lo go-make-slice.lo go-map-delete.lo \ go-map-index.lo go-map-len.lo go-map-range.lo go-nanotime.lo \ - go-new-channel.lo go-new-map.lo go-new.lo go-panic.lo \ - go-print.lo go-rec-big.lo go-rec-nb-big.lo go-rec-nb-small.lo \ - go-rec-small.lo go-recover.lo go-reflect.lo go-reflect-call.lo \ - go-reflect-chan.lo go-reflect-map.lo go-rune.lo \ - go-runtime-error.lo go-select.lo go-send-big.lo \ - go-send-nb-big.lo go-send-nb-small.lo go-send-small.lo \ - go-setenv.lo go-signal.lo go-strcmp.lo \ + go-new-map.lo go-new.lo go-panic.lo go-print.lo go-recover.lo \ + go-reflect.lo go-reflect-call.lo go-reflect-map.lo go-rune.lo \ + go-runtime-error.lo go-setenv.lo go-signal.lo go-strcmp.lo \ go-string-to-byte-array.lo go-string-to-int-array.lo \ go-strplus.lo go-strslice.lo go-trampoline.lo go-type-eface.lo \ go-type-error.lo go-type-identity.lo go-type-interface.lo \ go-type-string.lo go-typedesc-equal.lo go-typestring.lo \ go-unreflect.lo go-unsafe-new.lo go-unsafe-newarray.lo \ - go-unsafe-pointer.lo go-unwind.lo cpuprof.lo $(am__objects_1) \ - mcache.lo mcentral.lo $(am__objects_2) mfinal.lo mfixalloc.lo \ - mgc0.lo mheap.lo msize.lo proc.lo runtime.lo thread.lo \ - yield.lo $(am__objects_3) chan.lo iface.lo malloc.lo map.lo \ - mprof.lo reflect.lo runtime1.lo sema.lo sigqueue.lo string.lo + go-unsafe-pointer.lo go-unwind.lo chan.lo cpuprof.lo \ + $(am__objects_1) mcache.lo mcentral.lo $(am__objects_2) \ + mfinal.lo mfixalloc.lo mgc0.lo mheap.lo msize.lo proc.lo \ + runtime.lo thread.lo yield.lo $(am__objects_3) iface.lo \ + malloc.lo map.lo mprof.lo reflect.lo runtime1.lo sema.lo \ + sigqueue.lo string.lo am_libgo_la_OBJECTS = $(am__objects_4) libgo_la_OBJECTS = $(am_libgo_la_OBJECTS) libgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @@ -836,10 +825,7 @@ runtime_files = \ runtime/go-caller.c \ runtime/go-can-convert-interface.c \ runtime/go-cgo.c \ - runtime/go-chan-cap.c \ - runtime/go-chan-len.c \ runtime/go-check-interface.c \ - runtime/go-close.c \ runtime/go-construct-map.c \ runtime/go-convert-interface.c \ runtime/go-copy.c \ @@ -859,27 +845,16 @@ runtime_files = \ runtime/go-map-len.c \ runtime/go-map-range.c \ runtime/go-nanotime.c \ - runtime/go-new-channel.c \ runtime/go-new-map.c \ runtime/go-new.c \ runtime/go-panic.c \ runtime/go-print.c \ - runtime/go-rec-big.c \ - runtime/go-rec-nb-big.c \ - runtime/go-rec-nb-small.c \ - runtime/go-rec-small.c \ runtime/go-recover.c \ runtime/go-reflect.c \ runtime/go-reflect-call.c \ - runtime/go-reflect-chan.c \ runtime/go-reflect-map.c \ runtime/go-rune.c \ runtime/go-runtime-error.c \ - runtime/go-select.c \ - runtime/go-send-big.c \ - runtime/go-send-nb-big.c \ - runtime/go-send-nb-small.c \ - runtime/go-send-small.c \ runtime/go-setenv.c \ runtime/go-signal.c \ runtime/go-strcmp.c \ @@ -900,6 +875,7 @@ runtime_files = \ runtime/go-unsafe-newarray.c \ runtime/go-unsafe-pointer.c \ runtime/go-unwind.c \ + runtime/chan.c \ runtime/cpuprof.c \ $(runtime_lock_files) \ runtime/mcache.c \ @@ -915,7 +891,6 @@ runtime_files = \ runtime/thread.c \ runtime/yield.c \ $(rtems_task_variable_add_file) \ - chan.c \ iface.c \ malloc.c \ map.c \ @@ -2461,10 +2436,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-caller.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-can-convert-interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cgo.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-cap.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-len.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-check-interface.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-close.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-construct-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-convert-interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-copy.Plo@am__quote@ @@ -2485,27 +2457,16 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-len.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-range.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-nanotime.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-channel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-panic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-print.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-nb-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-nb-small.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-small.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-recover.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-call.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-chan.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rune.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-runtime-error.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-select.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-nb-big.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-nb-small.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-small.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-setenv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-signal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strcmp.Plo@am__quote@ @@ -2645,20 +2606,6 @@ go-cgo.lo: runtime/go-cgo.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-cgo.lo `test -f 'runtime/go-cgo.c' || echo '$(srcdir)/'`runtime/go-cgo.c -go-chan-cap.lo: runtime/go-chan-cap.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-chan-cap.lo -MD -MP -MF $(DEPDIR)/go-chan-cap.Tpo -c -o go-chan-cap.lo `test -f 'runtime/go-chan-cap.c' || echo '$(srcdir)/'`runtime/go-chan-cap.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-chan-cap.Tpo $(DEPDIR)/go-chan-cap.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-chan-cap.c' object='go-chan-cap.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-chan-cap.lo `test -f 'runtime/go-chan-cap.c' || echo '$(srcdir)/'`runtime/go-chan-cap.c - -go-chan-len.lo: runtime/go-chan-len.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-chan-len.lo -MD -MP -MF $(DEPDIR)/go-chan-len.Tpo -c -o go-chan-len.lo `test -f 'runtime/go-chan-len.c' || echo '$(srcdir)/'`runtime/go-chan-len.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-chan-len.Tpo $(DEPDIR)/go-chan-len.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-chan-len.c' object='go-chan-len.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-chan-len.lo `test -f 'runtime/go-chan-len.c' || echo '$(srcdir)/'`runtime/go-chan-len.c - go-check-interface.lo: runtime/go-check-interface.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-check-interface.lo -MD -MP -MF $(DEPDIR)/go-check-interface.Tpo -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-check-interface.Tpo $(DEPDIR)/go-check-interface.Plo @@ -2666,13 +2613,6 @@ go-check-interface.lo: runtime/go-check-interface.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c -go-close.lo: runtime/go-close.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-close.lo -MD -MP -MF $(DEPDIR)/go-close.Tpo -c -o go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-close.Tpo $(DEPDIR)/go-close.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-close.c' object='go-close.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c - go-construct-map.lo: runtime/go-construct-map.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-construct-map.lo -MD -MP -MF $(DEPDIR)/go-construct-map.Tpo -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-construct-map.Tpo $(DEPDIR)/go-construct-map.Plo @@ -2806,13 +2746,6 @@ go-nanotime.lo: runtime/go-nanotime.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-nanotime.lo `test -f 'runtime/go-nanotime.c' || echo '$(srcdir)/'`runtime/go-nanotime.c -go-new-channel.lo: runtime/go-new-channel.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-channel.lo -MD -MP -MF $(DEPDIR)/go-new-channel.Tpo -c -o go-new-channel.lo `test -f 'runtime/go-new-channel.c' || echo '$(srcdir)/'`runtime/go-new-channel.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-channel.Tpo $(DEPDIR)/go-new-channel.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-new-channel.c' object='go-new-channel.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-new-channel.lo `test -f 'runtime/go-new-channel.c' || echo '$(srcdir)/'`runtime/go-new-channel.c - go-new-map.lo: runtime/go-new-map.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-map.lo -MD -MP -MF $(DEPDIR)/go-new-map.Tpo -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-map.Tpo $(DEPDIR)/go-new-map.Plo @@ -2841,34 +2774,6 @@ go-print.lo: runtime/go-print.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-print.lo `test -f 'runtime/go-print.c' || echo '$(srcdir)/'`runtime/go-print.c -go-rec-big.lo: runtime/go-rec-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-big.lo -MD -MP -MF $(DEPDIR)/go-rec-big.Tpo -c -o go-rec-big.lo `test -f 'runtime/go-rec-big.c' || echo '$(srcdir)/'`runtime/go-rec-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-big.Tpo $(DEPDIR)/go-rec-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-big.c' object='go-rec-big.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-big.lo `test -f 'runtime/go-rec-big.c' || echo '$(srcdir)/'`runtime/go-rec-big.c - -go-rec-nb-big.lo: runtime/go-rec-nb-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-nb-big.lo -MD -MP -MF $(DEPDIR)/go-rec-nb-big.Tpo -c -o go-rec-nb-big.lo `test -f 'runtime/go-rec-nb-big.c' || echo '$(srcdir)/'`runtime/go-rec-nb-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-nb-big.Tpo $(DEPDIR)/go-rec-nb-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-nb-big.c' object='go-rec-nb-big.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-nb-big.lo `test -f 'runtime/go-rec-nb-big.c' || echo '$(srcdir)/'`runtime/go-rec-nb-big.c - -go-rec-nb-small.lo: runtime/go-rec-nb-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-nb-small.lo -MD -MP -MF $(DEPDIR)/go-rec-nb-small.Tpo -c -o go-rec-nb-small.lo `test -f 'runtime/go-rec-nb-small.c' || echo '$(srcdir)/'`runtime/go-rec-nb-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-nb-small.Tpo $(DEPDIR)/go-rec-nb-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-nb-small.c' object='go-rec-nb-small.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-nb-small.lo `test -f 'runtime/go-rec-nb-small.c' || echo '$(srcdir)/'`runtime/go-rec-nb-small.c - -go-rec-small.lo: runtime/go-rec-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-small.lo -MD -MP -MF $(DEPDIR)/go-rec-small.Tpo -c -o go-rec-small.lo `test -f 'runtime/go-rec-small.c' || echo '$(srcdir)/'`runtime/go-rec-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-small.Tpo $(DEPDIR)/go-rec-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-small.c' object='go-rec-small.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-small.lo `test -f 'runtime/go-rec-small.c' || echo '$(srcdir)/'`runtime/go-rec-small.c - go-recover.lo: runtime/go-recover.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-recover.lo -MD -MP -MF $(DEPDIR)/go-recover.Tpo -c -o go-recover.lo `test -f 'runtime/go-recover.c' || echo '$(srcdir)/'`runtime/go-recover.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-recover.Tpo $(DEPDIR)/go-recover.Plo @@ -2890,13 +2795,6 @@ go-reflect-call.lo: runtime/go-reflect-call.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-call.lo `test -f 'runtime/go-reflect-call.c' || echo '$(srcdir)/'`runtime/go-reflect-call.c -go-reflect-chan.lo: runtime/go-reflect-chan.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-chan.lo -MD -MP -MF $(DEPDIR)/go-reflect-chan.Tpo -c -o go-reflect-chan.lo `test -f 'runtime/go-reflect-chan.c' || echo '$(srcdir)/'`runtime/go-reflect-chan.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-chan.Tpo $(DEPDIR)/go-reflect-chan.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-reflect-chan.c' object='go-reflect-chan.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-chan.lo `test -f 'runtime/go-reflect-chan.c' || echo '$(srcdir)/'`runtime/go-reflect-chan.c - go-reflect-map.lo: runtime/go-reflect-map.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-map.lo -MD -MP -MF $(DEPDIR)/go-reflect-map.Tpo -c -o go-reflect-map.lo `test -f 'runtime/go-reflect-map.c' || echo '$(srcdir)/'`runtime/go-reflect-map.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-map.Tpo $(DEPDIR)/go-reflect-map.Plo @@ -2918,41 +2816,6 @@ go-runtime-error.lo: runtime/go-runtime-error.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-runtime-error.lo `test -f 'runtime/go-runtime-error.c' || echo '$(srcdir)/'`runtime/go-runtime-error.c -go-select.lo: runtime/go-select.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-select.lo -MD -MP -MF $(DEPDIR)/go-select.Tpo -c -o go-select.lo `test -f 'runtime/go-select.c' || echo '$(srcdir)/'`runtime/go-select.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-select.Tpo $(DEPDIR)/go-select.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-select.c' object='go-select.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-select.lo `test -f 'runtime/go-select.c' || echo '$(srcdir)/'`runtime/go-select.c - -go-send-big.lo: runtime/go-send-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-big.lo -MD -MP -MF $(DEPDIR)/go-send-big.Tpo -c -o go-send-big.lo `test -f 'runtime/go-send-big.c' || echo '$(srcdir)/'`runtime/go-send-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-big.Tpo $(DEPDIR)/go-send-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-big.c' object='go-send-big.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-big.lo `test -f 'runtime/go-send-big.c' || echo '$(srcdir)/'`runtime/go-send-big.c - -go-send-nb-big.lo: runtime/go-send-nb-big.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-nb-big.lo -MD -MP -MF $(DEPDIR)/go-send-nb-big.Tpo -c -o go-send-nb-big.lo `test -f 'runtime/go-send-nb-big.c' || echo '$(srcdir)/'`runtime/go-send-nb-big.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-nb-big.Tpo $(DEPDIR)/go-send-nb-big.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-nb-big.c' object='go-send-nb-big.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-nb-big.lo `test -f 'runtime/go-send-nb-big.c' || echo '$(srcdir)/'`runtime/go-send-nb-big.c - -go-send-nb-small.lo: runtime/go-send-nb-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-nb-small.lo -MD -MP -MF $(DEPDIR)/go-send-nb-small.Tpo -c -o go-send-nb-small.lo `test -f 'runtime/go-send-nb-small.c' || echo '$(srcdir)/'`runtime/go-send-nb-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-nb-small.Tpo $(DEPDIR)/go-send-nb-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-nb-small.c' object='go-send-nb-small.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-nb-small.lo `test -f 'runtime/go-send-nb-small.c' || echo '$(srcdir)/'`runtime/go-send-nb-small.c - -go-send-small.lo: runtime/go-send-small.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-small.lo -MD -MP -MF $(DEPDIR)/go-send-small.Tpo -c -o go-send-small.lo `test -f 'runtime/go-send-small.c' || echo '$(srcdir)/'`runtime/go-send-small.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-small.Tpo $(DEPDIR)/go-send-small.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-small.c' object='go-send-small.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-small.lo `test -f 'runtime/go-send-small.c' || echo '$(srcdir)/'`runtime/go-send-small.c - go-setenv.lo: runtime/go-setenv.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-setenv.lo -MD -MP -MF $(DEPDIR)/go-setenv.Tpo -c -o go-setenv.lo `test -f 'runtime/go-setenv.c' || echo '$(srcdir)/'`runtime/go-setenv.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-setenv.Tpo $(DEPDIR)/go-setenv.Plo @@ -3093,6 +2956,13 @@ go-unwind.lo: runtime/go-unwind.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c +chan.lo: runtime/chan.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT chan.lo -MD -MP -MF $(DEPDIR)/chan.Tpo -c -o chan.lo `test -f 'runtime/chan.c' || echo '$(srcdir)/'`runtime/chan.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/chan.Tpo $(DEPDIR)/chan.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/chan.c' object='chan.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o chan.lo `test -f 'runtime/chan.c' || echo '$(srcdir)/'`runtime/chan.c + cpuprof.lo: runtime/cpuprof.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cpuprof.lo -MD -MP -MF $(DEPDIR)/cpuprof.Tpo -c -o cpuprof.lo `test -f 'runtime/cpuprof.c' || echo '$(srcdir)/'`runtime/cpuprof.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cpuprof.Tpo $(DEPDIR)/cpuprof.Plo diff --git a/libgo/runtime/chan.c b/libgo/runtime/chan.c new file mode 100644 index 00000000000..a246992c60b --- /dev/null +++ b/libgo/runtime/chan.c @@ -0,0 +1,1248 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" +#include "go-type.h" + +#define NOSELGEN 1 + +static int32 debug = 0; + +typedef struct WaitQ WaitQ; +typedef struct SudoG SudoG; +typedef struct Select Select; +typedef struct Scase Scase; + +typedef struct __go_type_descriptor Type; +typedef struct __go_channel_type ChanType; + +struct SudoG +{ + G* g; // g and selgen constitute + uint32 selgen; // a weak pointer to g + SudoG* link; + byte* elem; // data element +}; + +struct WaitQ +{ + SudoG* first; + SudoG* last; +}; + +struct Hchan +{ + uint32 qcount; // total data in the q + uint32 dataqsiz; // size of the circular q + uint16 elemsize; + bool closed; + uint8 elemalign; + uint32 sendx; // send index + uint32 recvx; // receive index + WaitQ recvq; // list of recv waiters + WaitQ sendq; // list of send waiters + Lock; +}; + +// Buffer follows Hchan immediately in memory. +// chanbuf(c, i) is pointer to the i'th slot in the buffer. +#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i)) + +enum +{ + // Scase.kind + CaseRecv, + CaseSend, + CaseDefault, +}; + +struct Scase +{ + SudoG sg; // must be first member (cast to Scase) + Hchan* chan; // chan + uint16 kind; + uint16 index; // index to return + bool* receivedp; // pointer to received bool (recv2) +}; + +struct Select +{ + uint16 tcase; // total count of scase[] + uint16 ncase; // currently filled scase[] + uint16* pollorder; // case poll order + Hchan** lockorder; // channel lock order + Scase scase[1]; // one per case (in order of appearance) +}; + +static void dequeueg(WaitQ*); +static SudoG* dequeue(WaitQ*); +static void enqueue(WaitQ*, SudoG*); + +Hchan* +runtime_makechan_c(ChanType *t, int64 hint) +{ + Hchan *c; + int32 n; + const Type *elem; + + elem = t->__element_type; + + if(hint < 0 || (int32)hint != hint || (elem->__size > 0 && (uintptr)hint > ((uintptr)-1) / elem->__size)) + runtime_panicstring("makechan: size out of range"); + + n = sizeof(*c); + + // allocate memory in one call + c = (Hchan*)runtime_mal(n + hint*elem->__size); + c->elemsize = elem->__size; + c->elemalign = elem->__align; + c->dataqsiz = hint; + + if(debug) + runtime_printf("makechan: chan=%p; elemsize=%lld; elemalign=%d; dataqsiz=%d\n", + c, (long long)elem->__size, elem->__align, c->dataqsiz); + + return c; +} + +// For reflect +// func makechan(typ *ChanType, size uint32) (chan) +uintptr reflect_makechan(ChanType *, uint32) + asm ("libgo_reflect.reflect.makechan"); + +uintptr +reflect_makechan(ChanType *t, uint32 size) +{ + void *ret; + Hchan *c; + + c = runtime_makechan_c(t, size); + ret = runtime_mal(sizeof(void*)); + __builtin_memcpy(ret, &c, sizeof(void*)); + return (uintptr)ret; +} + +// makechan(t *ChanType, hint int64) (hchan *chan any); +Hchan* +__go_new_channel(ChanType *t, uintptr hint) +{ + return runtime_makechan_c(t, hint); +} + +/* + * generic single channel send/recv + * if the bool pointer is nil, + * then the full exchange will + * occur. if pres is not nil, + * then the protocol will not + * sleep but return if it could + * not complete. + * + * sleep can wake up with g->param == nil + * when a channel involved in the sleep has + * been closed. it is easiest to loop and re-run + * the operation; we'll see that it's now closed. + */ +void +runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres) +{ + SudoG *sg; + SudoG mysg; + G* gp; + G* g; + + g = runtime_g(); + + if(c == nil) { + USED(t); + if(pres != nil) { + *pres = false; + return; + } + g->status = Gwaiting; + g->waitreason = "chan send (nil chan)"; + runtime_gosched(); + return; // not reached + } + + if(runtime_gcwaiting) + runtime_gosched(); + + if(debug) { + runtime_printf("chansend: chan=%p\n", c); + } + + runtime_lock(c); + if(c->closed) + goto closed; + + if(c->dataqsiz > 0) + goto asynch; + + sg = dequeue(&c->recvq); + if(sg != nil) { + runtime_unlock(c); + + gp = sg->g; + gp->param = sg; + if(sg->elem != nil) + runtime_memmove(sg->elem, ep, c->elemsize); + runtime_ready(gp); + + if(pres != nil) + *pres = true; + return; + } + + if(pres != nil) { + runtime_unlock(c); + *pres = false; + return; + } + + mysg.elem = ep; + mysg.g = g; + mysg.selgen = NOSELGEN; + g->param = nil; + g->status = Gwaiting; + g->waitreason = "chan send"; + enqueue(&c->sendq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + if(g->param == nil) { + runtime_lock(c); + if(!c->closed) + runtime_throw("chansend: spurious wakeup"); + goto closed; + } + + return; + +asynch: + if(c->closed) + goto closed; + + if(c->qcount >= c->dataqsiz) { + if(pres != nil) { + runtime_unlock(c); + *pres = false; + return; + } + mysg.g = g; + mysg.elem = nil; + mysg.selgen = NOSELGEN; + g->status = Gwaiting; + g->waitreason = "chan send"; + enqueue(&c->sendq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + runtime_lock(c); + goto asynch; + } + runtime_memmove(chanbuf(c, c->sendx), ep, c->elemsize); + if(++c->sendx == c->dataqsiz) + c->sendx = 0; + c->qcount++; + + sg = dequeue(&c->recvq); + if(sg != nil) { + gp = sg->g; + runtime_unlock(c); + runtime_ready(gp); + } else + runtime_unlock(c); + if(pres != nil) + *pres = true; + return; + +closed: + runtime_unlock(c); + runtime_panicstring("send on closed channel"); +} + + +void +runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received) +{ + SudoG *sg; + SudoG mysg; + G *gp; + G *g; + + if(runtime_gcwaiting) + runtime_gosched(); + + if(debug) + runtime_printf("chanrecv: chan=%p\n", c); + + g = runtime_g(); + + if(c == nil) { + USED(t); + if(selected != nil) { + *selected = false; + return; + } + g->status = Gwaiting; + g->waitreason = "chan receive (nil chan)"; + runtime_gosched(); + return; // not reached + } + + runtime_lock(c); + if(c->dataqsiz > 0) + goto asynch; + + if(c->closed) + goto closed; + + sg = dequeue(&c->sendq); + if(sg != nil) { + runtime_unlock(c); + + if(ep != nil) + runtime_memmove(ep, sg->elem, c->elemsize); + gp = sg->g; + gp->param = sg; + runtime_ready(gp); + + if(selected != nil) + *selected = true; + if(received != nil) + *received = true; + return; + } + + if(selected != nil) { + runtime_unlock(c); + *selected = false; + return; + } + + mysg.elem = ep; + mysg.g = g; + mysg.selgen = NOSELGEN; + g->param = nil; + g->status = Gwaiting; + g->waitreason = "chan receive"; + enqueue(&c->recvq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + if(g->param == nil) { + runtime_lock(c); + if(!c->closed) + runtime_throw("chanrecv: spurious wakeup"); + goto closed; + } + + if(received != nil) + *received = true; + return; + +asynch: + if(c->qcount <= 0) { + if(c->closed) + goto closed; + + if(selected != nil) { + runtime_unlock(c); + *selected = false; + if(received != nil) + *received = false; + return; + } + mysg.g = g; + mysg.elem = nil; + mysg.selgen = NOSELGEN; + g->status = Gwaiting; + g->waitreason = "chan receive"; + enqueue(&c->recvq, &mysg); + runtime_unlock(c); + runtime_gosched(); + + runtime_lock(c); + goto asynch; + } + if(ep != nil) + runtime_memmove(ep, chanbuf(c, c->recvx), c->elemsize); + runtime_memclr(chanbuf(c, c->recvx), c->elemsize); + if(++c->recvx == c->dataqsiz) + c->recvx = 0; + c->qcount--; + + sg = dequeue(&c->sendq); + if(sg != nil) { + gp = sg->g; + runtime_unlock(c); + runtime_ready(gp); + } else + runtime_unlock(c); + + if(selected != nil) + *selected = true; + if(received != nil) + *received = true; + return; + +closed: + if(ep != nil) + runtime_memclr(ep, c->elemsize); + if(selected != nil) + *selected = true; + if(received != nil) + *received = false; + runtime_unlock(c); +} + +// The compiler generates a call to __go_send_small to send a value 8 +// bytes or smaller. +void +__go_send_small(ChanType *t, Hchan* c, uint64 val) +{ + byte b[sizeof(uint64)]; + + runtime_memclr(b, sizeof(uint64)); + __builtin_memcpy(b, &val, t->__element_type->__size); + runtime_chansend(t, c, b, nil); +} + +// The compiler generates a call to __go_send_big to send a value +// larger than 8 bytes or smaller. +void +__go_send_big(ChanType *t, Hchan* c, byte* p) +{ + runtime_chansend(t, c, p, nil); +} + +// The compiler generates a call to __go_receive_small to receive a +// value 8 bytes or smaller. +uint64 +__go_receive_small(ChanType *t, Hchan* c) +{ + union { + byte b[sizeof(uint64)]; + uint64 v; + } u; + + u.v = 0; + runtime_chanrecv(t, c, u.b, nil, nil); + return u.v; +} + +// The compiler generates a call to __go_receive_big to receive a +// value larger than 8 bytes. +void +__go_receive_big(ChanType *t, Hchan* c, byte* p) +{ + runtime_chanrecv(t, c, p, nil, nil); +} + +_Bool runtime_chanrecv2(ChanType *t, Hchan* c, byte* p) + __asm__("runtime.chanrecv2"); + +_Bool +runtime_chanrecv2(ChanType *t, Hchan* c, byte* p) +{ + bool received; + + runtime_chanrecv(t, c, p, nil, &received); + return received; +} + +// func selectnbsend(c chan any, elem any) bool +// +// compiler implements +// +// select { +// case c <- v: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if selectnbsend(c, v) { +// ... foo +// } else { +// ... bar +// } +// +_Bool +runtime_selectnbsend(ChanType *t, Hchan *c, byte *p) +{ + bool res; + + runtime_chansend(t, c, p, &res); + return res; +} + +// func selectnbrecv(elem *any, c chan any) bool +// +// compiler implements +// +// select { +// case v = <-c: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if selectnbrecv(&v, c) { +// ... foo +// } else { +// ... bar +// } +// +_Bool +runtime_selectnbrecv(ChanType *t, byte *v, Hchan *c) +{ + bool selected; + + runtime_chanrecv(t, c, v, &selected, nil); + return selected; +} + +// func selectnbrecv2(elem *any, ok *bool, c chan any) bool +// +// compiler implements +// +// select { +// case v, ok = <-c: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if c != nil && selectnbrecv2(&v, &ok, c) { +// ... foo +// } else { +// ... bar +// } +// +_Bool +runtime_selectnbrecv2(ChanType *t, byte *v, _Bool *received, Hchan *c) +{ + bool selected; + bool r; + + r = false; + runtime_chanrecv(t, c, v, &selected, received == nil ? nil : &r); + if(received != nil) + *received = r; + return selected; +} + +// For reflect: +// func chansend(c chan, val iword, nb bool) (selected bool) +// where an iword is the same word an interface value would use: +// the actual data if it fits, or else a pointer to the data. + +_Bool reflect_chansend(ChanType *, Hchan *, uintptr, _Bool) + __asm__("libgo_reflect.reflect.chansend"); + +_Bool +reflect_chansend(ChanType *t, Hchan *c, uintptr val, _Bool nb) +{ + bool selected; + bool *sp; + byte *vp; + + if(nb) { + selected = false; + sp = (bool*)&selected; + } else { + selected = true; + sp = nil; + } + if(__go_is_pointer_type(t->__element_type)) + vp = (byte*)&val; + else + vp = (byte*)val; + runtime_chansend(t, c, vp, sp); + return selected; +} + +// For reflect: +// func chanrecv(c chan, nb bool) (val iword, selected, received bool) +// where an iword is the same word an interface value would use: +// the actual data if it fits, or else a pointer to the data. + +struct chanrecv_ret +{ + uintptr val; + _Bool selected; + _Bool received; +}; + +struct chanrecv_ret reflect_chanrecv(ChanType *, Hchan *, _Bool) + __asm__("libgo_reflect.reflect.chanrecv"); + +struct chanrecv_ret +reflect_chanrecv(ChanType *t, Hchan *c, _Bool nb) +{ + struct chanrecv_ret ret; + byte *vp; + bool *sp; + bool selected; + bool received; + + if(nb) { + selected = false; + sp = &selected; + } else { + ret.selected = true; + sp = nil; + } + received = false; + if(__go_is_pointer_type(t->__element_type)) { + vp = (byte*)&ret.val; + } else { + vp = runtime_mal(t->__element_type->__size); + ret.val = (uintptr)vp; + } + runtime_chanrecv(t, c, vp, sp, &received); + if(nb) + ret.selected = selected; + ret.received = received; + return ret; +} + +static void newselect(int32, Select**); + +// newselect(size uint32) (sel *byte); + +void* runtime_newselect(int) __asm__("runtime.newselect"); + +void* +runtime_newselect(int size) +{ + Select *sel; + + newselect(size, &sel); + return (void*)sel; +} + +static void +newselect(int32 size, Select **selp) +{ + int32 n; + Select *sel; + + n = 0; + if(size > 1) + n = size-1; + + sel = runtime_mal(sizeof(*sel) + + n*sizeof(sel->scase[0]) + + size*sizeof(sel->lockorder[0]) + + size*sizeof(sel->pollorder[0])); + + sel->tcase = size; + sel->ncase = 0; + sel->pollorder = (void*)(sel->scase + size); + sel->lockorder = (void*)(sel->pollorder + size); + *selp = sel; + + if(debug) + runtime_printf("newselect s=%p size=%d\n", sel, size); +} + +// cut in half to give stack a chance to split +static void selectsend(Select *sel, Hchan *c, int index, void *elem); + +// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); + +void runtime_selectsend(Select *, Hchan *, void *, int) + __asm__("runtime.selectsend"); + +void +runtime_selectsend(Select *sel, Hchan *c, void *elem, int index) +{ + // nil cases do not compete + if(c == nil) + return; + + selectsend(sel, c, index, elem); +} + +static void +selectsend(Select *sel, Hchan *c, int index, void *elem) +{ + int32 i; + Scase *cas; + + i = sel->ncase; + if(i >= sel->tcase) + runtime_throw("selectsend: too many cases"); + sel->ncase = i+1; + cas = &sel->scase[i]; + + cas->index = index; + cas->chan = c; + cas->kind = CaseSend; + cas->sg.elem = elem; + + if(debug) + runtime_printf("selectsend s=%p index=%d chan=%p\n", + sel, cas->index, cas->chan); +} + +// cut in half to give stack a chance to split +static void selectrecv(Select *sel, Hchan *c, int index, void *elem, bool*); + +// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); + +void runtime_selectrecv(Select *, Hchan *, void *, int) + __asm__("runtime.selectrecv"); + +void +runtime_selectrecv(Select *sel, Hchan *c, void *elem, int index) +{ + // nil cases do not compete + if(c == nil) + return; + + selectrecv(sel, c, index, elem, nil); +} + +// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool); + +void runtime_selectrecv2(Select *, Hchan *, void *, bool *, int) + __asm__("runtime.selectrecv2"); + +void +runtime_selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, int index) +{ + // nil cases do not compete + if(c == nil) + return; + + selectrecv(sel, c, index, elem, received); +} + +static void +selectrecv(Select *sel, Hchan *c, int index, void *elem, bool *received) +{ + int32 i; + Scase *cas; + + i = sel->ncase; + if(i >= sel->tcase) + runtime_throw("selectrecv: too many cases"); + sel->ncase = i+1; + cas = &sel->scase[i]; + cas->index = index; + cas->chan = c; + + cas->kind = CaseRecv; + cas->sg.elem = elem; + cas->receivedp = received; + + if(debug) + runtime_printf("selectrecv s=%p index=%d chan=%p\n", + sel, cas->index, cas->chan); +} + +// cut in half to give stack a chance to split +static void selectdefault(Select*, int); + +// selectdefault(sel *byte) (selected bool); + +void runtime_selectdefault(Select *, int) __asm__("runtime.selectdefault"); + +void +runtime_selectdefault(Select *sel, int index) +{ + selectdefault(sel, index); +} + +static void +selectdefault(Select *sel, int index) +{ + int32 i; + Scase *cas; + + i = sel->ncase; + if(i >= sel->tcase) + runtime_throw("selectdefault: too many cases"); + sel->ncase = i+1; + cas = &sel->scase[i]; + cas->index = index; + cas->chan = nil; + + cas->kind = CaseDefault; + + if(debug) + runtime_printf("selectdefault s=%p index=%d\n", + sel, cas->index); +} + +static void +sellock(Select *sel) +{ + uint32 i; + Hchan *c, *c0; + + c = nil; + for(i=0; i<sel->ncase; i++) { + c0 = sel->lockorder[i]; + if(c0 && c0 != c) { + c = sel->lockorder[i]; + runtime_lock(c); + } + } +} + +static void +selunlock(Select *sel) +{ + uint32 i; + Hchan *c, *c0; + + c = nil; + for(i=sel->ncase; i-->0;) { + c0 = sel->lockorder[i]; + if(c0 && c0 != c) { + c = c0; + runtime_unlock(c); + } + } +} + +void +runtime_block(void) +{ + G *g; + + g = runtime_g(); + g->status = Gwaiting; // forever + g->waitreason = "select (no cases)"; + runtime_gosched(); +} + +static int selectgo(Select**); + +// selectgo(sel *byte); + +int runtime_selectgo(Select *) __asm__("runtime.selectgo"); + +int +runtime_selectgo(Select *sel) +{ + return selectgo(&sel); +} + +static int +selectgo(Select **selp) +{ + Select *sel; + uint32 o, i, j; + Scase *cas, *dfl; + Hchan *c; + SudoG *sg; + G *gp; + int index; + G *g; + + sel = *selp; + if(runtime_gcwaiting) + runtime_gosched(); + + if(debug) + runtime_printf("select: sel=%p\n", sel); + + g = runtime_g(); + + // The compiler rewrites selects that statically have + // only 0 or 1 cases plus default into simpler constructs. + // The only way we can end up with such small sel->ncase + // values here is for a larger select in which most channels + // have been nilled out. The general code handles those + // cases correctly, and they are rare enough not to bother + // optimizing (and needing to test). + + // generate permuted order + for(i=0; i<sel->ncase; i++) + sel->pollorder[i] = i; + for(i=1; i<sel->ncase; i++) { + o = sel->pollorder[i]; + j = runtime_fastrand1()%(i+1); + sel->pollorder[i] = sel->pollorder[j]; + sel->pollorder[j] = o; + } + + // sort the cases by Hchan address to get the locking order. + for(i=0; i<sel->ncase; i++) { + c = sel->scase[i].chan; + for(j=i; j>0 && sel->lockorder[j-1] >= c; j--) + sel->lockorder[j] = sel->lockorder[j-1]; + sel->lockorder[j] = c; + } + sellock(sel); + +loop: + // pass 1 - look for something already waiting + dfl = nil; + for(i=0; i<sel->ncase; i++) { + o = sel->pollorder[i]; + cas = &sel->scase[o]; + c = cas->chan; + + switch(cas->kind) { + case CaseRecv: + if(c->dataqsiz > 0) { + if(c->qcount > 0) + goto asyncrecv; + } else { + sg = dequeue(&c->sendq); + if(sg != nil) + goto syncrecv; + } + if(c->closed) + goto rclose; + break; + + case CaseSend: + if(c->closed) + goto sclose; + if(c->dataqsiz > 0) { + if(c->qcount < c->dataqsiz) + goto asyncsend; + } else { + sg = dequeue(&c->recvq); + if(sg != nil) + goto syncsend; + } + break; + + case CaseDefault: + dfl = cas; + break; + } + } + + if(dfl != nil) { + selunlock(sel); + cas = dfl; + goto retc; + } + + + // pass 2 - enqueue on all chans + for(i=0; i<sel->ncase; i++) { + o = sel->pollorder[i]; + cas = &sel->scase[o]; + c = cas->chan; + sg = &cas->sg; + sg->g = g; + sg->selgen = g->selgen; + + switch(cas->kind) { + case CaseRecv: + enqueue(&c->recvq, sg); + break; + + case CaseSend: + enqueue(&c->sendq, sg); + break; + } + } + + g->param = nil; + g->status = Gwaiting; + g->waitreason = "select"; + selunlock(sel); + runtime_gosched(); + + sellock(sel); + sg = g->param; + + // pass 3 - dequeue from unsuccessful chans + // otherwise they stack up on quiet channels + for(i=0; i<sel->ncase; i++) { + cas = &sel->scase[i]; + if(cas != (Scase*)sg) { + c = cas->chan; + if(cas->kind == CaseSend) + dequeueg(&c->sendq); + else + dequeueg(&c->recvq); + } + } + + if(sg == nil) + goto loop; + + cas = (Scase*)sg; + c = cas->chan; + + if(c->dataqsiz > 0) + runtime_throw("selectgo: shouldnt happen"); + + if(debug) + runtime_printf("wait-return: sel=%p c=%p cas=%p kind=%d\n", + sel, c, cas, cas->kind); + + if(cas->kind == CaseRecv) { + if(cas->receivedp != nil) + *cas->receivedp = true; + } + + selunlock(sel); + goto retc; + +asyncrecv: + // can receive from buffer + if(cas->receivedp != nil) + *cas->receivedp = true; + if(cas->sg.elem != nil) + runtime_memmove(cas->sg.elem, chanbuf(c, c->recvx), c->elemsize); + runtime_memclr(chanbuf(c, c->recvx), c->elemsize); + if(++c->recvx == c->dataqsiz) + c->recvx = 0; + c->qcount--; + sg = dequeue(&c->sendq); + if(sg != nil) { + gp = sg->g; + selunlock(sel); + runtime_ready(gp); + } else { + selunlock(sel); + } + goto retc; + +asyncsend: + // can send to buffer + runtime_memmove(chanbuf(c, c->sendx), cas->sg.elem, c->elemsize); + if(++c->sendx == c->dataqsiz) + c->sendx = 0; + c->qcount++; + sg = dequeue(&c->recvq); + if(sg != nil) { + gp = sg->g; + selunlock(sel); + runtime_ready(gp); + } else { + selunlock(sel); + } + goto retc; + +syncrecv: + // can receive from sleeping sender (sg) + selunlock(sel); + if(debug) + runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o); + if(cas->receivedp != nil) + *cas->receivedp = true; + if(cas->sg.elem != nil) + runtime_memmove(cas->sg.elem, sg->elem, c->elemsize); + gp = sg->g; + gp->param = sg; + runtime_ready(gp); + goto retc; + +rclose: + // read at end of closed channel + selunlock(sel); + if(cas->receivedp != nil) + *cas->receivedp = false; + if(cas->sg.elem != nil) + runtime_memclr(cas->sg.elem, c->elemsize); + goto retc; + +syncsend: + // can send to sleeping receiver (sg) + selunlock(sel); + if(debug) + runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o); + if(sg->elem != nil) + runtime_memmove(sg->elem, cas->sg.elem, c->elemsize); + gp = sg->g; + gp->param = sg; + runtime_ready(gp); + +retc: + // return index corresponding to chosen case + index = cas->index; + runtime_free(sel); + return index; + +sclose: + // send on closed channel + selunlock(sel); + runtime_panicstring("send on closed channel"); + return 0; // not reached +} + +// closechan(sel *byte); +void +runtime_closechan(Hchan *c) +{ + SudoG *sg; + G* gp; + + if(c == nil) + runtime_panicstring("close of nil channel"); + + if(runtime_gcwaiting) + runtime_gosched(); + + runtime_lock(c); + if(c->closed) { + runtime_unlock(c); + runtime_panicstring("close of closed channel"); + } + + c->closed = true; + + // release all readers + for(;;) { + sg = dequeue(&c->recvq); + if(sg == nil) + break; + gp = sg->g; + gp->param = nil; + runtime_ready(gp); + } + + // release all writers + for(;;) { + sg = dequeue(&c->sendq); + if(sg == nil) + break; + gp = sg->g; + gp->param = nil; + runtime_ready(gp); + } + + runtime_unlock(c); +} + +void +__go_builtin_close(Hchan *c) +{ + runtime_closechan(c); +} + +// For reflect +// func chanclose(c chan) + +void reflect_chanclose(uintptr) __asm__("libgo_reflect.reflect.chanclose"); + +void +reflect_chanclose(uintptr c) +{ + runtime_closechan((Hchan*)c); +} + +// For reflect +// func chanlen(c chan) (len int32) + +int32 reflect_chanlen(uintptr) __asm__("libgo_reflect.reflect.chanlen"); + +int32 +reflect_chanlen(uintptr ca) +{ + Hchan *c; + int32 len; + + c = (Hchan*)ca; + if(c == nil) + len = 0; + else + len = c->qcount; + return len; +} + +int +__go_chan_len(Hchan *c) +{ + return reflect_chanlen((uintptr)c); +} + +// For reflect +// func chancap(c chan) (cap int32) + +int32 reflect_chancap(uintptr) __asm__("libgo_reflect.reflect.chancap"); + +int32 +reflect_chancap(uintptr ca) +{ + Hchan *c; + int32 cap; + + c = (Hchan*)ca; + if(c == nil) + cap = 0; + else + cap = c->dataqsiz; + return cap; +} + +int +__go_chan_cap(Hchan *c) +{ + return reflect_chancap((uintptr)c); +} + +static SudoG* +dequeue(WaitQ *q) +{ + SudoG *sgp; + +loop: + sgp = q->first; + if(sgp == nil) + return nil; + q->first = sgp->link; + + // if sgp is stale, ignore it + if(sgp->selgen != NOSELGEN && + (sgp->selgen != sgp->g->selgen || + !runtime_cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) { + //prints("INVALID PSEUDOG POINTER\n"); + goto loop; + } + + return sgp; +} + +static void +dequeueg(WaitQ *q) +{ + SudoG **l, *sgp, *prevsgp; + G *g; + + g = runtime_g(); + prevsgp = nil; + for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) { + if(sgp->g == g) { + *l = sgp->link; + if(q->last == sgp) + q->last = prevsgp; + break; + } + } +} + +static void +enqueue(WaitQ *q, SudoG *sgp) +{ + sgp->link = nil; + if(q->first == nil) { + q->first = sgp; + q->last = sgp; + return; + } + q->last->link = sgp; + q->last = sgp; +} diff --git a/libgo/runtime/chan.goc b/libgo/runtime/chan.goc deleted file mode 100644 index c3cc3e39879..00000000000 --- a/libgo/runtime/chan.goc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime -#include "config.h" -#include "channel.h" - -#define nil NULL - -typedef _Bool bool; -typedef unsigned char byte; -typedef struct __go_channel chan; - -/* Do a channel receive with closed status. */ - -func chanrecv2(c *chan, val *byte) (received bool) { - uintptr_t element_size = c == nil ? 0 : c->element_type->__size; - if (element_size > 8) { - return __go_receive_big(c, val, 0); - } else { - union { - char b[8]; - uint64_t v; - } u; - - u.v = __go_receive_small_closed(c, 0, &received); -#ifndef WORDS_BIGENDIAN - __builtin_memcpy(val, u.b, element_size); -#else - __builtin_memcpy(val, u.b + 8 - element_size, element_size); -#endif - return received; - } -} - -/* Do a channel receive with closed status for a select statement. */ - -func chanrecv3(c *chan, val *byte) (received bool) { - uintptr_t element_size = c->element_type->__size; - if (element_size > 8) { - return __go_receive_big(c, val, 1); - } else { - union { - char b[8]; - uint64_t v; - } u; - - u.v = __go_receive_small_closed(c, 1, &received); -#ifndef WORDS_BIGENDIAN - __builtin_memcpy(val, u.b, element_size); -#else - __builtin_memcpy(val, u.b + 8 - element_size, element_size); -#endif - return received; - } -} diff --git a/libgo/runtime/channel.h b/libgo/runtime/channel.h deleted file mode 100644 index 9176c68f692..00000000000 --- a/libgo/runtime/channel.h +++ /dev/null @@ -1,152 +0,0 @@ -/* channel.h -- the channel type for Go. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> -#include <pthread.h> - -#include "go-type.h" - -/* This structure is used when a select is waiting for a synchronous - channel. */ - -struct __go_channel_select -{ - /* A pointer to the next select waiting for this channel. */ - struct __go_channel_select *next; - /* A pointer to the channel which this select will use. This starts - out as NULL and is set to the first channel which synchs up with - this one. This variable to which this points may only be - accessed when __go_select_data_mutex is held. */ - struct __go_channel **selected; - /* A pointer to a variable which must be set to true if the - goroutine which sets *SELECTED wants to read from the channel, - false if it wants to write to it. */ - _Bool *is_read; -}; - -/* A channel is a pointer to this structure. */ - -struct __go_channel -{ - /* A mutex to control access to the channel. */ - pthread_mutex_t lock; - /* A condition variable. This is signalled when data is added to - the channel and when data is removed from the channel. */ - pthread_cond_t cond; - /* The type of elements on this channel. */ - const struct __go_type_descriptor *element_type; - /* True if a goroutine is waiting to send on a synchronous - channel. */ - _Bool waiting_to_send; - /* True if a goroutine is waiting to receive on a synchronous - channel. */ - _Bool waiting_to_receive; - /* True if this channel was selected for send in a select statement. - This looks out all other sends. */ - _Bool selected_for_send; - /* True if this channel was selected for receive in a select - statement. This locks out all other receives. */ - _Bool selected_for_receive; - /* True if this channel has been closed. */ - _Bool is_closed; - /* The list of select statements waiting to send on a synchronous - channel. */ - struct __go_channel_select *select_send_queue; - /* The list of select statements waiting to receive on a synchronous - channel. */ - struct __go_channel_select *select_receive_queue; - /* If a select statement is waiting for this channel, it sets these - pointers. When something happens on the channel, the channel - locks the mutex, signals the condition, and unlocks the - mutex. */ - pthread_mutex_t *select_mutex; - pthread_cond_t *select_cond; - /* The number of entries in the circular buffer. */ - unsigned int num_entries; - /* Where to store the next value. */ - unsigned int next_store; - /* Where to fetch the next value. If next_fetch == next_store, the - buffer is empty. If next_store + 1 == next_fetch, the buffer is - full. */ - unsigned int next_fetch; - /* The circular buffer. */ - uint64_t data[]; -}; - -/* Try to link up with the structure generated by the frontend. */ -typedef struct __go_channel __go_channel; - -/* The mutex used to control access to the value pointed to by the - __go_channel_select selected field. No additional mutexes may be - acquired while this mutex is held. */ -extern pthread_mutex_t __go_select_data_mutex; - -extern struct __go_channel * -__go_new_channel (const struct __go_type_descriptor *, uintptr_t); - -extern _Bool __go_synch_with_select (struct __go_channel *, _Bool); - -extern void __go_broadcast_to_select (struct __go_channel *); - -extern void __go_send_acquire (struct __go_channel *, _Bool); - -extern _Bool __go_send_nonblocking_acquire (struct __go_channel *); - -extern void __go_send_release (struct __go_channel *); - -extern void __go_send_small (struct __go_channel *, uint64_t, _Bool); - -extern _Bool __go_send_nonblocking_small (struct __go_channel *, uint64_t); - -extern void __go_send_big (struct __go_channel *, const void *, _Bool); - -extern _Bool __go_send_nonblocking_big (struct __go_channel *, const void *); - -extern _Bool __go_receive_acquire (struct __go_channel *, _Bool); - -#define RECEIVE_NONBLOCKING_ACQUIRE_DATA 0 -#define RECEIVE_NONBLOCKING_ACQUIRE_NODATA 1 -#define RECEIVE_NONBLOCKING_ACQUIRE_CLOSED 2 - -extern int __go_receive_nonblocking_acquire (struct __go_channel *); - -extern uint64_t __go_receive_small (struct __go_channel *, _Bool); - -extern uint64_t __go_receive_small_closed (struct __go_channel *, _Bool, - _Bool *); - -extern void __go_receive_release (struct __go_channel *); - -struct __go_receive_nonblocking_small -{ - /* Value read from channel, or 0. */ - uint64_t __val; - /* True if value was read from channel. */ - _Bool __success; - /* True if channel is closed. */ - _Bool __closed; -}; - -extern struct __go_receive_nonblocking_small -__go_receive_nonblocking_small (struct __go_channel *); - -extern _Bool __go_receive_big (struct __go_channel *, void *, _Bool); - -extern _Bool __go_receive_nonblocking_big (struct __go_channel *, void *, - _Bool *); - -extern void __go_unlock_and_notify_selects (struct __go_channel *); - -extern _Bool __go_builtin_closed (struct __go_channel *); - -extern void __go_builtin_close (struct __go_channel *); - -extern int __go_chan_len (struct __go_channel *); - -extern int __go_chan_cap (struct __go_channel *); - -extern uintptr_t __go_select (uintptr_t, _Bool, struct __go_channel **, - _Bool *); diff --git a/libgo/runtime/go-chan-cap.c b/libgo/runtime/go-chan-cap.c deleted file mode 100644 index 2c7958dd9fc..00000000000 --- a/libgo/runtime/go-chan-cap.c +++ /dev/null @@ -1,41 +0,0 @@ -/* go-chan-cap.c -- the cap function applied to a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stddef.h> - -#include "go-assert.h" -#include "channel.h" - -/* Return the cap function applied to a channel--the size of the - buffer. This could be done inline but I'm doing it as a function - for now to make it easy to change the channel structure. */ - -int -__go_chan_cap (struct __go_channel *channel) -{ - int i; - int ret; - - if (channel == NULL) - return 0; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - if (channel->num_entries == 0) - ret = 0; - else - { - /* One slot is always unused. We added 1 when we created the - channel. */ - ret = channel->num_entries - 1; - } - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - return ret; -} diff --git a/libgo/runtime/go-chan-len.c b/libgo/runtime/go-chan-len.c deleted file mode 100644 index b3ced98aa05..00000000000 --- a/libgo/runtime/go-chan-len.c +++ /dev/null @@ -1,41 +0,0 @@ -/* go-chan-len.c -- the len function applied to a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stddef.h> - -#include "go-assert.h" -#include "channel.h" - -/* Return the len function applied to a channel--the number of - elements in the buffer. This could be done inline but I'm doing it - as a function for now to make it easy to change the channel - structure. */ - -int -__go_chan_len (struct __go_channel *channel) -{ - int i; - int ret; - - if (channel == NULL) - return 0; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - if (channel->num_entries == 0) - ret = 0; - else if (channel->next_fetch == channel->next_store) - ret = 0; - else - ret = ((channel->next_store + channel->num_entries - channel->next_fetch) - % channel->num_entries); - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - return ret; -} diff --git a/libgo/runtime/go-close.c b/libgo/runtime/go-close.c deleted file mode 100644 index 7e32286dae0..00000000000 --- a/libgo/runtime/go-close.c +++ /dev/null @@ -1,42 +0,0 @@ -/* go-close.c -- the builtin close function. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Close a channel. After a channel is closed, sends are no longer - permitted. Receives always return zero. */ - -void -__go_builtin_close (struct __go_channel *channel) -{ - int i; - - if (channel == NULL) - runtime_panicstring ("close of nil channel"); - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (channel->selected_for_send) - runtime_cond_wait (&channel->cond, &channel->lock); - - if (channel->is_closed) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - runtime_panicstring ("close of closed channel"); - } - - channel->is_closed = 1; - - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - - __go_unlock_and_notify_selects (channel); -} diff --git a/libgo/runtime/go-new-channel.c b/libgo/runtime/go-new-channel.c deleted file mode 100644 index fe13c5efab6..00000000000 --- a/libgo/runtime/go-new-channel.c +++ /dev/null @@ -1,70 +0,0 @@ -/* go-new-channel.c -- allocate a new channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stddef.h> -#include <stdint.h> - -#include "runtime.h" -#include "go-alloc.h" -#include "go-assert.h" -#include "channel.h" - -struct __go_channel* -__go_new_channel (const struct __go_type_descriptor *channel_type, - uintptr_t entries) -{ - const struct __go_channel_type *ctd; - const struct __go_type_descriptor *element_type; - uintptr_t element_size; - int ientries; - struct __go_channel* ret; - size_t alloc_size; - int i; - - __go_assert (channel_type->__code == GO_CHAN); - ctd = (const struct __go_channel_type *) channel_type; - element_type = ctd->__element_type; - - element_size = element_type->__size; - - ientries = (int) entries; - if (ientries < 0 - || (uintptr_t) ientries != entries - || (element_size > 0 && entries > (uintptr_t) -1 / element_size)) - runtime_panicstring ("chan size out of range"); - - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - /* We use a circular buffer which means that when next_fetch == - next_store we don't know whether the buffer is empty or full. So - we allocate an extra space, and always leave a space open. - FIXME. */ - if (entries != 0) - ++entries; - - ret = (struct __go_channel*) __go_alloc (sizeof (struct __go_channel) - + ((entries == 0 ? 1 : entries) - * alloc_size - * sizeof (uint64_t))); - i = pthread_mutex_init (&ret->lock, NULL); - __go_assert (i == 0); - i = pthread_cond_init (&ret->cond, NULL); - __go_assert (i == 0); - ret->element_type = element_type; - ret->waiting_to_send = 0; - ret->waiting_to_receive = 0; - ret->selected_for_send = 0; - ret->selected_for_receive = 0; - ret->is_closed = 0; - ret->select_send_queue = NULL; - ret->select_receive_queue = NULL; - ret->select_mutex = NULL; - ret->select_cond = NULL; - ret->num_entries = entries; - ret->next_store = 0; - ret->next_fetch = 0; - return ret; -} diff --git a/libgo/runtime/go-rec-big.c b/libgo/runtime/go-rec-big.c deleted file mode 100644 index d45e90af476..00000000000 --- a/libgo/runtime/go-rec-big.c +++ /dev/null @@ -1,43 +0,0 @@ -/* go-rec-big.c -- receive something larger than 64 bits on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "go-panic.h" -#include "channel.h" - -/* Returns true if a value was received, false if the channel is - closed. */ - -_Bool -__go_receive_big (struct __go_channel *channel, void *val, _Bool for_select) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - { - /* Block forever. */ - __go_select (0, 0, NULL, NULL); - } - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - if (!__go_receive_acquire (channel, for_select)) - { - __builtin_memset (val, 0, element_size); - return 0; - } - - offset = channel->next_fetch * alloc_size; - __builtin_memcpy (val, &channel->data[offset], element_size); - - __go_receive_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-rec-nb-big.c b/libgo/runtime/go-rec-nb-big.c deleted file mode 100644 index 659ea1dc33d..00000000000 --- a/libgo/runtime/go-rec-nb-big.c +++ /dev/null @@ -1,46 +0,0 @@ -/* go-rec-nb-big.c -- nonblocking receive of something big on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "channel.h" - -/* Return true if a value was received, false if not. */ - -_Bool -__go_receive_nonblocking_big (struct __go_channel* channel, void *val, - _Bool *closed) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - { - if (closed != NULL) - *closed = 0; - return 0; - } - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - int data = __go_receive_nonblocking_acquire (channel); - if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA) - { - __builtin_memset (val, 0, element_size); - if (closed != NULL) - *closed = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; - return 0; - } - - offset = channel->next_fetch * alloc_size; - __builtin_memcpy (val, &channel->data[offset], element_size); - - __go_receive_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-rec-nb-small.c b/libgo/runtime/go-rec-nb-small.c deleted file mode 100644 index c21878ce131..00000000000 --- a/libgo/runtime/go-rec-nb-small.c +++ /dev/null @@ -1,123 +0,0 @@ -/* go-rec-nb-small.c -- nonblocking receive of something smal on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Prepare to receive something on a nonblocking channel. */ - -int -__go_receive_nonblocking_acquire (struct __go_channel *channel) -{ - int i; - _Bool has_data; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (channel->selected_for_receive) - runtime_cond_wait (&channel->cond, &channel->lock); - - if (channel->is_closed - && (channel->num_entries == 0 - ? channel->next_store == 0 - : channel->next_fetch == channel->next_store)) - { - __go_unlock_and_notify_selects (channel); - return RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; - } - - if (channel->num_entries > 0) - has_data = channel->next_fetch != channel->next_store; - else - { - if (channel->waiting_to_receive) - { - /* Some other goroutine is already waiting for data on this - channel, so we can't pick it up. */ - has_data = 0; - } - else if (channel->next_store > 0) - { - /* There is data on the channel. */ - has_data = 1; - } - else if (__go_synch_with_select (channel, 0)) - { - /* We synched up with a select sending data, so there will - be data for us shortly. Tell the select to go, and then - wait for the data. */ - __go_broadcast_to_select (channel); - - while (channel->next_store == 0) - runtime_cond_wait (&channel->cond, &channel->lock); - - has_data = 1; - } - else - { - /* Otherwise there is no data. */ - has_data = 0; - } - - if (has_data) - { - channel->waiting_to_receive = 1; - __go_assert (channel->next_store == 1); - } - } - - if (!has_data) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - return RECEIVE_NONBLOCKING_ACQUIRE_NODATA; - } - - return RECEIVE_NONBLOCKING_ACQUIRE_DATA; -} - -/* Receive something 64 bits or smaller on a nonblocking channel. */ - -struct __go_receive_nonblocking_small -__go_receive_nonblocking_small (struct __go_channel *channel) -{ - uintptr_t element_size; - struct __go_receive_nonblocking_small ret; - - if (channel == NULL) - { - ret.__val = 0; - ret.__success = 0; - ret.__closed = 0; - return ret; - } - - element_size = channel->element_type->__size; - __go_assert (element_size <= sizeof (uint64_t)); - - int data = __go_receive_nonblocking_acquire (channel); - if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA) - { - ret.__val = 0; - ret.__success = 0; - ret.__closed = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; - return ret; - } - - ret.__val = channel->data[channel->next_fetch]; - - __go_receive_release (channel); - - ret.__success = 1; - ret.__closed = 0; - - return ret; -} diff --git a/libgo/runtime/go-rec-small.c b/libgo/runtime/go-rec-small.c deleted file mode 100644 index f26dbcdd993..00000000000 --- a/libgo/runtime/go-rec-small.c +++ /dev/null @@ -1,304 +0,0 @@ -/* go-rec-small.c -- receive something smaller than 64 bits on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* This mutex controls access to the selected field of struct - __go_channel_select. While this mutex is held, no other mutexes - may be acquired. */ - -pthread_mutex_t __go_select_data_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* Try to synchronize with a select waiting on a sychronized channel. - This is used by a send or receive. The channel is locked. This - returns true if it was able to synch. */ - -_Bool -__go_synch_with_select (struct __go_channel *channel, _Bool is_send) -{ - struct __go_channel_select *p; - int i; - - __go_assert (channel->num_entries == 0); - - i = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (i == 0); - - for (p = (is_send - ? channel->select_receive_queue - : channel->select_send_queue); - p != NULL; - p = p->next) - { - if (*p->selected == NULL) - { - *p->selected = channel; - *p->is_read = !is_send; - if (is_send) - channel->selected_for_receive = 1; - else - channel->selected_for_send = 1; - break; - } - } - - i = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (i == 0); - - /* The caller is responsible for signalling the select condition - variable so that the other select knows that something has - changed. We can't signal it here because we can't acquire the - select mutex while we hold a channel lock. */ - - return p != NULL; -} - -/* If we synch with a select, then we need to signal the select that - something has changed. This requires grabbing the select mutex, - which can only be done when the channel is unlocked. This routine - does the signalling. It is called with the channel locked. It - unlocks the channel, broadcasts the signal and relocks the - channel. */ - -void -__go_broadcast_to_select (struct __go_channel *channel) -{ - pthread_mutex_t *select_mutex; - pthread_cond_t *select_cond; - int i; - - select_mutex = channel->select_mutex; - select_cond = channel->select_cond; - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - __go_assert (select_mutex != NULL && select_cond != NULL); - - i = pthread_mutex_lock (select_mutex); - __go_assert (i == 0); - - i = pthread_cond_broadcast (select_cond); - __go_assert (i == 0); - - i = pthread_mutex_unlock (select_mutex); - __go_assert (i == 0); - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); -} - -/* Prepare to receive something on a channel. Return true if the - channel is acquired (which implies that there is data available), - false if it is closed. */ - -_Bool -__go_receive_acquire (struct __go_channel *channel, _Bool for_select) -{ - int i; - _Bool my_wait_lock; - _Bool synched_with_select; - - my_wait_lock = 0; - synched_with_select = 0; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (1) - { - _Bool need_broadcast; - - need_broadcast = 0; - - /* Check whether the channel is closed. */ - if (channel->is_closed - && (channel->num_entries == 0 - ? channel->next_store == 0 - : channel->next_fetch == channel->next_store)) - { - channel->selected_for_receive = 0; - __go_unlock_and_notify_selects (channel); - return 0; - } - - /* If somebody else has the channel locked for receiving, we - have to wait. If FOR_SELECT is true, then we are the one - with the lock. */ - if (!channel->selected_for_receive || for_select) - { - if (channel->num_entries == 0) - { - /* If somebody else is waiting to receive, we have to - wait. */ - if (!channel->waiting_to_receive || my_wait_lock) - { - _Bool was_marked; - - /* Lock the channel so that we get to receive - next. */ - was_marked = channel->waiting_to_receive; - channel->waiting_to_receive = 1; - my_wait_lock = 1; - - /* See if there is a value to receive. */ - if (channel->next_store > 0) - return 1; - - /* If we haven't already done so, try to synch with - a select waiting to send on this channel. If we - have already synched with a select, we are just - looping until the select eventually causes - something to be sent. */ - if (!synched_with_select && !for_select) - { - if (__go_synch_with_select (channel, 0)) - { - synched_with_select = 1; - need_broadcast = 1; - } - } - - /* If we marked the channel as waiting, we need to - signal, because something changed. It needs to - be a broadcast since there might be other - receivers waiting. */ - if (!was_marked) - { - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - } - } - } - else - { - /* If there is a value on the channel, we are OK. */ - if (channel->next_fetch != channel->next_store) - return 1; - } - } - - /* If we just synched with a select, then we need to signal the - select condition variable. We can only do that if we unlock - the channel. So we need to unlock, signal, lock, and go - around the loop again without waiting. */ - if (need_broadcast) - { - __go_broadcast_to_select (channel); - continue; - } - - /* Wait for something to change, then loop around and try - again. */ - - runtime_cond_wait (&channel->cond, &channel->lock); - } -} - -/* Finished receiving something on a channel. */ - -void -__go_receive_release (struct __go_channel *channel) -{ - int i; - - if (channel->num_entries != 0) - channel->next_fetch = (channel->next_fetch + 1) % channel->num_entries; - else - { - /* For a synchronous receiver, we tell the sender that we picked - up the value by setting the next_store field back to 0. - Using the mutexes should implement a memory barrier. */ - __go_assert (channel->next_store == 1); - channel->next_store = 0; - - channel->waiting_to_receive = 0; - } - - channel->selected_for_receive = 0; - - /* This is a broadcast to make sure that a synchronous sender sees - it. */ - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - - __go_unlock_and_notify_selects (channel); -} - -/* Unlock a channel and notify any waiting selects that something - happened. */ - -void -__go_unlock_and_notify_selects (struct __go_channel *channel) -{ - pthread_mutex_t* select_mutex; - pthread_cond_t* select_cond; - int i; - - select_mutex = channel->select_mutex; - select_cond = channel->select_cond; - - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - if (select_mutex != NULL) - { - i = pthread_mutex_lock (select_mutex); - __go_assert (i == 0); - i = pthread_cond_broadcast (select_cond); - __go_assert (i == 0); - i = pthread_mutex_unlock (select_mutex); - __go_assert (i == 0); - } -} - -/* Receive something 64 bits or smaller on a channel. */ - -uint64_t -__go_receive_small_closed (struct __go_channel *channel, _Bool for_select, - _Bool *received) -{ - uintptr_t element_size; - uint64_t ret; - - if (channel == NULL) - { - /* Block forever. */ - __go_select (0, 0, NULL, NULL); - } - - element_size = channel->element_type->__size; - __go_assert (element_size <= sizeof (uint64_t)); - - if (!__go_receive_acquire (channel, for_select)) - { - if (received != NULL) - *received = 0; - return 0; - } - - ret = channel->data[channel->next_fetch]; - - __go_receive_release (channel); - - if (received != NULL) - *received = 1; - - return ret; -} - -/* Called by the compiler. */ - -uint64_t -__go_receive_small (struct __go_channel *channel, _Bool for_select) -{ - return __go_receive_small_closed (channel, for_select, NULL); -} diff --git a/libgo/runtime/go-reflect-chan.c b/libgo/runtime/go-reflect-chan.c deleted file mode 100644 index 6f6693b6b54..00000000000 --- a/libgo/runtime/go-reflect-chan.c +++ /dev/null @@ -1,200 +0,0 @@ -/* go-reflect-chan.c -- channel reflection support for Go. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdlib.h> -#include <stdint.h> - -#include "config.h" -#include "go-alloc.h" -#include "go-assert.h" -#include "go-panic.h" -#include "go-type.h" -#include "channel.h" - -/* This file implements support for reflection on channels. These - functions are called from reflect/value.go. */ - -extern uintptr_t makechan (const struct __go_type_descriptor *, uint32_t) - asm ("libgo_reflect.reflect.makechan"); - -uintptr_t -makechan (const struct __go_type_descriptor *typ, uint32_t size) -{ - struct __go_channel *channel; - void *ret; - - channel = __go_new_channel (typ, size); - - ret = __go_alloc (sizeof (void *)); - __builtin_memcpy (ret, &channel, sizeof (void *)); - return (uintptr_t) ret; -} - -extern _Bool chansend (struct __go_channel_type *, uintptr_t, uintptr_t, _Bool) - asm ("libgo_reflect.reflect.chansend"); - -_Bool -chansend (struct __go_channel_type *ct, uintptr_t ch, uintptr_t val_i, - _Bool nb) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - uintptr_t element_size; - void *pv; - - __go_assert (ct->__common.__code == GO_CHAN); - - if (__go_is_pointer_type (ct->__element_type)) - pv = &val_i; - else - pv = (void *) val_i; - - element_size = ct->__element_type->__size; - if (element_size <= sizeof (uint64_t)) - { - union - { - char b[sizeof (uint64_t)]; - uint64_t v; - } u; - - __builtin_memset (u.b, 0, sizeof (uint64_t)); -#ifndef WORDS_BIGENDIAN - __builtin_memcpy (u.b, pv, element_size); -#else - __builtin_memcpy (u.b + sizeof (uint64_t) - element_size, pv, - element_size); -#endif - if (nb) - return __go_send_nonblocking_small (channel, u.v); - else - { - __go_send_small (channel, u.v, 0); - return 1; - } - } - else - { - if (nb) - return __go_send_nonblocking_big (channel, pv); - else - { - __go_send_big (channel, pv, 0); - return 1; - } - } -} - -struct chanrecv_ret -{ - uintptr_t val; - _Bool selected; - _Bool received; -}; - -extern struct chanrecv_ret chanrecv (struct __go_channel_type *, uintptr_t, - _Bool) - asm ("libgo_reflect.reflect.chanrecv"); - -struct chanrecv_ret -chanrecv (struct __go_channel_type *ct, uintptr_t ch, _Bool nb) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - void *pv; - uintptr_t element_size; - struct chanrecv_ret ret; - - __go_assert (ct->__common.__code == GO_CHAN); - - element_size = ct->__element_type->__size; - - if (__go_is_pointer_type (ct->__element_type)) - pv = &ret.val; - else - { - pv = __go_alloc (element_size); - ret.val = (uintptr_t) pv; - } - - if (element_size <= sizeof (uint64_t)) - { - union - { - char b[sizeof (uint64_t)]; - uint64_t v; - } u; - - if (!nb) - { - u.v = __go_receive_small_closed (channel, 0, &ret.received); - ret.selected = 1; - } - else - { - struct __go_receive_nonblocking_small s; - - s = __go_receive_nonblocking_small (channel); - ret.selected = s.__success || s.__closed; - ret.received = s.__success; - u.v = s.__val; - } - -#ifndef WORDS_BIGENDIAN - __builtin_memcpy (pv, u.b, element_size); -#else - __builtin_memcpy (pv, u.b + sizeof (uint64_t) - element_size, - element_size); -#endif - } - else - { - if (!nb) - { - ret.received = __go_receive_big (channel, pv, 0); - ret.selected = 1; - } - else - { - _Bool got; - _Bool closed; - - got = __go_receive_nonblocking_big (channel, pv, &closed); - ret.selected = got || closed; - ret.received = got; - } - } - - return ret; -} - -extern void chanclose (uintptr_t) asm ("libgo_reflect.reflect.chanclose"); - -void -chanclose (uintptr_t ch) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - - __go_builtin_close (channel); -} - -extern int32_t chanlen (uintptr_t) asm ("libgo_reflect.reflect.chanlen"); - -int32_t -chanlen (uintptr_t ch) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - - return (int32_t) __go_chan_len (channel); -} - -extern int32_t chancap (uintptr_t) asm ("libgo_reflect.reflect.chancap"); - -int32_t -chancap (uintptr_t ch) -{ - struct __go_channel *channel = (struct __go_channel *) ch; - - return (int32_t) __go_chan_cap (channel); -} diff --git a/libgo/runtime/go-select.c b/libgo/runtime/go-select.c deleted file mode 100644 index 677c699b52c..00000000000 --- a/libgo/runtime/go-select.c +++ /dev/null @@ -1,758 +0,0 @@ -/* go-select.c -- implement select. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <pthread.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdint.h> -#include <stdlib.h> -#include <unistd.h> - -#include "runtime.h" -#include "config.h" -#include "go-assert.h" -#include "channel.h" - -/* __go_select builds an array of these structures. */ - -struct select_channel -{ - /* The channel being selected. */ - struct __go_channel* channel; - /* If this channel is selected, the value to return. */ - uintptr_t retval; - /* If this channel is a duplicate of one which appears earlier in - the array, this is the array index of the earlier channel. This - is -1UL if this is not a dup. */ - uintptr_t dup_index; - /* An entry to put on the send or receive queue. */ - struct __go_channel_select queue_entry; - /* True if selected for send. */ - _Bool is_send; - /* True if channel is ready--it has data to receive or space to - send. */ - _Bool is_ready; -}; - -/* This mutex controls access to __go_select_cond. This mutex may not - be acquired if any channel locks are held. */ - -static pthread_mutex_t __go_select_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* When we have to wait for channels, we tell them to trigger this - condition variable when they send or receive something. */ - -static pthread_cond_t __go_select_cond = PTHREAD_COND_INITIALIZER; - -/* Sort the channels by address. This avoids deadlock when multiple - selects are running on overlapping sets of channels. */ - -static int -channel_sort (const void *p1, const void *p2) -{ - const struct select_channel *c1 = (const struct select_channel *) p1; - const struct select_channel *c2 = (const struct select_channel *) p2; - - if ((uintptr_t) c1->channel < (uintptr_t) c2->channel) - return -1; - else if ((uintptr_t) c1->channel > (uintptr_t) c2->channel) - return 1; - else - return 0; -} - -/* Return whether there is an entry on QUEUE which can be used for a - synchronous send or receive. */ - -static _Bool -is_queue_ready (struct __go_channel_select *queue) -{ - int x; - - if (queue == NULL) - return 0; - - x = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (x == 0); - - while (queue != NULL) - { - if (*queue->selected == NULL) - break; - queue = queue->next; - } - - x = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (x == 0); - - return queue != NULL; -} - -/* Return whether CHAN is ready. If IS_SEND is true check whether it - has space to send, otherwise check whether it has a value to - receive. */ - -static _Bool -is_channel_ready (struct __go_channel* channel, _Bool is_send) -{ - if (is_send) - { - if (channel->selected_for_send) - return 0; - if (channel->is_closed) - return 1; - if (channel->num_entries > 0) - { - /* An asynchronous channel is ready for sending if there is - room in the buffer. */ - return ((channel->next_store + 1) % channel->num_entries - != channel->next_fetch); - } - else - { - if (channel->waiting_to_send) - { - /* Some other goroutine is waiting to send on this - channel, so we can't. */ - return 0; - } - if (channel->waiting_to_receive) - { - /* Some other goroutine is waiting to receive a value, - so we can send one. */ - return 1; - } - if (is_queue_ready (channel->select_receive_queue)) - { - /* There is a select statement waiting to synchronize - with this one. */ - return 1; - } - return 0; - } - } - else - { - if (channel->selected_for_receive) - return 0; - if (channel->is_closed) - return 1; - if (channel->num_entries > 0) - { - /* An asynchronous channel is ready for receiving if there - is a value in the buffer. */ - return channel->next_fetch != channel->next_store; - } - else - { - if (channel->waiting_to_receive) - { - /* Some other goroutine is waiting to receive from this - channel, so it is not ready for us to receive. */ - return 0; - } - if (channel->next_store > 0) - { - /* There is data on the channel. */ - return 1; - } - if (is_queue_ready (channel->select_send_queue)) - { - /* There is a select statement waiting to synchronize - with this one. */ - return 1; - } - return 0; - } - } -} - -/* Mark a channel as selected. The channel is locked. IS_SELECTED is - true if the channel was selected for us by another goroutine. We - set *NEEDS_BROADCAST if we need to broadcast on the select - condition variable. Return true if we got it. */ - -static _Bool -mark_channel_selected (struct __go_channel *channel, _Bool is_send, - _Bool is_selected, _Bool *needs_broadcast) -{ - if (channel->num_entries == 0) - { - /* This is a synchronous channel. If there is no goroutine - currently waiting, but there is another select waiting, then - we need to tell that select to use this channel. That may - fail--there may be no other goroutines currently waiting--as - a third goroutine may already have claimed the select. */ - if (!is_selected - && !channel->is_closed - && (is_send - ? !channel->waiting_to_receive - : channel->next_store == 0)) - { - int x; - struct __go_channel_select *queue; - - x = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (x == 0); - - queue = (is_send - ? channel->select_receive_queue - : channel->select_send_queue); - __go_assert (queue != NULL); - - while (queue != NULL) - { - if (*queue->selected == NULL) - { - *queue->selected = channel; - *queue->is_read = !is_send; - break; - } - queue = queue->next; - } - - x = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (x == 0); - - if (queue == NULL) - return 0; - - if (is_send) - channel->selected_for_receive = 1; - else - channel->selected_for_send = 1; - - /* We are going to have to tell the other select that there - is something to do. */ - *needs_broadcast = 1; - } - } - - if (is_send) - channel->selected_for_send = 1; - else - channel->selected_for_receive = 1; - - return 1; -} - -/* Mark a channel to indicate that a select is waiting. The channel - is locked. */ - -static void -mark_select_waiting (struct select_channel *sc, - struct __go_channel **selected_pointer, - _Bool *selected_for_read_pointer) -{ - struct __go_channel *channel = sc->channel; - _Bool is_send = sc->is_send; - - if (channel->num_entries == 0) - { - struct __go_channel_select **pp; - - pp = (is_send - ? &channel->select_send_queue - : &channel->select_receive_queue); - - /* Add an entry to the queue of selects on this channel. */ - sc->queue_entry.next = *pp; - sc->queue_entry.selected = selected_pointer; - sc->queue_entry.is_read = selected_for_read_pointer; - - *pp = &sc->queue_entry; - } - - channel->select_mutex = &__go_select_mutex; - channel->select_cond = &__go_select_cond; - - /* We never actually clear the select_mutex and select_cond fields. - In order to clear them safely, we would need to have some way of - knowing when no select is waiting for the channel. Thus we - introduce a bit of inefficiency for every channel that select - needs to wait for. This is harmless other than the performance - cost. */ -} - -/* Remove the entry for this select waiting on this channel. The - channel is locked. We check both queues, because the channel may - be selected for both reading and writing. */ - -static void -clear_select_waiting (struct select_channel *sc, - struct __go_channel **selected_pointer) -{ - struct __go_channel *channel = sc->channel; - - if (channel->num_entries == 0) - { - _Bool found; - struct __go_channel_select **pp; - - found = 0; - - for (pp = &channel->select_send_queue; *pp != NULL; pp = &(*pp)->next) - { - if ((*pp)->selected == selected_pointer) - { - *pp = (*pp)->next; - found = 1; - break; - } - } - - for (pp = &channel->select_receive_queue; *pp != NULL; pp = &(*pp)->next) - { - if ((*pp)->selected == selected_pointer) - { - *pp = (*pp)->next; - found = 1; - break; - } - } - - __go_assert (found); - } -} - -/* Look through the list of channels to see which ones are ready. - Lock each channels, and set the is_ready flag. Return the number - of ready channels. */ - -static uintptr_t -lock_channels_find_ready (struct select_channel *channels, uintptr_t count) -{ - uintptr_t ready_count; - uintptr_t i; - - ready_count = 0; - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - _Bool is_send = channels[i].is_send; - uintptr_t dup_index = channels[i].dup_index; - int x; - - if (channel == NULL) - continue; - - if (dup_index != (uintptr_t) -1UL) - { - if (channels[dup_index].is_ready) - { - channels[i].is_ready = 1; - ++ready_count; - } - continue; - } - - x = pthread_mutex_lock (&channel->lock); - __go_assert (x == 0); - - if (is_channel_ready (channel, is_send)) - { - channels[i].is_ready = 1; - ++ready_count; - } - } - - return ready_count; -} - -/* The channel we are going to select has been forced by some other - goroutine. SELECTED_CHANNEL is the channel we will use, - SELECTED_FOR_READ is whether the other goroutine wants to read from - the channel. Note that the channel could be specified multiple - times in this select, so we must mark each appropriate entry for - this channel as ready. Every other channel is marked as not ready. - All the channels are locked before this routine is called. This - returns the number of ready channels. */ - -uintptr_t -force_selected_channel_ready (struct select_channel *channels, uintptr_t count, - struct __go_channel *selected_channel, - _Bool selected_for_read) -{ - uintptr_t ready_count; - uintptr_t i; - - ready_count = 0; - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - _Bool is_send = channels[i].is_send; - - if (channel == NULL) - continue; - - if (channel != selected_channel - || (is_send ? !selected_for_read : selected_for_read)) - channels[i].is_ready = 0; - else - { - channels[i].is_ready = 1; - ++ready_count; - } - } - __go_assert (ready_count > 0); - return ready_count; -} - -/* Unlock all the channels. */ - -static void -unlock_channels (struct select_channel *channels, uintptr_t count) -{ - uintptr_t i; - int x; - - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - - if (channel == NULL) - continue; - - if (channels[i].dup_index != (uintptr_t) -1UL) - continue; - - x = pthread_mutex_unlock (&channel->lock); - __go_assert (x == 0); - } -} - -/* At least one channel is ready. Randomly pick a channel to return. - Unlock all the channels. IS_SELECTED is true if the channel was - picked for us by some other goroutine. If SELECTED_POINTER is not - NULL, remove it from the queue for all the channels. Return the - retval field of the selected channel. This will return 0 if we - can't use the selected channel, because it relied on synchronizing - with some other select, and that select already synchronized with a - different channel. */ - -static uintptr_t -unlock_channels_and_select (struct select_channel *channels, - uintptr_t count, uintptr_t ready_count, - _Bool is_selected, - struct __go_channel **selected_pointer) -{ - uintptr_t selected; - uintptr_t ret; - _Bool needs_broadcast; - uintptr_t i; - int x; - - /* Pick which channel we are going to return. */ -#if defined(HAVE_RANDOM) - selected = (uintptr_t) random () % ready_count; -#else - selected = (uintptr_t) rand () % ready_count; -#endif - ret = 0; - needs_broadcast = 0; - - /* Look at the channels in reverse order so that we don't unlock a - duplicated channel until we have seen all its dups. */ - for (i = 0; i < count; ++i) - { - uintptr_t j = count - i - 1; - struct __go_channel *channel = channels[j].channel; - _Bool is_send = channels[j].is_send; - - if (channel == NULL) - continue; - - if (channels[j].is_ready) - { - if (selected == 0) - { - if (mark_channel_selected (channel, is_send, is_selected, - &needs_broadcast)) - ret = channels[j].retval; - } - - --selected; - } - - if (channels[j].dup_index == (uintptr_t) -1UL) - { - if (selected_pointer != NULL) - clear_select_waiting (&channels[j], selected_pointer); - - x = pthread_mutex_unlock (&channel->lock); - __go_assert (x == 0); - } - } - - /* The NEEDS_BROADCAST variable is set if we are synchronizing with - some other select statement. We can't do the actual broadcast - until we have unlocked all the channels. */ - - if (needs_broadcast) - { - x = pthread_mutex_lock (&__go_select_mutex); - __go_assert (x == 0); - - x = pthread_cond_broadcast (&__go_select_cond); - __go_assert (x == 0); - - x = pthread_mutex_unlock (&__go_select_mutex); - __go_assert (x == 0); - } - - return ret; -} - -/* Mark all channels to show that we are waiting for them. This is - called with the select mutex held, but none of the channels are - locked. This returns true if some channel was found to be - ready. */ - -static _Bool -mark_all_channels_waiting (struct select_channel* channels, uintptr_t count, - struct __go_channel **selected_pointer, - _Bool *selected_for_read_pointer) -{ - _Bool ret; - int x; - uintptr_t i; - - ret = 0; - for (i = 0; i < count; ++i) - { - struct __go_channel *channel = channels[i].channel; - _Bool is_send = channels[i].is_send; - - if (channel == NULL) - continue; - - if (channels[i].dup_index != (uintptr_t) -1UL) - { - uintptr_t j; - - /* A channel may be selected for both read and write. */ - if (channels[channels[i].dup_index].is_send == is_send) - continue; - else - { - for (j = channels[i].dup_index + 1; j < i; ++j) - { - if (channels[j].channel == channel - && channels[j].is_send == is_send) - break; - } - if (j < i) - continue; - } - } - - x = pthread_mutex_lock (&channel->lock); - __go_assert (x == 0); - - /* To avoid a race condition, we have to check again whether the - channel is ready. It may have become ready since we did the - first set of checks but before we acquired the select mutex. - If we don't check here, we could sleep forever on the select - condition variable. */ - if (is_channel_ready (channel, is_send)) - ret = 1; - - /* If SELECTED_POINTER is NULL, then we have already marked the - channel as waiting. */ - if (selected_pointer != NULL) - mark_select_waiting (&channels[i], selected_pointer, - selected_for_read_pointer); - - x = pthread_mutex_unlock (&channel->lock); - __go_assert (x == 0); - } - - return ret; -} - -/* Implement select. This is called by the compiler-generated code - with pairs of arguments: a pointer to a channel, and an int which - is non-zero for send, zero for receive. */ - -uintptr_t -__go_select (uintptr_t count, _Bool has_default, - struct __go_channel **channel_args, _Bool *is_send_args) -{ - struct select_channel stack_buffer[16]; - struct select_channel *allocated_buffer; - struct select_channel *channels; - uintptr_t i; - int x; - struct __go_channel *selected_channel; - _Bool selected_for_read; - _Bool is_queued; - - if (count < sizeof stack_buffer / sizeof stack_buffer[0]) - { - channels = &stack_buffer[0]; - allocated_buffer = NULL; - } - else - { - allocated_buffer = ((struct select_channel *) - malloc (count * sizeof (struct select_channel))); - channels = allocated_buffer; - } - - for (i = 0; i < count; ++i) - { - struct __go_channel *channel_arg = channel_args[i]; - _Bool is_send = is_send_args[i]; - - channels[i].channel = (struct __go_channel*) channel_arg; - channels[i].retval = i + 1; - channels[i].dup_index = (uintptr_t) -1UL; - channels[i].queue_entry.next = NULL; - channels[i].queue_entry.selected = NULL; - channels[i].is_send = is_send; - channels[i].is_ready = 0; - } - - qsort (channels, count, sizeof (struct select_channel), channel_sort); - - for (i = 0; i < count; ++i) - { - uintptr_t j; - - for (j = 0; j < i; ++j) - { - if (channels[j].channel == channels[i].channel) - { - channels[i].dup_index = j; - break; - } - } - } - - /* SELECT_CHANNEL is used to select synchronized channels. If no - channels are ready, we store a pointer to this variable on the - select queue for each synchronized channel. Because the variable - may be set by channel operations running in other goroutines, - SELECT_CHANNEL may only be accessed when all the channels are - locked and/or when the select_data_mutex is locked. */ - selected_channel = NULL; - - /* SELECTED_FOR_READ is set to true if SELECTED_CHANNEL was set by a - goroutine which wants to read from the channel. The access - restrictions for this are like those for SELECTED_CHANNEL. */ - selected_for_read = 0; - - /* IS_QUEUED is true if we have queued up this select on the queues - for any associated synchronous channels. We only do this if no - channels are ready the first time around the loop. */ - is_queued = 0; - - while (1) - { - int ready_count; - _Bool is_selected; - - /* Lock all channels, identify which ones are ready. */ - ready_count = lock_channels_find_ready (channels, count); - - /* All the channels are locked, so we can look at - SELECTED_CHANNEL. If it is not NULL, then our choice has - been forced by some other goroutine. This can only happen - after the first time through the loop. */ - is_selected = selected_channel != NULL; - if (is_selected) - ready_count = force_selected_channel_ready (channels, count, - selected_channel, - selected_for_read); - - if (ready_count > 0) - { - uintptr_t ret; - - ret = unlock_channels_and_select (channels, count, ready_count, - is_selected, - (is_queued - ? &selected_channel - : NULL)); - - /* If RET is zero, it means that the channel we picked - turned out not to be ready, because some other select - grabbed it during our traversal. Loop around and try - again. */ - if (ret == 0) - { - is_queued = 0; - /* We are no longer on any channel queues, so it is safe - to touch SELECTED_CHANNEL here. It must be NULL, - because otherwise that would somebody has promised to - synch up with us and then failed to do so. */ - __go_assert (selected_channel == NULL); - continue; - } - - if (allocated_buffer != NULL) - free (allocated_buffer); - - return ret; - } - - /* No channels were ready. */ - - unlock_channels (channels, count); - - if (has_default) - { - /* Use the default clause. */ - if (allocated_buffer != NULL) - free (allocated_buffer); - return 0; - } - - /* This is a blocking select. Grab the select lock, tell all - the channels to notify us when something happens, and wait - for something to happen. */ - - x = pthread_mutex_lock (&__go_select_mutex); - __go_assert (x == 0); - - /* Check whether CHANNEL_SELECTED was set while the channels - were unlocked. If it was set, then we can simply loop around - again. We need to check this while the select mutex is held. - It is possible that something will set CHANNEL_SELECTED while - we mark the channels as waiting. If this happens, that - goroutine is required to signal the select condition - variable, which means acquiring the select mutex. Since we - have the select mutex locked ourselves, we can not miss that - signal. */ - - x = pthread_mutex_lock (&__go_select_data_mutex); - __go_assert (x == 0); - - is_selected = selected_channel != NULL; - - x = pthread_mutex_unlock (&__go_select_data_mutex); - __go_assert (x == 0); - - if (!is_selected) - { - /* Mark the channels as waiting, and check whether they have - become ready. */ - if (!mark_all_channels_waiting (channels, count, - (is_queued - ? NULL - : &selected_channel), - (is_queued - ? NULL - : &selected_for_read))) - runtime_cond_wait (&__go_select_cond, &__go_select_mutex); - - is_queued = 1; - } - - x = pthread_mutex_unlock (&__go_select_mutex); - __go_assert (x == 0); - } -} diff --git a/libgo/runtime/go-send-big.c b/libgo/runtime/go-send-big.c deleted file mode 100644 index 61d4a0f13d9..00000000000 --- a/libgo/runtime/go-send-big.c +++ /dev/null @@ -1,34 +0,0 @@ -/* go-send-big.c -- send something bigger than uint64_t on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "go-panic.h" -#include "channel.h" - -void -__go_send_big (struct __go_channel* channel, const void *val, _Bool for_select) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - { - // Block forever. - __go_select (0, 0, NULL, NULL); - } - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - __go_send_acquire (channel, for_select); - - offset = channel->next_store * alloc_size; - __builtin_memcpy (&channel->data[offset], val, element_size); - - __go_send_release (channel); -} diff --git a/libgo/runtime/go-send-nb-big.c b/libgo/runtime/go-send-nb-big.c deleted file mode 100644 index e039874ef9a..00000000000 --- a/libgo/runtime/go-send-nb-big.c +++ /dev/null @@ -1,33 +0,0 @@ -/* go-send-nb-big.c -- nonblocking send of something big on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "channel.h" - -_Bool -__go_send_nonblocking_big (struct __go_channel* channel, const void *val) -{ - uintptr_t element_size; - size_t alloc_size; - size_t offset; - - if (channel == NULL) - return 0; - - element_size = channel->element_type->__size; - alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); - - if (!__go_send_nonblocking_acquire (channel)) - return 0; - - offset = channel->next_store * alloc_size; - __builtin_memcpy (&channel->data[offset], val, element_size); - - __go_send_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-send-nb-small.c b/libgo/runtime/go-send-nb-small.c deleted file mode 100644 index c77ee9183e2..00000000000 --- a/libgo/runtime/go-send-nb-small.c +++ /dev/null @@ -1,107 +0,0 @@ -/* go-send-nb-small.c -- nonblocking send of something small on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Prepare to send something on a nonblocking channel. Return true if - we acquired the channel, false if we did not acquire it because - there is no space to send a value. */ - -_Bool -__go_send_nonblocking_acquire (struct __go_channel *channel) -{ - int i; - _Bool has_space; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (channel->selected_for_send) - runtime_cond_wait (&channel->cond, &channel->lock); - - if (channel->is_closed) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - runtime_panicstring ("send on closed channel"); - } - - if (channel->num_entries > 0) - has_space = ((channel->next_store + 1) % channel->num_entries - != channel->next_fetch); - else - { - /* This is a synchronous channel. If somebody is current - sending, then we can't send. Otherwise, see if somebody is - waiting to receive, or see if we can synch with a select. */ - if (channel->waiting_to_send) - { - /* Some other goroutine is currently sending on this - channel, which means that we can't. */ - has_space = 0; - } - else if (channel->waiting_to_receive) - { - /* Some other goroutine is waiting to receive a value, so we - can send directly to them. */ - has_space = 1; - } - else if (__go_synch_with_select (channel, 1)) - { - /* We found a select waiting to receive data, so we can send - to that. */ - __go_broadcast_to_select (channel); - has_space = 1; - } - else - { - /* Otherwise, we can't send, because nobody is waiting to - receive. */ - has_space = 0; - } - - if (has_space) - { - channel->waiting_to_send = 1; - __go_assert (channel->next_store == 0); - } - } - - if (!has_space) - { - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - - return 0; - } - - return 1; -} - -/* Send something 64 bits or smaller on a channel. */ - -_Bool -__go_send_nonblocking_small (struct __go_channel *channel, uint64_t val) -{ - if (channel == NULL) - return 0; - - __go_assert (channel->element_type->__size <= sizeof (uint64_t)); - - if (!__go_send_nonblocking_acquire (channel)) - return 0; - - channel->data[channel->next_store] = val; - - __go_send_release (channel); - - return 1; -} diff --git a/libgo/runtime/go-send-small.c b/libgo/runtime/go-send-small.c deleted file mode 100644 index 06bcb41b9ad..00000000000 --- a/libgo/runtime/go-send-small.c +++ /dev/null @@ -1,159 +0,0 @@ -/* go-send-small.c -- send something 64 bits or smaller on a channel. - - Copyright 2009 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include <stdint.h> - -#include "runtime.h" -#include "go-assert.h" -#include "go-panic.h" -#include "channel.h" - -/* Prepare to send something on a channel. FOR_SELECT is true if this - call is being made after a select statement returned with this - channel selected. */ - -void -__go_send_acquire (struct __go_channel *channel, _Bool for_select) -{ - int i; - - i = pthread_mutex_lock (&channel->lock); - __go_assert (i == 0); - - while (1) - { - if (channel->is_closed) - { - if (for_select) - channel->selected_for_send = 0; - i = pthread_mutex_unlock (&channel->lock); - __go_assert (i == 0); - runtime_panicstring ("send on closed channel"); - } - - /* If somebody else has the channel locked for sending, we have - to wait. If FOR_SELECT is true, then we are the one with the - lock. */ - if (!channel->selected_for_send || for_select) - { - if (channel->num_entries == 0) - { - /* This is a synchronous channel. If nobody else is - waiting to send, we grab the channel and tell the - caller to send the data. We will then wait for a - receiver. */ - if (!channel->waiting_to_send) - { - __go_assert (channel->next_store == 0); - return; - } - } - else - { - /* If there is room on the channel, we are OK. */ - if ((channel->next_store + 1) % channel->num_entries - != channel->next_fetch) - return; - } - } - - /* Wait for something to change, then loop around and try - again. */ - - runtime_cond_wait (&channel->cond, &channel->lock); - } -} - -/* Finished sending something on a channel. */ - -void -__go_send_release (struct __go_channel *channel) -{ - int i; - - if (channel->num_entries != 0) - { - /* This is a buffered channel. Bump the store count and signal - the condition variable. */ - channel->next_store = (channel->next_store + 1) % channel->num_entries; - - i = pthread_cond_signal (&channel->cond); - __go_assert (i == 0); - } - else - { - _Bool synched_with_select; - - /* This is a synchronous channel. Indicate that we have a value - waiting. */ - channel->next_store = 1; - channel->waiting_to_send = 1; - - /* Tell everybody else to do something. This has to be a - broadcast because we might have both senders and receivers - waiting on the condition, but senders won't send another - signal. */ - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - - /* Wait until the value is received. */ - synched_with_select = 0; - while (1) - { - if (channel->next_store == 0) - break; - - /* If nobody is currently waiting to receive, try to synch - up with a select. */ - if (!channel->waiting_to_receive && !synched_with_select) - { - if (__go_synch_with_select (channel, 1)) - { - synched_with_select = 1; - __go_broadcast_to_select (channel); - continue; - } - } - - runtime_cond_wait (&channel->cond, &channel->lock); - } - - channel->waiting_to_send = 0; - - /* Using the mutexes should implement a memory barrier. */ - - /* We have to signal again since we cleared the waiting_to_send - field. This has to be a broadcast because both senders and - receivers might be waiting, but only senders will be able to - act. */ - i = pthread_cond_broadcast (&channel->cond); - __go_assert (i == 0); - } - - channel->selected_for_send = 0; - - __go_unlock_and_notify_selects (channel); -} - -/* Send something 64 bits or smaller on a channel. */ - -void -__go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select) -{ - if (channel == NULL) - { - // Block forever. - __go_select (0, 0, NULL, NULL); - } - - __go_assert (channel->element_type->__size <= sizeof (uint64_t)); - - __go_send_acquire (channel, for_select); - - channel->data[channel->next_store] = val; - - __go_send_release (channel); -} diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c index 958b421c871..cd165f45112 100644 --- a/libgo/runtime/go-signal.c +++ b/libgo/runtime/go-signal.c @@ -218,7 +218,7 @@ sighandler (int sig) /* Ignore a signal. */ static void -sigignore (int sig __attribute__ ((unused))) +sig_ignore (int sig __attribute__ ((unused))) { } @@ -247,7 +247,7 @@ runtime_initsig (int32 queue) if (signals[i].catch || signals[i].queue) sa.sa_handler = sighandler; else - sa.sa_handler = sigignore; + sa.sa_handler = sig_ignore; sa.sa_flags = signals[i].restart ? SA_RESTART : 0; if (sigaction (signals[i].sig, &sa, NULL) != 0) __go_assert (0); diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 9455ae88c5a..e28bc82f8ab 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -55,14 +55,15 @@ typedef struct M M; typedef union Note Note; typedef struct MCache MCache; typedef struct FixAlloc FixAlloc; +typedef struct Hchan Hchan; -typedef struct __go_defer_stack Defer; +typedef struct __go_open_array Slice; +typedef struct __go_string String; typedef struct __go_interface Iface; typedef struct __go_empty_interface Eface; typedef struct __go_type_descriptor Type; +typedef struct __go_defer_stack Defer; typedef struct __go_panic_stack Panic; -typedef struct __go_open_array Slice; -typedef struct __go_string String; typedef struct __go_func_type FuncType; typedef struct __go_map_type MapType; @@ -131,6 +132,7 @@ struct G bool fromgogo; // reached from gogo int16 status; int32 goid; + uint32 selgen; // valid sudog pointer const char* waitreason; // if status==Gwaiting G* schedlink; bool readyonstop; @@ -335,6 +337,3 @@ void reflect_call(const struct __go_func_type *, const void *, _Bool, _Bool, #ifdef __rtems__ void __wrap_rtems_task_variable_add(void **); #endif - -/* Temporary. */ -void runtime_cond_wait(pthread_cond_t*, pthread_mutex_t*); diff --git a/libgo/runtime/thread.c b/libgo/runtime/thread.c index 459fc85c780..d43e224ffb2 100644 --- a/libgo/runtime/thread.c +++ b/libgo/runtime/thread.c @@ -90,27 +90,3 @@ runtime_minit(void) if(sigaltstack(&ss, nil) < 0) *(int *)0xf1 = 0xf1; } - -// Temporary functions, which will be removed when we stop using -// condition variables. - -void -runtime_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) -{ - int i; - - runtime_entersyscall(); - - i = pthread_cond_wait(cond, mutex); - if(i != 0) - runtime_throw("pthread_cond_wait"); - i = pthread_mutex_unlock(mutex); - if(i != 0) - runtime_throw("pthread_mutex_unlock"); - - runtime_exitsyscall(); - - i = pthread_mutex_lock(mutex); - if(i != 0) - runtime_throw("pthread_mutex_lock"); -} |