This patch to the Go frontend by Cherry Zhang adds a -fgo-debug-optimization option to emit optimization diagnostics. This can be used for testing optimizations. Apply this to the range clear optimizations of maps and arrays. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline.
Ian gcc/go: 2019-05-07 Cherry Zhang <cherr...@google.com> * lang.opt (-fgo-debug-optimization): New option. * go-c.h (struct go_create_gogo_args): Add debug_optimization field. * go-lang.c (go_langhook_init): Set debug_optimization field. * gccgo.texi (Invoking gccgo): Document -fgo-debug-optimization. gcc/testsuite: 2019-05-07 Cherry Zhang <cherr...@google.com> * go.dg/arrayclear.go: New test. * go.dg/mapclear.go: New test.
Index: gcc/go/gccgo.texi =================================================================== --- gcc/go/gccgo.texi (revision 270877) +++ gcc/go/gccgo.texi (working copy) @@ -246,6 +246,11 @@ This runs escape analysis only on functi that match the given suffix @var{n}. This can be used to binary search across functions to uncover escape analysis bugs. +@item -fgo-debug-optimization +@cindex @option{-fgo-debug-optimization} +@cindex @option{-fno-go-debug-optimization} +Output optimization diagnostics. + @item -fgo-c-header=@var{file} @cindex @option{-fgo-c-header} Write top-level named Go struct definitions to @var{file} as C code. Index: gcc/go/go-c.h =================================================================== --- gcc/go/go-c.h (revision 270877) +++ gcc/go/go-c.h (working copy) @@ -49,6 +49,7 @@ struct go_create_gogo_args int debug_escape_level; const char* debug_escape_hash; int64_t nil_check_size_threshold; + bool debug_optimization; }; extern void go_create_gogo (const struct go_create_gogo_args*); Index: gcc/go/go-lang.c =================================================================== --- gcc/go/go-lang.c (revision 270877) +++ gcc/go/go-lang.c (working copy) @@ -118,6 +118,7 @@ go_langhook_init (void) args.debug_escape_level = go_debug_escape_level; args.debug_escape_hash = go_debug_escape_hash; args.nil_check_size_threshold = TARGET_AIX ? -1 : 4096; + args.debug_optimization = go_debug_optimization; args.linemap = go_get_linemap(); args.backend = go_get_backend(); go_create_gogo (&args); Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 270877) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -4b3015de639cf22ed11ff96097555700909827c8 +dc9c1b43753f392fdc2045bcb7a4abaa44fe79f1 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/go.cc =================================================================== --- gcc/go/gofrontend/go.cc (revision 270877) +++ gcc/go/gofrontend/go.cc (working copy) @@ -44,6 +44,8 @@ go_create_gogo(const struct go_create_go if (args->debug_escape_hash != NULL) ::gogo->set_debug_escape_hash(args->debug_escape_hash); ::gogo->set_nil_check_size_threshold(args->nil_check_size_threshold); + if (args->debug_optimization) + ::gogo->set_debug_optimization(args->debug_optimization); } // Parse the input files. Index: gcc/go/gofrontend/gogo.cc =================================================================== --- gcc/go/gofrontend/gogo.cc (revision 270877) +++ gcc/go/gofrontend/gogo.cc (working copy) @@ -55,6 +55,7 @@ Gogo::Gogo(Backend* backend, Linemap* li check_divide_overflow_(true), compiling_runtime_(false), debug_escape_level_(0), + debug_optimization_(false), nil_check_size_threshold_(4096), verify_types_(), interface_types_(), Index: gcc/go/gofrontend/gogo.h =================================================================== --- gcc/go/gofrontend/gogo.h (revision 270877) +++ gcc/go/gofrontend/gogo.h (working copy) @@ -326,6 +326,16 @@ class Gogo set_debug_escape_hash(const std::string& s) { this->debug_escape_hash_ = s; } + // Return whether to output optimization diagnostics. + bool + debug_optimization() const + { return this->debug_optimization_; } + + // Set the option to output optimization diagnostics. + void + set_debug_optimization(bool b) + { this->debug_optimization_ = b; } + // Return the size threshold used to determine whether to issue // a nil-check for a given pointer dereference. A threshold of -1 // implies that all potentially faulting dereference ops should @@ -1075,6 +1085,9 @@ class Gogo // -fgo-debug-escape-hash option. The analysis is run only on // functions with names that hash to the matching value. std::string debug_escape_hash_; + // Whether to output optimization diagnostics, from the + // -fgo-debug-optimization option. + bool debug_optimization_; // Nil-check size threshhold. int64_t nil_check_size_threshold_; // A list of types to verify. Index: gcc/go/gofrontend/statements.cc =================================================================== --- gcc/go/gofrontend/statements.cc (revision 270877) +++ gcc/go/gofrontend/statements.cc (working copy) @@ -5512,6 +5512,8 @@ For_range_statement::do_lower(Gogo* gogo range_temp, loc); if (clear != NULL) { + if (gogo->debug_optimization()) + go_inform(loc, "map range clear"); temp_block->add_statement(clear); return Statement::make_block_statement(temp_block, loc); } @@ -5527,6 +5529,8 @@ For_range_statement::do_lower(Gogo* gogo range_temp, loc); if (clear != NULL) { + if (gogo->debug_optimization()) + go_inform(loc, "array range clear"); temp_block->add_statement(clear); return Statement::make_block_statement(temp_block, loc); } Index: gcc/go/lang.opt =================================================================== --- gcc/go/lang.opt (revision 270877) +++ gcc/go/lang.opt (working copy) @@ -85,6 +85,10 @@ fgo-debug-escape-hash= Go Joined RejectNegative Var(go_debug_escape_hash) Init(0) -fgo-debug-escape-hash=<string> Hash value to debug escape analysis. +fgo-debug-optimization +Go Var(go_debug_optimization) Init(0) +Emit optimization diagnostics. + o Go Joined Separate ; Documented in common.opt Index: gcc/testsuite/go.dg/arrayclear.go =================================================================== --- gcc/testsuite/go.dg/arrayclear.go (nonexistent) +++ gcc/testsuite/go.dg/arrayclear.go (working copy) @@ -0,0 +1,20 @@ +// { dg-do compile } +// { dg-options "-fgo-debug-optimization" } + +package p + +var a [10]int + +func arrayClear() { + for i := range a { // { dg-error "array range clear" } + a[i] = 0 + } +} + +var s []int + +func sliceClear() { + for i := range s { // { dg-error "array range clear" } + s[i] = 0 + } +} Index: gcc/testsuite/go.dg/mapclear.go =================================================================== --- gcc/testsuite/go.dg/mapclear.go (nonexistent) +++ gcc/testsuite/go.dg/mapclear.go (working copy) @@ -0,0 +1,10 @@ +// { dg-do compile } +// { dg-options "-fgo-debug-optimization" } + +package p + +func clear(m map[int]int) { + for k := range m { // { dg-error "map range clear" } + delete(m, k) + } +}