aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2015-02-13 12:50:23 -0500
committerRuss Cox <rsc@golang.org>2015-02-13 12:51:56 -0500
commit87de9ce212988c8bdf0630750e772d8805091bcc (patch)
tree0bb1cc671417e9b851d35a4bbcd4d756e5aee4e9 /src
parent01925bd3f306c899cddfa59aa2ad41c9b77fcd74 (diff)
parent5f1efe738be296cdbc586348af92eab621d068f5 (diff)
downloadgo-87de9ce212988c8bdf0630750e772d8805091bcc.tar.xz
[dev.cc] all: merge master (5f1efe7) into dev.cc
Conflicts: src/cmd/dist/build.go Change-Id: I98a4b5e010bee91507b85bb8efd9c74e1a1f649c
Diffstat (limited to 'src')
-rw-r--r--src/cmd/5a/a.y20
-rw-r--r--src/cmd/5a/y.tab.c134
-rw-r--r--src/cmd/5g/cgen.c38
-rw-r--r--src/cmd/5g/galign.c95
-rw-r--r--src/cmd/5g/gg.h20
-rw-r--r--src/cmd/5g/ggen.c196
-rw-r--r--src/cmd/5g/gobj.c267
-rw-r--r--src/cmd/5g/gsubr.c591
-rw-r--r--src/cmd/5g/opt.h179
-rw-r--r--src/cmd/5g/peep.c109
-rw-r--r--src/cmd/5g/prog.c11
-rw-r--r--src/cmd/5g/reg.c1329
-rw-r--r--src/cmd/5l/5.out.h1
-rw-r--r--src/cmd/5l/asm.c158
-rw-r--r--src/cmd/5l/l.h41
-rw-r--r--src/cmd/5l/list.c30
-rw-r--r--src/cmd/5l/obj.c56
-rw-r--r--src/cmd/6g/cgen.c134
-rw-r--r--src/cmd/6g/galign.c99
-rw-r--r--src/cmd/6g/gg.h19
-rw-r--r--src/cmd/6g/ggen.c201
-rw-r--r--src/cmd/6g/gobj.c244
-rw-r--r--src/cmd/6g/gsubr.c550
-rw-r--r--src/cmd/6g/peep.c16
-rw-r--r--src/cmd/6g/prog.c2
-rw-r--r--src/cmd/6g/reg.c1176
-rw-r--r--src/cmd/6l/6.out.h1
-rw-r--r--src/cmd/6l/asm.c50
-rw-r--r--src/cmd/6l/l.h42
-rw-r--r--src/cmd/6l/list.c27
-rw-r--r--src/cmd/6l/obj.c45
-rw-r--r--src/cmd/8g/cgen.c106
-rw-r--r--src/cmd/8g/galign.c95
-rw-r--r--src/cmd/8g/gg.h20
-rw-r--r--src/cmd/8g/ggen.c196
-rw-r--r--src/cmd/8g/gobj.c257
-rw-r--r--src/cmd/8g/gsubr.c598
-rw-r--r--src/cmd/8g/opt.h192
-rw-r--r--src/cmd/8g/peep.c12
-rw-r--r--src/cmd/8g/prog.c2
-rw-r--r--src/cmd/8g/reg.c1187
-rw-r--r--src/cmd/8l/8.out.h1
-rw-r--r--src/cmd/8l/asm.c51
-rw-r--r--src/cmd/8l/l.h31
-rw-r--r--src/cmd/8l/list.c27
-rw-r--r--src/cmd/8l/obj.c42
-rw-r--r--src/cmd/9g/cgen.c68
-rw-r--r--src/cmd/9g/galign.c99
-rw-r--r--src/cmd/9g/gg.h23
-rw-r--r--src/cmd/9g/ggen.c70
-rw-r--r--src/cmd/9g/gobj.c250
-rw-r--r--src/cmd/9g/gsubr.c555
-rw-r--r--src/cmd/9g/opt.h175
-rw-r--r--src/cmd/9g/peep.c8
-rw-r--r--src/cmd/9g/prog.c1
-rw-r--r--src/cmd/9g/reg.c1176
-rw-r--r--src/cmd/9l/9.out.h2
-rw-r--r--src/cmd/9l/asm.c44
-rw-r--r--src/cmd/9l/l.h46
-rw-r--r--src/cmd/9l/obj.c47
-rw-r--r--src/cmd/api/goapi.go16
-rw-r--r--src/cmd/cgo/out.go6
-rw-r--r--src/cmd/dist/build.go21
-rw-r--r--src/cmd/dist/buildgc.go2
-rw-r--r--src/cmd/dist/buildruntime.go4
-rw-r--r--src/cmd/dist/util.go60
-rw-r--r--src/cmd/dist/vfp_arm.s15
-rw-r--r--src/cmd/dist/vfp_default.s14
-rw-r--r--src/cmd/gc/align.c18
-rw-r--r--src/cmd/gc/builtin.c11
-rw-r--r--src/cmd/gc/closure.c187
-rw-r--r--src/cmd/gc/const.c58
-rw-r--r--src/cmd/gc/cplx.c50
-rw-r--r--src/cmd/gc/dcl.c16
-rw-r--r--src/cmd/gc/esc.c14
-rw-r--r--src/cmd/gc/export.c2
-rw-r--r--src/cmd/gc/fmt.c4
-rw-r--r--src/cmd/gc/gen.c124
-rw-r--r--src/cmd/gc/go.h92
-rw-r--r--src/cmd/gc/gsubr.c654
-rw-r--r--src/cmd/gc/init.c2
-rw-r--r--src/cmd/gc/lex.c90
-rwxr-xr-xsrc/cmd/gc/mkbuiltin4
-rw-r--r--src/cmd/gc/mparith1.c60
-rw-r--r--src/cmd/gc/mparith2.c145
-rw-r--r--src/cmd/gc/obj.c226
-rw-r--r--src/cmd/gc/pgen.c64
-rw-r--r--src/cmd/gc/plive.c22
-rw-r--r--src/cmd/gc/popt.c304
-rw-r--r--src/cmd/gc/popt.h (renamed from src/cmd/6g/opt.h)53
-rw-r--r--src/cmd/gc/racewalk.c35
-rw-r--r--src/cmd/gc/range.c8
-rw-r--r--src/cmd/gc/reflect.c366
-rw-r--r--src/cmd/gc/reg.c1233
-rw-r--r--src/cmd/gc/runtime.go8
-rw-r--r--src/cmd/gc/select.c18
-rw-r--r--src/cmd/gc/sinit.c44
-rw-r--r--src/cmd/gc/subr.c54
-rw-r--r--src/cmd/gc/swt.c38
-rw-r--r--src/cmd/gc/typecheck.c473
-rw-r--r--src/cmd/gc/walk.c152
-rw-r--r--src/cmd/go/doc.go43
-rw-r--r--src/cmd/go/generate.go1
-rw-r--r--src/cmd/go/main.go4
-rwxr-xr-xsrc/cmd/go/mkdoc.sh9
-rw-r--r--src/cmd/go/test.go8
-rw-r--r--src/cmd/gofmt/doc.go7
-rw-r--r--src/cmd/ld/Makefile5
-rw-r--r--src/cmd/ld/data.c101
-rw-r--r--src/cmd/ld/decodesym.c47
-rw-r--r--src/cmd/ld/dwarf.c181
-rw-r--r--src/cmd/ld/elf.c232
-rw-r--r--src/cmd/ld/elf.h6
-rw-r--r--src/cmd/ld/go.c23
-rw-r--r--src/cmd/ld/ldelf.c23
-rw-r--r--src/cmd/ld/ldmacho.c27
-rw-r--r--src/cmd/ld/ldpe.c15
-rw-r--r--src/cmd/ld/lib.c109
-rw-r--r--src/cmd/ld/lib.h65
-rw-r--r--src/cmd/ld/macho.c137
-rw-r--r--src/cmd/ld/macho.h6
-rw-r--r--src/cmd/ld/pcln.c154
-rw-r--r--src/cmd/ld/pe.c27
-rw-r--r--src/cmd/ld/pobj.c48
-rw-r--r--src/cmd/ld/symtab.c41
-rw-r--r--src/cmd/pack/pack_test.go9
-rw-r--r--src/cmd/pprof/internal/report/report.go2
-rw-r--r--src/cmd/yacc/yacc.go4
-rw-r--r--src/compress/bzip2/bzip2_test.go4
-rw-r--r--src/compress/flate/deflate_test.go2
-rw-r--r--src/crypto/tls/handshake_server.go2
-rw-r--r--src/crypto/x509/verify.go2
-rw-r--r--src/crypto/x509/x509_test.go5
-rw-r--r--src/encoding/xml/marshal.go318
-rw-r--r--src/encoding/xml/marshal_test.go372
-rw-r--r--src/encoding/xml/read_test.go34
-rw-r--r--src/encoding/xml/xml.go45
-rw-r--r--src/expvar/expvar_test.go217
-rw-r--r--src/go/build/deps_test.go2
-rw-r--r--src/html/template/clone_test.go2
-rw-r--r--src/html/template/content_test.go2
-rw-r--r--src/image/image.go4
-rw-r--r--src/internal/syscall/windows/syscall_windows.go99
-rw-r--r--src/internal/syscall/windows/zsyscall_windows.go20
-rw-r--r--src/lib9/math_darwin_arm.c102
-rw-r--r--src/liblink/asm5.c16
-rw-r--r--src/liblink/go.c21
-rw-r--r--src/liblink/list5.c2
-rw-r--r--src/liblink/list6.c2
-rw-r--r--src/liblink/list8.c2
-rw-r--r--src/liblink/list9.c2
-rw-r--r--src/liblink/obj5.c10
-rw-r--r--src/liblink/obj6.c12
-rw-r--r--src/liblink/sym.c9
-rw-r--r--src/math/all_test.go2
-rw-r--r--src/math/big/float.go671
-rw-r--r--src/math/big/float_test.go531
-rw-r--r--src/math/big/floatconv.go25
-rw-r--r--src/math/big/floatconv_test.go252
-rw-r--r--src/math/big/ftoa.go184
-rw-r--r--src/math/big/int_test.go2
-rwxr-xr-xsrc/nacltest.bash2
-rw-r--r--src/net/dial.go8
-rw-r--r--src/net/hosts_test.go2
-rw-r--r--src/net/http/proxy_test.go2
-rw-r--r--src/net/http/request.go2
-rw-r--r--src/net/http/serve_test.go4
-rw-r--r--src/net/interface_test.go11
-rw-r--r--src/net/interface_windows.go244
-rw-r--r--src/net/net.go4
-rw-r--r--src/net/smtp/example_test.go24
-rw-r--r--src/net/smtp/smtp.go21
-rw-r--r--src/net/tcpsock_plan9.go2
-rw-r--r--src/net/tcpsock_posix.go2
-rw-r--r--src/net/udp_test.go58
-rw-r--r--src/net/udpsock_plan9.go8
-rw-r--r--src/net/udpsock_posix.go12
-rw-r--r--src/net/unixsock_plan9.go2
-rw-r--r--src/net/unixsock_posix.go2
-rw-r--r--src/os/os_test.go72
-rw-r--r--src/os/os_windows_test.go50
-rw-r--r--src/os/signal/signal.go2
-rw-r--r--src/os/signal/signal_plan9.go55
-rw-r--r--src/os/signal/signal_plan9_test.go181
-rw-r--r--src/os/signal/signal_stub.go17
-rw-r--r--src/path/filepath/path_test.go2
-rw-r--r--src/race.bat2
-rw-r--r--src/reflect/all_test.go2
-rw-r--r--src/reflect/type.go22
-rw-r--r--src/reflect/value.go15
-rw-r--r--src/runtime/asm_386.s10
-rw-r--r--src/runtime/asm_amd64.s10
-rw-r--r--src/runtime/asm_amd64p32.s10
-rw-r--r--src/runtime/asm_arm.s31
-rw-r--r--src/runtime/asm_ppc64x.s18
-rw-r--r--src/runtime/cgo/cgo.go2
-rw-r--r--src/runtime/cgo/gcc_arm.S4
-rw-r--r--src/runtime/cgo/gcc_darwin_arm.c99
-rw-r--r--src/runtime/compiler.go2
-rw-r--r--src/runtime/crash_test.go34
-rw-r--r--src/runtime/defs_darwin_arm.go245
-rw-r--r--src/runtime/defs_windows_386.go6
-rw-r--r--src/runtime/defs_windows_amd64.go6
-rw-r--r--src/runtime/gcwork.go338
-rw-r--r--src/runtime/hashmap.go16
-rw-r--r--src/runtime/heapdump.go2
-rw-r--r--src/runtime/iface_test.go42
-rw-r--r--src/runtime/malloc.go2
-rw-r--r--src/runtime/malloc1.go2
-rw-r--r--src/runtime/map_test.go10
-rw-r--r--src/runtime/mapspeed_test.go9
-rw-r--r--src/runtime/mbarrier.go7
-rw-r--r--src/runtime/mem_linux.go1
-rw-r--r--src/runtime/mem_plan9.go1
-rw-r--r--src/runtime/mem_windows.go10
-rw-r--r--src/runtime/mfinal.go9
-rw-r--r--src/runtime/mgc.go359
-rw-r--r--src/runtime/mgc0.go2
-rw-r--r--src/runtime/mheap.go16
-rw-r--r--src/runtime/netpoll_windows.go10
-rw-r--r--src/runtime/os1_windows.go61
-rw-r--r--src/runtime/os1_windows_386.go4
-rw-r--r--src/runtime/os1_windows_amd64.go4
-rw-r--r--src/runtime/os3_plan9.go6
-rw-r--r--src/runtime/os_darwin_arm.go17
-rw-r--r--src/runtime/os_plan9.go5
-rw-r--r--src/runtime/os_windows_386.go11
-rw-r--r--src/runtime/os_windows_amd64.go11
-rw-r--r--src/runtime/proc.go5
-rw-r--r--src/runtime/proc1.go16
-rw-r--r--src/runtime/proc_test.go12
-rw-r--r--src/runtime/race/race_test.go2
-rw-r--r--src/runtime/race/testdata/slice_test.go95
-rw-r--r--src/runtime/race_amd64.s3
-rw-r--r--src/runtime/rt0_darwin_arm.s18
-rw-r--r--src/runtime/runtime-gdb_test.go12
-rw-r--r--src/runtime/runtime2.go2
-rw-r--r--src/runtime/signal_darwin_arm.go44
-rw-r--r--src/runtime/signals_windows.h3
-rw-r--r--src/runtime/sigqueue.go2
-rw-r--r--src/runtime/sigqueue_plan9.go115
-rw-r--r--src/runtime/stack.h22
-rw-r--r--src/runtime/stack2.go6
-rw-r--r--src/runtime/string.go27
-rw-r--r--src/runtime/stubs3.go12
-rw-r--r--src/runtime/symtab.go10
-rw-r--r--src/runtime/sys_darwin_arm.s481
-rw-r--r--src/runtime/time.go1
-rw-r--r--src/runtime/tls_arm.s39
-rw-r--r--src/runtime/traceback.go23
-rw-r--r--src/sort/sort.go2
-rw-r--r--src/strconv/decimal.go6
-rw-r--r--src/strconv/ftoa.go55
-rw-r--r--src/sync/atomic/asm_darwin_arm.s99
-rw-r--r--src/syscall/asm_darwin_arm.s134
-rw-r--r--src/syscall/syscall_bsd.go35
-rw-r--r--src/syscall/syscall_darwin_arm.go70
-rw-r--r--src/syscall/syscall_windows.go19
-rw-r--r--src/syscall/zerrors_darwin_arm.go1349
-rw-r--r--src/syscall/zsyscall_darwin_arm.go1324
-rw-r--r--src/syscall/zsysnum_darwin_arm.go345
-rw-r--r--src/syscall/ztypes_darwin_arm.go447
-rw-r--r--src/syscall/ztypes_windows.go25
-rw-r--r--src/testing/benchmark.go34
-rw-r--r--src/time/sys_unix.go2
-rw-r--r--src/time/zoneinfo_plan9.go10
-rw-r--r--src/time/zoneinfo_unix.go6
-rw-r--r--src/time/zoneinfo_windows.go9
268 files changed, 14391 insertions, 13130 deletions
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
index 429f7437c6..10e9f6feea 100644
--- a/src/cmd/5a/a.y
+++ b/src/cmd/5a/a.y
@@ -460,20 +460,32 @@ fcon:
reglist:
spreg
{
- $$ = 1 << $1;
+ if($1 < REG_R0 || $1 > REG_R15)
+ yyerror("invalid register in reglist");
+
+ $$ = 1 << ($1&15);
}
| spreg '-' spreg
{
int i;
+
+ if($1 < REG_R0 || $1 > REG_R15)
+ yyerror("invalid register in reglist");
+ if($3 < REG_R0 || $3 > REG_R15)
+ yyerror("invalid register in reglist");
+
$$=0;
for(i=$1; i<=$3; i++)
- $$ |= 1<<i;
+ $$ |= 1<<(i&15);
for(i=$3; i<=$1; i++)
- $$ |= 1<<i;
+ $$ |= 1<<(i&15);
}
| spreg comma reglist
{
- $$ = (1<<$1) | $3;
+ if($1 < REG_R0 || $1 > REG_R15)
+ yyerror("invalid register in reglist");
+
+ $$ = (1<<($1&15)) | $3;
}
gen:
diff --git a/src/cmd/5a/y.tab.c b/src/cmd/5a/y.tab.c
index d9af383d78..416af9a321 100644
--- a/src/cmd/5a/y.tab.c
+++ b/src/cmd/5a/y.tab.c
@@ -580,14 +580,14 @@ static const yytype_uint16 yyrline[] =
220, 232, 237, 249, 260, 267, 274, 278, 282, 286,
293, 315, 323, 332, 339, 348, 359, 365, 368, 372,
377, 378, 381, 387, 398, 405, 412, 419, 427, 433,
- 438, 444, 447, 453, 461, 465, 474, 480, 481, 482,
- 483, 488, 494, 500, 506, 507, 510, 511, 519, 528,
- 529, 538, 539, 545, 548, 549, 550, 552, 560, 568,
- 577, 583, 589, 595, 603, 609, 617, 618, 622, 630,
- 631, 637, 638, 646, 647, 650, 656, 664, 672, 680,
- 690, 693, 697, 703, 704, 705, 708, 709, 713, 717,
- 721, 725, 731, 734, 740, 741, 745, 749, 753, 757,
- 761, 765, 769, 773, 777
+ 438, 444, 447, 453, 461, 468, 483, 492, 493, 494,
+ 495, 500, 506, 512, 518, 519, 522, 523, 531, 540,
+ 541, 550, 551, 557, 560, 561, 562, 564, 572, 580,
+ 589, 595, 601, 607, 615, 621, 629, 630, 634, 642,
+ 643, 649, 650, 658, 659, 662, 668, 676, 684, 692,
+ 702, 705, 709, 715, 716, 717, 720, 721, 725, 729,
+ 733, 737, 743, 746, 752, 753, 757, 761, 765, 769,
+ 773, 777, 781, 785, 789
};
#endif
@@ -2223,31 +2223,43 @@ yyreduce:
case 64:
#line 462 "a.y"
{
- (yyval.lval) = 1 << (yyvsp[(1) - (1)].lval);
+ if((yyvsp[(1) - (1)].lval) < REG_R0 || (yyvsp[(1) - (1)].lval) > REG_R15)
+ yyerror("invalid register in reglist");
+
+ (yyval.lval) = 1 << ((yyvsp[(1) - (1)].lval)&15);
}
break;
case 65:
-#line 466 "a.y"
+#line 469 "a.y"
{
int i;
+
+ if((yyvsp[(1) - (3)].lval) < REG_R0 || (yyvsp[(1) - (3)].lval) > REG_R15)
+ yyerror("invalid register in reglist");
+ if((yyvsp[(3) - (3)].lval) < REG_R0 || (yyvsp[(3) - (3)].lval) > REG_R15)
+ yyerror("invalid register in reglist");
+
(yyval.lval)=0;
for(i=(yyvsp[(1) - (3)].lval); i<=(yyvsp[(3) - (3)].lval); i++)
- (yyval.lval) |= 1<<i;
+ (yyval.lval) |= 1<<(i&15);
for(i=(yyvsp[(3) - (3)].lval); i<=(yyvsp[(1) - (3)].lval); i++)
- (yyval.lval) |= 1<<i;
+ (yyval.lval) |= 1<<(i&15);
}
break;
case 66:
-#line 475 "a.y"
+#line 484 "a.y"
{
- (yyval.lval) = (1<<(yyvsp[(1) - (3)].lval)) | (yyvsp[(3) - (3)].lval);
+ if((yyvsp[(1) - (3)].lval) < REG_R0 || (yyvsp[(1) - (3)].lval) > REG_R15)
+ yyerror("invalid register in reglist");
+
+ (yyval.lval) = (1<<((yyvsp[(1) - (3)].lval)&15)) | (yyvsp[(3) - (3)].lval);
}
break;
case 70:
-#line 484 "a.y"
+#line 496 "a.y"
{
(yyval.addr) = (yyvsp[(1) - (4)].addr);
(yyval.addr).reg = (yyvsp[(3) - (4)].lval);
@@ -2255,7 +2267,7 @@ yyreduce:
break;
case 71:
-#line 489 "a.y"
+#line 501 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_REG;
@@ -2264,7 +2276,7 @@ yyreduce:
break;
case 72:
-#line 495 "a.y"
+#line 507 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_REG;
@@ -2273,7 +2285,7 @@ yyreduce:
break;
case 73:
-#line 501 "a.y"
+#line 513 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_MEM;
@@ -2282,7 +2294,7 @@ yyreduce:
break;
case 77:
-#line 512 "a.y"
+#line 524 "a.y"
{
(yyval.addr) = (yyvsp[(1) - (1)].addr);
if((yyvsp[(1) - (1)].addr).name != NAME_EXTERN && (yyvsp[(1) - (1)].addr).name != NAME_STATIC) {
@@ -2291,7 +2303,7 @@ yyreduce:
break;
case 78:
-#line 520 "a.y"
+#line 532 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_MEM;
@@ -2301,7 +2313,7 @@ yyreduce:
break;
case 80:
-#line 530 "a.y"
+#line 542 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_MEM;
@@ -2311,7 +2323,7 @@ yyreduce:
break;
case 82:
-#line 540 "a.y"
+#line 552 "a.y"
{
(yyval.addr) = (yyvsp[(1) - (4)].addr);
(yyval.addr).type = TYPE_MEM;
@@ -2320,7 +2332,7 @@ yyreduce:
break;
case 87:
-#line 553 "a.y"
+#line 565 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_CONST;
@@ -2329,7 +2341,7 @@ yyreduce:
break;
case 88:
-#line 561 "a.y"
+#line 573 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_REG;
@@ -2338,7 +2350,7 @@ yyreduce:
break;
case 89:
-#line 569 "a.y"
+#line 581 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_REGREG;
@@ -2348,7 +2360,7 @@ yyreduce:
break;
case 90:
-#line 578 "a.y"
+#line 590 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_SHIFT;
@@ -2357,7 +2369,7 @@ yyreduce:
break;
case 91:
-#line 584 "a.y"
+#line 596 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_SHIFT;
@@ -2366,7 +2378,7 @@ yyreduce:
break;
case 92:
-#line 590 "a.y"
+#line 602 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_SHIFT;
@@ -2375,7 +2387,7 @@ yyreduce:
break;
case 93:
-#line 596 "a.y"
+#line 608 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_SHIFT;
@@ -2384,7 +2396,7 @@ yyreduce:
break;
case 94:
-#line 604 "a.y"
+#line 616 "a.y"
{
if((yyval.lval) < REG_R0 || (yyval.lval) > REG_R15)
print("register value out of range in shift\n");
@@ -2393,7 +2405,7 @@ yyreduce:
break;
case 95:
-#line 610 "a.y"
+#line 622 "a.y"
{
if((yyval.lval) < 0 || (yyval.lval) >= 32)
print("shift value out of range\n");
@@ -2402,14 +2414,14 @@ yyreduce:
break;
case 97:
-#line 619 "a.y"
+#line 631 "a.y"
{
(yyval.lval) = REGPC;
}
break;
case 98:
-#line 623 "a.y"
+#line 635 "a.y"
{
if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
print("register value out of range in R(...)\n");
@@ -2418,14 +2430,14 @@ yyreduce:
break;
case 100:
-#line 632 "a.y"
+#line 644 "a.y"
{
(yyval.lval) = REGSP;
}
break;
case 102:
-#line 639 "a.y"
+#line 651 "a.y"
{
if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
print("register value out of range in C(...)\n");
@@ -2434,7 +2446,7 @@ yyreduce:
break;
case 105:
-#line 651 "a.y"
+#line 663 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_REG;
@@ -2443,7 +2455,7 @@ yyreduce:
break;
case 106:
-#line 657 "a.y"
+#line 669 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_REG;
@@ -2452,7 +2464,7 @@ yyreduce:
break;
case 107:
-#line 665 "a.y"
+#line 677 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_MEM;
@@ -2463,7 +2475,7 @@ yyreduce:
break;
case 108:
-#line 673 "a.y"
+#line 685 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_MEM;
@@ -2474,7 +2486,7 @@ yyreduce:
break;
case 109:
-#line 681 "a.y"
+#line 693 "a.y"
{
(yyval.addr) = nullgen;
(yyval.addr).type = TYPE_MEM;
@@ -2485,140 +2497,140 @@ yyreduce:
break;
case 110:
-#line 690 "a.y"
+#line 702 "a.y"
{
(yyval.lval) = 0;
}
break;
case 111:
-#line 694 "a.y"
+#line 706 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 112:
-#line 698 "a.y"
+#line 710 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
case 117:
-#line 710 "a.y"
+#line 722 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
}
break;
case 118:
-#line 714 "a.y"
+#line 726 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
case 119:
-#line 718 "a.y"
+#line 730 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 120:
-#line 722 "a.y"
+#line 734 "a.y"
{
(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
}
break;
case 121:
-#line 726 "a.y"
+#line 738 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (3)].lval);
}
break;
case 122:
-#line 731 "a.y"
+#line 743 "a.y"
{
(yyval.lval) = 0;
}
break;
case 123:
-#line 735 "a.y"
+#line 747 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
case 125:
-#line 742 "a.y"
+#line 754 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
}
break;
case 126:
-#line 746 "a.y"
+#line 758 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
}
break;
case 127:
-#line 750 "a.y"
+#line 762 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
}
break;
case 128:
-#line 754 "a.y"
+#line 766 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
}
break;
case 129:
-#line 758 "a.y"
+#line 770 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
}
break;
case 130:
-#line 762 "a.y"
+#line 774 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
}
break;
case 131:
-#line 766 "a.y"
+#line 778 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
}
break;
case 132:
-#line 770 "a.y"
+#line 782 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
}
break;
case 133:
-#line 774 "a.y"
+#line 786 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
}
break;
case 134:
-#line 778 "a.y"
+#line 790 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
}
@@ -2626,7 +2638,7 @@ yyreduce:
/* Line 1267 of yacc.c. */
-#line 2630 "y.tab.c"
+#line 2642 "y.tab.c"
default: break;
}
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index 6acf6dfdf0..354e0cbfd6 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -1148,27 +1148,20 @@ bgen(Node *n, int true, int likely, Prog *to)
goto ret;
case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- p1 = gbranch(AB, T, 0);
- p2 = gbranch(AB, T, 0);
- patch(p1, pc);
- bgen(n->left, !true, -likely, p2);
- bgen(n->right, !true, -likely, p2);
- p1 = gbranch(AB, T, 0);
- patch(p1, to);
- patch(p2, pc);
- goto ret;
-
case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bgen(n->left, true, likely, to);
- bgen(n->right, true, likely, to);
+ if((n->op == OANDAND) == true) {
+ p1 = gbranch(AJMP, T, 0);
+ p2 = gbranch(AJMP, T, 0);
+ patch(p1, pc);
+ bgen(n->left, !true, -likely, p2);
+ bgen(n->right, !true, -likely, p2);
+ p1 = gbranch(AJMP, T, 0);
+ patch(p1, to);
+ patch(p2, pc);
+ } else {
+ bgen(n->left, true, likely, to);
+ bgen(n->right, true, likely, to);
+ }
goto ret;
case OEQ:
@@ -1626,6 +1619,8 @@ cadable(Node *n)
/*
* copy a composite value by moving its individual components.
* Slices, strings and interfaces are supported.
+ * Small structs or arrays with elements of basic type are
+ * also supported.
* nr is N when assigning a zero value.
* return 1 if can do, 0 if cant.
*/
@@ -1680,7 +1675,7 @@ componentgen(Node *nr, Node *nl)
nodl = *nl;
if(!cadable(nl)) {
- if(nr == N || !cadable(nr))
+ if(nr != N && !cadable(nr))
goto no;
igen(nl, &nodl, N);
freel = 1;
@@ -1700,7 +1695,6 @@ componentgen(Node *nr, Node *nl)
freer = 1;
}
-
// nl and nr are 'cadable' which basically means they are names (variables) now.
// If they are the same variable, don't generate any code, because the
// VARDEF we generate will mark the old value as dead incorrectly.
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
index 85ad347833..c4d74f0a71 100644
--- a/src/cmd/5g/galign.c
+++ b/src/cmd/5g/galign.c
@@ -42,61 +42,46 @@ betypeinit(void)
void
main(int argc, char **argv)
{
- arch.thechar = thechar;
- arch.thestring = thestring;
- arch.thelinkarch = thelinkarch;
- arch.typedefs = typedefs;
- arch.MAXWIDTH = MAXWIDTH;
- arch.afunclit = afunclit;
- arch.anyregalloc = anyregalloc;
- arch.betypeinit = betypeinit;
- arch.bgen = bgen;
- arch.cgen = cgen;
- arch.cgen_asop = cgen_asop;
- arch.cgen_call = cgen_call;
- arch.cgen_callinter = cgen_callinter;
- arch.cgen_ret = cgen_ret;
- arch.clearfat = clearfat;
- arch.clearp = clearp;
- arch.defframe = defframe;
- arch.dgostringptr = dgostringptr;
- arch.dgostrlitptr = dgostrlitptr;
- arch.dsname = dsname;
- arch.dsymptr = dsymptr;
- arch.dumpdata = dumpdata;
- arch.dumpit = dumpit;
- arch.excise = excise;
- arch.expandchecks = expandchecks;
- arch.fixautoused = fixautoused;
- arch.gclean = gclean;
- arch.gdata = gdata;
- arch.gdatacomplex = gdatacomplex;
- arch.gdatastring = gdatastring;
- arch.ggloblnod = ggloblnod;
- arch.ggloblsym = ggloblsym;
- arch.ginit = ginit;
- arch.gins = gins;
- arch.ginscall = ginscall;
- arch.gjmp = gjmp;
- arch.gtrack = gtrack;
- arch.gused = gused;
- arch.igen = igen;
- arch.isfat = isfat;
- arch.linkarchinit = linkarchinit;
- arch.markautoused = markautoused;
- arch.naddr = naddr;
- arch.newplist = newplist;
- arch.nodarg = nodarg;
- arch.patch = patch;
- arch.proginfo = proginfo;
- arch.regalloc = regalloc;
- arch.regfree = regfree;
- arch.regopt = regopt;
- arch.regtyp = regtyp;
- arch.sameaddr = sameaddr;
- arch.smallindir = smallindir;
- arch.stackaddr = stackaddr;
- arch.unpatch = unpatch;
+ thearch.thechar = thechar;
+ thearch.thestring = thestring;
+ thearch.thelinkarch = thelinkarch;
+ thearch.typedefs = typedefs;
+ thearch.REGSP = REGSP;
+ thearch.REGCTXT = REGCTXT;
+ thearch.MAXWIDTH = MAXWIDTH;
+ thearch.anyregalloc = anyregalloc;
+ thearch.betypeinit = betypeinit;
+ thearch.bgen = bgen;
+ thearch.cgen = cgen;
+ thearch.cgen_call = cgen_call;
+ thearch.cgen_callinter = cgen_callinter;
+ thearch.cgen_ret = cgen_ret;
+ thearch.clearfat = clearfat;
+ thearch.defframe = defframe;
+ thearch.excise = excise;
+ thearch.expandchecks = expandchecks;
+ thearch.gclean = gclean;
+ thearch.ginit = ginit;
+ thearch.gins = gins;
+ thearch.ginscall = ginscall;
+ thearch.igen = igen;
+ thearch.linkarchinit = linkarchinit;
+ thearch.peep = peep;
+ thearch.proginfo = proginfo;
+ thearch.regalloc = regalloc;
+ thearch.regfree = regfree;
+ thearch.regtyp = regtyp;
+ thearch.sameaddr = sameaddr;
+ thearch.smallindir = smallindir;
+ thearch.stackaddr = stackaddr;
+ thearch.excludedregs = excludedregs;
+ thearch.RtoB = RtoB;
+ thearch.FtoB = RtoB;
+ thearch.BtoR = BtoR;
+ thearch.BtoF = BtoF;
+ thearch.optoas = optoas;
+ thearch.doregbits = doregbits;
+ thearch.regnames = regnames;
gcmain(argc, argv);
}
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index 8a75311d73..b12c7e2561 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -17,10 +17,7 @@ enum
REGALLOC_FMAX = FREGEXT,
};
-EXTERN int32 dynloc;
EXTERN uchar reg[REGALLOC_FMAX+1];
-EXTERN int32 pcloc; // instruction counter
-EXTERN Strlit emptystring;
extern long unmappedzero;
/*
@@ -118,7 +115,6 @@ int anyregalloc(void);
void betypeinit(void);
void bgen(Node*, int, int, Prog*);
void cgen(Node*, Node*);
-void cgen_asop(Node*);
void cgen_call(Node*, int);
void cgen_callinter(Node*, Node*, int);
void cgen_ret(Node*);
@@ -163,3 +159,19 @@ int sameaddr(Addr*, Addr*);
int smallindir(Addr*, Addr*);
int stackaddr(Addr*);
Prog* unpatch(Prog*);
+
+/*
+ * reg.c
+ */
+uint64 excludedregs(void);
+uint64 RtoB(int);
+uint64 FtoB(int);
+int BtoR(uint64);
+int BtoF(uint64);
+uint64 doregbits(int);
+char** regnames(int*);
+
+/*
+ * peep.c
+ */
+void peep(Prog*);
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index b7c621be32..62b9beadb0 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -7,7 +7,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
static Prog* appendpp(Prog*, int, int, int, int32, int, int, int32);
static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0);
@@ -117,52 +117,6 @@ appendpp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int tre
return q;
}
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
- for (; p; p = p->link) {
- if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
- continue;
-
- if (p->from.node)
- ((Node*)(p->from.node))->used = 1;
-
- if (p->to.node)
- ((Node*)(p->to.node))->used = 1;
- }
-}
-
-// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
-void
-fixautoused(Prog* p)
-{
- Prog **lp;
-
- for (lp=&p; (p=*lp) != P; ) {
- if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
- *lp = p->link;
- continue;
- }
- if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
- // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
- // VARDEFs are interspersed with other code, and a jump might be using the
- // VARDEF as a target. Replace with a no-op instead. A later pass will remove
- // the no-ops.
- nopout(p);
- continue;
- }
-
- if (p->from.name == NAME_AUTO && p->from.node)
- p->from.offset += ((Node*)(p->from.node))->stkdelta;
-
- if (p->to.name == NAME_AUTO && p->to.node)
- p->to.offset += ((Node*)(p->to.node))->stkdelta;
-
- lp = &p->link;
- }
-}
-
/*
* generate:
* call f
@@ -176,7 +130,7 @@ void
ginscall(Node *f, int proc)
{
Prog *p;
- Node n1, r, r1, con;
+ Node r, r1, con;
int32 extra;
if(f->type != T) {
@@ -238,10 +192,7 @@ ginscall(Node *f, int proc)
p->to.reg = REGSP;
p->to.offset = 4;
- memset(&n1, 0, sizeof n1);
- n1.op = OADDR;
- n1.left = f;
- gins(AMOVW, &n1, &r);
+ gins(AMOVW, f, &r);
p = gins(AMOVW, &r, N);
p->to.type = TYPE_MEM;
p->to.reg = REGSP;
@@ -487,147 +438,6 @@ cgen_ret(Node *n)
}
/*
- * generate += *= etc.
- */
-void
-cgen_asop(Node *n)
-{
- Node n1, n2, n3, n4;
- Node *nl, *nr;
- Prog *p1;
- Addr addr;
- int a, w;
-
- nl = n->left;
- nr = n->right;
-
- if(nr->ullman >= UINF && nl->ullman >= UINF) {
- tempname(&n1, nr->type);
- cgen(nr, &n1);
- n2 = *n;
- n2.right = &n1;
- cgen_asop(&n2);
- goto ret;
- }
-
- if(!isint[nl->type->etype])
- goto hard;
- if(!isint[nr->type->etype])
- goto hard;
- if(is64(nl->type) || is64(nr->type))
- goto hard64;
-
- switch(n->etype) {
- case OADD:
- case OSUB:
- case OXOR:
- case OAND:
- case OOR:
- a = optoas(n->etype, nl->type);
- if(nl->addable) {
- if(smallintconst(nr))
- n3 = *nr;
- else {
- regalloc(&n3, nr->type, N);
- cgen(nr, &n3);
- }
- regalloc(&n2, nl->type, N);
- cgen(nl, &n2);
- gins(a, &n3, &n2);
- cgen(&n2, nl);
- regfree(&n2);
- if(n3.op != OLITERAL)
- regfree(&n3);
- goto ret;
- }
- if(nr->ullman < UINF)
- if(sudoaddable(a, nl, &addr, &w)) {
- w = optoas(OAS, nl->type);
- regalloc(&n2, nl->type, N);
- p1 = gins(w, N, &n2);
- p1->from = addr;
- regalloc(&n3, nr->type, N);
- cgen(nr, &n3);
- gins(a, &n3, &n2);
- p1 = gins(w, &n2, N);
- p1->to = addr;
- regfree(&n2);
- regfree(&n3);
- sudoclean();
- goto ret;
- }
- }
-
-hard:
- n2.op = 0;
- n1.op = 0;
- if(nr->op == OLITERAL) {
- // don't allocate a register for literals.
- } else if(nr->ullman >= nl->ullman || nl->addable) {
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- nr = &n2;
- } else {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- if(!nl->addable) {
- igen(nl, &n1, N);
- nl = &n1;
- }
-
- n3 = *n;
- n3.left = nl;
- n3.right = nr;
- n3.op = n->etype;
-
- regalloc(&n4, nl->type, N);
- cgen(&n3, &n4);
- gmove(&n4, nl);
-
- if(n1.op)
- regfree(&n1);
- if(n2.op == OREGISTER)
- regfree(&n2);
- regfree(&n4);
- goto ret;
-
-hard64:
- if(nr->ullman > nl->ullman) {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- igen(nl, &n1, N);
- } else {
- igen(nl, &n1, N);
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- }
-
- n3 = *n;
- n3.left = &n1;
- n3.right = &n2;
- n3.op = n->etype;
-
- cgen(&n3, &n1);
-
-ret:
- ;
-}
-
-int
-samereg(Node *a, Node *b)
-{
- if(a->op != OREGISTER)
- return 0;
- if(b->op != OREGISTER)
- return 0;
- if(a->val.u.reg != b->val.u.reg)
- return 0;
- return 1;
-}
-
-/*
* generate high multiply
* res = (nl * nr) >> wordsize
*/
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
deleted file mode 100644
index 13d06efe55..0000000000
--- a/src/cmd/5g/gobj.c
+++ /dev/null
@@ -1,267 +0,0 @@
-// Derived from Inferno utils/5c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int
-dsname(Sym *sym, int off, char *t, int n)
-{
- Prog *p;
-
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.etype = TINT32;
- p->from.offset = off;
- p->from.reg = 0;
- p->from.sym = linksym(sym);
-
- p->from3.type = TYPE_CONST;
- p->from3.offset = n;
-
- p->to.type = TYPE_SCONST;
- p->to.name = NAME_NONE;
- p->to.reg = 0;
- p->to.offset = 0;
- memmove(p->to.u.sval, t, n);
- return off + n;
-}
-
-/*
- * make a refer to the data s, s+len
- * emitting DATA if needed.
- */
-void
-datastring(char *s, int len, Addr *a)
-{
- Sym *sym;
-
- sym = stringsym(s, len);
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- a->etype = TINT32;
- a->offset = widthptr+4; // skip header
- a->reg = 0;
- a->sym = linksym(sym);
- a->node = sym->def;
-}
-
-/*
- * make a refer to the string sval,
- * emitting DATA if needed.
- */
-void
-datagostring(Strlit *sval, Addr *a)
-{
- Sym *sym;
-
- sym = stringsym(sval->s, sval->len);
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- a->etype = TSTRING;
- a->offset = 0; // header
- a->reg = 0;
- a->sym = linksym(sym);
- a->node = sym->def;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
- Prog *p;
- vlong v;
-
- if(nr->op == OLITERAL) {
- switch(nr->val.ctype) {
- case CTCPLX:
- gdatacomplex(nam, nr->val.u.cval);
- return;
- case CTSTR:
- gdatastring(nam, nr->val.u.sval);
- return;
- }
- }
-
- if(wid == 8 && is64(nr->type)) {
- v = mpgetfix(nr->val.u.xval);
- p = gins(ADATA, nam, nodintconst(v));
- p->from3.type = TYPE_CONST;
- p->from3.offset = 4;
- p = gins(ADATA, nam, nodintconst(v>>32));
- p->from3.type = TYPE_CONST;
- p->from3.offset = 4;
- p->from.offset += 4;
- return;
- }
- p = gins(ADATA, nam, nr);
- p->from3.type = TYPE_CONST;
- p->from3.offset = wid;
-}
-
-void
-gdatacomplex(Node *nam, Mpcplx *cval)
-{
- Prog *p;
- int w;
-
- w = cplxsubtype(nam->type->etype);
- w = types[w]->width;
-
- p = gins(ADATA, nam, N);
- p->from3.type = TYPE_CONST;
- p->from3.offset = w;
- p->to.type = TYPE_FCONST;
- p->to.u.dval = mpgetflt(&cval->real);
-
- p = gins(ADATA, nam, N);
- p->from3.type = TYPE_CONST;
- p->from3.offset = w;
- p->from.offset += w;
- p->to.type = TYPE_FCONST;
- p->to.u.dval = mpgetflt(&cval->imag);
-}
-
-void
-gdatastring(Node *nam, Strlit *sval)
-{
- Prog *p;
- Node nod1;
-
- p = gins(ADATA, nam, N);
- datastring(sval->s, sval->len, &p->to);
- p->from3.type = TYPE_CONST;
- p->from3.offset = types[tptr]->width;
- p->to.type = TYPE_CONST;
- p->to.etype = TINT32;
-//print("%P\n", p);
-
- nodconst(&nod1, types[TINT32], sval->len);
- p = gins(ADATA, nam, &nod1);
- p->from3.type = TYPE_CONST;
- p->from3.offset = types[TINT32]->width;
- p->from.offset += types[tptr]->width;
-}
-
-int
-dstringptr(Sym *s, int off, char *str)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
-
- datastring(str, strlen(str)+1, &p->to);
- p->to.type = TYPE_CONST;
- p->to.etype = TINT32;
- off += widthptr;
-
- return off;
-}
-
-int
-dgostrlitptr(Sym *s, int off, Strlit *lit)
-{
- Prog *p;
-
- if(lit == nil)
- return duintptr(s, off, 0);
-
- off = rnd(off, widthptr);
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
- datagostring(lit, &p->to);
- p->to.type = TYPE_CONST;
- p->to.etype = TINT32;
- off += widthptr;
-
- return off;
-}
-
-int
-dgostringptr(Sym *s, int off, char *str)
-{
- int n;
- Strlit *lit;
-
- if(str == nil)
- return duintptr(s, off, 0);
-
- n = strlen(str);
- lit = mal(sizeof *lit + n);
- strcpy(lit->s, str);
- lit->len = n;
- return dgostrlitptr(s, off, lit);
-}
-
-int
-dsymptr(Sym *s, int off, Sym *x, int xoff)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
-
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
- p->to.type = TYPE_ADDR;
- p->to.name = NAME_EXTERN;
- p->to.sym = linksym(x);
- p->to.offset = xoff;
- off += widthptr;
-
- return off;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->scond = zprog.scond;
- p->from = zprog.from;
- p->to = zprog.to;
- p->reg = zprog.reg;
-}
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index ef5a509147..bdb70270a8 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -38,229 +38,6 @@
// At the same time, can raise StackBig in ../../runtime/stack.h.
long unmappedzero = 4096;
-void
-clearp(Prog *p)
-{
- p->as = AEND;
- p->reg = 0;
- p->scond = C_SCOND_NONE;
- p->from.type = TYPE_NONE;
- p->from.name = NAME_NONE;
- p->from.reg = 0;
- p->to.type = TYPE_NONE;
- p->to.name = NAME_NONE;
- p->to.reg = 0;
- p->pc = pcloc;
- pcloc++;
-}
-
-static int ddumped;
-static Prog *dfirst;
-static Prog *dpc;
-
-/*
- * generate and return proc with p->as = as,
- * linked into program. pc is next instruction.
- */
-Prog*
-prog(int as)
-{
- Prog *p;
-
- if(as == ADATA || as == AGLOBL) {
- if(ddumped)
- fatal("already dumped data");
- if(dpc == nil) {
- dpc = mal(sizeof(*dpc));
- dfirst = dpc;
- }
- p = dpc;
- dpc = mal(sizeof(*dpc));
- p->link = dpc;
- p->reg = 0; // used for flags
- } else {
- p = pc;
- pc = mal(sizeof(*pc));
- clearp(pc);
- p->link = pc;
- }
-
- if(lineno == 0) {
- if(debug['K'])
- warn("prog: line 0");
- }
-
- p->as = as;
- p->lineno = lineno;
- return p;
-}
-
-void
-dumpdata(void)
-{
- ddumped = 1;
- if(dfirst == nil)
- return;
- newplist();
- *pc = *dfirst;
- pc = dpc;
- clearp(pc);
-}
-
-/*
- * generate a branch.
- * t is ignored.
- * likely values are for branch prediction:
- * -1 unlikely
- * 0 no opinion
- * +1 likely
- */
-Prog*
-gbranch(int as, Type *t, int likely)
-{
- Prog *p;
-
- USED(t);
- USED(likely); // TODO: record this for linker
-
- p = prog(as);
- p->to.type = TYPE_BRANCH;
- p->to.u.branch = P;
- return p;
-}
-
-/*
- * patch previous branch to jump to to.
- */
-void
-patch(Prog *p, Prog *to)
-{
- if(p->to.type != TYPE_BRANCH)
- fatal("patch: not a branch");
- p->to.u.branch = to;
- p->to.offset = to->pc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
- Prog *q;
-
- if(p->to.type != TYPE_BRANCH)
- fatal("unpatch: not a branch");
- q = p->to.u.branch;
- p->to.u.branch = P;
- p->to.offset = 0;
- return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
- Plist *pl;
-
- pl = linknewplist(ctxt);
-
- pc = mal(sizeof(*pc));
- clearp(pc);
- pl->firstpc = pc;
-
- return pl;
-}
-
-void
-gused(Node *n)
-{
- gins(ANOP, n, N); // used
-}
-
-Prog*
-gjmp(Prog *to)
-{
- Prog *p;
-
- p = gbranch(AB, T, 0);
- if(to != P)
- patch(p, to);
- return p;
-}
-
-void
-ggloblnod(Node *nam)
-{
- Prog *p;
-
- p = gins(AGLOBL, nam, N);
- p->lineno = nam->lineno;
- p->from.sym->gotype = linksym(ngotype(nam));
- p->to.sym = nil;
- p->to.type = TYPE_CONST;
- p->to.offset = nam->type->width;
- if(nam->readonly)
- p->from3.offset = RODATA;
- if(nam->type != T && !haspointers(nam->type))
- p->from3.offset |= NOPTR;
-}
-
-void
-ggloblsym(Sym *s, int32 width, int8 flags)
-{
- Prog *p;
-
- p = gins(AGLOBL, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->to.type = TYPE_CONST;
- p->to.name = NAME_NONE;
- p->to.offset = width;
- p->from3.offset = flags;
-}
-
-void
-gtrack(Sym *s)
-{
- Prog *p;
-
- p = gins(AUSEFIELD, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
-}
-
-int
-isfat(Type *t)
-{
- if(t != T)
- switch(t->etype) {
- case TSTRUCT:
- case TARRAY:
- case TSTRING:
- case TINTER: // maybe remove later
- return 1;
- }
- return 0;
-}
-
-/*
- * naddr of func generates code for address of func.
- * if using opcode that can take address implicitly,
- * call afunclit to fix up the argument.
- * also fix up direct register references to be TYPE_MEM.
- */
-void
-afunclit(Addr *a, Node *n)
-{
- if(a->type == TYPE_ADDR && a->name == NAME_EXTERN || a->type == TYPE_REG) {
- a->type = TYPE_MEM;
- if(n->op == ONAME)
- a->sym = linksym(n->sym);
- }
-}
-
static int resvd[] =
{
9, // reserved for m
@@ -292,7 +69,7 @@ gclean(void)
yyerror("reg %R left allocated\n", i);
}
-int32
+int
anyregalloc(void)
{
int i, j;
@@ -427,101 +204,6 @@ regfree(Node *n)
}
/*
- * initialize n to be register r of type t.
- */
-void
-nodreg(Node *n, Type *t, int r)
-{
- if(t == T)
- fatal("nodreg: t nil");
-
- memset(n, 0, sizeof(*n));
- n->op = OREGISTER;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.reg = r;
- n->type = t;
-}
-
-/*
- * initialize n to be indirect of register r; n is type t.
- */
-void
-nodindreg(Node *n, Type *t, int r)
-{
- nodreg(n, t, r);
- n->op = OINDREG;
-}
-
-Node*
-nodarg(Type *t, int fp)
-{
- Node *n;
- NodeList *l;
- Type *first;
- Iter savet;
-
- // entire argument struct, not just one arg
- if(t->etype == TSTRUCT && t->funarg) {
- n = nod(ONAME, N, N);
- n->sym = lookup(".args");
- n->type = t;
- first = structfirst(&savet, &t);
- if(first == nil)
- fatal("nodarg: bad struct");
- if(first->width == BADWIDTH)
- fatal("nodarg: offset not computed for %T", t);
- n->xoffset = first->width;
- n->addable = 1;
- goto fp;
- }
-
- if(t->etype != TFIELD)
- fatal("nodarg: not field %T", t);
-
- if(fp == 1) {
- for(l=curfn->dcl; l; l=l->next) {
- n = l->n;
- if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
- return n;
- }
- }
-
- n = nod(ONAME, N, N);
- n->type = t->type;
- n->sym = t->sym;
- if(t->width == BADWIDTH)
- fatal("nodarg: offset not computed for %T", t);
- n->xoffset = t->width;
- n->addable = 1;
- n->orig = t->nname;
-
-fp:
- // Rewrite argument named _ to __,
- // or else the assignment to _ will be
- // discarded during code generation.
- if(isblank(n))
- n->sym = lookup("__");
-
- switch(fp) {
- default:
- fatal("nodarg %T %d", t, fp);
-
- case 0: // output arg for calling another function
- n->op = OINDREG;
- n->val.u.reg = REGSP;
- n->xoffset += 4;
- break;
-
- case 1: // input arg to current function
- n->class = PPARAM;
- break;
- }
- n->typecheck = 1;
- return n;
-}
-
-/*
* return constant i node.
* overwritten by next call, but useful in calls to gins.
*/
@@ -536,22 +218,6 @@ ncon(uint32 i)
return &n;
}
-/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
- switch(n->op) {
- case OINDREG:
- case ONAME:
- case OPARAM:
- case OCLOSUREVAR:
- return 1;
- }
- return 0;
-}
-
Node sclean[10];
int nsclean;
@@ -573,22 +239,25 @@ split64(Node *n, Node *lo, Node *hi)
nsclean++;
switch(n->op) {
default:
- if(!dotaddable(n, &n1)) {
- igen(n, &n1, N);
- sclean[nsclean-1] = n1;
- }
- n = &n1;
- goto common;
- case ONAME:
- if(n->class == PPARAMREF) {
- cgen(n->heapaddr, &n1);
- sclean[nsclean-1] = n1;
- // fall through.
+ switch(n->op) {
+ default:
+ if(!dotaddable(n, &n1)) {
+ igen(n, &n1, N);
+ sclean[nsclean-1] = n1;
+ }
n = &n1;
+ break;
+ case ONAME:
+ if(n->class == PPARAMREF) {
+ cgen(n->heapaddr, &n1);
+ sclean[nsclean-1] = n1;
+ n = &n1;
+ }
+ break;
+ case OINDREG:
+ // nothing
+ break;
}
- goto common;
- case OINDREG:
- common:
*lo = *n;
*hi = *n;
lo->type = types[TUINT32];
@@ -1182,228 +851,6 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
}
/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
- Sym *s;
-
- a->type = TYPE_NONE;
- a->name = NAME_NONE;
- a->reg = 0;
- a->gotype = nil;
- a->node = N;
- a->etype = 0;
- if(n == N)
- return;
-
- if(n->type != T && n->type->etype != TIDEAL) {
- dowidth(n->type);
- a->width = n->type->width;
- }
-
- switch(n->op) {
- default:
- fatal("naddr: bad %O %D", n->op, a);
- break;
-
- case OREGISTER:
- a->type = TYPE_REG;
- a->reg = n->val.u.reg;
- a->sym = nil;
- break;
-
- case OINDEX:
- case OIND:
- fatal("naddr: OINDEX");
-// naddr(n->left, a);
-// if(a->type >= D_AX && a->type <= D_DI)
-// a->type += D_INDIR;
-// else
-// if(a->type == TYPE_ADDR)
-// a->type = TYPE_NONE+D_INDIR;
-// else
-// if(a->type == TYPE_ADDR) {
-// a->type = a->index;
-// a->index = TYPE_NONE;
-// } else
-// goto bad;
-// if(n->op == OINDEX) {
-// a->index = idx.reg;
-// a->scale = n->scale;
-// }
-// break;
-
- case OINDREG:
- a->type = TYPE_MEM;
- a->reg = n->val.u.reg;
- a->sym = linksym(n->sym);
- a->offset = n->xoffset;
- break;
-
- case OPARAM:
- // n->left is PHEAP ONAME for stack parameter.
- // compute address of actual parameter on stack.
- a->etype = simtype[n->left->type->etype];
- a->width = n->left->type->width;
- a->offset = n->xoffset;
- a->sym = linksym(n->left->sym);
- a->type = TYPE_MEM;
- a->name = NAME_PARAM;
- a->node = n->left->orig;
- break;
-
- case OCLOSUREVAR:
- if(!curfn->needctxt)
- fatal("closurevar without needctxt");
- a->type = TYPE_MEM;
- a->reg = REG_R7;
- a->offset = n->xoffset;
- a->sym = nil;
- break;
-
- case OCFUNC:
- naddr(n->left, a, canemitcode);
- a->sym = linksym(n->left->sym);
- break;
-
- case ONAME:
- a->etype = 0;
- a->width = 0;
- a->reg = 0;
- if(n->type != T) {
- a->etype = simtype[n->type->etype];
- a->width = n->type->width;
- }
- a->offset = n->xoffset;
- s = n->sym;
- a->node = n->orig;
- //if(a->node >= (Node*)&n)
- // fatal("stack node");
- if(s == S)
- s = lookup(".noname");
- if(n->method) {
- if(n->type != T)
- if(n->type->sym != S)
- if(n->type->sym->pkg != nil)
- s = pkglookup(s->name, n->type->sym->pkg);
- }
-
- a->type = TYPE_MEM;
- switch(n->class) {
- default:
- fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
- case PEXTERN:
- a->name = NAME_EXTERN;
- break;
- case PAUTO:
- a->name = NAME_AUTO;
- break;
- case PPARAM:
- case PPARAMOUT:
- a->name = NAME_PARAM;
- break;
- case PFUNC:
- a->name = NAME_EXTERN;
- a->type = TYPE_ADDR;
- s = funcsym(s);
- break;
- }
- a->sym = linksym(s);
- break;
-
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- fatal("naddr: const %lT", n->type);
- break;
- case CTFLT:
- a->type = TYPE_FCONST;
- a->u.dval = mpgetflt(n->val.u.fval);
- break;
- case CTINT:
- case CTRUNE:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = mpgetfix(n->val.u.xval);
- break;
- case CTSTR:
- datagostring(n->val.u.sval, a);
- break;
- case CTBOOL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = n->val.u.bval;
- break;
- case CTNIL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = 0;
- break;
- }
- break;
-
- case OITAB:
- // itable of interface value
- naddr(n->left, a, canemitcode);
- a->etype = simtype[tptr];
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // len(nil)
- a->width = widthptr;
- break;
-
- case OSPTR:
- // pointer in a string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // ptr(nil)
- a->etype = simtype[tptr];
- a->offset += Array_array;
- a->width = widthptr;
- break;
-
- case OLEN:
- // len of string or slice
- naddr(n->left, a, canemitcode);
- a->etype = TINT32;
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // len(nil)
- a->offset += Array_nel;
- break;
-
- case OCAP:
- // cap of string or slice
- naddr(n->left, a, canemitcode);
- a->etype = TINT32;
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // cap(nil)
- a->offset += Array_cap;
- break;
-
- case OADDR:
- naddr(n->left, a, canemitcode);
- a->etype = tptr;
- switch(a->type) {
- case TYPE_MEM:
- a->type = TYPE_ADDR;
- break;
-
- case TYPE_REG:
- case TYPE_ADDR:
- break;
-
- default:
- fatal("naddr: OADDR %d\n", a->type);
- }
- }
-
- if(a->width < 0)
- fatal("naddr: bad width for %N -> %D", n, a);
-}
-
-/*
* return Axxx for Oxxx on type t.
*/
int
@@ -1812,6 +1259,8 @@ sudoaddable(int as, Node *n, Addr *a, int *w)
if(n->type == T)
return 0;
+ memset(a, 0, sizeof *a);
+
switch(n->op) {
case OLITERAL:
if(!isconst(n, CTINT))
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
deleted file mode 100644
index 524607419d..0000000000
--- a/src/cmd/5g/opt.h
+++ /dev/null
@@ -1,179 +0,0 @@
-// Inferno utils/5c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/gc.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-#define Z N
-#define Adr Addr
-
-#define D_HI TYPE_NONE
-#define D_LO TYPE_NONE
-
-#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
-#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
-#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
-#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
-
-#define CLOAD 5
-#define CREF 5
-#define CINF 1000
-#define LOOP 3
-
-typedef struct Reg Reg;
-typedef struct Rgn Rgn;
-
-/*c2go
-extern Node *Z;
-enum
-{
- D_HI = TYPE_NONE,
- D_LO = TYPE_NONE,
- CLOAD = 5,
- CREF = 5,
- CINF = 1000,
- LOOP = 3,
-};
-
-uint32 BLOAD(Reg*);
-uint32 BSTORE(Reg*);
-uint64 LOAD(Reg*);
-uint64 STORE(Reg*);
-*/
-
-// A Reg is a wrapper around a single Prog (one instruction) that holds
-// register optimization information while the optimizer runs.
-// r->prog is the instruction.
-// r->prog->opt points back to r.
-struct Reg
-{
- Flow f;
-
- Bits set; // regopt variables written by this instruction.
- Bits use1; // regopt variables read by prog->from.
- Bits use2; // regopt variables read by prog->to.
-
- // refahead/refbehind are the regopt variables whose current
- // value may be used in the following/preceding instructions
- // up to a CALL (or the value is clobbered).
- Bits refbehind;
- Bits refahead;
- // calahead/calbehind are similar, but for variables in
- // instructions that are reachable after hitting at least one
- // CALL.
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- int32 regu; // register used bitmap
-};
-#define R ((Reg*)0)
-/*c2go extern Reg *R; */
-
-#define NRGN 600
-/*c2go enum { NRGN = 600 }; */
-
-// A Rgn represents a single regopt variable over a region of code
-// where a register could potentially be dedicated to that variable.
-// The code encompassed by a Rgn is defined by the flow graph,
-// starting at enter, flood-filling forward while varno is refahead
-// and backward while varno is refbehind, and following branches. A
-// single variable may be represented by multiple disjoint Rgns and
-// each Rgn may choose a different register for that variable.
-// Registers are allocated to regions greedily in order of descending
-// cost.
-struct Rgn
-{
- Reg* enter;
- short cost;
- short varno;
- short regno;
-};
-
-EXTERN Reg zreg;
-EXTERN Reg* freer;
-EXTERN Reg** rpo2r;
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-EXTERN int32 regbits;
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-EXTERN Bits ivar;
-EXTERN Bits ovar;
-EXTERN int change;
-EXTERN int32 maxnr;
-EXTERN int32* idom;
-
-EXTERN struct
-{
- int32 ncvtreg;
- int32 nspill;
- int32 nreload;
- int32 ndelmov;
- int32 nvar;
- int32 naddr;
-} ostats;
-
-/*
- * reg.c
- */
-Reg* rega(void);
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Reg *r, Adr *a);
-void prop(Reg*, Bits, Bits);
-void synch(Reg*, Bits);
-uint32 allreg(uint32, Rgn*);
-void paint1(Reg*, int);
-uint32 paint2(Reg*, int, int);
-void paint3(Reg*, int, uint32, int);
-void addreg(Adr*, int);
-void dumpit(char *str, Flow *r0, int);
-
-/*
- * peep.c
- */
-void peep(Prog*);
-void excise(Flow*);
-int copyu(Prog*, Adr*, Adr*);
-
-uint32 RtoB(int);
-uint32 FtoB(int);
-int BtoR(uint32);
-int BtoF(uint32);
-
-/*
- * prog.c
- */
-void proginfo(ProgInfo*, Prog*);
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
index 1a4df8d622..7fe3e1071f 100644
--- a/src/cmd/5g/peep.c
+++ b/src/cmd/5g/peep.c
@@ -32,7 +32,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
static int xtramodes(Graph*, Flow*, Adr*);
static int shortprop(Flow *r);
@@ -47,6 +47,7 @@ static Flow* findpre(Flow *r, Adr *v);
static int copyau1(Prog *p, Adr *v);
static int isdconst(Addr *a);
static int isfloatreg(Addr*);
+static int copyu(Prog *p, Adr *v, Adr *s);
static uint32 gactive;
@@ -64,7 +65,7 @@ peep(Prog *firstp)
Prog *p;
int t;
- g = flowstart(firstp, sizeof(Flow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
gactive = 0;
@@ -121,15 +122,14 @@ loop1:
}
break;
-#ifdef NOTDEF
-XXX
+ /*
if(p->scond == C_SCOND_NONE)
if(regtyp(&p->to))
if(isdconst(&p->from)) {
constprop(&p->from, &p->to, r->s1);
}
break;
-#endif
+ */
}
}
if(t)
@@ -561,8 +561,6 @@ gotit:
* AXXX (x<<y),a,b
* ..
*/
-#define FAIL(msg) { if(debug['P']) print("\t%s; FAILURE\n", msg); return 0; }
-/*c2go void FAIL(char*); */
int
shiftprop(Flow *r)
@@ -573,8 +571,11 @@ shiftprop(Flow *r)
Adr a;
p = r->prog;
- if(p->to.type != TYPE_REG)
- FAIL("BOTCH: result not reg");
+ if(p->to.type != TYPE_REG) {
+ if(debug['P'])
+ print("\tBOTCH: result not reg; FAILURE\n");
+ return 0;
+ }
n = p->to.reg;
a = zprog.from;
if(p->reg != 0 && p->reg != p->to.reg) {
@@ -587,28 +588,43 @@ shiftprop(Flow *r)
for(;;) {
/* find first use of shift result; abort if shift operands or result are changed */
r1 = uniqs(r1);
- if(r1 == nil)
- FAIL("branch");
- if(uniqp(r1) == nil)
- FAIL("merge");
+ if(r1 == nil) {
+ if(debug['P'])
+ print("\tbranch; FAILURE\n");
+ return 0;
+ }
+ if(uniqp(r1) == nil) {
+ if(debug['P'])
+ print("\tmerge; FAILURE\n");
+ return 0;
+ }
p1 = r1->prog;
if(debug['P'])
print("\n%P", p1);
switch(copyu(p1, &p->to, nil)) {
case 0: /* not used or set */
if((p->from.type == TYPE_REG && copyu(p1, &p->from, nil) > 1) ||
- (a.type == TYPE_REG && copyu(p1, &a, nil) > 1))
- FAIL("args modified");
+ (a.type == TYPE_REG && copyu(p1, &a, nil) > 1)) {
+ if(debug['P'])
+ print("\targs modified; FAILURE\n");
+ return 0;
+ }
continue;
- case 3: /* set, not used */
- FAIL("BOTCH: noref");
+ case 3: /* set, not used */ {
+ if(debug['P'])
+ print("\tBOTCH: noref; FAILURE\n");
+ return 0;
+ }
}
break;
}
/* check whether substitution can be done */
switch(p1->as) {
default:
- FAIL("non-dpi");
+ if(debug['P'])
+ print("\tnon-dpi; FAILURE\n");
+ return 0;
+
case AAND:
case AEOR:
case AADD:
@@ -619,8 +635,11 @@ shiftprop(Flow *r)
case ARSB:
case ARSC:
if(p1->reg == n || (p1->reg == 0 && p1->to.type == TYPE_REG && p1->to.reg == n)) {
- if(p1->from.type != TYPE_REG)
- FAIL("can't swap");
+ if(p1->from.type != TYPE_REG) {
+ if(debug['P'])
+ print("\tcan't swap; FAILURE\n");
+ return 0;
+ }
p1->reg = p1->from.reg;
p1->from.reg = n;
switch(p1->as) {
@@ -644,15 +663,27 @@ shiftprop(Flow *r)
case ATST:
case ACMP:
case ACMN:
- if(p1->reg == n)
- FAIL("can't swap");
- if(p1->reg == 0 && p1->to.reg == n)
- FAIL("shift result used twice");
+ if(p1->reg == n) {
+ if(debug['P'])
+ print("\tcan't swap; FAILURE\n");
+ return 0;
+ }
+ if(p1->reg == 0 && p1->to.reg == n) {
+ if(debug['P'])
+ print("\tshift result used twice; FAILURE\n");
+ return 0;
+ }
// case AMVN:
- if(p1->from.type == TYPE_SHIFT)
- FAIL("shift result used in shift");
- if(p1->from.type != TYPE_REG || p1->from.reg != n)
- FAIL("BOTCH: where is it used?");
+ if(p1->from.type == TYPE_SHIFT) {
+ if(debug['P'])
+ print("\tshift result used in shift; FAILURE\n");
+ return 0;
+ }
+ if(p1->from.type != TYPE_REG || p1->from.reg != n) {
+ if(debug['P'])
+ print("\tBOTCH: where is it used?; FAILURE\n");
+ return 0;
+ }
break;
}
/* check whether shift result is used subsequently */
@@ -660,8 +691,11 @@ shiftprop(Flow *r)
if(p1->to.reg != n)
for (;;) {
r1 = uniqs(r1);
- if(r1 == nil)
- FAIL("inconclusive");
+ if(r1 == nil) {
+ if(debug['P'])
+ print("\tinconclusive; FAILURE\n");
+ return 0;
+ }
p1 = r1->prog;
if(debug['P'])
print("\n%P", p1);
@@ -671,7 +705,9 @@ shiftprop(Flow *r)
case 3: /* set, not used */
break;
default:/* used */
- FAIL("reused");
+ if(debug['P'])
+ print("\treused; FAILURE\n");
+ return 0;
}
break;
}
@@ -941,7 +977,7 @@ xtramodes(Graph *g, Flow *r, Adr *a)
* 4 if set and used
* 0 otherwise (not touched)
*/
-int
+static int
copyu(Prog *p, Adr *v, Adr *s)
{
switch(p->as) {
@@ -1572,3 +1608,12 @@ smallindir(Addr *a, Addr *reg)
a->reg == reg->reg &&
0 <= a->offset && a->offset < 4096;
}
+
+void
+excise(Flow *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ nopout(p);
+}
diff --git a/src/cmd/5g/prog.c b/src/cmd/5g/prog.c
index a77f2336e9..9d5adefe69 100644
--- a/src/cmd/5g/prog.c
+++ b/src/cmd/5g/prog.c
@@ -5,7 +5,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
enum
{
@@ -148,4 +148,13 @@ proginfo(ProgInfo *info, Prog *p)
if(((p->scond & C_SCOND) != C_SCOND_NONE) && (info->flags & RightWrite))
info->flags |= RightRead;
+
+ switch(p->as) {
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ info->regset |= RtoB(REG_R12);
+ break;
+ }
}
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index 93090ebe42..1216e01bd5 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -32,66 +32,11 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
-#define NREGVAR 32
-#define REGBITS ((uint64)0xffffffffull)
-/*c2go enum {
+enum {
NREGVAR = 32,
- REGBITS = 0xffffffff,
};
-*/
-
- void addsplits(void);
-static Reg* firstr;
-static int first = 1;
-
-int
-rcmp(const void *a1, const void *a2)
-{
- Rgn *p1, *p2;
- int c1, c2;
-
- p1 = (Rgn*)a1;
- p2 = (Rgn*)a2;
- c1 = p2->cost;
- c2 = p1->cost;
- if(c1 -= c2)
- return c1;
- return p2->varno - p1->varno;
-}
-
-void
-excise(Flow *r)
-{
- Prog *p;
-
- p = r->prog;
- nopout(p);
-}
-
-static void
-setaddrs(Bits bit)
-{
- int i, n;
- Var *v;
- Node *node;
-
- while(bany(&bit)) {
- // convert each bit to a variable
- i = bnum(bit);
- node = var[i].node;
- n = var[i].name;
- biclr(&bit, i);
-
- // disable all pieces of that variable
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node && v->name == n)
- v->addr = 2;
- }
- }
-}
static char* regname[] = {
".R0",
@@ -128,1188 +73,26 @@ static char* regname[] = {
".F15",
};
-static Node* regnodes[NREGVAR];
-
-static void walkvardef(Node *n, Reg *r, int active);
-
-void
-regopt(Prog *firstp)
-{
- Reg *r, *r1;
- Prog *p;
- Graph *g;
- int i, z, active;
- uint32 vreg;
- Bits bit;
- ProgInfo info;
-
- if(first) {
- fmtinstall('Q', Qconv);
- first = 0;
- }
-
- mergetemp(firstp);
-
- /*
- * control flow is more complicated in generated go code
- * than in generated c code. define pseudo-variables for
- * registers, so we have complete register usage information.
- */
- nvar = NREGVAR;
- memset(var, 0, NREGVAR*sizeof var[0]);
- for(i=0; i<NREGVAR; i++) {
- if(regnodes[i] == N)
- regnodes[i] = newname(lookup(regname[i]));
- var[i].node = regnodes[i];
- }
-
- regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- ivar.b[z] = 0;
- ovar.b[z] = 0;
- }
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- g = flowstart(firstp, sizeof(Reg));
- if(g == nil) {
- for(i=0; i<nvar; i++)
- var[i].node->opt = nil;
- return;
- }
-
- firstr = (Reg*)g->start;
-
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- p = r->f.prog;
- if(p->as == AVARDEF || p->as == AVARKILL)
- continue;
- proginfo(&info, p);
-
- // Avoid making variables for direct-called functions.
- if(p->as == ABL && p->to.name == NAME_EXTERN)
- continue;
-
- bit = mkvar(r, &p->from);
- if(info.flags & LeftRead)
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
- if(info.flags & LeftAddr)
- setaddrs(bit);
-
- if(info.flags & RegRead)
- r->use1.b[0] |= RtoB(p->reg);
-
- if(info.flags & (RightAddr | RightRead | RightWrite)) {
- bit = mkvar(r, &p->to);
- if(info.flags & RightAddr)
- setaddrs(bit);
- if(info.flags & RightRead)
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- if(info.flags & RightWrite)
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- }
-
- /* the mod/div runtime routines smash R12 */
- if(p->as == ADIV || p->as == ADIVU || p->as == AMOD || p->as == AMODU)
- r->set.b[0] |= RtoB(REG_R12);
- }
- if(firstr == R)
- return;
-
- for(i=0; i<nvar; i++) {
- Var *v = var+i;
- if(v->addr) {
- bit = blsh(i);
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- }
-
- if(debug['R'] && debug['v'])
- print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
- i, v->addr, v->etype, v->width, v->node, v->offset);
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass1", &firstr->f, 1);
-
- /*
- * pass 2
- * find looping structure
- */
- flowrpo(g);
-
- if(debug['R'] && debug['v'])
- dumpit("pass2", &firstr->f, 1);
-
- /*
- * pass 2.5
- * iterate propagating fat vardef covering forward
- * r->act records vars with a VARDEF since the last CALL.
- * (r->act will be reused in pass 5 for something else,
- * but we'll be done with it by then.)
- */
- active = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- r->f.active = 0;
- r->act = zbits;
- }
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- p = r->f.prog;
- if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
- active++;
- walkvardef(p->to.node, r, active);
- }
- }
-
- /*
- * pass 3
- * iterate propagating usage
- * back until flow graph is complete
- */
-loop1:
- change = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->f.active = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- if(r->f.prog->as == ARET)
- prop(r, zbits, zbits);
-loop11:
- /* pick up unreachable code */
- i = 0;
- for(r = firstr; r != R; r = r1) {
- r1 = (Reg*)r->f.link;
- if(r1 && r1->f.active && !r->f.active) {
- prop(r, zbits, zbits);
- i = 1;
- }
- }
- if(i)
- goto loop11;
- if(change)
- goto loop1;
-
- if(debug['R'] && debug['v'])
- dumpit("pass3", &firstr->f, 1);
-
-
- /*
- * pass 4
- * iterate propagating register/variable synchrony
- * forward until graph is complete
- */
-loop2:
- change = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->f.active = 0;
- synch(firstr, zbits);
- if(change)
- goto loop2;
-
- addsplits();
-
- if(debug['R'] && debug['v'])
- dumpit("pass4", &firstr->f, 1);
-
- if(debug['R'] > 1) {
- print("\nprop structure:\n");
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- print("%d:%P", r->f.loop, r->f.prog);
- for(z=0; z<BITS; z++) {
- bit.b[z] = r->set.b[z] |
- r->refahead.b[z] | r->calahead.b[z] |
- r->refbehind.b[z] | r->calbehind.b[z] |
- r->use1.b[z] | r->use2.b[z];
- bit.b[z] &= ~addrs.b[z];
- }
-
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->use1))
- print(" u1=%Q", r->use1);
- if(bany(&r->use2))
- print(" u2=%Q", r->use2);
- if(bany(&r->set))
- print(" st=%Q", r->set);
- if(bany(&r->refahead))
- print(" ra=%Q", r->refahead);
- if(bany(&r->calahead))
- print(" ca=%Q", r->calahead);
- if(bany(&r->refbehind))
- print(" rb=%Q", r->refbehind);
- if(bany(&r->calbehind))
- print(" cb=%Q", r->calbehind);
- }
- print("\n");
- }
- }
-
- /*
- * pass 4.5
- * move register pseudo-variables into regu.
- */
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
-
- r->set.b[0] &= ~REGBITS;
- r->use1.b[0] &= ~REGBITS;
- r->use2.b[0] &= ~REGBITS;
- r->refbehind.b[0] &= ~REGBITS;
- r->refahead.b[0] &= ~REGBITS;
- r->calbehind.b[0] &= ~REGBITS;
- r->calahead.b[0] &= ~REGBITS;
- r->regdiff.b[0] &= ~REGBITS;
- r->act.b[0] &= ~REGBITS;
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass4.5", &firstr->f, 1);
-
- /*
- * pass 5
- * isolate regions
- * calculate costs (paint1)
- */
- r = firstr;
- if(r) {
- for(z=0; z<BITS; z++)
- bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
- ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
- if(bany(&bit) && !r->f.refset) {
- // should never happen - all variables are preset
- if(debug['w'])
- print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
- r->f.refset = 1;
- }
- }
-
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->act = zbits;
- rgp = region;
- nregion = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- for(z=0; z<BITS; z++)
- bit.b[z] = r->set.b[z] &
- ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
- if(bany(&bit) && !r->f.refset) {
- if(debug['w'])
- print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
- r->f.refset = 1;
- excise(&r->f);
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- rgp->enter = r;
- rgp->varno = i;
- change = 0;
- if(debug['R'] > 1)
- print("\n");
- paint1(r, i);
- biclr(&bit, i);
- if(change <= 0) {
- if(debug['R'])
- print("%L $%d: %Q\n",
- r->f.prog->lineno, change, blsh(i));
- continue;
- }
- rgp->cost = change;
- nregion++;
- if(nregion >= NRGN) {
- if(debug['R'] > 1)
- print("too many regions\n");
- goto brk;
- }
- rgp++;
- }
- }
-brk:
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- if(debug['R'] && debug['v'])
- dumpit("pass5", &firstr->f, 1);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- if(debug['R'] && debug['v'])
- print("\nregisterizing\n");
- for(i=0; i<nregion; i++) {
- if(debug['R'] && debug['v'])
- print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
- bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno, 0);
- vreg = allreg(vreg, rgp);
- if(debug['R']) {
- print("%L $%d %R: %Q\n",
- rgp->enter->f.prog->lineno,
- rgp->cost,
- rgp->regno,
- bit);
- }
- if(rgp->regno != 0)
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- rgp++;
- }
-
- /*
- * free aux structures. peep allocates new ones.
- */
- for(i=0; i<nvar; i++)
- var[i].node->opt = nil;
- flowend(g);
- firstr = R;
-
- if(debug['R'] && debug['v']) {
- // Rebuild flow graph, since we inserted instructions
- g = flowstart(firstp, sizeof(Reg));
- firstr = (Reg*)g->start;
- dumpit("pass6", &firstr->f, 1);
- flowend(g);
- firstr = R;
- }
-
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P']) {
- peep(firstp);
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass7", &firstr->f, 1);
-
- /*
- * last pass
- * eliminate nops
- * free aux structures
- * adjust the stack pointer
- * MOVW.W R1,-12(R13) <<- start
- * MOVW R0,R1
- * MOVW R1,8(R13)
- * MOVW $0,R1
- * MOVW R1,4(R13)
- * BL ,runtime.newproc+0(SB)
- * MOVW &ft+-32(SP),R7 <<- adjust
- * MOVW &j+-40(SP),R6 <<- adjust
- * MOVW autotmp_0003+-24(SP),R5 <<- adjust
- * MOVW $12(R13),R13 <<- finish
- */
- vreg = 0;
- for(p = firstp; p != P; p = p->link) {
- while(p->link != P && p->link->as == ANOP)
- p->link = p->link->link;
- if(p->to.type == TYPE_BRANCH)
- while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
- p->to.u.branch = p->to.u.branch->link;
- if(p->as == AMOVW && p->to.reg == 13) {
- if(p->scond & C_WBIT) {
- vreg = -p->to.offset; // in adjust region
-// print("%P adjusting %d\n", p, vreg);
- continue;
- }
- if(p->from.type == TYPE_CONST && p->to.type == TYPE_REG) {
- if(p->from.offset != vreg)
- print("in and out different\n");
-// print("%P finish %d\n", p, vreg);
- vreg = 0; // done adjust region
- continue;
- }
-
-// print("%P %d %d from type\n", p, p->from.type, TYPE_CONST);
-// print("%P %d %d to type\n\n", p, p->to.type, TYPE_REG);
- }
-
- if(p->as == AMOVW && vreg != 0) {
- if(p->from.sym != nil)
- if(p->from.name == NAME_AUTO || p->from.name == NAME_PARAM) {
- p->from.offset += vreg;
-// print("%P adjusting from %d %d\n", p, vreg, p->from.type);
- }
- if(p->to.sym != nil)
- if(p->to.name == NAME_AUTO || p->to.name == NAME_PARAM) {
- p->to.offset += vreg;
-// print("%P adjusting to %d %d\n", p, vreg, p->from.type);
- }
- }
- }
-}
-
-static void
-walkvardef(Node *n, Reg *r, int active)
-{
- Reg *r1, *r2;
- int bn;
- Var *v;
-
- for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
- if(r1->f.active == active)
- break;
- r1->f.active = active;
- if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
- break;
- for(v=n->opt; v!=nil; v=v->nextinnode) {
- bn = v - var;
- biset(&r1->act, bn);
- }
- if(r1->f.prog->as == ABL)
- break;
- }
-
- for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
- if(r2->f.s2 != nil)
- walkvardef(n, (Reg*)r2->f.s2, active);
-}
-
-void
-addsplits(void)
-{
- Reg *r, *r1;
- int z, i;
- Bits bit;
-
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- if(r->f.loop > 1)
- continue;
- if(r->f.prog->as == ABL)
- continue;
- if(r->f.prog->as == ADUFFZERO)
- continue;
- if(r->f.prog->as == ADUFFCOPY)
- continue;
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) {
- if(r1->f.loop <= 1)
- continue;
- for(z=0; z<BITS; z++)
- bit.b[z] = r1->calbehind.b[z] &
- (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
- ~(r->calahead.b[z] & addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- biclr(&bit, i);
- }
- }
- }
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1, *p2;
- Adr *a;
- Var *v;
-
- p1 = mal(sizeof(*p1));
- *p1 = zprog;
- p = r->f.prog;
-
- // If there's a stack fixup coming (after BL newproc or BL deferproc),
- // delay the load until after the fixup.
- p2 = p->link;
- if(p2 && p2->as == AMOVW && p2->from.type == TYPE_ADDR && p2->from.reg == REGSP && p2->to.reg == REGSP && p2->to.type == TYPE_REG)
- p = p2;
-
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->name = v->name;
- a->node = v->node;
- a->sym = linksym(v->node->sym);
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = TYPE_MEM;
- if(a->etype == TARRAY)
- a->type = TYPE_ADDR;
- else if(a->sym == nil)
- a->type = TYPE_CONST;
-
- if(v->addr)
- fatal("addmove: shouldn't be doing this %A\n", a);
-
- switch(v->etype) {
- default:
- print("What is this %E\n", v->etype);
-
- case TINT8:
- p1->as = AMOVBS;
- break;
- case TBOOL:
- case TUINT8:
-//print("movbu %E %d %S\n", v->etype, bn, v->sym);
- p1->as = AMOVBU;
- break;
- case TINT16:
- p1->as = AMOVHS;
- break;
- case TUINT16:
- p1->as = AMOVHU;
- break;
- case TINT32:
- case TUINT32:
- case TPTR32:
- p1->as = AMOVW;
- break;
- case TFLOAT32:
- p1->as = AMOVF;
- break;
- case TFLOAT64:
- p1->as = AMOVD;
- break;
- }
-
- p1->from.type = TYPE_REG;
- p1->from.reg = rn;
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = TYPE_REG;
- a->reg = rn;
- if(v->etype == TUINT8 || v->etype == TBOOL)
- p1->as = AMOVBU;
- if(v->etype == TUINT16)
- p1->as = AMOVHU;
- }
- if(debug['R'])
- print("%P\t.a%P\n", p, p1);
-}
-
-static int
-overlap(int32 o1, int w1, int32 o2, int w2)
-{
- int32 t1, t2;
-
- t1 = o1+w1;
- t2 = o2+w2;
-
- if(!(t1 > o2 && t2 > o1))
- return 0;
-
- return 1;
-}
-
-Bits
-mkvar(Reg *r, Adr *a)
-{
- Var *v;
- int i, t, n, et, z, w, flag;
- int32 o;
- Bits bit;
- Node *node;
-
- // mark registers used
- t = a->type;
-
- flag = 0;
- switch(t) {
- default:
- print("type %d %d %D\n", t, a->name, a);
- goto none;
-
- case TYPE_NONE:
- case TYPE_FCONST:
- case TYPE_BRANCH:
- break;
-
-
- case TYPE_REGREG:
- case TYPE_REGREG2:
- bit = zbits;
- if(a->offset != 0)
- bit.b[0] |= RtoB(a->offset);
- if(a->reg != 0)
- bit.b[0] |= RtoB(a->reg);
- return bit;
-
- case TYPE_CONST:
- if(a->reg != 0)
- fatal("found CONST instead of ADDR: %D", a);
- break;
-
- case TYPE_ADDR:
- case TYPE_REG:
- case TYPE_SHIFT:
- if(a->reg != 0) {
- bit = zbits;
- bit.b[0] = RtoB(a->reg);
- return bit;
- }
- break;
-
- case TYPE_MEM:
- if(a->reg != 0) {
- if(a == &r->f.prog->from)
- r->use1.b[0] |= RtoB(a->reg);
- else
- r->use2.b[0] |= RtoB(a->reg);
- if(r->f.prog->scond & (C_PBIT|C_WBIT))
- r->set.b[0] |= RtoB(a->reg);
- }
- break;
- }
-
- switch(a->name) {
- default:
- goto none;
-
- case NAME_EXTERN:
- case NAME_STATIC:
- case NAME_AUTO:
- case NAME_PARAM:
- n = a->name;
- break;
- }
-
- node = a->node;
- if(node == N || node->op != ONAME || node->orig == N)
- goto none;
- node = node->orig;
- if(node->orig != node)
- fatal("%D: bad node", a);
- if(node->sym == S || node->sym->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- w = a->width;
- if(w < 0)
- fatal("bad width %d for %D", w, a);
-
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node && v->name == n) {
- if(v->offset == o)
- if(v->etype == et)
- if(v->width == w)
- if(!flag)
- return blsh(i);
-
- // if they overlap, disable both
- if(overlap(v->offset, v->width, o, w)) {
- v->addr = 1;
- flag = 1;
- }
- }
- }
-
- switch(et) {
- case 0:
- case TFUNC:
- goto none;
- }
-
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && node)
- fatal("variable not optimized: %D", a);
-
- // If we're not tracking a word in a variable, mark the rest as
- // having its address taken, so that we keep the whole thing
- // live at all calls. otherwise we might optimize away part of
- // a variable but not all of it.
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node)
- v->addr = 1;
- }
- goto none;
- }
-
- i = nvar;
- nvar++;
-//print("var %d %E %D %S\n", i, et, a, s);
- v = var+i;
- v->offset = o;
- v->name = n;
- v->etype = et;
- v->width = w;
- v->addr = flag; // funny punning
- v->node = node;
-
- // node->opt is the head of a linked list
- // of Vars within the given Node, so that
- // we can start at a Var and find all the other
- // Vars in the same Go variable.
- v->nextinnode = node->opt;
- node->opt = v;
-
- bit = blsh(i);
- if(n == NAME_EXTERN || n == NAME_STATIC)
- for(z=0; z<BITS; z++)
- externs.b[z] |= bit.b[z];
- if(n == NAME_PARAM)
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
-
- if(node->class == PPARAM)
- for(z=0; z<BITS; z++)
- ivar.b[z] |= bit.b[z];
- if(node->class == PPARAMOUT)
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
-
- // Treat values with their address taken as live at calls,
- // because the garbage collector's liveness analysis in ../gc/plive.c does.
- // These must be consistent or else we will elide stores and the garbage
- // collector will see uninitialized data.
- // The typical case where our own analysis is out of sync is when the
- // node appears to have its address taken but that code doesn't actually
- // get generated and therefore doesn't show up as an address being
- // taken when we analyze the instruction stream.
- // One instance of this case is when a closure uses the same name as
- // an outer variable for one of its own variables declared with :=.
- // The parser flags the outer variable as possibly shared, and therefore
- // sets addrtaken, even though it ends up not being actually shared.
- // If we were better about _ elision, _ = &x would suffice too.
- // The broader := in a closure problem is mentioned in a comment in
- // closure.c:/^typecheckclosure and dcl.c:/^oldname.
- if(node->addrtaken)
- v->addr = 1;
-
- // Disable registerization for globals, because:
- // (1) we might panic at any time and we want the recovery code
- // to see the latest values (issue 1304).
- // (2) we don't know what pointers might point at them and we want
- // loads via those pointers to see updated values and vice versa (issue 7995).
- //
- // Disable registerization for results if using defer, because the deferred func
- // might recover and return, causing the current values to be used.
- if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
- v->addr = 1;
-
- if(debug['R'])
- print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
-
- return bit;
-
-none:
- return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
+char**
+regnames(int *n)
{
- Reg *r1, *r2;
- int z, i, j;
- Var *v, *v1;
-
- for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(r1->f.prog->as) {
- case ABL:
- if(noreturn(r1->f.prog))
- break;
-
- // Mark all input variables (ivar) as used, because that's what the
- // liveness bitmaps say. The liveness bitmaps say that so that a
- // panic will not show stale values in the parameter dump.
- // Mark variables with a recent VARDEF (r1->act) as used,
- // so that the optimizer flushes initializations to memory,
- // so that if a garbage collection happens during this CALL,
- // the collector will see initialized memory. Again this is to
- // match what the liveness bitmaps say.
- for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
- ref.b[z] = 0;
- }
-
- // cal.b is the current approximation of what's live across the call.
- // Every bit in cal.b is a single stack word. For each such word,
- // find all the other tracked stack words in the same Go variable
- // (struct/slice/string/interface) and mark them live too.
- // This is necessary because the liveness analysis for the garbage
- // collector works at variable granularity, not at word granularity.
- // It is fundamental for slice/string/interface: the garbage collector
- // needs the whole value, not just some of the words, in order to
- // interpret the other bits correctly. Specifically, slice needs a consistent
- // ptr and cap, string needs a consistent ptr and len, and interface
- // needs a consistent type word and data word.
- for(z=0; z<BITS; z++) {
- if(cal.b[z] == 0)
- continue;
- for(i=0; i<64; i++) {
- if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
- continue;
- v = var+z*64+i;
- if(v->node->opt == nil) // v represents fixed register, not Go variable
- continue;
-
- // v->node->opt is the head of a linked list of Vars
- // corresponding to tracked words from the Go variable v->node.
- // Walk the list and set all the bits.
- // For a large struct this could end up being quadratic:
- // after the first setting, the outer loop (for z, i) would see a 1 bit
- // for all of the remaining words in the struct, and for each such
- // word would go through and turn on all the bits again.
- // To avoid the quadratic behavior, we only turn on the bits if
- // v is the head of the list or if the head's bit is not yet turned on.
- // This will set the bits at most twice, keeping the overall loop linear.
- v1 = v->node->opt;
- j = v1 - var;
- if(v == v1 || !btest(&cal, j)) {
- for(; v1 != nil; v1 = v1->nextinnode) {
- j = v1 - var;
- biset(&cal, j);
- }
- }
- }
- }
- break;
-
- case ATEXT:
- for(z=0; z<BITS; z++) {
- cal.b[z] = 0;
- ref.b[z] = 0;
- }
- break;
-
- case ARET:
- for(z=0; z<BITS; z++) {
- cal.b[z] = externs.b[z] | ovar.b[z];
- ref.b[z] = 0;
- }
- break;
- }
- for(z=0; z<BITS; z++) {
- ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
- r1->use1.b[z] | r1->use2.b[z];
- cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
- r1->refbehind.b[z] = ref.b[z];
- r1->calbehind.b[z] = cal.b[z];
- }
- if(r1->f.active)
- break;
- r1->f.active = 1;
- }
- for(; r != r1; r = (Reg*)r->f.p1)
- for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
- prop(r2, r->refbehind, r->calbehind);
+ *n = NREGVAR;
+ return regname;
}
-void
-synch(Reg *r, Bits dif)
+uint64
+excludedregs(void)
{
- Reg *r1;
- int z;
-
- for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
- for(z=0; z<BITS; z++) {
- dif.b[z] = (dif.b[z] &
- ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
- r1->set.b[z] | r1->regdiff.b[z];
- if(dif.b[z] != r1->regdiff.b[z]) {
- r1->regdiff.b[z] = dif.b[z];
- change++;
- }
- }
- if(r1->f.active)
- break;
- r1->f.active = 1;
- for(z=0; z<BITS; z++)
- dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if(r1->f.s2 != nil)
- synch((Reg*)r1->f.s2, dif);
- }
+ return RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
}
-uint32
-allreg(uint32 b, Rgn *r)
+uint64
+doregbits(int r)
{
- Var *v;
- int i;
-
- v = var + r->varno;
- r->regno = 0;
- switch(v->etype) {
-
- default:
- fatal("unknown etype %d/%E", bitno(b), v->etype);
- break;
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TPTR32:
- i = BtoR(~b);
- if(i && r->cost >= 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TFLOAT32:
- case TFLOAT64:
- i = BtoF(~b);
- if(i && r->cost >= 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TINT64:
- case TUINT64:
- case TPTR64:
- case TINTER:
- case TSTRUCT:
- case TARRAY:
- break;
- }
+ USED(r);
return 0;
}
-void
-paint1(Reg *r, int bn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint64 bb;
-
- z = bn/64;
- bb = 1LL<<(bn%64);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
- change -= CLOAD * r->f.loop;
- if(debug['R'] > 1)
- print("%d%P\td %Q $%d\n", r->f.loop,
- r->f.prog, blsh(bn), change);
- }
- for(;;) {
- r->act.b[z] |= bb;
- p = r->f.prog;
-
-
- if(r->f.prog->as != ANOP) { // don't give credit for NOPs
- if(r->use1.b[z] & bb) {
- change += CREF * r->f.loop;
- if(debug['R'] > 1)
- print("%d%P\tu1 %Q $%d\n", r->f.loop,
- p, blsh(bn), change);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->f.loop;
- if(debug['R'] > 1)
- print("%d%P\tu2 %Q $%d\n", r->f.loop,
- p, blsh(bn), change);
- }
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->f.loop;
- if(debug['R'] > 1)
- print("%d%P\tst %Q $%d\n", r->f.loop,
- p, blsh(bn), change);
- }
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- paint1(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint1(r1, bn);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-uint32
-paint2(Reg *r, int bn, int depth)
-{
- Reg *r1;
- int z;
- uint64 bb, vreg;
-
- z = bn/64;
- bb = 1LL << (bn%64);
- vreg = regbits;
- if(!(r->act.b[z] & bb))
- return vreg;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(!(r1->act.b[z] & bb))
- break;
- r = r1;
- }
- for(;;) {
- if(debug['R'] && debug['v'])
- print(" paint2 %d %P\n", depth, r->f.prog);
-
- r->act.b[z] &= ~bb;
-
- vreg |= r->regu;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn, depth+1);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn, depth+1);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(!(r->act.b[z] & bb))
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
- return vreg;
-}
-
-void
-paint3(Reg *r, int bn, uint32 rb, int rn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint64 bb;
-
- z = bn/64;
- bb = 1LL << (bn%64);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
- addmove(r, bn, rn, 0);
-
- for(;;) {
- r->act.b[z] |= bb;
- p = r->f.prog;
-
- if(r->use1.b[z] & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->from, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- if(debug['R'])
- print("%P", p);
- addreg(&p->to, rn);
- if(debug['R'])
- print("\t.c%P\n", p);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(r, bn, rn, 1);
- r->regu |= rb;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Adr *a, int rn)
-{
- a->sym = nil;
- a->node = nil;
- a->name = NAME_NONE;
- a->type = TYPE_REG;
- a->reg = rn;
-}
-
/*
* bit reg
* 0 R0
@@ -1324,26 +107,26 @@ addreg(Adr *a, int rn)
* ... ...
* 31 F15
*/
-uint32
+uint64
RtoB(int r)
{
if(REG_R0 <= r && r <= REG_R15) {
if(r >= REGTMP-2 && r != REG_R12) // excluded R9 and R10 for m and g, but not R12
return 0;
- return 1L << (r - REG_R0);
+ return 1ULL << (r - REG_R0);
}
if(REG_F0 <= r && r <= REG_F15) {
if(r < REG_F2 || r > REG_F0+NFREG-1)
return 0;
- return 1L << ((r - REG_F0) + 16);
+ return 1ULL << ((r - REG_F0) + 16);
}
return 0;
}
int
-BtoR(uint32 b)
+BtoR(uint64 b)
{
// TODO Allow R0 and R1, but be careful with a 0 return
// TODO Allow R9. Only R10 is reserved now (just g, not m).
@@ -1354,88 +137,10 @@ BtoR(uint32 b)
}
int
-BtoF(uint32 b)
+BtoF(uint64 b)
{
b &= 0xfffc0000L;
if(b == 0)
return 0;
return bitno(b) - 16 + REG_F0;
}
-
-void
-dumpone(Flow *f, int isreg)
-{
- int z;
- Bits bit;
- Reg *r;
-
- print("%d:%P", f->loop, f->prog);
- if(isreg) {
- r = (Reg*)f;
- for(z=0; z<BITS; z++)
- bit.b[z] =
- r->set.b[z] |
- r->use1.b[z] |
- r->use2.b[z] |
- r->refbehind.b[z] |
- r->refahead.b[z] |
- r->calbehind.b[z] |
- r->calahead.b[z] |
- r->regdiff.b[z] |
- r->act.b[z] |
- 0;
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->set))
- print(" s:%Q", r->set);
- if(bany(&r->use1))
- print(" u1:%Q", r->use1);
- if(bany(&r->use2))
- print(" u2:%Q", r->use2);
- if(bany(&r->refbehind))
- print(" rb:%Q ", r->refbehind);
- if(bany(&r->refahead))
- print(" ra:%Q ", r->refahead);
- if(bany(&r->calbehind))
- print(" cb:%Q ", r->calbehind);
- if(bany(&r->calahead))
- print(" ca:%Q ", r->calahead);
- if(bany(&r->regdiff))
- print(" d:%Q ", r->regdiff);
- if(bany(&r->act))
- print(" a:%Q ", r->act);
- }
- }
- print("\n");
-}
-
-void
-dumpit(char *str, Flow *r0, int isreg)
-{
- Flow *r, *r1;
-
- print("\n%s\n", str);
- for(r = r0; r != nil; r = r->link) {
- dumpone(r, isreg);
- r1 = r->p2;
- if(r1 != nil) {
- print(" pred:");
- for(; r1 != nil; r1 = r1->p2link)
- print(" %.4ud", (int)r1->prog->pc);
- if(r->p1 != nil)
- print(" (and %.4ud)", (int)r->p1->prog->pc);
- else
- print(" (only)");
- print("\n");
- }
- // Print successors if it's not just the next one
- if(r->s1 != r->link || r->s2 != nil) {
- print(" succ:");
- if(r->s1 != nil)
- print(" %.4ud", (int)r->s1->prog->pc);
- if(r->s2 != nil)
- print(" %.4ud", (int)r->s2->prog->pc);
- print("\n");
- }
- }
-}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index fa1dcc34e8..a266a6b87c 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -91,6 +91,7 @@ enum
REGG = REGEXT-0,
REGM = REGEXT-1,
+ REGCTXT = REG_R7,
REGTMP = REG_R11,
REGSP = REG_R13,
REGLINK = REG_R14,
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 5993079126..ed4d68a1fb 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -33,16 +33,9 @@
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/macho.h"
#include "../ld/dwarf.h"
-
-char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
-char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
-char openbsddynld[] = "XXX";
-char netbsddynld[] = "/libexec/ld.elf_so";
-char dragonflydynld[] = "XXX";
-char solarisdynld[] = "XXX";
-
static int
needlib(char *name)
{
@@ -63,8 +56,6 @@ needlib(char *name)
return 0;
}
-int nelfsym = 1;
-
static void addpltsym(Link*, LSym*);
static void addgotsym(Link*, LSym*);
static void addgotsyminternal(Link*, LSym*);
@@ -127,11 +118,11 @@ adddynrel(LSym *s, Reloc *r)
addgotsym(ctxt, targ);
}
r->type = R_CONST; // write r->add during relocsym
- r->sym = S;
+ r->sym = nil;
r->add += targ->got;
return;
- case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P
+ case 256 + R_ARM_GOT_PREL: // GOT(nil) + A - nil
if(targ->type != SDYNIMPORT) {
addgotsyminternal(ctxt, targ);
} else {
@@ -178,7 +169,7 @@ adddynrel(LSym *s, Reloc *r)
// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
r->sym->type = 0;
}
- r->sym = S;
+ r->sym = nil;
return;
case 256 + R_ARM_PC24:
@@ -210,9 +201,9 @@ adddynrel(LSym *s, Reloc *r)
adddynsym(ctxt, targ);
rel = linklookup(ctxt, ".rel", 0);
addaddrplus(ctxt, rel, s, r->off);
- adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
+ adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a nil + A dynmic reloc
r->type = R_CONST; // write r->add during relocsym
- r->sym = S;
+ r->sym = nil;
return;
}
break;
@@ -227,7 +218,7 @@ elfreloc1(Reloc *r, vlong sectoff)
{
int32 elfsym;
- LPUT(sectoff);
+ thearch.lput(sectoff);
elfsym = r->xsym->elfsym;
switch(r->type) {
@@ -236,14 +227,14 @@ elfreloc1(Reloc *r, vlong sectoff)
case R_ADDR:
if(r->siz == 4)
- LPUT(R_ARM_ABS32 | elfsym<<8);
+ thearch.lput(R_ARM_ABS32 | elfsym<<8);
else
return -1;
break;
case R_PCREL:
if(r->siz == 4)
- LPUT(R_ARM_REL32 | elfsym<<8);
+ thearch.lput(R_ARM_REL32 | elfsym<<8);
else
return -1;
break;
@@ -251,9 +242,9 @@ elfreloc1(Reloc *r, vlong sectoff)
case R_CALLARM:
if(r->siz == 4) {
if((r->add & 0xff000000) == 0xeb000000) // BL
- LPUT(R_ARM_CALL | elfsym<<8);
+ thearch.lput(R_ARM_CALL | elfsym<<8);
else
- LPUT(R_ARM_JUMP24 | elfsym<<8);
+ thearch.lput(R_ARM_JUMP24 | elfsym<<8);
} else
return -1;
break;
@@ -261,9 +252,9 @@ elfreloc1(Reloc *r, vlong sectoff)
case R_TLS:
if(r->siz == 4) {
if(flag_shared)
- LPUT(R_ARM_TLS_IE32 | elfsym<<8);
+ thearch.lput(R_ARM_TLS_IE32 | elfsym<<8);
else
- LPUT(R_ARM_TLS_LE32 | elfsym<<8);
+ thearch.lput(R_ARM_TLS_LE32 | elfsym<<8);
} else
return -1;
break;
@@ -301,10 +292,58 @@ elfsetupplt(void)
int
machoreloc1(Reloc *r, vlong sectoff)
{
- USED(r);
- USED(sectoff);
+ uint32 v;
+ LSym *rs;
- return -1;
+ rs = r->xsym;
+
+ if(rs->type == SHOSTOBJ || r->type == R_CALLARM) {
+ if(rs->dynid < 0) {
+ diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
+ return -1;
+ }
+ v = rs->dynid;
+ v |= 1<<27; // external relocation
+ } else {
+ v = rs->sect->extnum;
+ if(v == 0) {
+ diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type);
+ return -1;
+ }
+ }
+
+ switch(r->type) {
+ default:
+ return -1;
+ case R_ADDR:
+ v |= MACHO_GENERIC_RELOC_VANILLA<<28;
+ break;
+ case R_CALLARM:
+ v |= 1<<24; // pc-relative bit
+ v |= MACHO_ARM_RELOC_BR24<<28;
+ break;
+ }
+
+ switch(r->siz) {
+ default:
+ return -1;
+ case 1:
+ v |= 0<<25;
+ break;
+ case 2:
+ v |= 1<<25;
+ break;
+ case 4:
+ v |= 2<<25;
+ break;
+ case 8:
+ v |= 3<<25;
+ break;
+ }
+
+ thearch.lput(sectoff);
+ thearch.lput(v);
+ return 0;
}
@@ -333,6 +372,14 @@ archreloc(Reloc *r, LSym *s, vlong *val)
diag("missing section for %s", rs->name);
r->xsym = rs;
+ // ld64 for arm seems to want the symbol table to contain offset
+ // into the section rather than pseudo virtual address that contains
+ // the section load address.
+ // we need to compensate that by removing the instruction's address
+ // from addend.
+ if(HEADTYPE == Hdarwin)
+ r->xadd -= symaddr(s) + r->off;
+
*val = braddoff((0xff000000U & (uint32)r->add),
(0xffffff & (uint32)(r->xadd / 4)));
return 0;
@@ -539,6 +586,8 @@ adddynlib(char *lib)
if(s->size == 0)
addstring(s, "");
elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ } else if(HEADTYPE == Hdarwin) {
+ machoadddynlib(lib);
} else {
diag("adddynlib: unsupported binary format");
}
@@ -547,7 +596,7 @@ adddynlib(char *lib)
void
asmb(void)
{
- uint32 symo;
+ uint32 symo, dwarfoff, machlink;
Section *sect;
LSym *sym;
int i;
@@ -583,6 +632,22 @@ asmb(void)
cseek(segdata.fileoff);
datblk(segdata.vaddr, segdata.filelen);
+ machlink = 0;
+ if(HEADTYPE == Hdarwin) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+ if(!debug['w']) { // TODO(minux): enable DWARF Support
+ dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
+ cseek(dwarfoff);
+
+ segdwarf.fileoff = cpos();
+ dwarfemitdebugsections();
+ segdwarf.filelen = cpos() - segdwarf.fileoff;
+ }
+ machlink = domacholink();
+ }
+
/* output symbol table */
symsize = 0;
lcsize = 0;
@@ -599,6 +664,9 @@ asmb(void)
case Hplan9:
symo = segdata.fileoff+segdata.filelen;
break;
+ case Hdarwin:
+ symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
+ break;
ElfSym:
symo = segdata.fileoff+segdata.filelen;
symo = rnd(symo, INITRND);
@@ -635,6 +703,10 @@ asmb(void)
cflush();
}
break;
+ case Hdarwin:
+ if(linkmode == LinkExternal)
+ machoemitreloc();
+ break;
}
}
@@ -646,14 +718,14 @@ asmb(void)
switch(HEADTYPE) {
default:
case Hplan9: /* plan 9 */
- LPUT(0x647); /* magic */
- LPUT(segtext.filelen); /* sizes */
- LPUT(segdata.filelen);
- LPUT(segdata.len - segdata.filelen);
- LPUT(symsize); /* nsyms */
- LPUT(entryvalue()); /* va of entry */
- LPUT(0L);
- LPUT(lcsize);
+ thearch.lput(0x647); /* magic */
+ thearch.lput(segtext.filelen); /* sizes */
+ thearch.lput(segdata.filelen);
+ thearch.lput(segdata.len - segdata.filelen);
+ thearch.lput(symsize); /* nsyms */
+ thearch.lput(entryvalue()); /* va of entry */
+ thearch.lput(0L);
+ thearch.lput(lcsize);
break;
case Hlinux:
case Hfreebsd:
@@ -662,6 +734,9 @@ asmb(void)
case Hnacl:
asmbelf(symo);
break;
+ case Hdarwin:
+ asmbmacho();
+ break;
}
cflush();
if(debug['c']){
@@ -673,18 +748,3 @@ asmb(void)
print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize);
}
}
-
-int32
-rnd(int32 v, int32 r)
-{
- int32 c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index f9cdc5bd7e..b32b89bb06 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -32,7 +32,6 @@
#include <libc.h>
#include <bio.h>
#include <link.h>
-#include "5.out.h"
enum
{
@@ -41,43 +40,14 @@ enum
IntSize = 4,
RegSize = 4,
MaxAlign = 8, // max data alignment
- FuncAlign = 4 // single-instruction alignment
+ FuncAlign = 4, // single-instruction alignment
+ MINLC = 4,
};
#ifndef EXTERN
#define EXTERN extern
#endif
-#define P ((Prog*)0)
-#define S ((LSym*)0)
-
-enum
-{
-/* mark flags */
- FOLL = 1<<0,
- LABEL = 1<<1,
- LEAF = 1<<2,
-
- MINLC = 4,
-};
-
-EXTERN int32 autosize;
-EXTERN LSym* datap;
-EXTERN int debug[128];
-EXTERN char* noname;
-EXTERN Prog* lastp;
-EXTERN int32 lcsize;
-EXTERN char literal[32];
-EXTERN int nerrors;
-EXTERN int32 instoffset;
-EXTERN char* rpath;
-EXTERN uint32 stroffset;
-EXTERN int32 symsize;
-EXTERN int armsize;
-
-#pragma varargck type "I" uint32*
-
-int Iconv(Fmt *fp);
void adddynlib(char *lib);
void adddynrel(LSym *s, Reloc *r);
void adddynrela(LSym *rel, LSym *s, Reloc *r);
@@ -89,13 +59,6 @@ int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);
void listinit(void);
int machoreloc1(Reloc *r, vlong sectoff);
-void main(int argc, char *argv[]);
-int32 rnd(int32 v, int32 r);
-
-/* Native is little-endian */
-#define LPUT(a) lputl(a)
-#define WPUT(a) wputl(a)
-#define VPUT(a) abort()
/* Used by ../ld/dwarf.c */
enum
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
index 875fc3e6b2..d4cc8acd7c 100644
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -37,34 +37,4 @@ void
listinit(void)
{
listinit5();
- fmtinstall('I', Iconv);
-}
-
-int
-Iconv(Fmt *fp)
-{
- int i, n;
- uint32 *p;
- char *s;
- Fmt fmt;
-
- n = fp->prec;
- fp->prec = 0;
- if(!(fp->flags&FmtPrec) || n < 0)
- return fmtstrcpy(fp, "%I");
- fp->flags &= ~FmtPrec;
- p = va_arg(fp->args, uint32*);
-
- // format into temporary buffer and
- // call fmtstrcpy to handle padding.
- fmtstrinit(&fmt);
- for(i=0; i<n/4; i++) {
- if(i > 0)
- fmtprint(&fmt, " ");
- fmtprint(&fmt, "%.8ux", *p++);
- }
- s = fmtstrflush(&fmt);
- fmtstrcpy(fp, s);
- free(s);
- return 0;
}
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index c6f60ee7c8..a7bd0f45ea 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -33,15 +33,55 @@
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/macho.h"
#include "../ld/dwarf.h"
#include <ar.h>
-char *thestring = "arm";
-LinkArch *thelinkarch = &linkarm;
+void
+main(int argc, char **argv)
+{
+ linkarchinit();
+ ldmain(argc, argv);
+}
+
void
linkarchinit(void)
{
+ thestring = "arm";
+ thelinkarch = &linkarm;
+
+ thearch.thechar = thechar;
+ thearch.ptrsize = thelinkarch->ptrsize;
+ thearch.intsize = thelinkarch->ptrsize;
+ thearch.regsize = thelinkarch->regsize;
+ thearch.funcalign = FuncAlign;
+ thearch.maxalign = MaxAlign;
+ thearch.minlc = MINLC;
+ thearch.dwarfregsp = DWARFREGSP;
+
+ thearch.adddynlib = adddynlib;
+ thearch.adddynrel = adddynrel;
+ thearch.adddynsym = adddynsym;
+ thearch.archinit = archinit;
+ thearch.archreloc = archreloc;
+ thearch.archrelocvariant = archrelocvariant;
+ thearch.asmb = asmb;
+ thearch.elfreloc1 = elfreloc1;
+ thearch.elfsetupplt = elfsetupplt;
+ thearch.gentext = gentext;
+ thearch.listinit = listinit;
+ thearch.machoreloc1 = machoreloc1;
+ thearch.lput = lputl;
+ thearch.wput = wputl;
+ thearch.vput = vputl;
+
+ thearch.linuxdynld = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
+ thearch.freebsddynld = "/usr/libexec/ld-elf.so.1";
+ thearch.openbsddynld = "XXX";
+ thearch.netbsddynld = "/libexec/ld.elf_so";
+ thearch.dragonflydynld = "XXX";
+ thearch.solarisdynld = "XXX";
}
void
@@ -64,6 +104,7 @@ archinit(void)
case Hlinux:
case Hfreebsd:
case Hnacl:
+ case Hdarwin:
break;
}
@@ -104,6 +145,17 @@ archinit(void)
if(INITRND == -1)
INITRND = 0x10000;
break;
+ case Hdarwin: /* apple MACH */
+ debug['w'] = 1; // disable DWARF generataion
+ machoinit();
+ HEADR = INITIAL_MACHO_HEADR;
+ if(INITTEXT == -1)
+ INITTEXT = 4096+HEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4096;
+ break;
}
if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%ux is ignored because of -R0x%ux\n",
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index d1645cc568..77ab2d2167 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -790,7 +790,7 @@ agenr(Node *n, Node *a, Node *res)
void
agen(Node *n, Node *res)
{
- Node *nl, *nr;
+ Node *nl;
Node n1, n2;
if(debug['g']) {
@@ -827,8 +827,6 @@ agen(Node *n, Node *res)
}
nl = n->left;
- nr = n->right;
- USED(nr);
switch(n->op) {
default:
@@ -1065,17 +1063,7 @@ bgen(Node *n, int true, int likely, Prog *to)
switch(n->op) {
default:
- def:
- regalloc(&n1, n->type, N);
- cgen(n, &n1);
- nodconst(&n2, n->type, 0);
- gins(optoas(OCMP, n->type), &n1, &n2);
- a = AJNE;
- if(!true)
- a = AJEQ;
- patch(gbranch(a, n->type, likely), to);
- regfree(&n1);
- goto ret;
+ goto def;
case OLITERAL:
// need to ask if it is bool?
@@ -1095,27 +1083,20 @@ bgen(Node *n, int true, int likely, Prog *to)
goto ret;
case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- p1 = gbranch(AJMP, T, 0);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- bgen(n->left, !true, -likely, p2);
- bgen(n->right, !true, -likely, p2);
- p1 = gbranch(AJMP, T, 0);
- patch(p1, to);
- patch(p2, pc);
- goto ret;
-
case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bgen(n->left, true, likely, to);
- bgen(n->right, true, likely, to);
+ if((n->op == OANDAND) == true) {
+ p1 = gbranch(AJMP, T, 0);
+ p2 = gbranch(AJMP, T, 0);
+ patch(p1, pc);
+ bgen(n->left, !true, -likely, p2);
+ bgen(n->right, !true, -likely, p2);
+ p1 = gbranch(AJMP, T, 0);
+ patch(p1, to);
+ patch(p2, pc);
+ } else {
+ bgen(n->left, true, likely, to);
+ bgen(n->right, true, likely, to);
+ }
goto ret;
case OEQ:
@@ -1273,6 +1254,18 @@ bgen(Node *n, int true, int likely, Prog *to)
}
goto ret;
+def:
+ regalloc(&n1, n->type, N);
+ cgen(n, &n1);
+ nodconst(&n2, n->type, 0);
+ gins(optoas(OCMP, n->type), &n1, &n2);
+ a = AJNE;
+ if(!true)
+ a = AJEQ;
+ patch(gbranch(a, n->type, likely), to);
+ regfree(&n1);
+ goto ret;
+
ret:
;
}
@@ -1390,22 +1383,25 @@ sgen(Node *n, Node *ns, int64 w)
return;
}
+ nodreg(&noddi, types[tptr], REG_DI);
+ nodreg(&nodsi, types[tptr], REG_SI);
+
if(n->ullman >= ns->ullman) {
- agenr(n, &nodr, N);
+ agenr(n, &nodr, &nodsi);
if(ns->op == ONAME)
gvardef(ns);
- agenr(ns, &nodl, N);
+ agenr(ns, &nodl, &noddi);
} else {
if(ns->op == ONAME)
gvardef(ns);
- agenr(ns, &nodl, N);
- agenr(n, &nodr, N);
+ agenr(ns, &nodl, &noddi);
+ agenr(n, &nodr, &nodsi);
}
- nodreg(&noddi, types[tptr], REG_DI);
- nodreg(&nodsi, types[tptr], REG_SI);
- gmove(&nodl, &noddi);
- gmove(&nodr, &nodsi);
+ if(nodl.val.u.reg != REG_DI)
+ gmove(&nodl, &noddi);
+ if(nodr.val.u.reg != REG_SI)
+ gmove(&nodr, &nodsi);
regfree(&nodl);
regfree(&nodr);
@@ -1454,6 +1450,18 @@ sgen(Node *n, Node *ns, int64 w)
p->to.sym = linksym(pkglookup("duffcopy", runtimepkg));
// 14 and 128 = magic constants: see ../../runtime/asm_amd64.s
p->to.offset = 14*(128-q);
+ } else if(!nacl && c == 0) {
+ // We don't need the MOVSQ side-effect of updating SI and DI,
+ // and issuing a sequence of MOVQs directly is faster.
+ nodsi.op = OINDREG;
+ noddi.op = OINDREG;
+ while(q > 0) {
+ gmove(&nodsi, &cx); // MOVQ x+(SI),CX
+ gmove(&cx, &noddi); // MOVQ CX,x+(DI)
+ nodsi.xoffset += 8;
+ noddi.xoffset += 8;
+ q--;
+ }
} else
while(q > 0) {
gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+
@@ -1468,24 +1476,29 @@ sgen(Node *n, Node *ns, int64 w)
} else if(w < 8 || c <= 4) {
nodsi.op = OINDREG;
noddi.op = OINDREG;
+ cx.type = types[TINT32];
nodsi.type = types[TINT32];
noddi.type = types[TINT32];
if(c > 4) {
nodsi.xoffset = 0;
noddi.xoffset = 0;
- gmove(&nodsi, &noddi);
+ gmove(&nodsi, &cx);
+ gmove(&cx, &noddi);
}
nodsi.xoffset = c-4;
noddi.xoffset = c-4;
- gmove(&nodsi, &noddi);
+ gmove(&nodsi, &cx);
+ gmove(&cx, &noddi);
} else {
nodsi.op = OINDREG;
noddi.op = OINDREG;
+ cx.type = types[TINT64];
nodsi.type = types[TINT64];
noddi.type = types[TINT64];
nodsi.xoffset = c-8;
noddi.xoffset = c-8;
- gmove(&nodsi, &noddi);
+ gmove(&nodsi, &cx);
+ gmove(&cx, &noddi);
}
}
@@ -1519,7 +1532,7 @@ cadable(Node *n)
int
componentgen(Node *nr, Node *nl)
{
- Node nodl, nodr;
+ Node nodl, nodr, tmp;
Type *t;
int freel, freer;
vlong fldcount;
@@ -1567,7 +1580,7 @@ componentgen(Node *nr, Node *nl)
nodl = *nl;
if(!cadable(nl)) {
- if(nr == N || !cadable(nr))
+ if(nr != N && !cadable(nr))
goto no;
igen(nl, &nodl, N);
freel = 1;
@@ -1579,6 +1592,12 @@ componentgen(Node *nr, Node *nl)
igen(nr, &nodr, N);
freer = 1;
}
+ } else {
+ // When zeroing, prepare a register containing zero.
+ nodconst(&tmp, nl->type, 0);
+ regalloc(&nodr, types[TUINT], N);
+ gmove(&tmp, &nodr);
+ freer = 1;
}
// nl and nr are 'cadable' which basically means they are names (variables) now.
@@ -1615,8 +1634,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
@@ -1625,8 +1643,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_cap-Array_nel;
@@ -1635,8 +1652,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_cap-Array_nel;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
goto yes;
@@ -1650,8 +1666,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
@@ -1660,8 +1675,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
goto yes;
@@ -1675,8 +1689,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
@@ -1685,8 +1698,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
goto yes;
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
index 83833e189b..fa9998b0ee 100644
--- a/src/cmd/6g/galign.c
+++ b/src/cmd/6g/galign.c
@@ -15,9 +15,9 @@ linkarchinit(void)
{
if(strcmp(getgoarch(), "amd64p32") == 0) {
thelinkarch = &linkamd64p32;
- arch.thelinkarch = thelinkarch;
+ thearch.thelinkarch = thelinkarch;
thestring = "amd64p32";
- arch.thestring = "amd64p32";
+ thearch.thestring = "amd64p32";
}
}
@@ -65,61 +65,46 @@ betypeinit(void)
void
main(int argc, char **argv)
{
- arch.thechar = thechar;
- arch.thestring = thestring;
- arch.thelinkarch = thelinkarch;
- arch.typedefs = typedefs;
- arch.MAXWIDTH = MAXWIDTH;
- arch.afunclit = afunclit;
- arch.anyregalloc = anyregalloc;
- arch.betypeinit = betypeinit;
- arch.bgen = bgen;
- arch.cgen = cgen;
- arch.cgen_asop = cgen_asop;
- arch.cgen_call = cgen_call;
- arch.cgen_callinter = cgen_callinter;
- arch.cgen_ret = cgen_ret;
- arch.clearfat = clearfat;
- arch.clearp = clearp;
- arch.defframe = defframe;
- arch.dgostringptr = dgostringptr;
- arch.dgostrlitptr = dgostrlitptr;
- arch.dsname = dsname;
- arch.dsymptr = dsymptr;
- arch.dumpdata = dumpdata;
- arch.dumpit = dumpit;
- arch.excise = excise;
- arch.expandchecks = expandchecks;
- arch.fixautoused = fixautoused;
- arch.gclean = gclean;
- arch.gdata = gdata;
- arch.gdatacomplex = gdatacomplex;
- arch.gdatastring = gdatastring;
- arch.ggloblnod = ggloblnod;
- arch.ggloblsym = ggloblsym;
- arch.ginit = ginit;
- arch.gins = gins;
- arch.ginscall = ginscall;
- arch.gjmp = gjmp;
- arch.gtrack = gtrack;
- arch.gused = gused;
- arch.igen = igen;
- arch.isfat = isfat;
- arch.linkarchinit = linkarchinit;
- arch.markautoused = markautoused;
- arch.naddr = naddr;
- arch.newplist = newplist;
- arch.nodarg = nodarg;
- arch.patch = patch;
- arch.proginfo = proginfo;
- arch.regalloc = regalloc;
- arch.regfree = regfree;
- arch.regopt = regopt;
- arch.regtyp = regtyp;
- arch.sameaddr = sameaddr;
- arch.smallindir = smallindir;
- arch.stackaddr = stackaddr;
- arch.unpatch = unpatch;
+ thearch.thechar = thechar;
+ thearch.thestring = thestring;
+ thearch.thelinkarch = thelinkarch;
+ thearch.typedefs = typedefs;
+ thearch.REGSP = REGSP;
+ thearch.REGCTXT = REGCTXT;
+ thearch.MAXWIDTH = MAXWIDTH;
+ thearch.anyregalloc = anyregalloc;
+ thearch.betypeinit = betypeinit;
+ thearch.bgen = bgen;
+ thearch.cgen = cgen;
+ thearch.cgen_call = cgen_call;
+ thearch.cgen_callinter = cgen_callinter;
+ thearch.cgen_ret = cgen_ret;
+ thearch.clearfat = clearfat;
+ thearch.defframe = defframe;
+ thearch.excise = excise;
+ thearch.expandchecks = expandchecks;
+ thearch.gclean = gclean;
+ thearch.ginit = ginit;
+ thearch.gins = gins;
+ thearch.ginscall = ginscall;
+ thearch.igen = igen;
+ thearch.linkarchinit = linkarchinit;
+ thearch.peep = peep;
+ thearch.proginfo = proginfo;
+ thearch.regalloc = regalloc;
+ thearch.regfree = regfree;
+ thearch.regtyp = regtyp;
+ thearch.sameaddr = sameaddr;
+ thearch.smallindir = smallindir;
+ thearch.stackaddr = stackaddr;
+ thearch.excludedregs = excludedregs;
+ thearch.RtoB = RtoB;
+ thearch.FtoB = FtoB;
+ thearch.BtoR = BtoR;
+ thearch.BtoF = BtoF;
+ thearch.optoas = optoas;
+ thearch.doregbits = doregbits;
+ thearch.regnames = regnames;
gcmain(argc, argv);
}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index 7a09f673ef..a6dfad9c8e 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -9,10 +9,7 @@
#include "../gc/go.h"
#include "../6l/6.out.h"
-EXTERN int32 dynloc;
EXTERN uchar reg[MAXREG];
-EXTERN int32 pcloc; // instruction counter
-EXTERN Strlit emptystring;
EXTERN Node* panicdiv;
extern vlong unmappedzero;
extern int addptr;
@@ -117,7 +114,6 @@ int anyregalloc(void);
void betypeinit(void);
void bgen(Node*, int, int, Prog*);
void cgen(Node*, Node*);
-void cgen_asop(Node*);
void cgen_call(Node*, int);
void cgen_callinter(Node*, Node*, int);
void cgen_ret(Node*);
@@ -163,3 +159,18 @@ int smallindir(Addr*, Addr*);
int stackaddr(Addr*);
Prog* unpatch(Prog*);
+/*
+ * reg.c
+ */
+uint64 excludedregs(void);
+uint64 RtoB(int);
+uint64 FtoB(int);
+int BtoR(uint64);
+int BtoF(uint64);
+uint64 doregbits(int);
+char** regnames(int*);
+
+/*
+ * peep.c
+ */
+void peep(Prog*);
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 9f4b4d4ae3..72104589a3 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -7,7 +7,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
static Prog *appendpp(Prog*, int, int, int, vlong, int, int, vlong);
static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
@@ -115,52 +115,6 @@ appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int tre
return q;
}
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
- for (; p; p = p->link) {
- if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
- continue;
-
- if (p->from.node)
- ((Node*)(p->from.node))->used = 1;
-
- if (p->to.node)
- ((Node*)(p->to.node))->used = 1;
- }
-}
-
-// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
-void
-fixautoused(Prog *p)
-{
- Prog **lp;
-
- for (lp=&p; (p=*lp) != P; ) {
- if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
- *lp = p->link;
- continue;
- }
- if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
- // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
- // VARDEFs are interspersed with other code, and a jump might be using the
- // VARDEF as a target. Replace with a no-op instead. A later pass will remove
- // the no-ops.
- nopout(p);
- continue;
- }
- if (p->from.name == NAME_AUTO && p->from.node)
- p->from.offset += ((Node*)(p->from.node))->stkdelta;
-
- if (p->to.name == NAME_AUTO && p->to.node)
- p->to.offset += ((Node*)(p->to.node))->stkdelta;
-
- lp = &p->link;
- }
-}
-
-
/*
* generate:
* call f
@@ -478,159 +432,6 @@ cgen_ret(Node *n)
}
/*
- * generate += *= etc.
- */
-void
-cgen_asop(Node *n)
-{
- Node n1, n2, n3, n4;
- Node *nl, *nr;
- Prog *p1;
- Addr addr;
- int a;
-
- nl = n->left;
- nr = n->right;
-
- if(nr->ullman >= UINF && nl->ullman >= UINF) {
- tempname(&n1, nr->type);
- cgen(nr, &n1);
- n2 = *n;
- n2.right = &n1;
- cgen_asop(&n2);
- goto ret;
- }
-
- if(!isint[nl->type->etype])
- goto hard;
- if(!isint[nr->type->etype])
- goto hard;
-
- switch(n->etype) {
- case OADD:
- if(smallintconst(nr))
- if(mpgetfix(nr->val.u.xval) == 1) {
- a = optoas(OINC, nl->type);
- if(nl->addable) {
- gins(a, N, nl);
- goto ret;
- }
- if(sudoaddable(a, nl, &addr)) {
- p1 = gins(a, N, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- }
- break;
-
- case OSUB:
- if(smallintconst(nr))
- if(mpgetfix(nr->val.u.xval) == 1) {
- a = optoas(ODEC, nl->type);
- if(nl->addable) {
- gins(a, N, nl);
- goto ret;
- }
- if(sudoaddable(a, nl, &addr)) {
- p1 = gins(a, N, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- }
- break;
- }
-
- switch(n->etype) {
- case OADD:
- case OSUB:
- case OXOR:
- case OAND:
- case OOR:
- a = optoas(n->etype, nl->type);
- if(nl->addable) {
- if(smallintconst(nr)) {
- gins(a, nr, nl);
- goto ret;
- }
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- gins(a, &n2, nl);
- regfree(&n2);
- goto ret;
- }
- if(nr->ullman < UINF)
- if(sudoaddable(a, nl, &addr)) {
- if(smallintconst(nr)) {
- p1 = gins(a, nr, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- p1 = gins(a, &n2, N);
- p1->to = addr;
- regfree(&n2);
- sudoclean();
- goto ret;
- }
- }
-
-hard:
- n2.op = 0;
- n1.op = 0;
- if(nr->op == OLITERAL) {
- // don't allocate a register for literals.
- } else if(nr->ullman >= nl->ullman || nl->addable) {
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- nr = &n2;
- } else {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- if(!nl->addable) {
- igen(nl, &n1, N);
- nl = &n1;
- }
-
- n3 = *n;
- n3.left = nl;
- n3.right = nr;
- n3.op = n->etype;
-
- regalloc(&n4, nl->type, N);
- cgen(&n3, &n4);
- gmove(&n4, nl);
-
- if(n1.op)
- regfree(&n1);
- if(n2.op == OREGISTER)
- regfree(&n2);
- regfree(&n4);
-
-ret:
- ;
-}
-
-int
-samereg(Node *a, Node *b)
-{
- if(a == N || b == N)
- return 0;
- if(a->op != OREGISTER)
- return 0;
- if(b->op != OREGISTER)
- return 0;
- if(a->val.u.reg != b->val.u.reg)
- return 0;
- return 1;
-}
-
-/*
* generate division.
* generates one of:
* res = nl / nr
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
deleted file mode 100644
index 33ee4d65c4..0000000000
--- a/src/cmd/6g/gobj.c
+++ /dev/null
@@ -1,244 +0,0 @@
-// Derived from Inferno utils/6c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int
-dsname(Sym *s, int off, char *t, int n)
-{
- Prog *p;
-
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.offset = off;
- p->from.sym = linksym(s);
- p->from3.type = TYPE_CONST;
- p->from3.offset = n;
-
- p->to.type = TYPE_SCONST;
- memmove(p->to.u.sval, t, n);
- return off + n;
-}
-
-/*
- * make a refer to the data s, s+len
- * emitting DATA if needed.
- */
-void
-datastring(char *s, int len, Addr *a)
-{
- Sym *sym;
-
- sym = stringsym(s, len);
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- a->sym = linksym(sym);
- a->node = sym->def;
- a->offset = widthptr+widthint; // skip header
- a->etype = simtype[TINT];
-}
-
-/*
- * make a refer to the string sval,
- * emitting DATA if needed.
- */
-void
-datagostring(Strlit *sval, Addr *a)
-{
- Sym *sym;
-
- sym = stringsym(sval->s, sval->len);
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- a->sym = linksym(sym);
- a->node = sym->def;
- a->offset = 0; // header
- a->etype = TSTRING;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
- Prog *p;
-
- if(nr->op == OLITERAL) {
- switch(nr->val.ctype) {
- case CTCPLX:
- gdatacomplex(nam, nr->val.u.cval);
- return;
- case CTSTR:
- gdatastring(nam, nr->val.u.sval);
- return;
- }
- }
- p = gins(ADATA, nam, nr);
- p->from3.type = TYPE_CONST;
- p->from3.offset = wid;
-}
-
-void
-gdatacomplex(Node *nam, Mpcplx *cval)
-{
- Prog *p;
- int w;
-
- w = cplxsubtype(nam->type->etype);
- w = types[w]->width;
-
- p = gins(ADATA, nam, N);
- p->from3.type = TYPE_CONST;
- p->from3.offset = w;
- p->to.type = TYPE_FCONST;
- p->to.u.dval = mpgetflt(&cval->real);
-
- p = gins(ADATA, nam, N);
- p->from3.type = TYPE_CONST;
- p->from3.offset = w;
- p->from.offset += w;
- p->to.type = TYPE_FCONST;
- p->to.u.dval = mpgetflt(&cval->imag);
-}
-
-void
-gdatastring(Node *nam, Strlit *sval)
-{
- Prog *p;
- Node nod1;
-
- p = gins(ADATA, nam, N);
- datastring(sval->s, sval->len, &p->to);
- p->from3.type = TYPE_CONST;
- p->from3.offset = types[tptr]->width;
- p->to.type = TYPE_ADDR;
-//print("%P\n", p);
-
- nodconst(&nod1, types[TINT], sval->len);
- p = gins(ADATA, nam, &nod1);
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthint;
- p->from.offset += widthptr;
-}
-
-int
-dstringptr(Sym *s, int off, char *str)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
-
- datastring(str, strlen(str)+1, &p->to);
- p->to.type = TYPE_ADDR;
- p->to.etype = simtype[TINT];
- off += widthptr;
-
- return off;
-}
-
-int
-dgostrlitptr(Sym *s, int off, Strlit *lit)
-{
- Prog *p;
-
- if(lit == nil)
- return duintptr(s, off, 0);
-
- off = rnd(off, widthptr);
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
- datagostring(lit, &p->to);
- p->to.type = TYPE_ADDR;
- p->to.etype = simtype[TINT];
- off += widthptr;
-
- return off;
-}
-
-int
-dgostringptr(Sym *s, int off, char *str)
-{
- int n;
- Strlit *lit;
-
- if(str == nil)
- return duintptr(s, off, 0);
-
- n = strlen(str);
- lit = mal(sizeof *lit + n);
- strcpy(lit->s, str);
- lit->len = n;
- return dgostrlitptr(s, off, lit);
-}
-
-int
-dsymptr(Sym *s, int off, Sym *x, int xoff)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
-
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
- p->to.type = TYPE_ADDR;
- p->to.name = NAME_EXTERN;
- p->to.sym = linksym(x);
- p->to.offset = xoff;
- off += widthptr;
-
- return off;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from = zprog.from;
- p->to = zprog.to;
-}
-
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 697016c6f3..55d3425081 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -37,225 +37,6 @@
// the text segment up higher in 6l for all GOOS.
// At the same time, can raise StackBig in ../../runtime/stack.h.
vlong unmappedzero = 4096;
-
-void
-clearp(Prog *p)
-{
- p->as = AEND;
- p->from.type = TYPE_NONE;
- p->from.index = TYPE_NONE;
- p->to.type = TYPE_NONE;
- p->to.index = TYPE_NONE;
- p->pc = pcloc;
- pcloc++;
-}
-
-static int ddumped;
-static Prog *dfirst;
-static Prog *dpc;
-
-/*
- * generate and return proc with p->as = as,
- * linked into program. pc is next instruction.
- */
-Prog*
-prog(int as)
-{
- Prog *p;
-
- if(as == ADATA || as == AGLOBL) {
- if(ddumped)
- fatal("already dumped data");
- if(dpc == nil) {
- dpc = mal(sizeof(*dpc));
- dfirst = dpc;
- }
- p = dpc;
- dpc = mal(sizeof(*dpc));
- p->link = dpc;
- } else {
- p = pc;
- pc = mal(sizeof(*pc));
- clearp(pc);
- p->link = pc;
- }
-
- if(lineno == 0) {
- if(debug['K'])
- warn("prog: line 0");
- }
-
- p->as = as;
- p->lineno = lineno;
- return p;
-}
-
-void
-dumpdata(void)
-{
- ddumped = 1;
- if(dfirst == nil)
- return;
- newplist();
- *pc = *dfirst;
- pc = dpc;
- clearp(pc);
-}
-
-/*
- * generate a branch.
- * t is ignored.
- * likely values are for branch prediction:
- * -1 unlikely
- * 0 no opinion
- * +1 likely
- */
-Prog*
-gbranch(int as, Type *t, int likely)
-{
- Prog *p;
-
- USED(t);
-
- p = prog(as);
- p->to.type = TYPE_BRANCH;
- p->to.u.branch = P;
- if(as != AJMP && likely != 0) {
- p->from.type = TYPE_CONST;
- p->from.offset = likely > 0;
- }
- return p;
-}
-
-/*
- * patch previous branch to jump to to.
- */
-void
-patch(Prog *p, Prog *to)
-{
- if(p->to.type != TYPE_BRANCH)
- fatal("patch: not a branch");
- p->to.u.branch = to;
- p->to.offset = to->pc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
- Prog *q;
-
- if(p->to.type != TYPE_BRANCH)
- fatal("unpatch: not a branch");
- q = p->to.u.branch;
- p->to.u.branch = P;
- p->to.offset = 0;
- return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
- Plist *pl;
-
- pl = linknewplist(ctxt);
-
- pc = mal(sizeof(*pc));
- clearp(pc);
- pl->firstpc = pc;
-
- return pl;
-}
-
-void
-gused(Node *n)
-{
- gins(ANOP, n, N); // used
-}
-
-Prog*
-gjmp(Prog *to)
-{
- Prog *p;
-
- p = gbranch(AJMP, T, 0);
- if(to != P)
- patch(p, to);
- return p;
-}
-
-void
-ggloblnod(Node *nam)
-{
- Prog *p;
-
- p = gins(AGLOBL, nam, N);
- p->lineno = nam->lineno;
- p->from.sym->gotype = linksym(ngotype(nam));
- p->to.sym = nil;
- p->to.type = TYPE_CONST;
- p->to.offset = nam->type->width;
- if(nam->readonly)
- p->from3.offset = RODATA;
- if(nam->type != T && !haspointers(nam->type))
- p->from3.offset |= NOPTR;
-}
-
-void
-gtrack(Sym *s)
-{
- Prog *p;
-
- p = gins(AUSEFIELD, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
-}
-
-void
-ggloblsym(Sym *s, int32 width, int8 flags)
-{
- Prog *p;
-
- p = gins(AGLOBL, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->to.type = TYPE_CONST;
- p->to.offset = width;
- p->from3.offset = flags;
-}
-
-int
-isfat(Type *t)
-{
- if(t != T)
- switch(t->etype) {
- case TSTRUCT:
- case TARRAY:
- case TSTRING:
- case TINTER: // maybe remove later
- return 1;
- }
- return 0;
-}
-
-/*
- * naddr of func generates code for address of func.
- * if using opcode that can take address implicitly,
- * call afunclit to fix up the argument.
- */
-void
-afunclit(Addr *a, Node *n)
-{
- if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
- a->type = TYPE_MEM;
- a->sym = linksym(n->sym);
- }
-}
-
static int resvd[] =
{
REG_DI, // for movstring
@@ -314,7 +95,7 @@ gclean(void)
yyerror("reg %R left allocated\n", i);
}
-int32
+int
anyregalloc(void)
{
int i, j;
@@ -422,105 +203,6 @@ regfree(Node *n)
}
/*
- * initialize n to be register r of type t.
- */
-void
-nodreg(Node *n, Type *t, int r)
-{
- if(t == T)
- fatal("nodreg: t nil");
-
- memset(n, 0, sizeof(*n));
- n->op = OREGISTER;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.reg = r;
- n->type = t;
-}
-
-/*
- * initialize n to be indirect of register r; n is type t.
- */
-void
-nodindreg(Node *n, Type *t, int r)
-{
- nodreg(n, t, r);
- n->op = OINDREG;
-}
-
-Node*
-nodarg(Type *t, int fp)
-{
- Node *n;
- NodeList *l;
- Type *first;
- Iter savet;
-
- // entire argument struct, not just one arg
- if(t->etype == TSTRUCT && t->funarg) {
- n = nod(ONAME, N, N);
- n->sym = lookup(".args");
- n->type = t;
- first = structfirst(&savet, &t);
- if(first == nil)
- fatal("nodarg: bad struct");
- if(first->width == BADWIDTH)
- fatal("nodarg: offset not computed for %T", t);
- n->xoffset = first->width;
- n->addable = 1;
- goto fp;
- }
-
- if(t->etype != TFIELD)
- fatal("nodarg: not field %T", t);
-
- if(fp == 1) {
- for(l=curfn->dcl; l; l=l->next) {
- n = l->n;
- if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
- return n;
- }
- }
-
- n = nod(ONAME, N, N);
- n->type = t->type;
- n->sym = t->sym;
-
- if(t->width == BADWIDTH)
- fatal("nodarg: offset not computed for %T", t);
- n->xoffset = t->width;
- n->addable = 1;
- n->orig = t->nname;
-
-fp:
- // Rewrite argument named _ to __,
- // or else the assignment to _ will be
- // discarded during code generation.
- if(isblank(n))
- n->sym = lookup("__");
-
- switch(fp) {
- case 0: // output arg
- n->op = OINDREG;
- n->val.u.reg = REG_SP;
- break;
-
- case 1: // input arg
- n->class = PPARAM;
- break;
-
- case 2: // offset output arg
-fatal("shouldn't be used");
- n->op = OINDREG;
- n->val.u.reg = REG_SP;
- n->xoffset += types[tptr]->width;
- break;
- }
- n->typecheck = 1;
- return n;
-}
-
-/*
* generate
* as $c, reg
*/
@@ -577,27 +259,6 @@ ginscon(int as, vlong c, Node *n2)
/*c2go int CASE(int, int); */
/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
- switch(n->op) {
- case OITAB:
- case OSPTR:
- case OLEN:
- case OCAP:
- case OINDREG:
- case ONAME:
- case OPARAM:
- case OCLOSUREVAR:
- case OADDR:
- return 1;
- }
- return 0;
-}
-
-/*
* set up nodes representing 2^63
*/
Node bigi;
@@ -1112,213 +773,6 @@ fixlargeoffset(Node *n)
}
/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
- Sym *s;
-
- a->scale = 0;
- a->reg = REG_NONE;
- a->index = REG_NONE;
- a->type = TYPE_NONE;
- a->name = NAME_NONE;
- a->gotype = nil;
- a->node = N;
- a->width = 0;
- if(n == N)
- return;
-
- if(n->type != T && n->type->etype != TIDEAL) {
- dowidth(n->type);
- a->width = n->type->width;
- }
-
- switch(n->op) {
- default:
- fatal("naddr: bad %O %D", n->op, a);
- break;
-
- case OREGISTER:
- a->type = TYPE_REG;
- a->reg = n->val.u.reg;
- a->sym = nil;
- break;
-
- case OINDREG:
- a->type = TYPE_MEM;
- a->reg = n->val.u.reg;
- a->sym = linksym(n->sym);
- a->offset = n->xoffset;
- if(a->offset != (int32)a->offset)
- yyerror("offset %lld too large for OINDREG", a->offset);
- break;
-
- case OPARAM:
- // n->left is PHEAP ONAME for stack parameter.
- // compute address of actual parameter on stack.
- a->etype = simtype[n->left->type->etype];
- a->width = n->left->type->width;
- a->offset = n->xoffset;
- a->sym = linksym(n->left->sym);
- a->type = TYPE_MEM;
- a->name = NAME_PARAM;
- a->node = n->left->orig;
- break;
-
- case OCLOSUREVAR:
- if(!curfn->needctxt)
- fatal("closurevar without needctxt");
- a->type = TYPE_MEM;
- a->reg = REG_DX;
- a->sym = nil;
- a->offset = n->xoffset;
- break;
-
- case OCFUNC:
- naddr(n->left, a, canemitcode);
- a->sym = linksym(n->left->sym);
- break;
-
- case ONAME:
- a->etype = 0;
- if(n->type != T)
- a->etype = simtype[n->type->etype];
- a->offset = n->xoffset;
- s = n->sym;
- a->node = n->orig;
- //if(a->node >= (Node*)&n)
- // fatal("stack node");
- if(s == S)
- s = lookup(".noname");
- if(n->method) {
- if(n->type != T)
- if(n->type->sym != S)
- if(n->type->sym->pkg != nil)
- s = pkglookup(s->name, n->type->sym->pkg);
- }
-
- a->type = TYPE_MEM;
- switch(n->class) {
- default:
- fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
- case PEXTERN:
- a->name = NAME_EXTERN;
- break;
- case PAUTO:
- a->name = NAME_AUTO;
- break;
- case PPARAM:
- case PPARAMOUT:
- a->name = NAME_PARAM;
- break;
- case PFUNC:
- a->name = NAME_EXTERN;
- a->type = TYPE_ADDR;
- a->width = widthptr;
- s = funcsym(s);
- break;
- }
- a->sym = linksym(s);
- break;
-
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- fatal("naddr: const %lT", n->type);
- break;
- case CTFLT:
- a->type = TYPE_FCONST;
- a->u.dval = mpgetflt(n->val.u.fval);
- break;
- case CTINT:
- case CTRUNE:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = mpgetfix(n->val.u.xval);
- break;
- case CTSTR:
- datagostring(n->val.u.sval, a);
- break;
- case CTBOOL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = n->val.u.bval;
- break;
- case CTNIL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = 0;
- break;
- }
- break;
-
- case OADDR:
- naddr(n->left, a, canemitcode);
- a->width = widthptr;
- if(a->type != TYPE_MEM)
- fatal("naddr: OADDR %D", a);
- a->type = TYPE_ADDR;
- break;
-
- case OITAB:
- // itable of interface value
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // itab(nil)
- a->etype = tptr;
- a->width = widthptr;
- break;
-
- case OSPTR:
- // pointer in a string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // ptr(nil)
- a->etype = simtype[tptr];
- a->offset += Array_array;
- a->width = widthptr;
- break;
-
- case OLEN:
- // len of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // len(nil)
- a->etype = simtype[TUINT];
- a->offset += Array_nel;
- a->width = widthint;
- break;
-
- case OCAP:
- // cap of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // cap(nil)
- a->etype = simtype[TUINT];
- a->offset += Array_cap;
- a->width = widthint;
- break;
-
-// case OADD:
-// if(n->right->op == OLITERAL) {
-// v = n->right->vconst;
-// naddr(n->left, a, canemitcode);
-// } else
-// if(n->left->op == OLITERAL) {
-// v = n->left->vconst;
-// naddr(n->right, a, canemitcode);
-// } else
-// goto bad;
-// a->offset += v;
-// break;
-
- }
-}
-
-/*
* return Axxx for Oxxx on type t.
*/
int
@@ -1966,6 +1420,8 @@ sudoaddable(int as, Node *n, Addr *a)
if(n->type == T)
return 0;
+ memset(a, 0, sizeof *a);
+
switch(n->op) {
case OLITERAL:
if(!isconst(n, CTINT))
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
index e05a06087f..261cb6e0a1 100644
--- a/src/cmd/6g/peep.c
+++ b/src/cmd/6g/peep.c
@@ -31,7 +31,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
static void conprop(Flow *r);
static void elimshortmov(Graph *g);
@@ -44,9 +44,15 @@ static int copy1(Adr*, Adr*, Flow*, int);
static int copyas(Adr*, Adr*);
static int copyau(Adr*, Adr*);
static int copysub(Adr*, Adr*, Adr*, int);
+static int copyu(Prog*, Adr*, Adr*);
static uint32 gactive;
+enum
+{
+ exregoffset = REG_R15,
+};
+
// do we need the carry bit
static int
needc(Prog *p)
@@ -91,7 +97,7 @@ peep(Prog *firstp)
Prog *p, *p1;
int t;
- g = flowstart(firstp, sizeof(Flow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
gactive = 0;
@@ -737,7 +743,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f)
* 4 if set and used
* 0 otherwise (not touched)
*/
-int
+static int
copyu(Prog *p, Adr *v, Adr *s)
{
ProgInfo info;
@@ -761,7 +767,7 @@ copyu(Prog *p, Adr *v, Adr *s)
case ACALL:
if(REGEXT && v->type == TYPE_REG && v->reg <= REGEXT && v->reg > exregoffset)
return 2;
- if(REGARG >= 0 && v->type == TYPE_REG && v->reg == (uchar)REGARG)
+ if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG)
return 2;
if(v->type == p->from.type && v->reg == p->from.reg)
return 2;
@@ -776,7 +782,7 @@ copyu(Prog *p, Adr *v, Adr *s)
return 3;
case ATEXT:
- if(REGARG >= 0 && v->type == TYPE_REG && v->reg == (uchar)REGARG)
+ if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG)
return 3;
return 0;
}
diff --git a/src/cmd/6g/prog.c b/src/cmd/6g/prog.c
index 32d5256f8c..79b7911e5b 100644
--- a/src/cmd/6g/prog.c
+++ b/src/cmd/6g/prog.c
@@ -5,7 +5,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
// Matches real RtoB but can be used in global initializer.
#define RtoB(r) (1<<((r)-REG_AX))
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index 7db44245f1..e01f265a13 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -31,56 +31,11 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
-#define NREGVAR 32 /* 16 general + 16 floating */
-#define REGBITS ((uint64)0xffffffffull)
-/*c2go enum {
+enum {
NREGVAR = 32,
- REGBITS = 0xffffffff,
};
-*/
-
-static Reg* firstr;
-static int first = 1;
-
-int
-rcmp(const void *a1, const void *a2)
-{
- Rgn *p1, *p2;
- int c1, c2;
-
- p1 = (Rgn*)a1;
- p2 = (Rgn*)a2;
- c1 = p2->cost;
- c2 = p1->cost;
- if(c1 -= c2)
- return c1;
- return p2->varno - p1->varno;
-}
-
-static void
-setaddrs(Bits bit)
-{
- int i, n;
- Var *v;
- Node *node;
-
- while(bany(&bit)) {
- // convert each bit to a variable
- i = bnum(bit);
- node = var[i].node;
- n = var[i].name;
- biclr(&bit, i);
-
- // disable all pieces of that variable
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node && v->name == n)
- v->addr = 2;
- }
- }
-}
static char* regname[] = {
".AX",
@@ -117,471 +72,23 @@ static char* regname[] = {
".X15",
};
-static Node* regnodes[NREGVAR];
-
-static void walkvardef(Node *n, Reg *r, int active);
-
-void
-regopt(Prog *firstp)
-{
- Reg *r, *r1;
- Prog *p;
- Graph *g;
- ProgInfo info;
- int i, z, active;
- uint32 vreg;
- Bits bit;
-
- if(first) {
- fmtinstall('Q', Qconv);
- exregoffset = REG_R15;
- first = 0;
- }
-
- mergetemp(firstp);
-
- /*
- * control flow is more complicated in generated go code
- * than in generated c code. define pseudo-variables for
- * registers, so we have complete register usage information.
- */
- nvar = NREGVAR;
- memset(var, 0, NREGVAR*sizeof var[0]);
- for(i=0; i<NREGVAR; i++) {
- if(regnodes[i] == N)
- regnodes[i] = newname(lookup(regname[i]));
- var[i].node = regnodes[i];
- }
-
- regbits = RtoB(REG_SP);
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- ivar.b[z] = 0;
- ovar.b[z] = 0;
- }
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- g = flowstart(firstp, sizeof(Reg));
- if(g == nil) {
- for(i=0; i<nvar; i++)
- var[i].node->opt = nil;
- return;
- }
-
- firstr = (Reg*)g->start;
-
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- p = r->f.prog;
- if(p->as == AVARDEF || p->as == AVARKILL)
- continue;
- proginfo(&info, p);
-
- // Avoid making variables for direct-called functions.
- if(p->as == ACALL && p->to.type == TYPE_MEM && p->to.name == NAME_EXTERN)
- continue;
-
- r->use1.b[0] |= info.reguse | info.regindex;
- r->set.b[0] |= info.regset;
-
- bit = mkvar(r, &p->from);
- if(bany(&bit)) {
- if(info.flags & LeftAddr)
- setaddrs(bit);
- if(info.flags & LeftRead)
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
- if(info.flags & LeftWrite)
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- }
-
- bit = mkvar(r, &p->to);
- if(bany(&bit)) {
- if(info.flags & RightAddr)
- setaddrs(bit);
- if(info.flags & RightRead)
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- if(info.flags & RightWrite)
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- }
- }
-
- for(i=0; i<nvar; i++) {
- Var *v = var+i;
- if(v->addr) {
- bit = blsh(i);
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- }
-
- if(debug['R'] && debug['v'])
- print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
- i, v->addr, v->etype, v->width, v->node, v->offset);
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass1", &firstr->f, 1);
-
- /*
- * pass 2
- * find looping structure
- */
- flowrpo(g);
-
- if(debug['R'] && debug['v'])
- dumpit("pass2", &firstr->f, 1);
-
- /*
- * pass 2.5
- * iterate propagating fat vardef covering forward
- * r->act records vars with a VARDEF since the last CALL.
- * (r->act will be reused in pass 5 for something else,
- * but we'll be done with it by then.)
- */
- active = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- r->f.active = 0;
- r->act = zbits;
- }
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- p = r->f.prog;
- if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
- active++;
- walkvardef(p->to.node, r, active);
- }
- }
-
- /*
- * pass 3
- * iterate propagating usage
- * back until flow graph is complete
- */
-loop1:
- change = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->f.active = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- if(r->f.prog->as == ARET)
- prop(r, zbits, zbits);
-loop11:
- /* pick up unreachable code */
- i = 0;
- for(r = firstr; r != R; r = r1) {
- r1 = (Reg*)r->f.link;
- if(r1 && r1->f.active && !r->f.active) {
- prop(r, zbits, zbits);
- i = 1;
- }
- }
- if(i)
- goto loop11;
- if(change)
- goto loop1;
-
- if(debug['R'] && debug['v'])
- dumpit("pass3", &firstr->f, 1);
-
- /*
- * pass 4
- * iterate propagating register/variable synchrony
- * forward until graph is complete
- */
-loop2:
- change = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->f.active = 0;
- synch(firstr, zbits);
- if(change)
- goto loop2;
-
- if(debug['R'] && debug['v'])
- dumpit("pass4", &firstr->f, 1);
-
- /*
- * pass 4.5
- * move register pseudo-variables into regu.
- */
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
-
- r->set.b[0] &= ~REGBITS;
- r->use1.b[0] &= ~REGBITS;
- r->use2.b[0] &= ~REGBITS;
- r->refbehind.b[0] &= ~REGBITS;
- r->refahead.b[0] &= ~REGBITS;
- r->calbehind.b[0] &= ~REGBITS;
- r->calahead.b[0] &= ~REGBITS;
- r->regdiff.b[0] &= ~REGBITS;
- r->act.b[0] &= ~REGBITS;
- }
-
- /*
- * pass 5
- * isolate regions
- * calculate costs (paint1)
- */
- r = firstr;
- if(r) {
- for(z=0; z<BITS; z++)
- bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
- ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
- if(bany(&bit) && !r->f.refset) {
- // should never happen - all variables are preset
- if(debug['w'])
- print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
- r->f.refset = 1;
- }
- }
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->act = zbits;
- rgp = region;
- nregion = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- for(z=0; z<BITS; z++)
- bit.b[z] = r->set.b[z] &
- ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
- if(bany(&bit) && !r->f.refset) {
- if(debug['w'])
- print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
- r->f.refset = 1;
- excise(&r->f);
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- rgp->enter = r;
- rgp->varno = i;
- change = 0;
- paint1(r, i);
- biclr(&bit, i);
- if(change <= 0)
- continue;
- rgp->cost = change;
- nregion++;
- if(nregion >= NRGN) {
- if(debug['R'] && debug['v'])
- print("too many regions\n");
- goto brk;
- }
- rgp++;
- }
- }
-brk:
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- if(debug['R'] && debug['v'])
- dumpit("pass5", &firstr->f, 1);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- if(debug['R'] && debug['v'])
- print("\nregisterizing\n");
- for(i=0; i<nregion; i++) {
- if(debug['R'] && debug['v'])
- print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
- bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno, 0);
- vreg = allreg(vreg, rgp);
- if(rgp->regno != 0) {
- if(debug['R'] && debug['v']) {
- Var *v;
-
- v = var + rgp->varno;
- print("registerize %N+%lld (bit=%2d et=%2E) in %R\n",
- v->node, v->offset, rgp->varno, v->etype, rgp->regno);
- }
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- }
- rgp++;
- }
-
- /*
- * free aux structures. peep allocates new ones.
- */
- for(i=0; i<nvar; i++)
- var[i].node->opt = nil;
- flowend(g);
- firstr = R;
-
- if(debug['R'] && debug['v']) {
- // Rebuild flow graph, since we inserted instructions
- g = flowstart(firstp, sizeof(Reg));
- firstr = (Reg*)g->start;
- dumpit("pass6", &firstr->f, 1);
- flowend(g);
- firstr = R;
- }
-
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P'])
- peep(firstp);
-
- /*
- * eliminate nops
- */
- for(p=firstp; p!=P; p=p->link) {
- while(p->link != P && p->link->as == ANOP)
- p->link = p->link->link;
- if(p->to.type == TYPE_BRANCH)
- while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
- p->to.u.branch = p->to.u.branch->link;
- }
-
- if(debug['R']) {
- if(ostats.ncvtreg ||
- ostats.nspill ||
- ostats.nreload ||
- ostats.ndelmov ||
- ostats.nvar ||
- ostats.naddr ||
- 0)
- print("\nstats\n");
-
- if(ostats.ncvtreg)
- print(" %4d cvtreg\n", ostats.ncvtreg);
- if(ostats.nspill)
- print(" %4d spill\n", ostats.nspill);
- if(ostats.nreload)
- print(" %4d reload\n", ostats.nreload);
- if(ostats.ndelmov)
- print(" %4d delmov\n", ostats.ndelmov);
- if(ostats.nvar)
- print(" %4d var\n", ostats.nvar);
- if(ostats.naddr)
- print(" %4d addr\n", ostats.naddr);
-
- memset(&ostats, 0, sizeof(ostats));
- }
-}
-
-static void
-walkvardef(Node *n, Reg *r, int active)
+char**
+regnames(int *n)
{
- Reg *r1, *r2;
- int bn;
- Var *v;
-
- for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
- if(r1->f.active == active)
- break;
- r1->f.active = active;
- if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
- break;
- for(v=n->opt; v!=nil; v=v->nextinnode) {
- bn = v - var;
- biset(&r1->act, bn);
- }
- if(r1->f.prog->as == ACALL)
- break;
- }
-
- for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
- if(r2->f.s2 != nil)
- walkvardef(n, (Reg*)r2->f.s2, active);
+ *n = NREGVAR;
+ return regname;
}
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
+uint64
+excludedregs(void)
{
- Prog *p, *p1;
- Adr *a;
- Var *v;
-
- p1 = mal(sizeof(*p1));
- clearp(p1);
- p1->pc = 9999;
-
- p = r->f.prog;
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = TYPE_MEM;
- a->name = v->name;
- a->node = v->node;
- a->sym = linksym(v->node->sym);
-
- // need to clean this up with wptr and
- // some of the defaults
- p1->as = AMOVL;
- switch(simtype[(uchar)v->etype]) {
- default:
- fatal("unknown type %E", v->etype);
- case TINT8:
- case TUINT8:
- case TBOOL:
- p1->as = AMOVB;
- break;
- case TINT16:
- case TUINT16:
- p1->as = AMOVW;
- break;
- case TINT64:
- case TUINT64:
- case TPTR64:
- p1->as = AMOVQ;
- break;
- case TFLOAT32:
- p1->as = AMOVSS;
- break;
- case TFLOAT64:
- p1->as = AMOVSD;
- break;
- case TINT32:
- case TUINT32:
- case TPTR32:
- break;
- }
-
- p1->from.type = TYPE_REG;
- p1->from.reg = rn;
- p1->from.name = NAME_NONE;
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = TYPE_REG;
- a->reg = rn;
- if(v->etype == TUINT8)
- p1->as = AMOVB;
- if(v->etype == TUINT16)
- p1->as = AMOVW;
- }
- if(debug['R'] && debug['v'])
- print("%P ===add=== %P\n", p, p1);
- ostats.nspill++;
+ return RtoB(REG_SP);
}
-uint32
+uint64
doregbits(int r)
{
- uint32 b;
+ uint64 b;
b = 0;
if(r >= REG_AX && r <= REG_R15)
@@ -598,592 +105,19 @@ doregbits(int r)
return b;
}
-static int
-overlap(int64 o1, int w1, int64 o2, int w2)
-{
- int64 t1, t2;
-
- t1 = o1+w1;
- t2 = o2+w2;
-
- if(!(t1 > o2 && t2 > o1))
- return 0;
-
- return 1;
-}
-
-Bits
-mkvar(Reg *r, Adr *a)
-{
- Var *v;
- int i, n, et, z, flag;
- int64 w;
- uint32 regu;
- int64 o;
- Bits bit;
- Node *node;
-
- /*
- * mark registers used
- */
- if(a->type == TYPE_NONE)
- goto none;
-
- if(r != R)
- r->use1.b[0] |= doregbits(a->index);
-
- switch(a->type) {
- default:
- regu = doregbits(a->reg);
- if(regu == 0)
- goto none;
- bit = zbits;
- bit.b[0] = regu;
- return bit;
-
- case TYPE_ADDR:
- a->type = TYPE_MEM;
- bit = mkvar(r, a);
- setaddrs(bit);
- a->type = TYPE_ADDR;
- ostats.naddr++;
- goto none;
-
- case TYPE_MEM:
- switch(a->name) {
- default:
- goto none;
- case NAME_EXTERN:
- case NAME_STATIC:
- case NAME_PARAM:
- case NAME_AUTO:
- n = a->name;
- break;
- }
- }
-
- node = a->node;
- if(node == N || node->op != ONAME || node->orig == N)
- goto none;
- node = node->orig;
- if(node->orig != node)
- fatal("%D: bad node", a);
- if(node->sym == S || node->sym->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- w = a->width;
- if(w < 0)
- fatal("bad width %lld for %D", w, a);
-
- flag = 0;
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node && v->name == n) {
- if(v->offset == o)
- if(v->etype == et)
- if(v->width == w)
- return blsh(i);
-
- // if they overlaps, disable both
- if(overlap(v->offset, v->width, o, w)) {
-// print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
- v->addr = 1;
- flag = 1;
- }
- }
- }
- switch(et) {
- case 0:
- case TFUNC:
- goto none;
- }
-
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && node != N)
- fatal("variable not optimized: %#N", node);
-
- // If we're not tracking a word in a variable, mark the rest as
- // having its address taken, so that we keep the whole thing
- // live at all calls. otherwise we might optimize away part of
- // a variable but not all of it.
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node)
- v->addr = 1;
- }
- goto none;
- }
-
- i = nvar;
- nvar++;
- v = var+i;
- v->offset = o;
- v->name = n;
- v->etype = et;
- v->width = w;
- v->addr = flag; // funny punning
- v->node = node;
-
- // node->opt is the head of a linked list
- // of Vars within the given Node, so that
- // we can start at a Var and find all the other
- // Vars in the same Go variable.
- v->nextinnode = node->opt;
- node->opt = v;
-
- bit = blsh(i);
- if(n == NAME_EXTERN || n == NAME_STATIC)
- for(z=0; z<BITS; z++)
- externs.b[z] |= bit.b[z];
- if(n == NAME_PARAM)
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
-
- if(node->class == PPARAM)
- for(z=0; z<BITS; z++)
- ivar.b[z] |= bit.b[z];
- if(node->class == PPARAMOUT)
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
-
- // Treat values with their address taken as live at calls,
- // because the garbage collector's liveness analysis in ../gc/plive.c does.
- // These must be consistent or else we will elide stores and the garbage
- // collector will see uninitialized data.
- // The typical case where our own analysis is out of sync is when the
- // node appears to have its address taken but that code doesn't actually
- // get generated and therefore doesn't show up as an address being
- // taken when we analyze the instruction stream.
- // One instance of this case is when a closure uses the same name as
- // an outer variable for one of its own variables declared with :=.
- // The parser flags the outer variable as possibly shared, and therefore
- // sets addrtaken, even though it ends up not being actually shared.
- // If we were better about _ elision, _ = &x would suffice too.
- // The broader := in a closure problem is mentioned in a comment in
- // closure.c:/^typecheckclosure and dcl.c:/^oldname.
- if(node->addrtaken)
- v->addr = 1;
-
- // Disable registerization for globals, because:
- // (1) we might panic at any time and we want the recovery code
- // to see the latest values (issue 1304).
- // (2) we don't know what pointers might point at them and we want
- // loads via those pointers to see updated values and vice versa (issue 7995).
- //
- // Disable registerization for results if using defer, because the deferred func
- // might recover and return, causing the current values to be used.
- if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
- v->addr = 1;
-
- if(debug['R'])
- print("bit=%2d et=%2E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
- ostats.nvar++;
-
- return bit;
-
-none:
- return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
- Reg *r1, *r2;
- int z, i, j;
- Var *v, *v1;
-
- for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(r1->f.prog->as) {
- case ACALL:
- if(noreturn(r1->f.prog))
- break;
-
- // Mark all input variables (ivar) as used, because that's what the
- // liveness bitmaps say. The liveness bitmaps say that so that a
- // panic will not show stale values in the parameter dump.
- // Mark variables with a recent VARDEF (r1->act) as used,
- // so that the optimizer flushes initializations to memory,
- // so that if a garbage collection happens during this CALL,
- // the collector will see initialized memory. Again this is to
- // match what the liveness bitmaps say.
- for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
- ref.b[z] = 0;
- }
-
- // cal.b is the current approximation of what's live across the call.
- // Every bit in cal.b is a single stack word. For each such word,
- // find all the other tracked stack words in the same Go variable
- // (struct/slice/string/interface) and mark them live too.
- // This is necessary because the liveness analysis for the garbage
- // collector works at variable granularity, not at word granularity.
- // It is fundamental for slice/string/interface: the garbage collector
- // needs the whole value, not just some of the words, in order to
- // interpret the other bits correctly. Specifically, slice needs a consistent
- // ptr and cap, string needs a consistent ptr and len, and interface
- // needs a consistent type word and data word.
- for(z=0; z<BITS; z++) {
- if(cal.b[z] == 0)
- continue;
- for(i=0; i<64; i++) {
- if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
- continue;
- v = var+z*64+i;
- if(v->node->opt == nil) // v represents fixed register, not Go variable
- continue;
-
- // v->node->opt is the head of a linked list of Vars
- // corresponding to tracked words from the Go variable v->node.
- // Walk the list and set all the bits.
- // For a large struct this could end up being quadratic:
- // after the first setting, the outer loop (for z, i) would see a 1 bit
- // for all of the remaining words in the struct, and for each such
- // word would go through and turn on all the bits again.
- // To avoid the quadratic behavior, we only turn on the bits if
- // v is the head of the list or if the head's bit is not yet turned on.
- // This will set the bits at most twice, keeping the overall loop linear.
- v1 = v->node->opt;
- j = v1 - var;
- if(v == v1 || !btest(&cal, j)) {
- for(; v1 != nil; v1 = v1->nextinnode) {
- j = v1 - var;
- biset(&cal, j);
- }
- }
- }
- }
- break;
-
- case ATEXT:
- for(z=0; z<BITS; z++) {
- cal.b[z] = 0;
- ref.b[z] = 0;
- }
- break;
-
- case ARET:
- for(z=0; z<BITS; z++) {
- cal.b[z] = externs.b[z] | ovar.b[z];
- ref.b[z] = 0;
- }
- break;
- }
- for(z=0; z<BITS; z++) {
- ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
- r1->use1.b[z] | r1->use2.b[z];
- cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
- r1->refbehind.b[z] = ref.b[z];
- r1->calbehind.b[z] = cal.b[z];
- }
- if(r1->f.active)
- break;
- r1->f.active = 1;
- }
- for(; r != r1; r = (Reg*)r->f.p1)
- for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
- prop(r2, r->refbehind, r->calbehind);
-}
-
-void
-synch(Reg *r, Bits dif)
-{
- Reg *r1;
- int z;
-
- for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
- for(z=0; z<BITS; z++) {
- dif.b[z] = (dif.b[z] &
- ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
- r1->set.b[z] | r1->regdiff.b[z];
- if(dif.b[z] != r1->regdiff.b[z]) {
- r1->regdiff.b[z] = dif.b[z];
- change++;
- }
- }
- if(r1->f.active)
- break;
- r1->f.active = 1;
- for(z=0; z<BITS; z++)
- dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if(r1->f.s2 != nil)
- synch((Reg*)r1->f.s2, dif);
- }
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
- Var *v;
- int i;
-
- v = var + r->varno;
- r->regno = 0;
- switch(v->etype) {
-
- default:
- fatal("unknown etype %d/%E", bitno(b), v->etype);
- break;
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TPTR32:
- case TPTR64:
- i = BtoR(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TFLOAT32:
- case TFLOAT64:
- i = BtoF(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return FtoB(i);
- }
- break;
- }
- return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
- Reg *r1;
- int z;
- uint64 bb;
-
- z = bn/64;
- bb = 1LL<<(bn%64);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
- change -= CLOAD * r->f.loop;
- }
- for(;;) {
- r->act.b[z] |= bb;
-
- if(r->f.prog->as != ANOP) { // don't give credit for NOPs
- if(r->use1.b[z] & bb)
- change += CREF * r->f.loop;
- if((r->use2.b[z]|r->set.b[z]) & bb)
- change += CREF * r->f.loop;
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->f.loop;
- }
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- paint1(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint1(r1, bn);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-uint32
-paint2(Reg *r, int bn, int depth)
-{
- Reg *r1;
- int z;
- uint64 bb, vreg;
-
- z = bn/64;
- bb = 1LL << (bn%64);
- vreg = regbits;
- if(!(r->act.b[z] & bb))
- return vreg;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(!(r1->act.b[z] & bb))
- break;
- r = r1;
- }
- for(;;) {
- if(debug['R'] && debug['v'])
- print(" paint2 %d %P\n", depth, r->f.prog);
-
- r->act.b[z] &= ~bb;
-
- vreg |= r->regu;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn, depth+1);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn, depth+1);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(!(r->act.b[z] & bb))
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-
- return vreg;
-}
-
-void
-paint3(Reg *r, int bn, uint32 rb, int rn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint64 bb;
-
- z = bn/64;
- bb = 1LL << (bn%64);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
- addmove(r, bn, rn, 0);
- for(;;) {
- r->act.b[z] |= bb;
- p = r->f.prog;
-
- if(r->use1.b[z] & bb) {
- if(debug['R'] && debug['v'])
- print("%P", p);
- addreg(&p->from, rn);
- if(debug['R'] && debug['v'])
- print(" ===change== %P\n", p);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- if(debug['R'] && debug['v'])
- print("%P", p);
- addreg(&p->to, rn);
- if(debug['R'] && debug['v'])
- print(" ===change== %P\n", p);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(r, bn, rn, 1);
- r->regu |= rb;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Adr *a, int rn)
-{
- a->sym = nil;
- a->node = nil;
- a->offset = 0;
- a->type = TYPE_REG;
- a->reg = rn;
- a->name = 0;
-
- ostats.ncvtreg++;
-}
-
-uint32
+uint64
RtoB(int r)
{
if(r < REG_AX || r > REG_R15)
return 0;
- return 1L << (r-REG_AX);
+ return 1ULL << (r-REG_AX);
}
int
-BtoR(uint32 b)
+BtoR(uint64 b)
{
- b &= 0xffffL;
+ b &= 0xffffULL;
if(nacl)
b &= ~((1<<(REG_BP-REG_AX)) | (1<<(REG_R15-REG_AX)));
else if(framepointer_enabled)
@@ -1200,16 +134,16 @@ BtoR(uint32 b)
* ...
* 31 X15
*/
-uint32
+uint64
FtoB(int f)
{
if(f < REG_X0 || f > REG_X15)
return 0;
- return 1L << (f - REG_X0 + 16);
+ return 1ULL << (f - REG_X0 + 16);
}
int
-BtoF(uint32 b)
+BtoF(uint64 b)
{
b &= 0xFFFF0000L;
@@ -1217,77 +151,3 @@ BtoF(uint32 b)
return 0;
return bitno(b) - 16 + REG_X0;
}
-
-void
-dumpone(Flow *f, int isreg)
-{
- int z;
- Bits bit;
- Reg *r;
-
- print("%d:%P", f->loop, f->prog);
- if(isreg) {
- r = (Reg*)f;
- for(z=0; z<BITS; z++)
- bit.b[z] =
- r->set.b[z] |
- r->use1.b[z] |
- r->use2.b[z] |
- r->refbehind.b[z] |
- r->refahead.b[z] |
- r->calbehind.b[z] |
- r->calahead.b[z] |
- r->regdiff.b[z] |
- r->act.b[z] |
- 0;
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->set))
- print(" s:%Q", r->set);
- if(bany(&r->use1))
- print(" u1:%Q", r->use1);
- if(bany(&r->use2))
- print(" u2:%Q", r->use2);
- if(bany(&r->refbehind))
- print(" rb:%Q ", r->refbehind);
- if(bany(&r->refahead))
- print(" ra:%Q ", r->refahead);
- if(bany(&r->calbehind))
- print(" cb:%Q ", r->calbehind);
- if(bany(&r->calahead))
- print(" ca:%Q ", r->calahead);
- if(bany(&r->regdiff))
- print(" d:%Q ", r->regdiff);
- if(bany(&r->act))
- print(" a:%Q ", r->act);
- }
- }
- print("\n");
-}
-
-void
-dumpit(char *str, Flow *r0, int isreg)
-{
- Flow *r, *r1;
-
- print("\n%s\n", str);
- for(r = r0; r != nil; r = r->link) {
- dumpone(r, isreg);
- r1 = r->p2;
- if(r1 != nil) {
- print(" pred:");
- for(; r1 != nil; r1 = r1->p2link)
- print(" %.4ud", (int)r1->prog->pc);
- print("\n");
- }
- // Print successors if it's not just the next one
- if(r->s1 != r->link || r->s2 != nil) {
- print(" succ:");
- if(r->s1 != nil)
- print(" %.4ud", (int)r->s1->prog->pc);
- if(r->s2 != nil)
- print(" %.4ud", (int)r->s2->prog->pc);
- print("\n");
- }
- }
-}
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index 01d9bb7535..e25c6efec8 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -834,6 +834,7 @@ enum
FREGRET = REG_X0,
REGSP = REG_SP,
REGTMP = REG_DI,
+ REGCTXT = REG_DX,
REGEXT = REG_R15, /* compiler allocates external registers R15 down */
FREGMIN = REG_X0+5, /* first register variable */
FREGEXT = REG_X0+15, /* first external register */
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index 032c1eea09..a983373fa0 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -39,13 +39,6 @@
#define PADDR(a) ((uint32)(a) & ~0x80000000)
-char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
-char freebsddynld[] = "/libexec/ld-elf.so.1";
-char openbsddynld[] = "/usr/libexec/ld.so";
-char netbsddynld[] = "/libexec/ld.elf_so";
-char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
-char solarisdynld[] = "/lib/amd64/ld.so.1";
-
char zeroes[32];
static int
@@ -68,8 +61,6 @@ needlib(char *name)
return 0;
}
-int nelfsym = 1;
-
static void addpltsym(LSym*);
static void addgotsym(LSym*);
@@ -236,7 +227,7 @@ adddynrel(LSym *s, Reloc *r)
r->type = 256; // ignore during relocsym
return;
}
- if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
+ if(HEADTYPE == Hdarwin && s->size == thearch.ptrsize && r->off == 0) {
// Mach-O relocations are a royal pain to lay out.
// They use a compact stateful bytecode representation
// that is too much bother to deal with.
@@ -271,7 +262,7 @@ elfreloc1(Reloc *r, vlong sectoff)
{
int32 elfsym;
- VPUT(sectoff);
+ thearch.vput(sectoff);
elfsym = r->xsym->elfsym;
switch(r->type) {
@@ -280,16 +271,16 @@ elfreloc1(Reloc *r, vlong sectoff)
case R_ADDR:
if(r->siz == 4)
- VPUT(R_X86_64_32 | (uint64)elfsym<<32);
+ thearch.vput(R_X86_64_32 | (uint64)elfsym<<32);
else if(r->siz == 8)
- VPUT(R_X86_64_64 | (uint64)elfsym<<32);
+ thearch.vput(R_X86_64_64 | (uint64)elfsym<<32);
else
return -1;
break;
case R_TLS_LE:
if(r->siz == 4)
- VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
+ thearch.vput(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
else
return -1;
break;
@@ -297,16 +288,16 @@ elfreloc1(Reloc *r, vlong sectoff)
case R_CALL:
if(r->siz == 4) {
if(r->xsym->type == SDYNIMPORT)
- VPUT(R_X86_64_GOTPCREL | (uint64)elfsym<<32);
+ thearch.vput(R_X86_64_GOTPCREL | (uint64)elfsym<<32);
else
- VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
+ thearch.vput(R_X86_64_PC32 | (uint64)elfsym<<32);
} else
return -1;
break;
case R_PCREL:
if(r->siz == 4) {
- VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
+ thearch.vput(R_X86_64_PC32 | (uint64)elfsym<<32);
} else
return -1;
break;
@@ -314,15 +305,15 @@ elfreloc1(Reloc *r, vlong sectoff)
case R_TLS:
if(r->siz == 4) {
if(flag_shared)
- VPUT(R_X86_64_GOTTPOFF | (uint64)elfsym<<32);
+ thearch.vput(R_X86_64_GOTTPOFF | (uint64)elfsym<<32);
else
- VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
+ thearch.vput(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
} else
return -1;
break;
}
- VPUT(r->xadd);
+ thearch.vput(r->xadd);
return 0;
}
@@ -382,8 +373,8 @@ machoreloc1(Reloc *r, vlong sectoff)
break;
}
- LPUT(sectoff);
- LPUT(v);
+ thearch.lput(sectoff);
+ thearch.lput(v);
return 0;
}
@@ -798,18 +789,3 @@ asmb(void)
}
cflush();
}
-
-vlong
-rnd(vlong v, vlong r)
-{
- vlong c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index 24eaa453dd..acc97d93d4 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -32,7 +32,6 @@
#include <libc.h>
#include <bio.h>
#include <link.h>
-#include "6.out.h"
#ifndef EXTERN
#define EXTERN extern
@@ -42,49 +41,14 @@ enum
{
thechar = '6',
MaxAlign = 32, // max data alignment
-
- // Loop alignment constants:
- // want to align loop entry to LoopAlign-byte boundary,
- // and willing to insert at most MaxLoopPad bytes of NOP to do so.
- // We define a loop entry as the target of a backward jump.
- //
- // gcc uses MaxLoopPad = 10 for its 'generic x86-64' config,
- // and it aligns all jump targets, not just backward jump targets.
- //
- // As of 6/1/2012, the effect of setting MaxLoopPad = 10 here
- // is very slight but negative, so the alignment is disabled by
- // setting MaxLoopPad = 0. The code is here for reference and
- // for future experiments.
- //
- LoopAlign = 16,
- MaxLoopPad = 0,
-
FuncAlign = 16
};
-EXTERN int PtrSize;
-EXTERN int IntSize;
-EXTERN int RegSize;
-
-#define P ((Prog*)0)
-#define S ((LSym*)0)
enum
{
MINLC = 1,
};
-#pragma varargck type "I" uchar*
-
-EXTERN LSym* datap;
-EXTERN int debug[128];
-EXTERN char literal[32];
-EXTERN int32 lcsize;
-EXTERN char* rpath;
-EXTERN int32 spsize;
-EXTERN LSym* symlist;
-EXTERN int32 symsize;
-
-int Iconv(Fmt *fp);
void adddynlib(char *lib);
void adddynrel(LSym *s, Reloc *r);
void adddynrela(LSym *rela, LSym *s, Reloc *r);
@@ -96,12 +60,6 @@ int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);
void listinit(void);
int machoreloc1(Reloc *r, vlong sectoff);
-vlong rnd(vlong v, vlong r);
-
-/* Native is little-endian */
-#define LPUT(a) lputl(a)
-#define WPUT(a) wputl(a)
-#define VPUT(a) vputl(a)
/* Used by ../ld/dwarf.c */
enum
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
index d960fcc915..6c4ea79f91 100644
--- a/src/cmd/6l/list.c
+++ b/src/cmd/6l/list.c
@@ -37,31 +37,4 @@ void
listinit(void)
{
listinit6();
- fmtinstall('I', Iconv);
-}
-
-int
-Iconv(Fmt *fp)
-{
- int i, n;
- uchar *p;
- char *s;
- Fmt fmt;
-
- n = fp->prec;
- fp->prec = 0;
- if(!(fp->flags&FmtPrec) || n < 0)
- return fmtstrcpy(fp, "%I");
- fp->flags &= ~FmtPrec;
- p = va_arg(fp->args, uchar*);
-
- // format into temporary buffer and
- // call fmtstrcpy to handle padding.
- fmtstrinit(&fmt);
- for(i=0; i<n; i++)
- fmtprint(&fmt, "%.2ux", *p++);
- s = fmtstrflush(&fmt);
- fmtstrcpy(fp, s);
- free(s);
- return 0;
}
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index 3b8e8f4d7a..0a2b2cb59e 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -38,17 +38,52 @@
#include "../ld/pe.h"
#include <ar.h>
-char* thestring = "amd64";
-LinkArch* thelinkarch = &linkamd64;
+void
+main(int argc, char **argv)
+{
+ linkarchinit();
+ ldmain(argc, argv);
+}
void
linkarchinit(void)
{
+ thestring = "amd64";
+ thelinkarch = &linkamd64;
if(strcmp(getgoarch(), "amd64p32") == 0)
thelinkarch = &linkamd64p32;
- PtrSize = thelinkarch->ptrsize;
- IntSize = PtrSize;
- RegSize = thelinkarch->regsize;
+
+ thearch.thechar = thechar;
+ thearch.ptrsize = thelinkarch->ptrsize;
+ thearch.intsize = thelinkarch->ptrsize;
+ thearch.regsize = thelinkarch->regsize;
+ thearch.funcalign = FuncAlign;
+ thearch.maxalign = MaxAlign;
+ thearch.minlc = MINLC;
+ thearch.dwarfregsp = DWARFREGSP;
+
+ thearch.adddynlib = adddynlib;
+ thearch.adddynrel = adddynrel;
+ thearch.adddynsym = adddynsym;
+ thearch.archinit = archinit;
+ thearch.archreloc = archreloc;
+ thearch.archrelocvariant = archrelocvariant;
+ thearch.asmb = asmb;
+ thearch.elfreloc1 = elfreloc1;
+ thearch.elfsetupplt = elfsetupplt;
+ thearch.gentext = gentext;
+ thearch.listinit = listinit;
+ thearch.machoreloc1 = machoreloc1;
+ thearch.lput = lputl;
+ thearch.wput = wputl;
+ thearch.vput = vputl;
+
+ thearch.linuxdynld = "/lib64/ld-linux-x86-64.so.2";
+ thearch.freebsddynld = "/libexec/ld-elf.so.1";
+ thearch.openbsddynld = "/usr/libexec/ld.so";
+ thearch.netbsddynld = "/libexec/ld.elf_so";
+ thearch.dragonflydynld = "/usr/libexec/ld-elf.so.2";
+ thearch.solarisdynld = "/lib/amd64/ld.so.1";
}
void
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index eabf52ae81..f06927c905 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -956,17 +956,7 @@ bgen(Node *n, int true, int likely, Prog *to)
switch(n->op) {
default:
- def:
- regalloc(&n1, n->type, N);
- cgen(n, &n1);
- nodconst(&n2, n->type, 0);
- gins(optoas(OCMP, n->type), &n1, &n2);
- a = AJNE;
- if(!true)
- a = AJEQ;
- patch(gbranch(a, n->type, likely), to);
- regfree(&n1);
- return;
+ goto def;
case OLITERAL:
// need to ask if it is bool?
@@ -986,27 +976,20 @@ bgen(Node *n, int true, int likely, Prog *to)
return;
case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- p1 = gbranch(AJMP, T, 0);
- p2 = gbranch(AJMP, T, 0);
- patch(p1, pc);
- bgen(n->left, !true, -likely, p2);
- bgen(n->right, !true, -likely, p2);
- p1 = gbranch(AJMP, T, 0);
- patch(p1, to);
- patch(p2, pc);
- return;
-
case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bgen(n->left, true, likely, to);
- bgen(n->right, true, likely, to);
+ if((n->op == OANDAND) == true) {
+ p1 = gbranch(AJMP, T, 0);
+ p2 = gbranch(AJMP, T, 0);
+ patch(p1, pc);
+ bgen(n->left, !true, -likely, p2);
+ bgen(n->right, !true, -likely, p2);
+ p1 = gbranch(AJMP, T, 0);
+ patch(p1, to);
+ patch(p2, pc);
+ } else {
+ bgen(n->left, true, likely, to);
+ bgen(n->right, true, likely, to);
+ }
return;
case OEQ:
@@ -1150,6 +1133,19 @@ cmp:
regfree(nr);
break;
}
+ return;
+
+def:
+ regalloc(&n1, n->type, N);
+ cgen(n, &n1);
+ nodconst(&n2, n->type, 0);
+ gins(optoas(OCMP, n->type), &n1, &n2);
+ a = AJNE;
+ if(!true)
+ a = AJEQ;
+ patch(gbranch(a, n->type, likely), to);
+ regfree(&n1);
+ return;
}
/*
@@ -1213,7 +1209,7 @@ stkof(Node *n)
void
sgen(Node *n, Node *res, int64 w)
{
- Node dst, src, tdst, tsrc;
+ Node dst, src, tdst, tsrc, cx;
int32 c, q, odst, osrc;
NodeList *l;
Prog *p;
@@ -1329,6 +1325,19 @@ sgen(Node *n, Node *res, int64 w)
p->to.sym = linksym(pkglookup("duffcopy", runtimepkg));
// 10 and 128 = magic constants: see ../../runtime/asm_386.s
p->to.offset = 10*(128-q);
+ } else if(!nacl && c == 0) {
+ nodreg(&cx, types[TINT32], REG_CX);
+ // We don't need the MOVSL side-effect of updating SI and DI,
+ // and issuing a sequence of MOVLs directly is faster.
+ src.op = OINDREG;
+ dst.op = OINDREG;
+ while(q > 0) {
+ gmove(&src, &cx); // MOVL x+(SI),CX
+ gmove(&cx, &dst); // MOVL CX,x+(DI)
+ src.xoffset += 4;
+ dst.xoffset += 4;
+ q--;
+ }
} else
while(q > 0) {
gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+
@@ -1360,13 +1369,15 @@ cadable(Node *n)
/*
* copy a composite value by moving its individual components.
* Slices, strings and interfaces are supported.
+ * Small structs or arrays with elements of basic type are
+ * also supported.
* nr is N when assigning a zero value.
* return 1 if can do, 0 if can't.
*/
int
componentgen(Node *nr, Node *nl)
{
- Node nodl, nodr;
+ Node nodl, nodr, tmp;
Type *t;
int freel, freer;
vlong fldcount;
@@ -1414,7 +1425,7 @@ componentgen(Node *nr, Node *nl)
nodl = *nl;
if(!cadable(nl)) {
- if(nr == N || !cadable(nr))
+ if(nr != N && !cadable(nr))
goto no;
igen(nl, &nodl, N);
freel = 1;
@@ -1426,6 +1437,12 @@ componentgen(Node *nr, Node *nl)
igen(nr, &nodr, N);
freer = 1;
}
+ } else {
+ // When zeroing, prepare a register containing zero.
+ nodconst(&tmp, nl->type, 0);
+ regalloc(&nodr, types[TUINT], N);
+ gmove(&tmp, &nodr);
+ freer = 1;
}
// nl and nr are 'cadable' which basically means they are names (variables) now.
@@ -1462,8 +1479,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
@@ -1472,8 +1488,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_cap-Array_nel;
@@ -1482,8 +1497,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_cap-Array_nel;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
goto yes;
@@ -1497,8 +1511,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
@@ -1507,8 +1520,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
goto yes;
@@ -1522,8 +1534,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
@@ -1532,8 +1543,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
goto yes;
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
index 83c323516d..33951adfd2 100644
--- a/src/cmd/8g/galign.c
+++ b/src/cmd/8g/galign.c
@@ -42,61 +42,46 @@ betypeinit(void)
void
main(int argc, char **argv)
{
- arch.thechar = thechar;
- arch.thestring = thestring;
- arch.thelinkarch = thelinkarch;
- arch.typedefs = typedefs;
- arch.MAXWIDTH = MAXWIDTH;
- arch.afunclit = afunclit;
- arch.anyregalloc = anyregalloc;
- arch.betypeinit = betypeinit;
- arch.bgen = bgen;
- arch.cgen = cgen;
- arch.cgen_asop = cgen_asop;
- arch.cgen_call = cgen_call;
- arch.cgen_callinter = cgen_callinter;
- arch.cgen_ret = cgen_ret;
- arch.clearfat = clearfat;
- arch.clearp = clearp;
- arch.defframe = defframe;
- arch.dgostringptr = dgostringptr;
- arch.dgostrlitptr = dgostrlitptr;
- arch.dsname = dsname;
- arch.dsymptr = dsymptr;
- arch.dumpdata = dumpdata;
- arch.dumpit = dumpit;
- arch.excise = excise;
- arch.expandchecks = expandchecks;
- arch.fixautoused = fixautoused;
- arch.gclean = gclean;
- arch.gdata = gdata;
- arch.gdatacomplex = gdatacomplex;
- arch.gdatastring = gdatastring;
- arch.ggloblnod = ggloblnod;
- arch.ggloblsym = ggloblsym;
- arch.ginit = ginit;
- arch.gins = gins;
- arch.ginscall = ginscall;
- arch.gjmp = gjmp;
- arch.gtrack = gtrack;
- arch.gused = gused;
- arch.igen = igen;
- arch.isfat = isfat;
- arch.linkarchinit = linkarchinit;
- arch.markautoused = markautoused;
- arch.naddr = naddr;
- arch.newplist = newplist;
- arch.nodarg = nodarg;
- arch.patch = patch;
- arch.proginfo = proginfo;
- arch.regalloc = regalloc;
- arch.regfree = regfree;
- arch.regopt = regopt;
- arch.regtyp = regtyp;
- arch.sameaddr = sameaddr;
- arch.smallindir = smallindir;
- arch.stackaddr = stackaddr;
- arch.unpatch = unpatch;
+ thearch.thechar = thechar;
+ thearch.thestring = thestring;
+ thearch.thelinkarch = thelinkarch;
+ thearch.typedefs = typedefs;
+ thearch.REGSP = REGSP;
+ thearch.REGCTXT = REGCTXT;
+ thearch.MAXWIDTH = MAXWIDTH;
+ thearch.anyregalloc = anyregalloc;
+ thearch.betypeinit = betypeinit;
+ thearch.bgen = bgen;
+ thearch.cgen = cgen;
+ thearch.cgen_call = cgen_call;
+ thearch.cgen_callinter = cgen_callinter;
+ thearch.cgen_ret = cgen_ret;
+ thearch.clearfat = clearfat;
+ thearch.defframe = defframe;
+ thearch.excise = excise;
+ thearch.expandchecks = expandchecks;
+ thearch.gclean = gclean;
+ thearch.ginit = ginit;
+ thearch.gins = gins;
+ thearch.ginscall = ginscall;
+ thearch.igen = igen;
+ thearch.linkarchinit = linkarchinit;
+ thearch.peep = peep;
+ thearch.proginfo = proginfo;
+ thearch.regalloc = regalloc;
+ thearch.regfree = regfree;
+ thearch.regtyp = regtyp;
+ thearch.sameaddr = sameaddr;
+ thearch.smallindir = smallindir;
+ thearch.stackaddr = stackaddr;
+ thearch.excludedregs = excludedregs;
+ thearch.RtoB = RtoB;
+ thearch.FtoB = FtoB;
+ thearch.BtoR = BtoR;
+ thearch.BtoF = BtoF;
+ thearch.optoas = optoas;
+ thearch.doregbits = doregbits;
+ thearch.regnames = regnames;
gcmain(argc, argv);
}
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
index b2b1178a52..872d946592 100644
--- a/src/cmd/8g/gg.h
+++ b/src/cmd/8g/gg.h
@@ -17,10 +17,7 @@ enum
Fpop2 = 1<<2,
};
-EXTERN int32 dynloc;
EXTERN uchar reg[MAXREG];
-EXTERN int32 pcloc; // instruction counter
-EXTERN Strlit emptystring;
EXTERN Node* panicdiv;
extern uint32 unmappedzero;
@@ -130,7 +127,6 @@ int anyregalloc(void);
void betypeinit(void);
void bgen(Node*, int, int, Prog*);
void cgen(Node*, Node*);
-void cgen_asop(Node*);
void cgen_call(Node*, int);
void cgen_callinter(Node*, Node*, int);
void cgen_ret(Node*);
@@ -175,3 +171,19 @@ int sameaddr(Addr*, Addr*);
int smallindir(Addr*, Addr*);
int stackaddr(Addr*);
Prog* unpatch(Prog*);
+
+/*
+ * reg.c
+ */
+uint64 excludedregs(void);
+uint64 RtoB(int);
+uint64 FtoB(int);
+int BtoR(uint64);
+int BtoF(uint64);
+uint64 doregbits(int);
+char** regnames(int*);
+
+/*
+ * peep.c
+ */
+void peep(Prog*);
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 2fd4a601ff..8188348282 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -7,7 +7,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
static Prog *appendpp(Prog*, int, int, int, vlong, int, int, vlong);
static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
@@ -106,52 +106,6 @@ appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int tre
return q;
}
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
- for (; p; p = p->link) {
- if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
- continue;
-
- if (p->from.node)
- ((Node*)(p->from.node))->used = 1;
-
- if (p->to.node)
- ((Node*)(p->to.node))->used = 1;
- }
-}
-
-// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
-void
-fixautoused(Prog* p)
-{
- Prog **lp;
-
- for (lp=&p; (p=*lp) != P; ) {
- if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
- *lp = p->link;
- continue;
- }
- if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
- // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
- // VARDEFs are interspersed with other code, and a jump might be using the
- // VARDEF as a target. Replace with a no-op instead. A later pass will remove
- // the no-ops.
- nopout(p);
- continue;
- }
-
- if (p->from.type == TYPE_MEM && p->from.name == NAME_AUTO && p->from.node)
- p->from.offset += ((Node*)(p->from.node))->stkdelta;
-
- if (p->to.type == TYPE_MEM && p->to.name == NAME_AUTO && p->to.node)
- p->to.offset += ((Node*)(p->to.node))->stkdelta;
-
- lp = &p->link;
- }
-}
-
void
clearfat(Node *nl)
{
@@ -525,154 +479,6 @@ cgen_ret(Node *n)
}
/*
- * generate += *= etc.
- */
-void
-cgen_asop(Node *n)
-{
- Node n1, n2, n3, n4;
- Node *nl, *nr;
- Prog *p1;
- Addr addr;
- int a;
-
- nl = n->left;
- nr = n->right;
-
- if(nr->ullman >= UINF && nl->ullman >= UINF) {
- tempname(&n1, nr->type);
- cgen(nr, &n1);
- n2 = *n;
- n2.right = &n1;
- cgen_asop(&n2);
- goto ret;
- }
-
- if(!isint[nl->type->etype])
- goto hard;
- if(!isint[nr->type->etype])
- goto hard;
- if(is64(nl->type) || is64(nr->type))
- goto hard;
-
- switch(n->etype) {
- case OADD:
- if(smallintconst(nr))
- if(mpgetfix(nr->val.u.xval) == 1) {
- a = optoas(OINC, nl->type);
- if(nl->addable) {
- gins(a, N, nl);
- goto ret;
- }
- if(sudoaddable(a, nl, &addr)) {
- p1 = gins(a, N, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- }
- break;
-
- case OSUB:
- if(smallintconst(nr))
- if(mpgetfix(nr->val.u.xval) == 1) {
- a = optoas(ODEC, nl->type);
- if(nl->addable) {
- gins(a, N, nl);
- goto ret;
- }
- if(sudoaddable(a, nl, &addr)) {
- p1 = gins(a, N, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- }
- break;
- }
-
- switch(n->etype) {
- case OADD:
- case OSUB:
- case OXOR:
- case OAND:
- case OOR:
- a = optoas(n->etype, nl->type);
- if(nl->addable) {
- if(smallintconst(nr)) {
- gins(a, nr, nl);
- goto ret;
- }
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- gins(a, &n2, nl);
- regfree(&n2);
- goto ret;
- }
- if(nr->ullman < UINF)
- if(sudoaddable(a, nl, &addr)) {
- if(smallintconst(nr)) {
- p1 = gins(a, nr, N);
- p1->to = addr;
- sudoclean();
- goto ret;
- }
- regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
- p1 = gins(a, &n2, N);
- p1->to = addr;
- regfree(&n2);
- sudoclean();
- goto ret;
- }
- }
-
-hard:
- n2.op = 0;
- n1.op = 0;
- if(nr->ullman >= nl->ullman || nl->addable) {
- mgen(nr, &n2, N);
- nr = &n2;
- } else {
- tempname(&n2, nr->type);
- cgen(nr, &n2);
- nr = &n2;
- }
- if(!nl->addable) {
- igen(nl, &n1, N);
- nl = &n1;
- }
-
- n3 = *n;
- n3.left = nl;
- n3.right = nr;
- n3.op = n->etype;
-
- mgen(&n3, &n4, N);
- gmove(&n4, nl);
-
- if(n1.op)
- regfree(&n1);
- mfree(&n2);
- mfree(&n4);
-
-ret:
- ;
-}
-
-int
-samereg(Node *a, Node *b)
-{
- if(a->op != OREGISTER)
- return 0;
- if(b->op != OREGISTER)
- return 0;
- if(a->val.u.reg != b->val.u.reg)
- return 0;
- return 1;
-}
-
-/*
* generate division.
* caller must set:
* ax = allocated AX register
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
deleted file mode 100644
index b59d2268dd..0000000000
--- a/src/cmd/8g/gobj.c
+++ /dev/null
@@ -1,257 +0,0 @@
-// Derived from Inferno utils/8c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int
-dsname(Sym *s, int off, char *t, int n)
-{
- Prog *p;
-
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = n;
- p->from.sym = linksym(s);
-
- p->to.type = TYPE_SCONST;
- memmove(p->to.u.sval, t, n);
- return off + n;
-}
-
-/*
- * make a refer to the data s, s+len
- * emitting DATA if needed.
- */
-void
-datastring(char *s, int len, Addr *a)
-{
- Sym *sym;
-
- sym = stringsym(s, len);
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- a->sym = linksym(sym);
- a->node = sym->def;
- a->offset = widthptr+4; // skip header
- a->etype = TINT32;
-}
-
-/*
- * make a refer to the string sval,
- * emitting DATA if needed.
- */
-void
-datagostring(Strlit *sval, Addr *a)
-{
- Sym *sym;
-
- sym = stringsym(sval->s, sval->len);
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- a->sym = linksym(sym);
- a->node = sym->def;
- a->offset = 0; // header
- a->etype = TSTRING;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
- Prog *p;
- vlong v;
-
- if(nr->op == OLITERAL) {
- switch(nr->val.ctype) {
- case CTCPLX:
- gdatacomplex(nam, nr->val.u.cval);
- return;
- case CTSTR:
- gdatastring(nam, nr->val.u.sval);
- return;
- }
- }
-
- if(wid == 8 && is64(nr->type)) {
- v = mpgetfix(nr->val.u.xval);
- p = gins(ADATA, nam, nodintconst(v));
- p->from3.type = TYPE_CONST;
- p->from3.offset = 4;
- p = gins(ADATA, nam, nodintconst(v>>32));
- p->from3.type = TYPE_CONST;
- p->from3.offset = 4;
- p->from.offset += 4;
- return;
- }
- p = gins(ADATA, nam, nr);
- p->from3.type = TYPE_CONST;
- p->from3.offset = wid;
-}
-
-void
-gdatacomplex(Node *nam, Mpcplx *cval)
-{
- Prog *p;
- int w;
-
- w = cplxsubtype(nam->type->etype);
- w = types[w]->width;
-
- p = gins(ADATA, nam, N);
- p->from3.type = TYPE_CONST;
- p->from3.offset = w;
- p->to.type = TYPE_FCONST;
- p->to.u.dval = mpgetflt(&cval->real);
-
- p = gins(ADATA, nam, N);
- p->from3.type = TYPE_CONST;
- p->from3.offset = w;
- p->from.offset += w;
- p->to.type = TYPE_FCONST;
- p->to.u.dval = mpgetflt(&cval->imag);
-}
-
-void
-gdatastring(Node *nam, Strlit *sval)
-{
- Prog *p;
- Node nod1;
-
- p = gins(ADATA, nam, N);
- datastring(sval->s, sval->len, &p->to);
- p->from3.type = TYPE_CONST;
- p->from3.offset = types[tptr]->width;
- p->to.type = TYPE_ADDR;
-//print("%P\n", p);
-
- nodconst(&nod1, types[TINT32], sval->len);
- p = gins(ADATA, nam, &nod1);
- p->from3.type = TYPE_CONST;
- p->from3.offset = types[TINT32]->width;
- p->from.offset += types[tptr]->width;
-}
-
-int
-dstringptr(Sym *s, int off, char *str)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
-
- datastring(str, strlen(str)+1, &p->to);
- p->to.type = TYPE_ADDR;
- p->to.etype = TINT32;
- off += widthptr;
-
- return off;
-}
-
-int
-dgostrlitptr(Sym *s, int off, Strlit *lit)
-{
- Prog *p;
-
- if(lit == nil)
- return duintptr(s, off, 0);
-
- off = rnd(off, widthptr);
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
- datagostring(lit, &p->to);
- p->to.type = TYPE_ADDR;
- p->to.etype = TINT32;
- off += widthptr;
-
- return off;
-}
-
-int
-dgostringptr(Sym *s, int off, char *str)
-{
- int n;
- Strlit *lit;
-
- if(str == nil)
- return duintptr(s, off, 0);
-
- n = strlen(str);
- lit = mal(sizeof *lit + n);
- strcpy(lit->s, str);
- lit->len = n;
- return dgostrlitptr(s, off, lit);
-}
-
-int
-dsymptr(Sym *s, int off, Sym *x, int xoff)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
-
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
- p->to.type = TYPE_ADDR;
- p->to.name = NAME_EXTERN;
- p->to.sym = linksym(x);
- p->to.offset = xoff;
- off += widthptr;
-
- return off;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from = zprog.from;
- p->to = zprog.to;
-}
-
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index dd75e9f092..b82f7622ef 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -41,225 +41,6 @@ uint32 unmappedzero = 4096;
#define CASE(a,b) (((a)<<16)|((b)<<0))
/*c2go int CASE(int, int);*/
-void
-clearp(Prog *p)
-{
- p->as = AEND;
- p->from.type = TYPE_NONE;
- p->from.index = TYPE_NONE;
- p->to.type = TYPE_NONE;
- p->to.index = TYPE_NONE;
- p->pc = pcloc;
- pcloc++;
-}
-
-static int ddumped;
-static Prog *dfirst;
-static Prog *dpc;
-
-/*
- * generate and return proc with p->as = as,
- * linked into program. pc is next instruction.
- */
-Prog*
-prog(int as)
-{
- Prog *p;
-
- if(as == ADATA || as == AGLOBL) {
- if(ddumped)
- fatal("already dumped data");
- if(dpc == nil) {
- dpc = mal(sizeof(*dpc));
- dfirst = dpc;
- }
- p = dpc;
- dpc = mal(sizeof(*dpc));
- p->link = dpc;
- } else {
- p = pc;
- pc = mal(sizeof(*pc));
- clearp(pc);
- p->link = pc;
- }
-
- if(lineno == 0) {
- if(debug['K'])
- warn("prog: line 0");
- }
-
- p->as = as;
- p->lineno = lineno;
- return p;
-}
-
-void
-dumpdata(void)
-{
- ddumped = 1;
- if(dfirst == nil)
- return;
- newplist();
- *pc = *dfirst;
- pc = dpc;
- clearp(pc);
-}
-
-/*
- * generate a branch.
- * t is ignored.
- * likely values are for branch prediction:
- * -1 unlikely
- * 0 no opinion
- * +1 likely
- */
-Prog*
-gbranch(int as, Type *t, int likely)
-{
- Prog *p;
-
- USED(t);
- p = prog(as);
- p->to.type = TYPE_BRANCH;
- p->to.u.branch = P;
- if(likely != 0) {
- p->from.type = TYPE_CONST;
- p->from.offset = likely > 0;
- }
- return p;
-}
-
-/*
- * patch previous branch to jump to to.
- */
-void
-patch(Prog *p, Prog *to)
-{
- if(p->to.type != TYPE_BRANCH)
- fatal("patch: not a branch");
- p->to.u.branch = to;
- p->to.offset = to->pc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
- Prog *q;
-
- if(p->to.type != TYPE_BRANCH)
- fatal("unpatch: not a branch");
- q = p->to.u.branch;
- p->to.u.branch = P;
- p->to.offset = 0;
- return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
- Plist *pl;
-
- pl = linknewplist(ctxt);
-
- pc = mal(sizeof(*pc));
- clearp(pc);
- pl->firstpc = pc;
-
- return pl;
-}
-
-void
-gused(Node *n)
-{
- gins(ANOP, n, N); // used
-}
-
-Prog*
-gjmp(Prog *to)
-{
- Prog *p;
-
- p = gbranch(AJMP, T, 0);
- if(to != P)
- patch(p, to);
- return p;
-}
-
-void
-ggloblnod(Node *nam)
-{
- Prog *p;
-
- p = gins(AGLOBL, nam, N);
- p->lineno = nam->lineno;
- p->from.sym->gotype = linksym(ngotype(nam));
- p->to.sym = nil;
- p->to.type = TYPE_CONST;
- p->to.offset = nam->type->width;
- if(nam->readonly)
- p->from3.offset = RODATA;
- if(nam->type != T && !haspointers(nam->type))
- p->from3.offset |= NOPTR;
-}
-
-void
-ggloblsym(Sym *s, int32 width, int8 flags)
-{
- Prog *p;
-
- p = gins(AGLOBL, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.index = REG_NONE;
- p->from.sym = linksym(s);
- p->to.type = TYPE_CONST;
- p->to.index = REG_NONE;
- p->to.offset = width;
- p->from3.offset = flags;
-}
-
-void
-gtrack(Sym *s)
-{
- Prog *p;
-
- p = gins(AUSEFIELD, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
-}
-
-int
-isfat(Type *t)
-{
- if(t != T)
- switch(t->etype) {
- case TSTRUCT:
- case TARRAY:
- case TSTRING:
- case TINTER: // maybe remove later
- return 1;
- }
- return 0;
-}
-
-/*
- * naddr of func generates code for address of func.
- * if using opcode that can take address implicitly,
- * call afunclit to fix up the argument.
- */
-void
-afunclit(Addr *a, Node *n)
-{
- if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
- a->type = TYPE_MEM;
- a->sym = linksym(n->sym);
- }
-}
-
/*
* return Axxx for Oxxx on type t.
*/
@@ -406,6 +187,14 @@ optoas(int op, Type *t)
case CASE(OAS, TPTR32):
a = AMOVL;
break;
+
+ case CASE(OAS, TFLOAT32):
+ a = AMOVSS;
+ break;
+
+ case CASE(OAS, TFLOAT64):
+ a = AMOVSD;
+ break;
case CASE(OADD, TINT8):
case CASE(OADD, TUINT8):
@@ -878,7 +667,7 @@ gclean(void)
yyerror("reg %R left allocated\n", i);
}
-int32
+int
anyregalloc(void)
{
int i, j;
@@ -935,9 +724,9 @@ regalloc(Node *n, Type *t, Node *o)
if(reg[i] == 0)
goto out;
- fprint(2, "registers allocated at\n");
+ print("registers allocated at\n");
for(i=REG_AX; i<=REG_DI; i++)
- fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
+ print("\t%R\t%#lux\n", i, regpc[i]);
fatal("out of fixed registers");
goto err;
@@ -955,9 +744,9 @@ regalloc(Node *n, Type *t, Node *o)
for(i=REG_X0; i<=REG_X7; i++)
if(reg[i] == 0)
goto out;
- fprint(2, "registers allocated at\n");
+ print("registers allocated at\n");
for(i=REG_X0; i<=REG_X7; i++)
- fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
+ print("\t%R\t%#lux\n", i, regpc[i]);
fatal("out of floating registers");
}
yyerror("regalloc: unknown type %T", t);
@@ -1002,105 +791,6 @@ regfree(Node *n)
}
/*
- * initialize n to be register r of type t.
- */
-void
-nodreg(Node *n, Type *t, int r)
-{
- if(t == T)
- fatal("nodreg: t nil");
-
- memset(n, 0, sizeof(*n));
- n->op = OREGISTER;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.reg = r;
- n->type = t;
-}
-
-/*
- * initialize n to be indirect of register r; n is type t.
- */
-void
-nodindreg(Node *n, Type *t, int r)
-{
- nodreg(n, t, r);
- n->op = OINDREG;
-}
-
-Node*
-nodarg(Type *t, int fp)
-{
- Node *n;
- NodeList *l;
- Type *first;
- Iter savet;
-
- // entire argument struct, not just one arg
- switch(t->etype) {
- default:
- fatal("nodarg %T", t);
-
- case TSTRUCT:
- if(!t->funarg)
- fatal("nodarg: TSTRUCT but not funarg");
- n = nod(ONAME, N, N);
- n->sym = lookup(".args");
- n->type = t;
- first = structfirst(&savet, &t);
- if(first == nil)
- fatal("nodarg: bad struct");
- if(first->width == BADWIDTH)
- fatal("nodarg: offset not computed for %T", t);
- n->xoffset = first->width;
- n->addable = 1;
- break;
-
- case TFIELD:
- if(fp == 1 && t->sym != S && !isblanksym(t->sym)) {
- for(l=curfn->dcl; l; l=l->next) {
- n = l->n;
- if((n->class == PPARAM || n->class == PPARAMOUT) && n->sym == t->sym)
- return n;
- }
- }
-
- n = nod(ONAME, N, N);
- n->type = t->type;
- n->sym = t->sym;
- if(t->width == BADWIDTH)
- fatal("nodarg: offset not computed for %T", t);
- n->xoffset = t->width;
- n->addable = 1;
- n->orig = t->nname;
- break;
- }
-
- // Rewrite argument named _ to __,
- // or else the assignment to _ will be
- // discarded during code generation.
- if(isblank(n))
- n->sym = lookup("__");
-
- switch(fp) {
- default:
- fatal("nodarg %T %d", t, fp);
-
- case 0: // output arg
- n->op = OINDREG;
- n->val.u.reg = REG_SP;
- break;
-
- case 1: // input arg
- n->class = PPARAM;
- break;
- }
-
- n->typecheck = 1;
- return n;
-}
-
-/*
* generate
* as $c, reg
*/
@@ -1142,26 +832,6 @@ ncon(uint32 i)
return &n;
}
-/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
- switch(n->op) {
- case OITAB:
- case OSPTR:
- case OLEN:
- case OCAP:
- case OINDREG:
- case ONAME:
- case OPARAM:
- case OCLOSUREVAR:
- return 1;
- }
- return 0;
-}
-
Node sclean[10];
int nsclean;
@@ -1183,22 +853,25 @@ split64(Node *n, Node *lo, Node *hi)
nsclean++;
switch(n->op) {
default:
- if(!dotaddable(n, &n1)) {
- igen(n, &n1, N);
- sclean[nsclean-1] = n1;
- }
- n = &n1;
- goto common;
- case ONAME:
- if(n->class == PPARAMREF) {
- cgen(n->heapaddr, &n1);
- sclean[nsclean-1] = n1;
- // fall through.
+ switch(n->op) {
+ default:
+ if(!dotaddable(n, &n1)) {
+ igen(n, &n1, N);
+ sclean[nsclean-1] = n1;
+ }
n = &n1;
+ break;
+ case ONAME:
+ if(n->class == PPARAMREF) {
+ cgen(n->heapaddr, &n1);
+ sclean[nsclean-1] = n1;
+ n = &n1;
+ }
+ break;
+ case OINDREG:
+ // nothing
+ break;
}
- goto common;
- case OINDREG:
- common:
*lo = *n;
*hi = *n;
lo->type = types[TUINT32];
@@ -1408,8 +1081,8 @@ gmove(Node *f, Node *t)
gins(AMOVL, &flo, &tlo);
gins(AMOVL, &fhi, &thi);
} else {
- nodreg(&r1, t->type, REG_AX);
- nodreg(&r2, t->type, REG_DX);
+ nodreg(&r1, types[TUINT32], REG_AX);
+ nodreg(&r2, types[TUINT32], REG_DX);
gins(AMOVL, &flo, &r1);
gins(AMOVL, &fhi, &r2);
gins(AMOVL, &r1, &tlo);
@@ -1796,7 +1469,7 @@ floatmove_387(Node *f, Node *t)
gmove(f, &t1);
switch(tt) {
default:
- fatal("gmove %T", t);
+ fatal("gmove %N", t);
case TINT8:
gins(ACMPL, &t1, ncon(-0x80));
p1 = gbranch(optoas(OLT, types[TINT32]), T, -1);
@@ -2165,209 +1838,6 @@ gins(int as, Node *f, Node *t)
return p;
}
-/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
- Sym *s;
-
- a->scale = 0;
- a->reg = REG_NONE;
- a->index = REG_NONE;
- a->type = TYPE_NONE;
- a->name = NAME_NONE;
- a->gotype = nil;
- a->node = N;
- if(n == N)
- return;
-
- switch(n->op) {
- default:
- fatal("naddr: bad %O %D", n->op, a);
- break;
-
- case OREGISTER:
- a->type = TYPE_REG;
- a->reg = n->val.u.reg;
- a->sym = nil;
- break;
-
- case OINDREG:
- a->type = TYPE_MEM;
- a->reg = n->val.u.reg;
- a->sym = linksym(n->sym);
- a->offset = n->xoffset;
- break;
-
- case OPARAM:
- // n->left is PHEAP ONAME for stack parameter.
- // compute address of actual parameter on stack.
- a->etype = n->left->type->etype;
- a->width = n->left->type->width;
- a->offset = n->xoffset;
- a->sym = linksym(n->left->sym);
- a->type = TYPE_MEM;
- a->name = NAME_PARAM;
- a->node = n->left->orig;
- break;
-
- case OCLOSUREVAR:
- if(!curfn->needctxt)
- fatal("closurevar without needctxt");
- a->type = TYPE_MEM;
- a->reg = REG_DX;
- a->offset = n->xoffset;
- a->sym = nil;
- break;
-
- case OCFUNC:
- naddr(n->left, a, canemitcode);
- a->sym = linksym(n->left->sym);
- break;
-
- case ONAME:
- a->etype = 0;
- a->width = 0;
- if(n->type != T) {
- a->etype = simtype[n->type->etype];
- dowidth(n->type);
- a->width = n->type->width;
- }
- a->offset = n->xoffset;
- s = n->sym;
- a->node = n->orig;
- //if(a->node >= (Node*)&n)
- // fatal("stack node");
- if(s == S)
- s = lookup(".noname");
- if(n->method) {
- if(n->type != T)
- if(n->type->sym != S)
- if(n->type->sym->pkg != nil)
- s = pkglookup(s->name, n->type->sym->pkg);
- }
-
- switch(n->class) {
- default:
- fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
- case PEXTERN:
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- break;
- case PAUTO:
- a->type = TYPE_MEM;
- a->name = NAME_AUTO;
- break;
- case PPARAM:
- case PPARAMOUT:
- a->type = TYPE_MEM;
- a->name = NAME_PARAM;
- break;
- case PFUNC:
- a->type = TYPE_ADDR;
- a->name = NAME_EXTERN;
- s = funcsym(s);
- break;
- }
- a->sym = linksym(s);
- break;
-
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- fatal("naddr: const %lT", n->type);
- break;
- case CTFLT:
- a->type = TYPE_FCONST;
- a->u.dval = mpgetflt(n->val.u.fval);
- break;
- case CTINT:
- case CTRUNE:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = mpgetfix(n->val.u.xval);
- break;
- case CTSTR:
- datagostring(n->val.u.sval, a);
- break;
- case CTBOOL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = n->val.u.bval;
- break;
- case CTNIL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = 0;
- break;
- }
- break;
-
- case OADDR:
- naddr(n->left, a, canemitcode);
- if(a->type != TYPE_MEM)
- fatal("naddr: OADDR %D", a);
- a->type = TYPE_ADDR;
- break;
-
- case OITAB:
- // itable of interface value
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // len(nil)
- a->etype = tptr;
- a->width = widthptr;
- break;
-
- case OSPTR:
- // pointer in a string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // ptr(nil)
- a->etype = simtype[tptr];
- a->offset += Array_array;
- a->width = widthptr;
- break;
-
- case OLEN:
- // len of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // len(nil)
- a->etype = TUINT32;
- a->offset += Array_nel;
- a->width = 4;
- break;
-
- case OCAP:
- // cap of string or slice
- naddr(n->left, a, canemitcode);
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // cap(nil)
- a->etype = TUINT32;
- a->offset += Array_cap;
- a->width = 4;
- break;
-
-// case OADD:
-// if(n->right->op == OLITERAL) {
-// v = n->right->vconst;
-// naddr(n->left, a, canemitcode);
-// } else
-// if(n->left->op == OLITERAL) {
-// v = n->left->vconst;
-// naddr(n->right, a, canemitcode);
-// } else
-// goto bad;
-// a->offset += v;
-// break;
-
- }
-}
-
int
dotaddable(Node *n, Node *n1)
{
@@ -2398,7 +1868,7 @@ sudoaddable(int as, Node *n, Addr *a)
{
USED(as);
USED(n);
- USED(a);
+ memset(a, 0, sizeof *a);
return 0;
}
diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h
deleted file mode 100644
index 8378d5d456..0000000000
--- a/src/cmd/8g/opt.h
+++ /dev/null
@@ -1,192 +0,0 @@
-// Derived from Inferno utils/6c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-#define Z N
-#define Adr Addr
-
-#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
-#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
-#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
-#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
-
-#define CLOAD 5
-#define CREF 5
-#define CINF 1000
-#define LOOP 3
-
-typedef struct Reg Reg;
-typedef struct Rgn Rgn;
-
-/*c2go
-extern Node *Z;
-enum
-{
- CLOAD = 5,
- CREF = 5,
- CINF = 1000,
- LOOP = 3,
-};
-
-uint32 BLOAD(Reg*);
-uint32 BSTORE(Reg*);
-uint64 LOAD(Reg*);
-uint64 STORE(Reg*);
-*/
-
-// A Reg is a wrapper around a single Prog (one instruction) that holds
-// register optimization information while the optimizer runs.
-// r->prog is the instruction.
-// r->prog->opt points back to r.
-struct Reg
-{
- Flow f;
-
- Bits set; // regopt variables written by this instruction.
- Bits use1; // regopt variables read by prog->from.
- Bits use2; // regopt variables read by prog->to.
-
- // refahead/refbehind are the regopt variables whose current
- // value may be used in the following/preceding instructions
- // up to a CALL (or the value is clobbered).
- Bits refbehind;
- Bits refahead;
- // calahead/calbehind are similar, but for variables in
- // instructions that are reachable after hitting at least one
- // CALL.
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- int32 regu; // register used bitmap
- int32 rpo; // reverse post ordering
- int32 active;
-
- uint16 loop; // x5 for every loop
- uchar refset; // diagnostic generated
-
- Reg* p1; // predecessors of this instruction: p1,
- Reg* p2; // and then p2 linked though p2link.
- Reg* p2link;
- Reg* s1; // successors of this instruction (at most two: s1 and s2).
- Reg* s2;
- Reg* link; // next instruction in function code
- Prog* prog; // actual instruction
-};
-#define R ((Reg*)0)
-/*c2go extern Reg *R; */
-
-#define NRGN 600
-/*c2go enum { NRGN = 600 }; */
-
-// A Rgn represents a single regopt variable over a region of code
-// where a register could potentially be dedicated to that variable.
-// The code encompassed by a Rgn is defined by the flow graph,
-// starting at enter, flood-filling forward while varno is refahead
-// and backward while varno is refbehind, and following branches. A
-// single variable may be represented by multiple disjoint Rgns and
-// each Rgn may choose a different register for that variable.
-// Registers are allocated to regions greedily in order of descending
-// cost.
-struct Rgn
-{
- Reg* enter;
- short cost;
- short varno;
- short regno;
-};
-
-EXTERN int32 exregoffset; // not set
-EXTERN int32 exfregoffset; // not set
-EXTERN Reg zreg;
-EXTERN Reg* freer;
-EXTERN Reg** rpo2r;
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-EXTERN int32 regbits;
-EXTERN int32 exregbits;
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-EXTERN Bits ivar;
-EXTERN Bits ovar;
-EXTERN int change;
-EXTERN int32 maxnr;
-EXTERN int32* idom;
-
-EXTERN struct
-{
- int32 ncvtreg;
- int32 nspill;
- int32 nreload;
- int32 ndelmov;
- int32 nvar;
- int32 naddr;
-} ostats;
-
-/*
- * reg.c
- */
-Reg* rega(void);
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Adr*);
-void prop(Reg*, Bits, Bits);
-void loopit(Reg*, int32);
-void synch(Reg*, Bits);
-uint32 allreg(uint32, Rgn*);
-void paint1(Reg*, int);
-uint32 paint2(Reg*, int, int);
-void paint3(Reg*, int, uint32, int);
-void addreg(Adr*, int);
-void dumpone(Flow*, int);
-void dumpit(char*, Flow*, int);
-
-/*
- * peep.c
- */
-void peep(Prog*);
-void excise(Flow*);
-int copyu(Prog*, Adr*, Adr*);
-
-uint32 RtoB(int);
-uint32 FtoB(int);
-int BtoR(uint32);
-int BtoF(uint32);
-
-/*
- * prog.c
- */
-void proginfo(ProgInfo*, Prog*);
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
index 6c0865a7e8..712c8fe11b 100644
--- a/src/cmd/8g/peep.c
+++ b/src/cmd/8g/peep.c
@@ -31,10 +31,11 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
enum {
REGEXT = 0,
+ exregoffset = REG_DI,
};
static void conprop(Flow *r);
@@ -45,6 +46,7 @@ static int copy1(Adr*, Adr*, Flow*, int);
static int copyas(Adr*, Adr*);
static int copyau(Adr*, Adr*);
static int copysub(Adr*, Adr*, Adr*, int);
+static int copyu(Prog*, Adr*, Adr*);
static uint32 gactive;
@@ -92,7 +94,7 @@ peep(Prog *firstp)
Prog *p, *p1;
int t;
- g = flowstart(firstp, sizeof(Flow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
gactive = 0;
@@ -535,7 +537,7 @@ copy1(Adr *v1, Adr *v2, Flow *r, int f)
* 4 if set and used
* 0 otherwise (not touched)
*/
-int
+static int
copyu(Prog *p, Adr *v, Adr *s)
{
ProgInfo info;
@@ -559,7 +561,7 @@ copyu(Prog *p, Adr *v, Adr *s)
case ACALL:
if(REGEXT && v->type == TYPE_REG && v->reg <= REGEXT && v->reg > exregoffset)
return 2;
- if(REGARG >= 0 && v->type == TYPE_REG && v->reg == (uchar)REGARG)
+ if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG)
return 2;
if(v->type == p->from.type && v->reg == p->from.reg)
return 2;
@@ -574,7 +576,7 @@ copyu(Prog *p, Adr *v, Adr *s)
return 3;
case ATEXT:
- if(REGARG >= 0 && v->type == TYPE_REG && v->reg == (uchar)REGARG)
+ if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG)
return 3;
return 0;
}
diff --git a/src/cmd/8g/prog.c b/src/cmd/8g/prog.c
index 8a7371b5c4..e77a026a93 100644
--- a/src/cmd/8g/prog.c
+++ b/src/cmd/8g/prog.c
@@ -5,7 +5,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
// Matches real RtoB but can be used in global initializer.
#define RtoB(r) (1<<((r)-REG_AX))
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index 7d2de53549..0470bdf7b5 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -31,523 +31,34 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
-#define NREGVAR 16 /* 8 integer + 8 floating */
-#define REGBITS ((uint64)0xffffull)
-/*c2go enum {
- NREGVAR = 16,
- REGBITS = (1<<NREGVAR) - 1,
+enum {
+ NREGVAR = 16, /* 8 integer + 8 floating */
};
-*/
-
-static Reg* firstr;
-static int first = 1;
-
-int
-rcmp(const void *a1, const void *a2)
-{
- Rgn *p1, *p2;
- int c1, c2;
-
- p1 = (Rgn*)a1;
- p2 = (Rgn*)a2;
- c1 = p2->cost;
- c2 = p1->cost;
- if(c1 -= c2)
- return c1;
- return p2->varno - p1->varno;
-}
-
-static void
-setaddrs(Bits bit)
-{
- int i, n;
- Var *v;
- Node *node;
-
- while(bany(&bit)) {
- // convert each bit to a variable
- i = bnum(bit);
- node = var[i].node;
- n = var[i].name;
- biclr(&bit, i);
-
- // disable all pieces of that variable
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node && v->name == n)
- v->addr = 2;
- }
- }
-}
static char* regname[] = {
".ax", ".cx", ".dx", ".bx", ".sp", ".bp", ".si", ".di",
".x0", ".x1", ".x2", ".x3", ".x4", ".x5", ".x6", ".x7",
};
-static Node* regnodes[NREGVAR];
-
-static void walkvardef(Node *n, Reg *r, int active);
-
-void
-regopt(Prog *firstp)
+char**
+regnames(int *n)
{
- Reg *r, *r1;
- Prog *p;
- Graph *g;
- ProgInfo info;
- int i, z, active;
- uint32 vreg;
- Bits bit;
-
- if(first) {
- fmtinstall('Q', Qconv);
- exregoffset = REG_DI; // no externals
- first = 0;
- }
-
- mergetemp(firstp);
-
- /*
- * control flow is more complicated in generated go code
- * than in generated c code. define pseudo-variables for
- * registers, so we have complete register usage information.
- */
- nvar = NREGVAR;
- memset(var, 0, NREGVAR*sizeof var[0]);
- for(i=0; i<NREGVAR; i++) {
- if(regnodes[i] == N)
- regnodes[i] = newname(lookup(regname[i]));
- var[i].node = regnodes[i];
- }
-
- regbits = RtoB(REG_SP);
- for(z=0; z<BITS; z++) {
- externs.b[z] = 0;
- params.b[z] = 0;
- consts.b[z] = 0;
- addrs.b[z] = 0;
- ivar.b[z] = 0;
- ovar.b[z] = 0;
- }
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- g = flowstart(firstp, sizeof(Reg));
- if(g == nil) {
- for(i=0; i<nvar; i++)
- var[i].node->opt = nil;
- return;
- }
-
- firstr = (Reg*)g->start;
-
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- p = r->f.prog;
- if(p->as == AVARDEF || p->as == AVARKILL)
- continue;
- proginfo(&info, p);
-
- // Avoid making variables for direct-called functions.
- if(p->as == ACALL && p->to.type == TYPE_MEM && p->to.name == NAME_EXTERN)
- continue;
-
- r->use1.b[0] |= info.reguse | info.regindex;
- r->set.b[0] |= info.regset;
-
- bit = mkvar(r, &p->from);
- if(bany(&bit)) {
- if(info.flags & LeftAddr)
- setaddrs(bit);
- if(info.flags & LeftRead)
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
- if(info.flags & LeftWrite)
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- }
-
- bit = mkvar(r, &p->to);
- if(bany(&bit)) {
- if(info.flags & RightAddr)
- setaddrs(bit);
- if(info.flags & RightRead)
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- if(info.flags & RightWrite)
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- }
- }
- if(firstr == R)
- return;
-
- for(i=0; i<nvar; i++) {
- Var *v = var+i;
- if(v->addr) {
- bit = blsh(i);
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- }
-
- if(debug['R'] && debug['v'])
- print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
- i, v->addr, v->etype, v->width, v->node, v->offset);
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass1", &firstr->f, 1);
-
- /*
- * pass 2
- * find looping structure
- */
- flowrpo(g);
-
- if(debug['R'] && debug['v'])
- dumpit("pass2", &firstr->f, 1);
-
- /*
- * pass 2.5
- * iterate propagating fat vardef covering forward
- * r->act records vars with a VARDEF since the last CALL.
- * (r->act will be reused in pass 5 for something else,
- * but we'll be done with it by then.)
- */
- active = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- r->f.active = 0;
- r->act = zbits;
- }
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- p = r->f.prog;
- if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
- active++;
- walkvardef(p->to.node, r, active);
- }
- }
-
- /*
- * pass 3
- * iterate propagating usage
- * back until flow graph is complete
- */
-loop1:
- change = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->f.active = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- if(r->f.prog->as == ARET)
- prop(r, zbits, zbits);
-loop11:
- /* pick up unreachable code */
- i = 0;
- for(r = firstr; r != R; r = r1) {
- r1 = (Reg*)r->f.link;
- if(r1 && r1->f.active && !r->f.active) {
- prop(r, zbits, zbits);
- i = 1;
- }
- }
- if(i)
- goto loop11;
- if(change)
- goto loop1;
-
- if(debug['R'] && debug['v'])
- dumpit("pass3", &firstr->f, 1);
-
- /*
- * pass 4
- * iterate propagating register/variable synchrony
- * forward until graph is complete
- */
-loop2:
- change = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->f.active = 0;
- synch(firstr, zbits);
- if(change)
- goto loop2;
-
- if(debug['R'] && debug['v'])
- dumpit("pass4", &firstr->f, 1);
-
- /*
- * pass 4.5
- * move register pseudo-variables into regu.
- */
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
-
- r->set.b[0] &= ~REGBITS;
- r->use1.b[0] &= ~REGBITS;
- r->use2.b[0] &= ~REGBITS;
- r->refbehind.b[0] &= ~REGBITS;
- r->refahead.b[0] &= ~REGBITS;
- r->calbehind.b[0] &= ~REGBITS;
- r->calahead.b[0] &= ~REGBITS;
- r->regdiff.b[0] &= ~REGBITS;
- r->act.b[0] &= ~REGBITS;
- }
-
- /*
- * pass 5
- * isolate regions
- * calculate costs (paint1)
- */
- r = firstr;
- if(r) {
- for(z=0; z<BITS; z++)
- bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
- ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
- if(bany(&bit) && !r->f.refset) {
- // should never happen - all variables are preset
- if(debug['w'])
- print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
- r->f.refset = 1;
- }
- }
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->act = zbits;
- rgp = region;
- nregion = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- for(z=0; z<BITS; z++)
- bit.b[z] = r->set.b[z] &
- ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
- if(bany(&bit) && !r->f.refset) {
- if(debug['w'])
- print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
- r->f.refset = 1;
- excise(&r->f);
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- rgp->enter = r;
- rgp->varno = i;
- change = 0;
- paint1(r, i);
- biclr(&bit, i);
- if(change <= 0)
- continue;
- rgp->cost = change;
- nregion++;
- if(nregion >= NRGN) {
- if(debug['R'] && debug['v'])
- print("too many regions\n");
- goto brk;
- }
- rgp++;
- }
- }
-brk:
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- if(debug['R'] && debug['v'])
- print("\nregisterizing\n");
- for(i=0; i<nregion; i++) {
- if(debug['R'] && debug['v'])
- print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
- bit = blsh(rgp->varno);
- vreg = paint2(rgp->enter, rgp->varno, 0);
- vreg = allreg(vreg, rgp);
- if(rgp->regno != 0)
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- rgp++;
- }
-
- /*
- * free aux structures. peep allocates new ones.
- */
- for(i=0; i<nvar; i++)
- var[i].node->opt = nil;
- flowend(g);
- firstr = R;
-
- if(debug['R'] && debug['v']) {
- // Rebuild flow graph, since we inserted instructions
- g = flowstart(firstp, sizeof(Reg));
- firstr = (Reg*)g->start;
- dumpit("pass6", &firstr->f, 1);
- flowend(g);
- firstr = R;
- }
-
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P'])
- peep(firstp);
-
- /*
- * eliminate nops
- */
- for(p=firstp; p!=P; p=p->link) {
- while(p->link != P && p->link->as == ANOP)
- p->link = p->link->link;
- if(p->to.type == TYPE_BRANCH)
- while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
- p->to.u.branch = p->to.u.branch->link;
- }
-
- if(!use_sse)
- for(p=firstp; p!=P; p=p->link) {
- if(p->from.reg >= REG_X0 && p->from.reg <= REG_X7)
- fatal("invalid use of %R with GO386=387: %P", p->from.reg, p);
- if(p->to.reg >= REG_X0 && p->to.reg <= REG_X7)
- fatal("invalid use of %R with GO386=387: %P", p->to.reg, p);
- }
-
- if(debug['R']) {
- if(ostats.ncvtreg ||
- ostats.nspill ||
- ostats.nreload ||
- ostats.ndelmov ||
- ostats.nvar ||
- ostats.naddr ||
- 0)
- print("\nstats\n");
-
- if(ostats.ncvtreg)
- print(" %4d cvtreg\n", ostats.ncvtreg);
- if(ostats.nspill)
- print(" %4d spill\n", ostats.nspill);
- if(ostats.nreload)
- print(" %4d reload\n", ostats.nreload);
- if(ostats.ndelmov)
- print(" %4d delmov\n", ostats.ndelmov);
- if(ostats.nvar)
- print(" %4d var\n", ostats.nvar);
- if(ostats.naddr)
- print(" %4d addr\n", ostats.naddr);
-
- memset(&ostats, 0, sizeof(ostats));
- }
+ *n = NREGVAR;
+ return regname;
}
-static void
-walkvardef(Node *n, Reg *r, int active)
+uint64
+excludedregs(void)
{
- Reg *r1, *r2;
- int bn;
- Var *v;
-
- for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
- if(r1->f.active == active)
- break;
- r1->f.active = active;
- if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
- break;
- for(v=n->opt; v!=nil; v=v->nextinnode) {
- bn = v - var;
- biset(&r1->act, bn);
- }
- if(r1->f.prog->as == ACALL)
- break;
- }
-
- for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
- if(r2->f.s2 != nil)
- walkvardef(n, (Reg*)r2->f.s2, active);
+ return RtoB(REG_SP);
}
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1;
- Adr *a;
- Var *v;
-
- p1 = mal(sizeof(*p1));
- clearp(p1);
- p1->pc = 9999;
-
- p = r->f.prog;
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = TYPE_MEM;
- a->name = v->name;
- a->node = v->node;
- a->sym = linksym(v->node->sym);
-
- // need to clean this up with wptr and
- // some of the defaults
- p1->as = AMOVL;
- switch(v->etype) {
- default:
- fatal("unknown type %E", v->etype);
- case TINT8:
- case TUINT8:
- case TBOOL:
- p1->as = AMOVB;
- break;
- case TINT16:
- case TUINT16:
- p1->as = AMOVW;
- break;
- case TFLOAT32:
- p1->as = AMOVSS;
- break;
- case TFLOAT64:
- p1->as = AMOVSD;
- break;
- case TINT:
- case TUINT:
- case TINT32:
- case TUINT32:
- case TPTR32:
- break;
- }
-
- p1->from.type = TYPE_REG;
- p1->from.reg = rn;
- p1->from.name = 0;
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = TYPE_REG;
- a->reg = rn;
- if(v->etype == TUINT8)
- p1->as = AMOVB;
- if(v->etype == TUINT16)
- p1->as = AMOVW;
- }
- if(debug['R'] && debug['v'])
- print("%P ===add=== %P\n", p, p1);
- ostats.nspill++;
-}
-
-uint32
+uint64
doregbits(int r)
{
- uint32 b;
+ uint64 b;
b = 0;
if(r >= REG_AX && r <= REG_DI)
@@ -564,605 +75,17 @@ doregbits(int r)
return b;
}
-static int
-overlap(int32 o1, int w1, int32 o2, int w2)
-{
- int32 t1, t2;
-
- t1 = o1+w1;
- t2 = o2+w2;
-
- if(!(t1 > o2 && t2 > o1))
- return 0;
-
- return 1;
-}
-
-Bits
-mkvar(Reg *r, Adr *a)
-{
- Var *v;
- int i, n, et, z, w, flag, regu;
- int32 o;
- Bits bit;
- Node *node;
-
- /*
- * mark registers used
- */
- if(a->type == TYPE_NONE)
- goto none;
-
- if(r != R)
- r->use1.b[0] |= doregbits(a->index);
-
- switch(a->type) {
- default:
- regu = doregbits(a->reg);
- if(regu == 0)
- goto none;
- bit = zbits;
- bit.b[0] = regu;
- return bit;
-
- case TYPE_ADDR:
- a->type = TYPE_MEM;
- bit = mkvar(r, a);
- setaddrs(bit);
- a->type = TYPE_ADDR;
- ostats.naddr++;
- goto none;
-
- case TYPE_MEM:
- switch(a->name) {
- default:
- goto none;
- case NAME_EXTERN:
- case NAME_STATIC:
- case NAME_PARAM:
- case NAME_AUTO:
- n = a->name;
- break;
- }
- }
-
- node = a->node;
- if(node == N || node->op != ONAME || node->orig == N)
- goto none;
- node = node->orig;
- if(node->orig != node)
- fatal("%D: bad node", a);
- if(node->sym == S || node->sym->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- w = a->width;
- if(w < 0)
- fatal("bad width %d for %D", w, a);
-
- flag = 0;
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node && v->name == n) {
- if(v->offset == o)
- if(v->etype == et)
- if(v->width == w)
- return blsh(i);
-
- // if they overlap, disable both
- if(overlap(v->offset, v->width, o, w)) {
- if(debug['R'])
- print("disable %s\n", node->sym->name);
- v->addr = 1;
- flag = 1;
- }
- }
- }
-
- switch(et) {
- case 0:
- case TFUNC:
- goto none;
- }
-
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && node != N)
- fatal("variable not optimized: %D", a);
-
- // If we're not tracking a word in a variable, mark the rest as
- // having its address taken, so that we keep the whole thing
- // live at all calls. otherwise we might optimize away part of
- // a variable but not all of it.
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node)
- v->addr = 1;
- }
- goto none;
- }
-
- i = nvar;
- nvar++;
- v = var+i;
- v->offset = o;
- v->name = n;
- v->etype = et;
- v->width = w;
- v->addr = flag; // funny punning
- v->node = node;
-
- // node->opt is the head of a linked list
- // of Vars within the given Node, so that
- // we can start at a Var and find all the other
- // Vars in the same Go variable.
- v->nextinnode = node->opt;
- node->opt = v;
-
- bit = blsh(i);
- if(n == NAME_EXTERN || n == NAME_STATIC)
- for(z=0; z<BITS; z++)
- externs.b[z] |= bit.b[z];
- if(n == NAME_PARAM)
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
-
- if(node->class == PPARAM)
- for(z=0; z<BITS; z++)
- ivar.b[z] |= bit.b[z];
- if(node->class == PPARAMOUT)
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
-
- // Treat values with their address taken as live at calls,
- // because the garbage collector's liveness analysis in ../gc/plive.c does.
- // These must be consistent or else we will elide stores and the garbage
- // collector will see uninitialized data.
- // The typical case where our own analysis is out of sync is when the
- // node appears to have its address taken but that code doesn't actually
- // get generated and therefore doesn't show up as an address being
- // taken when we analyze the instruction stream.
- // One instance of this case is when a closure uses the same name as
- // an outer variable for one of its own variables declared with :=.
- // The parser flags the outer variable as possibly shared, and therefore
- // sets addrtaken, even though it ends up not being actually shared.
- // If we were better about _ elision, _ = &x would suffice too.
- // The broader := in a closure problem is mentioned in a comment in
- // closure.c:/^typecheckclosure and dcl.c:/^oldname.
- if(node->addrtaken)
- v->addr = 1;
-
- // Disable registerization for globals, because:
- // (1) we might panic at any time and we want the recovery code
- // to see the latest values (issue 1304).
- // (2) we don't know what pointers might point at them and we want
- // loads via those pointers to see updated values and vice versa (issue 7995).
- //
- // Disable registerization for results if using defer, because the deferred func
- // might recover and return, causing the current values to be used.
- if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
- v->addr = 1;
-
- if(debug['R'])
- print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
- ostats.nvar++;
-
- return bit;
-
-none:
- return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
- Reg *r1, *r2;
- int z, i, j;
- Var *v, *v1;
-
- for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(r1->f.prog->as) {
- case ACALL:
- if(noreturn(r1->f.prog))
- break;
-
- // Mark all input variables (ivar) as used, because that's what the
- // liveness bitmaps say. The liveness bitmaps say that so that a
- // panic will not show stale values in the parameter dump.
- // Mark variables with a recent VARDEF (r1->act) as used,
- // so that the optimizer flushes initializations to memory,
- // so that if a garbage collection happens during this CALL,
- // the collector will see initialized memory. Again this is to
- // match what the liveness bitmaps say.
- for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
- ref.b[z] = 0;
- }
-
- // cal.b is the current approximation of what's live across the call.
- // Every bit in cal.b is a single stack word. For each such word,
- // find all the other tracked stack words in the same Go variable
- // (struct/slice/string/interface) and mark them live too.
- // This is necessary because the liveness analysis for the garbage
- // collector works at variable granularity, not at word granularity.
- // It is fundamental for slice/string/interface: the garbage collector
- // needs the whole value, not just some of the words, in order to
- // interpret the other bits correctly. Specifically, slice needs a consistent
- // ptr and cap, string needs a consistent ptr and len, and interface
- // needs a consistent type word and data word.
- for(z=0; z<BITS; z++) {
- if(cal.b[z] == 0)
- continue;
- for(i=0; i<64; i++) {
- if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
- continue;
- v = var+z*64+i;
- if(v->node->opt == nil) // v represents fixed register, not Go variable
- continue;
-
- // v->node->opt is the head of a linked list of Vars
- // corresponding to tracked words from the Go variable v->node.
- // Walk the list and set all the bits.
- // For a large struct this could end up being quadratic:
- // after the first setting, the outer loop (for z, i) would see a 1 bit
- // for all of the remaining words in the struct, and for each such
- // word would go through and turn on all the bits again.
- // To avoid the quadratic behavior, we only turn on the bits if
- // v is the head of the list or if the head's bit is not yet turned on.
- // This will set the bits at most twice, keeping the overall loop linear.
- v1 = v->node->opt;
- j = v1 - var;
- if(v == v1 || !btest(&cal, j)) {
- for(; v1 != nil; v1 = v1->nextinnode) {
- j = v1 - var;
- biset(&cal, j);
- }
- }
- }
- }
- break;
-
- case ATEXT:
- for(z=0; z<BITS; z++) {
- cal.b[z] = 0;
- ref.b[z] = 0;
- }
- break;
-
- case ARET:
- for(z=0; z<BITS; z++) {
- cal.b[z] = externs.b[z] | ovar.b[z];
- ref.b[z] = 0;
- }
- break;
- }
- for(z=0; z<BITS; z++) {
- ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
- r1->use1.b[z] | r1->use2.b[z];
- cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
- r1->refbehind.b[z] = ref.b[z];
- r1->calbehind.b[z] = cal.b[z];
- }
- if(r1->f.active)
- break;
- r1->f.active = 1;
- }
- for(; r != r1; r = (Reg*)r->f.p1)
- for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
- prop(r2, r->refbehind, r->calbehind);
-}
-
-void
-synch(Reg *r, Bits dif)
-{
- Reg *r1;
- int z;
-
- for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
- for(z=0; z<BITS; z++) {
- dif.b[z] = (dif.b[z] &
- ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
- r1->set.b[z] | r1->regdiff.b[z];
- if(dif.b[z] != r1->regdiff.b[z]) {
- r1->regdiff.b[z] = dif.b[z];
- change++;
- }
- }
- if(r1->f.active)
- break;
- r1->f.active = 1;
- for(z=0; z<BITS; z++)
- dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if((Reg*)r1->f.s2 != R)
- synch((Reg*)r1->f.s2, dif);
- }
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
- Var *v;
- int i;
-
- v = var + r->varno;
- r->regno = 0;
- switch(v->etype) {
-
- default:
- fatal("unknown etype %d/%E", bitno(b), v->etype);
- break;
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TPTR32:
- i = BtoR(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TFLOAT32:
- case TFLOAT64:
- if(!use_sse)
- break;
- i = BtoF(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return FtoB(i);
- }
- break;
- }
- return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint64 bb, rbz;
-
- z = bn/64;
- bb = 1LL<<(bn%64);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- rbz = ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z]));
- if(LOAD(r) & rbz & bb) {
- change -= CLOAD * r->f.loop;
- }
- for(;;) {
- r->act.b[z] |= bb;
- p = r->f.prog;
-
- if(r->f.prog->as != ANOP) { // don't give credit for NOPs
- if(r->use1.b[z] & bb) {
- change += CREF * r->f.loop;
- if(p->as == AFMOVL || p->as == AFMOVW)
- if(BtoR(bb) != REG_F0)
- change = -CINF;
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- change += CREF * r->f.loop;
- if(p->as == AFMOVL || p->as == AFMOVW)
- if(BtoR(bb) != REG_F0)
- change = -CINF;
- }
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->f.loop;
- if(p->as == AFMOVL || p->as == AFMOVW)
- if(BtoR(bb) != REG_F0)
- change = -CINF;
- }
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- paint1(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint1(r1, bn);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-uint32
-paint2(Reg *r, int bn, int depth)
-{
- Reg *r1;
- int z;
- uint64 bb, vreg;
-
- z = bn/64;
- bb = 1LL << (bn%64);
- vreg = regbits;
- if(!(r->act.b[z] & bb))
- return vreg;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(!(r1->act.b[z] & bb))
- break;
- r = r1;
- }
- for(;;) {
- if(debug['R'] && debug['v'])
- print(" paint2 %d %P\n", depth, r->f.prog);
-
- r->act.b[z] &= ~bb;
-
- vreg |= r->regu;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn, depth+1);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn, depth+1);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(!(r->act.b[z] & bb))
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-
- return vreg;
-}
-
-void
-paint3(Reg *r, int bn, uint32 rb, int rn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint64 bb, rbz;
-
- z = bn/64;
- bb = 1LL << (bn%64);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- rbz = ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z]));
- if(LOAD(r) & rbz & bb)
- addmove(r, bn, rn, 0);
- for(;;) {
- r->act.b[z] |= bb;
- p = r->f.prog;
-
- if(r->use1.b[z] & bb) {
- if(debug['R'] && debug['v'])
- print("%P", p);
- addreg(&p->from, rn);
- if(debug['R'] && debug['v'])
- print(" ===change== %P\n", p);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- if(debug['R'] && debug['v'])
- print("%P", p);
- addreg(&p->to, rn);
- if(debug['R'] && debug['v'])
- print(" ===change== %P\n", p);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(r, bn, rn, 1);
- r->regu |= rb;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Adr *a, int rn)
-{
- a->sym = nil;
- a->node = nil;
- a->offset = 0;
- a->type = TYPE_REG;
- a->reg = rn;
- a->name = 0;
-
- ostats.ncvtreg++;
-}
-
-uint32
+uint64
RtoB(int r)
{
if(r < REG_AX || r > REG_DI)
return 0;
- return 1L << (r-REG_AX);
+ return 1ULL << (r-REG_AX);
}
int
-BtoR(uint32 b)
+BtoR(uint64 b)
{
b &= 0xffL;
@@ -1171,93 +94,19 @@ BtoR(uint32 b)
return bitno(b) + REG_AX;
}
-uint32
+uint64
FtoB(int f)
{
if(f < REG_X0 || f > REG_X7)
return 0;
- return 1L << (f - REG_X0 + 8);
+ return 1ULL << (f - REG_X0 + 8);
}
int
-BtoF(uint32 b)
+BtoF(uint64 b)
{
b &= 0xFF00L;
if(b == 0)
return 0;
return bitno(b) - 8 + REG_X0;
}
-
-void
-dumpone(Flow *f, int isreg)
-{
- int z;
- Bits bit;
- Reg *r;
-
- print("%d:%P", f->loop, f->prog);
- if(isreg) {
- r = (Reg*)f;
- for(z=0; z<BITS; z++)
- bit.b[z] =
- r->set.b[z] |
- r->use1.b[z] |
- r->use2.b[z] |
- r->refbehind.b[z] |
- r->refahead.b[z] |
- r->calbehind.b[z] |
- r->calahead.b[z] |
- r->regdiff.b[z] |
- r->act.b[z] |
- 0;
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->set))
- print(" s:%Q", r->set);
- if(bany(&r->use1))
- print(" u1:%Q", r->use1);
- if(bany(&r->use2))
- print(" u2:%Q", r->use2);
- if(bany(&r->refbehind))
- print(" rb:%Q ", r->refbehind);
- if(bany(&r->refahead))
- print(" ra:%Q ", r->refahead);
- if(bany(&r->calbehind))
- print(" cb:%Q ", r->calbehind);
- if(bany(&r->calahead))
- print(" ca:%Q ", r->calahead);
- if(bany(&r->regdiff))
- print(" d:%Q ", r->regdiff);
- if(bany(&r->act))
- print(" a:%Q ", r->act);
- }
- }
- print("\n");
-}
-
-void
-dumpit(char *str, Flow *r0, int isreg)
-{
- Flow *r, *r1;
-
- print("\n%s\n", str);
- for(r = r0; r != nil; r = r->link) {
- dumpone(r, isreg);
- r1 = r->p2;
- if(r1 != nil) {
- print(" pred:");
- for(; r1 != nil; r1 = r1->p2link)
- print(" %.4ud", (int)r1->prog->pc);
- print("\n");
- }
- // Print successors if it's not just the next one
- if(r->s1 != r->link || r->s2 != nil) {
- print(" succ:");
- if(r->s1 != nil)
- print(" %.4ud", (int)r->s1->prog->pc);
- if(r->s2 != nil)
- print(" %.4ud", (int)r->s2->prog->pc);
- print("\n");
- }
- }
-}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index 28d7dab7fb..273a8ad523 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -634,6 +634,7 @@ enum
FREGRET = REG_F0,
REGSP = REG_SP,
REGTMP = REG_DI,
+ REGCTXT = REG_DX,
};
/*
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index 44d1ecc035..2da1651c8b 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -37,13 +37,6 @@
#include "../ld/macho.h"
#include "../ld/pe.h"
-char linuxdynld[] = "/lib/ld-linux.so.2";
-char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
-char openbsddynld[] = "/usr/libexec/ld.so";
-char netbsddynld[] = "/usr/libexec/ld.elf_so";
-char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
-char solarisdynld[] = "/lib/ld.so.1";
-
static int
needlib(char *name)
{
@@ -64,8 +57,6 @@ needlib(char *name)
return 0;
}
-int nelfsym = 1;
-
static void addpltsym(Link*, LSym*);
static void addgotsym(Link*, LSym*);
@@ -141,7 +132,7 @@ adddynrel(LSym *s, Reloc *r)
}
addgotsym(ctxt, targ);
r->type = R_CONST; // write r->add during relocsym
- r->sym = S;
+ r->sym = nil;
r->add += targ->got;
return;
@@ -218,7 +209,7 @@ adddynrel(LSym *s, Reloc *r)
addaddrplus(ctxt, rel, s, r->off);
adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_386_32));
r->type = R_CONST; // write r->add during relocsym
- r->sym = S;
+ r->sym = nil;
return;
}
if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
@@ -256,7 +247,7 @@ elfreloc1(Reloc *r, vlong sectoff)
{
int32 elfsym;
- LPUT(sectoff);
+ thearch.lput(sectoff);
elfsym = r->xsym->elfsym;
switch(r->type) {
@@ -265,7 +256,7 @@ elfreloc1(Reloc *r, vlong sectoff)
case R_ADDR:
if(r->siz == 4)
- LPUT(R_386_32 | elfsym<<8);
+ thearch.lput(R_386_32 | elfsym<<8);
else
return -1;
break;
@@ -273,7 +264,7 @@ elfreloc1(Reloc *r, vlong sectoff)
case R_CALL:
case R_PCREL:
if(r->siz == 4)
- LPUT(R_386_PC32 | elfsym<<8);
+ thearch.lput(R_386_PC32 | elfsym<<8);
else
return -1;
break;
@@ -281,7 +272,7 @@ elfreloc1(Reloc *r, vlong sectoff)
case R_TLS_LE:
case R_TLS_IE:
if(r->siz == 4)
- LPUT(R_386_TLS_LE | elfsym<<8);
+ thearch.lput(R_386_TLS_LE | elfsym<<8);
else
return -1;
}
@@ -342,8 +333,8 @@ machoreloc1(Reloc *r, vlong sectoff)
break;
}
- LPUT(sectoff);
- LPUT(v);
+ thearch.lput(sectoff);
+ thearch.lput(v);
return 0;
}
@@ -715,29 +706,3 @@ asmb(void)
}
cflush();
}
-
-void
-s8put(char *n)
-{
- char name[8];
- int i;
-
- strncpy(name, n, sizeof(name));
- for(i=0; i<sizeof(name); i++)
- cput(name[i]);
-}
-
-int32
-rnd(int32 v, int32 r)
-{
- int32 c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index 3c84d1b21f..e844bc4180 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -32,7 +32,6 @@
#include <libc.h>
#include <bio.h>
#include <link.h>
-#include "8.out.h"
#ifndef EXTERN
#define EXTERN extern
@@ -45,30 +44,10 @@ enum
IntSize = 4,
RegSize = 4,
MaxAlign = 32, // max data alignment
- FuncAlign = 16
-};
-
-#define P ((Prog*)0)
-#define S ((LSym*)0)
-
-enum
-{
+ FuncAlign = 16,
MINLC = 1,
};
-#pragma varargck type "I" uchar*
-
-EXTERN LSym* datap;
-EXTERN int debug[128];
-EXTERN char literal[32];
-EXTERN Prog* firstp;
-EXTERN int32 lcsize;
-EXTERN char* rpath;
-EXTERN int32 spsize;
-EXTERN LSym* symlist;
-EXTERN int32 symsize;
-
-int Iconv(Fmt *fp);
void adddynlib(char *lib);
void adddynrel(LSym *s, Reloc *r);
void adddynrela(LSym *rela, LSym *s, Reloc *r);
@@ -80,14 +59,6 @@ int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);
void listinit(void);
int machoreloc1(Reloc *r, vlong sectoff);
-int32 rnd(int32 v, int32 r);
-void s8put(char *n);
-char* xsymname(LSym *s);
-
-/* Native is little-endian */
-#define LPUT(a) lputl(a)
-#define WPUT(a) wputl(a)
-#define VPUT(a) vputl(a)
/* Used by ../ld/dwarf.c */
enum
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
index 0a75340603..4cd8f08d34 100644
--- a/src/cmd/8l/list.c
+++ b/src/cmd/8l/list.c
@@ -37,31 +37,4 @@ void
listinit(void)
{
listinit8();
- fmtinstall('I', Iconv);
-}
-
-int
-Iconv(Fmt *fp)
-{
- int i, n;
- uchar *p;
- char *s;
- Fmt fmt;
-
- n = fp->prec;
- fp->prec = 0;
- if(!(fp->flags&FmtPrec) || n < 0)
- return fmtstrcpy(fp, "%I");
- fp->flags &= ~FmtPrec;
- p = va_arg(fp->args, uchar*);
-
- // format into temporary buffer and
- // call fmtstrcpy to handle padding.
- fmtstrinit(&fmt);
- for(i=0; i<n; i++)
- fmtprint(&fmt, "%.2ux", *p++);
- s = fmtstrflush(&fmt);
- fmtstrcpy(fp, s);
- free(s);
- return 0;
}
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index 1b65c5eb9e..41900d6543 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -38,12 +38,50 @@
#include "../ld/pe.h"
#include <ar.h>
-char* thestring = "386";
-LinkArch* thelinkarch = &link386;
+void
+main(int argc, char **argv)
+{
+ linkarchinit();
+ ldmain(argc, argv);
+}
void
linkarchinit(void)
{
+ thestring = "386";
+ thelinkarch = &link386;
+
+ thearch.thechar = thechar;
+ thearch.ptrsize = thelinkarch->ptrsize;
+ thearch.intsize = thelinkarch->ptrsize;
+ thearch.regsize = thelinkarch->regsize;
+ thearch.funcalign = FuncAlign;
+ thearch.maxalign = MaxAlign;
+ thearch.minlc = MINLC;
+ thearch.dwarfregsp = DWARFREGSP;
+
+ thearch.adddynlib = adddynlib;
+ thearch.adddynrel = adddynrel;
+ thearch.adddynsym = adddynsym;
+ thearch.archinit = archinit;
+ thearch.archreloc = archreloc;
+ thearch.archrelocvariant = archrelocvariant;
+ thearch.asmb = asmb;
+ thearch.elfreloc1 = elfreloc1;
+ thearch.elfsetupplt = elfsetupplt;
+ thearch.gentext = gentext;
+ thearch.listinit = listinit;
+ thearch.machoreloc1 = machoreloc1;
+ thearch.lput = lputl;
+ thearch.wput = wputl;
+ thearch.vput = vputl;
+
+ thearch.linuxdynld = "/lib/ld-linux.so.2";
+ thearch.freebsddynld = "/usr/libexec/ld-elf.so.1";
+ thearch.openbsddynld = "/usr/libexec/ld.so";
+ thearch.netbsddynld = "/usr/libexec/ld.elf_so";
+ thearch.dragonflydynld = "/usr/libexec/ld-elf.so.2";
+ thearch.solarisdynld = "/lib/ld.so.1";
}
void
diff --git a/src/cmd/9g/cgen.c b/src/cmd/9g/cgen.c
index 706658de0e..009ea1ed7a 100644
--- a/src/cmd/9g/cgen.c
+++ b/src/cmd/9g/cgen.c
@@ -805,7 +805,7 @@ ginsadd(int as, vlong off, Node *dst)
void
agen(Node *n, Node *res)
{
- Node *nl, *nr;
+ Node *nl;
Node n1, n2, n3;
if(debug['g']) {
@@ -848,8 +848,6 @@ agen(Node *n, Node *res)
}
nl = n->left;
- nr = n->right;
- USED(nr);
switch(n->op) {
default:
@@ -1109,27 +1107,20 @@ bgen(Node *n, int true, int likely, Prog *to)
goto ret;
case OANDAND:
- if(!true)
- goto caseor;
-
- caseand:
- p1 = gbranch(ABR, T, 0);
- p2 = gbranch(ABR, T, 0);
- patch(p1, pc);
- bgen(n->left, !true, -likely, p2);
- bgen(n->right, !true, -likely, p2);
- p1 = gbranch(ABR, T, 0);
- patch(p1, to);
- patch(p2, pc);
- goto ret;
-
case OOROR:
- if(!true)
- goto caseand;
-
- caseor:
- bgen(n->left, true, likely, to);
- bgen(n->right, true, likely, to);
+ if((n->op == OANDAND) == true) {
+ p1 = gbranch(AJMP, T, 0);
+ p2 = gbranch(AJMP, T, 0);
+ patch(p1, pc);
+ bgen(n->left, !true, -likely, p2);
+ bgen(n->right, !true, -likely, p2);
+ p1 = gbranch(AJMP, T, 0);
+ patch(p1, to);
+ patch(p2, pc);
+ } else {
+ bgen(n->left, true, likely, to);
+ bgen(n->right, true, likely, to);
+ }
goto ret;
case OEQ:
@@ -1554,7 +1545,7 @@ cadable(Node *n)
int
componentgen(Node *nr, Node *nl)
{
- Node nodl, nodr;
+ Node nodl, nodr, tmp;
Type *t;
int freel, freer;
vlong fldcount;
@@ -1602,7 +1593,7 @@ componentgen(Node *nr, Node *nl)
nodl = *nl;
if(!cadable(nl)) {
- if(nr == N || !cadable(nr))
+ if(nr != N && !cadable(nr))
goto no;
igen(nl, &nodl, N);
freel = 1;
@@ -1614,6 +1605,12 @@ componentgen(Node *nr, Node *nl)
igen(nr, &nodr, N);
freer = 1;
}
+ } else {
+ // When zeroing, prepare a register containing zero.
+ nodconst(&tmp, nl->type, 0);
+ regalloc(&nodr, types[TUINT], N);
+ gmove(&tmp, &nodr);
+ freer = 1;
}
// nl and nr are 'cadable' which basically means they are names (variables) now.
@@ -1650,8 +1647,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
@@ -1660,8 +1656,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_cap-Array_nel;
@@ -1670,8 +1665,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_cap-Array_nel;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
goto yes;
@@ -1685,8 +1679,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
@@ -1695,8 +1688,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
goto yes;
@@ -1710,8 +1702,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
@@ -1720,8 +1711,7 @@ componentgen(Node *nr, Node *nl)
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
nodr.type = nodl.type;
- } else
- nodconst(&nodr, nodl.type, 0);
+ }
gmove(&nodr, &nodl);
goto yes;
diff --git a/src/cmd/9g/galign.c b/src/cmd/9g/galign.c
index df4291e90e..74856e2af0 100644
--- a/src/cmd/9g/galign.c
+++ b/src/cmd/9g/galign.c
@@ -14,12 +14,12 @@ void
linkarchinit(void)
{
thestring = getgoarch();
- arch.thestring = thestring;
+ thearch.thestring = thestring;
if(strcmp(thestring, "ppc64le") == 0)
thelinkarch = &linkppc64le;
else
thelinkarch = &linkppc64;
- arch.thelinkarch = thelinkarch;
+ thearch.thelinkarch = thelinkarch;
}
vlong MAXWIDTH = 1LL<<50;
@@ -49,61 +49,46 @@ betypeinit(void)
void
main(int argc, char **argv)
{
- arch.thechar = thechar;
- arch.thestring = thestring;
- arch.thelinkarch = thelinkarch;
- arch.typedefs = typedefs;
- arch.MAXWIDTH = MAXWIDTH;
- arch.afunclit = afunclit;
- arch.anyregalloc = anyregalloc;
- arch.betypeinit = betypeinit;
- arch.bgen = bgen;
- arch.cgen = cgen;
- arch.cgen_asop = cgen_asop;
- arch.cgen_call = cgen_call;
- arch.cgen_callinter = cgen_callinter;
- arch.cgen_ret = cgen_ret;
- arch.clearfat = clearfat;
- arch.clearp = clearp;
- arch.defframe = defframe;
- arch.dgostringptr = dgostringptr;
- arch.dgostrlitptr = dgostrlitptr;
- arch.dsname = dsname;
- arch.dsymptr = dsymptr;
- arch.dumpdata = dumpdata;
- arch.dumpit = dumpit;
- arch.excise = excise;
- arch.expandchecks = expandchecks;
- arch.fixautoused = fixautoused;
- arch.gclean = gclean;
- arch.gdata = gdata;
- arch.gdatacomplex = gdatacomplex;
- arch.gdatastring = gdatastring;
- arch.ggloblnod = ggloblnod;
- arch.ggloblsym = ggloblsym;
- arch.ginit = ginit;
- arch.gins = gins;
- arch.ginscall = ginscall;
- arch.gjmp = gjmp;
- arch.gtrack = gtrack;
- arch.gused = gused;
- arch.igen = igen;
- arch.isfat = isfat;
- arch.linkarchinit = linkarchinit;
- arch.markautoused = markautoused;
- arch.naddr = naddr;
- arch.newplist = newplist;
- arch.nodarg = nodarg;
- arch.patch = patch;
- arch.proginfo = proginfo;
- arch.regalloc = regalloc;
- arch.regfree = regfree;
- arch.regopt = regopt;
- arch.regtyp = regtyp;
- arch.sameaddr = sameaddr;
- arch.smallindir = smallindir;
- arch.stackaddr = stackaddr;
- arch.unpatch = unpatch;
+ thearch.thechar = thechar;
+ thearch.thestring = thestring;
+ thearch.thelinkarch = thelinkarch;
+ thearch.typedefs = typedefs;
+ thearch.REGSP = REGSP;
+ thearch.REGCTXT = REGCTXT;
+ thearch.MAXWIDTH = MAXWIDTH;
+ thearch.anyregalloc = anyregalloc;
+ thearch.betypeinit = betypeinit;
+ thearch.bgen = bgen;
+ thearch.cgen = cgen;
+ thearch.cgen_call = cgen_call;
+ thearch.cgen_callinter = cgen_callinter;
+ thearch.cgen_ret = cgen_ret;
+ thearch.clearfat = clearfat;
+ thearch.defframe = defframe;
+ thearch.excise = excise;
+ thearch.expandchecks = expandchecks;
+ thearch.gclean = gclean;
+ thearch.ginit = ginit;
+ thearch.gins = gins;
+ thearch.ginscall = ginscall;
+ thearch.igen = igen;
+ thearch.linkarchinit = linkarchinit;
+ thearch.peep = peep;
+ thearch.proginfo = proginfo;
+ thearch.regalloc = regalloc;
+ thearch.regfree = regfree;
+ thearch.regtyp = regtyp;
+ thearch.sameaddr = sameaddr;
+ thearch.smallindir = smallindir;
+ thearch.stackaddr = stackaddr;
+ thearch.excludedregs = excludedregs;
+ thearch.RtoB = RtoB;
+ thearch.FtoB = RtoB;
+ thearch.BtoR = BtoR;
+ thearch.BtoF = BtoF;
+ thearch.optoas = optoas;
+ thearch.doregbits = doregbits;
+ thearch.regnames = regnames;
gcmain(argc, argv);
}
diff --git a/src/cmd/9g/gg.h b/src/cmd/9g/gg.h
index 367a858e86..938675937e 100644
--- a/src/cmd/9g/gg.h
+++ b/src/cmd/9g/gg.h
@@ -9,13 +9,7 @@
#include "../gc/go.h"
#include "../9l/9.out.h"
-// TODO(minux): Remove when no longer used.
-#define noimpl sysfatal("%s not implemented (%s:%d).", __func__, __FILE__, __LINE__)
-
-EXTERN int32 dynloc;
EXTERN uchar reg[NREG+NFREG];
-EXTERN int32 pcloc; // instruction counter
-EXTERN Strlit emptystring;
EXTERN Node* panicdiv;
extern vlong unmappedzero;
@@ -112,7 +106,6 @@ int anyregalloc(void);
void betypeinit(void);
void bgen(Node*, int, int, Prog*);
void cgen(Node*, Node*);
-void cgen_asop(Node*);
void cgen_call(Node*, int);
void cgen_callinter(Node*, Node*, int);
void cgen_ret(Node*);
@@ -158,3 +151,19 @@ int smallindir(Addr*, Addr*);
int stackaddr(Addr*);
Prog* unpatch(Prog*);
+
+/*
+ * reg.c
+ */
+uint64 excludedregs(void);
+uint64 RtoB(int);
+uint64 FtoB(int);
+int BtoR(uint64);
+int BtoF(uint64);
+uint64 doregbits(int);
+char** regnames(int*);
+
+/*
+ * peep.c
+ */
+void peep(Prog*);
diff --git a/src/cmd/9g/ggen.c b/src/cmd/9g/ggen.c
index 3865051018..7b34282685 100644
--- a/src/cmd/9g/ggen.c
+++ b/src/cmd/9g/ggen.c
@@ -7,7 +7,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
static Prog *appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset);
static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi);
@@ -113,51 +113,6 @@ appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int tre
return q;
}
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog *p)
-{
- for (; p; p = p->link) {
- if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
- continue;
-
- if (p->from.node)
- ((Node*)(p->from.node))->used = 1;
-
- if (p->to.node)
- ((Node*)(p->to.node))->used = 1;
- }
-}
-
-// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
-void
-fixautoused(Prog *p)
-{
- Prog **lp;
-
- for (lp=&p; (p=*lp) != P; ) {
- if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
- *lp = p->link;
- continue;
- }
- if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
- // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
- // VARDEFs are interspersed with other code, and a jump might be using the
- // VARDEF as a target. Replace with a no-op instead. A later pass will remove
- // the no-ops.
- nopout(p);
- continue;
- }
- if (p->from.name == NAME_AUTO && p->from.node)
- p->from.offset += ((Node*)(p->from.node))->stkdelta;
-
- if (p->to.name == NAME_AUTO && p->to.node)
- p->to.offset += ((Node*)(p->to.node))->stkdelta;
-
- lp = &p->link;
- }
-}
-
/*
* generate: BL reg, f
* where both reg and f are registers.
@@ -226,7 +181,7 @@ ginscall(Node *f, int proc)
gins(AUNDEF, N, N);
break;
}
- nodreg(&reg, types[tptr], REGENV);
+ nodreg(&reg, types[tptr], REGCTXT);
nodreg(&r1, types[tptr], REG_R3);
gmove(f, &reg);
reg.op = OINDREG;
@@ -487,27 +442,6 @@ cgen_ret(Node *n)
}
}
-void
-cgen_asop(Node *n)
-{
- USED(n);
- fatal("cgen_asop"); // no longer used
-}
-
-int
-samereg(Node *a, Node *b)
-{
- if(a == N || b == N)
- return 0;
- if(a->op != OREGISTER)
- return 0;
- if(b->op != OREGISTER)
- return 0;
- if(a->val.u.reg != b->val.u.reg)
- return 0;
- return 1;
-}
-
/*
* generate division.
* generates one of:
diff --git a/src/cmd/9g/gobj.c b/src/cmd/9g/gobj.c
deleted file mode 100644
index 35e4f458f1..0000000000
--- a/src/cmd/9g/gobj.c
+++ /dev/null
@@ -1,250 +0,0 @@
-// Derived from Inferno utils/6c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int
-dsname(Sym *s, int off, char *t, int n)
-{
- Prog *p;
-
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.offset = off;
- p->from.sym = linksym(s);
-
- p->from3.type = TYPE_CONST;
- p->from3.offset = n;
-
- p->to.type = TYPE_SCONST;
- p->to.name = NAME_NONE;
- p->to.offset = 0;
- memmove(p->to.u.sval, t, n);
- return off + n;
-}
-
-/*
- * make a refer to the data s, s+len
- * emitting DATA if needed.
- */
-void
-datastring(char *s, int len, Addr *a)
-{
- Sym *sym;
-
- sym = stringsym(s, len);
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- a->etype = simtype[TINT];
- a->offset = widthptr+widthint; // skip header
- a->reg = 0;
- a->sym = linksym(sym);
- a->node = sym->def;
-}
-
-/*
- * make a refer to the string sval,
- * emitting DATA if needed.
- */
-void
-datagostring(Strlit *sval, Addr *a)
-{
- Sym *sym;
-
- sym = stringsym(sval->s, sval->len);
- a->type = TYPE_MEM;
- a->name = NAME_EXTERN;
- a->sym = linksym(sym);
- a->reg = 0;
- a->node = sym->def;
- a->offset = 0; // header
- a->etype = TSTRING;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
- Prog *p;
-
- if(nr->op == OLITERAL) {
- switch(nr->val.ctype) {
- case CTCPLX:
- gdatacomplex(nam, nr->val.u.cval);
- return;
- case CTSTR:
- gdatastring(nam, nr->val.u.sval);
- return;
- }
- }
- p = gins(ADATA, nam, nr);
- p->from3.type = TYPE_CONST;
- p->from3.offset = wid;
-}
-
-void
-gdatacomplex(Node *nam, Mpcplx *cval)
-{
- Prog *p;
- int w;
-
- w = cplxsubtype(nam->type->etype);
- w = types[w]->width;
-
- p = gins(ADATA, nam, N);
- p->from3.type = TYPE_CONST;
- p->from3.offset = w;
- p->to.type = TYPE_FCONST;
- p->to.u.dval = mpgetflt(&cval->real);
-
- p = gins(ADATA, nam, N);
- p->from3.type = TYPE_CONST;
- p->from3.offset = w;
- p->from.offset += w;
- p->to.type = TYPE_FCONST;
- p->to.u.dval = mpgetflt(&cval->imag);
-}
-
-void
-gdatastring(Node *nam, Strlit *sval)
-{
- Prog *p;
- Node nod1;
-
- p = gins(ADATA, nam, N);
- datastring(sval->s, sval->len, &p->to);
- p->from3.type = TYPE_CONST;
- p->from3.offset = types[tptr]->width;
- p->to.type = TYPE_ADDR;
- p->to.etype = simtype[tptr];
-
- nodconst(&nod1, types[TINT], sval->len);
- p = gins(ADATA, nam, &nod1);
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthint;
- p->from.offset += widthptr;
-}
-
-int
-dstringptr(Sym *s, int off, char *str)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
-
- datastring(str, strlen(str)+1, &p->to);
- p->to.type = TYPE_CONST;
- p->to.etype = simtype[TINT];
- off += widthptr;
-
- return off;
-}
-
-int
-dgostrlitptr(Sym *s, int off, Strlit *lit)
-{
- Prog *p;
-
- if(lit == nil)
- return duintptr(s, off, 0);
-
- off = rnd(off, widthptr);
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
- datagostring(lit, &p->to);
- p->to.type = TYPE_ADDR;
- p->to.etype = simtype[TINT];
- off += widthptr;
-
- return off;
-}
-
-int
-dgostringptr(Sym *s, int off, char *str)
-{
- int n;
- Strlit *lit;
-
- if(str == nil)
- return duintptr(s, off, 0);
-
- n = strlen(str);
- lit = mal(sizeof *lit + n);
- strcpy(lit->s, str);
- lit->len = n;
- return dgostrlitptr(s, off, lit);
-}
-
-int
-dsymptr(Sym *s, int off, Sym *x, int xoff)
-{
- Prog *p;
-
- off = rnd(off, widthptr);
-
- p = gins(ADATA, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->from.offset = off;
- p->from3.type = TYPE_CONST;
- p->from3.offset = widthptr;
- p->to.type = TYPE_ADDR;
- p->to.name = NAME_EXTERN;
- p->to.sym = linksym(x);
- p->to.offset = xoff;
- off += widthptr;
-
- return off;
-}
-
-void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from = zprog.from;
- p->from3 = zprog.from3;
- p->reg = zprog.reg;
- p->to = zprog.to;
-}
diff --git a/src/cmd/9g/gsubr.c b/src/cmd/9g/gsubr.c
index 49f184d51e..1fb1511361 100644
--- a/src/cmd/9g/gsubr.c
+++ b/src/cmd/9g/gsubr.c
@@ -38,227 +38,6 @@
// At the same time, can raise StackBig in ../../runtime/stack.h.
vlong unmappedzero = 4096;
-void
-clearp(Prog *p)
-{
- *p = zprog;
- p->as = AEND;
- p->pc = pcloc;
- pcloc++;
-}
-
-static int ddumped;
-static Prog *dfirst;
-static Prog *dpc;
-
-/*
- * generate and return proc with p->as = as,
- * linked into program. pc is next instruction.
- */
-Prog*
-prog(int as)
-{
- Prog *p;
-
- if(as == ADATA || as == AGLOBL) {
- if(ddumped)
- fatal("already dumped data");
- if(dpc == nil) {
- dpc = mal(sizeof(*dpc));
- dfirst = dpc;
- }
- p = dpc;
- dpc = mal(sizeof(*dpc));
- p->link = dpc;
- p->reg = 0; // used for flags
- } else {
- p = pc;
- pc = mal(sizeof(*pc));
- clearp(pc);
- p->link = pc;
- }
-
- if(lineno == 0) {
- if(debug['K'])
- warn("prog: line 0");
- }
-
- p->as = as;
- p->lineno = lineno;
- return p;
-}
-
-void
-dumpdata(void)
-{
- ddumped = 1;
- if(dfirst == nil)
- return;
- newplist();
- *pc = *dfirst;
- pc = dpc;
- clearp(pc);
-}
-
-/*
- * generate a branch.
- * t is ignored.
- * likely values are for branch prediction:
- * -1 unlikely
- * 0 no opinion
- * +1 likely
- */
-Prog*
-gbranch(int as, Type *t, int likely)
-{
- Prog *p;
-
- USED(t);
-
- p = prog(as);
- p->to.type = TYPE_BRANCH;
- p->to.u.branch = P;
- // TODO(minux): Enable this code.
- // Note: liblink used Bcc CR0, label form, so we need another way
- // to set likely/unlikely flag. Also note the y bit is not exactly
- // likely/unlikely bit.
- if(0 && as != ABR && likely != 0) {
- p->from.type = TYPE_CONST;
- p->from.offset = likely > 0;
- }
- return p;
-}
-
-/*
- * patch previous branch to jump to to.
- */
-void
-patch(Prog *p, Prog *to)
-{
- if(p->to.type != TYPE_BRANCH)
- fatal("patch: not a branch");
- p->to.u.branch = to;
- p->to.offset = to->pc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
- Prog *q;
-
- if(p->to.type != TYPE_BRANCH)
- fatal("unpatch: not a branch");
- q = p->to.u.branch;
- p->to.u.branch = P;
- p->to.offset = 0;
- return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
- Plist *pl;
-
- pl = linknewplist(ctxt);
-
- pc = mal(sizeof(*pc));
- clearp(pc);
- pl->firstpc = pc;
-
- return pl;
-}
-
-void
-gused(Node *n)
-{
- gins(ANOP, n, N); // used
-}
-
-Prog*
-gjmp(Prog *to)
-{
- Prog *p;
-
- p = gbranch(ABR, T, 0);
- if(to != P)
- patch(p, to);
- return p;
-}
-
-void
-ggloblnod(Node *nam)
-{
- Prog *p;
-
- p = gins(AGLOBL, nam, N);
- p->lineno = nam->lineno;
- p->from.sym->gotype = linksym(ngotype(nam));
- p->to.sym = nil;
- p->to.type = TYPE_CONST;
- p->to.offset = nam->type->width;
- if(nam->readonly)
- p->from3.offset = RODATA;
- if(nam->type != T && !haspointers(nam->type))
- p->from3.offset |= NOPTR;
-}
-
-void
-gtrack(Sym *s)
-{
- Prog *p;
-
- p = gins(AUSEFIELD, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
-}
-
-void
-ggloblsym(Sym *s, int32 width, int8 flags)
-{
- Prog *p;
-
- p = gins(AGLOBL, N, N);
- p->from.type = TYPE_MEM;
- p->from.name = NAME_EXTERN;
- p->from.sym = linksym(s);
- p->to.type = TYPE_CONST;
- p->to.name = NAME_NONE;
- p->to.offset = width;
- p->from3.offset = flags;
-}
-
-int
-isfat(Type *t)
-{
- if(t != T)
- switch(t->etype) {
- case TSTRUCT:
- case TARRAY:
- case TSTRING:
- case TINTER: // maybe remove later
- return 1;
- }
- return 0;
-}
-
-/*
- * naddr of func generates code for address of func.
- * if using opcode that can take address implicitly,
- * call afunclit to fix up the argument.
- */
-void
-afunclit(Addr *a, Node *n)
-{
- if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
- a->type = TYPE_MEM;
- a->sym = linksym(n->sym);
- }
-}
-
static int resvd[] =
{
REGZERO,
@@ -308,7 +87,7 @@ gclean(void)
yyerror("reg %R left allocated, %p\n", i+REG_R0, regpc[i]);
}
-int32
+int
anyregalloc(void)
{
int i, j;
@@ -432,109 +211,6 @@ regfree(Node *n)
}
/*
- * initialize n to be register r of type t.
- */
-void
-nodreg(Node *n, Type *t, int r)
-{
- if(t == T)
- fatal("nodreg: t nil");
-
- memset(n, 0, sizeof(*n));
- n->op = OREGISTER;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.reg = r;
- n->type = t;
-}
-
-/*
- * initialize n to be indirect of register r; n is type t.
- */
-void
-nodindreg(Node *n, Type *t, int r)
-{
- nodreg(n, t, r);
- n->op = OINDREG;
-}
-
-Node*
-nodarg(Type *t, int fp)
-{
- Node *n;
- NodeList *l;
- Type *first;
- Iter savet;
-
- // entire argument struct, not just one arg
- if(t->etype == TSTRUCT && t->funarg) {
- n = nod(ONAME, N, N);
- n->sym = lookup(".args");
- n->type = t;
- first = structfirst(&savet, &t);
- if(first == nil)
- fatal("nodarg: bad struct");
- if(first->width == BADWIDTH)
- fatal("nodarg: offset not computed for %T", t);
- n->xoffset = first->width;
- n->addable = 1;
- goto fp;
- }
-
- if(t->etype != TFIELD)
- fatal("nodarg: not field %T", t);
-
- if(fp == 1) {
- for(l=curfn->dcl; l; l=l->next) {
- n = l->n;
- if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
- return n;
- }
- }
-
- n = nod(ONAME, N, N);
- n->type = t->type;
- n->sym = t->sym;
-
- if(t->width == BADWIDTH)
- fatal("nodarg: offset not computed for %T", t);
- n->xoffset = t->width;
- n->addable = 1;
- n->orig = t->nname;
-
-fp:
- // Rewrite argument named _ to __,
- // or else the assignment to _ will be
- // discarded during code generation.
- if(isblank(n))
- n->sym = lookup("__");
-
- switch(fp) {
- default:
- fatal("nodarg %T %d", t, fp);
-
- case 0: // output arg for calling another function
- n->op = OINDREG;
- n->val.u.reg = REGSP;
- n->xoffset += 8;
- break;
-
- case 1: // input arg to current function
- n->class = PPARAM;
- break;
-
- case 2: // offset output arg
-fatal("shouldn't be used");
- n->op = OINDREG;
- n->val.u.reg = REGSP;
- n->xoffset += types[tptr]->width;
- break;
- }
- n->typecheck = 1;
- return n;
-}
-
-/*
* generate
* as $c, n
*/
@@ -595,27 +271,6 @@ ginscon2(int as, Node *n2, vlong c)
/*c2go int CASE(int, int); */
/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
- switch(n->op) {
- case OITAB:
- case OSPTR:
- case OLEN:
- case OCAP:
- case OINDREG:
- case ONAME:
- case OPARAM:
- case OCLOSUREVAR:
- case OADDR:
- return 1;
- }
- return 0;
-}
-
-/*
* set up nodes representing 2^63
*/
Node bigi;
@@ -1077,8 +732,7 @@ fixlargeoffset(Node *n)
if(n->xoffset != (int32)n->xoffset) {
// TODO(minux): offset too large, move into R31 and add to R31 instead.
// this is used only in test/fixedbugs/issue6036.go.
- print("offset too large: %N\n", n);
- noimpl;
+ fatal("offset too large: %N", n);
a = *n;
a.op = OREGISTER;
a.type = types[tptr];
@@ -1090,208 +744,6 @@ fixlargeoffset(Node *n)
}
/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
- Sym *s;
-
- a->type = TYPE_NONE;
- a->name = NAME_NONE;
- a->reg = 0;
- a->gotype = nil;
- a->node = N;
- a->etype = 0;
- a->width = 0;
- if(n == N)
- return;
-
- if(n->type != T && n->type->etype != TIDEAL) {
- dowidth(n->type);
- a->width = n->type->width;
- }
-
- switch(n->op) {
- default:
- fatal("naddr: bad %O %D", n->op, a);
- break;
-
- case ONAME:
- a->etype = 0;
- a->reg = 0;
- if(n->type != T)
- a->etype = simtype[n->type->etype];
- a->offset = n->xoffset;
- s = n->sym;
- a->node = n->orig;
- //if(a->node >= (Node*)&n)
- // fatal("stack node");
- if(s == S)
- s = lookup(".noname");
- if(n->method) {
- if(n->type != T)
- if(n->type->sym != S)
- if(n->type->sym->pkg != nil)
- s = pkglookup(s->name, n->type->sym->pkg);
- }
-
- a->type = TYPE_MEM;
- switch(n->class) {
- default:
- fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
- case PEXTERN:
- a->name = NAME_EXTERN;
- break;
- case PAUTO:
- a->name = NAME_AUTO;
- break;
- case PPARAM:
- case PPARAMOUT:
- a->name = NAME_PARAM;
- break;
- case PFUNC:
- a->name = NAME_EXTERN;
- a->type = TYPE_ADDR;
- a->width = widthptr;
- s = funcsym(s);
- break;
- }
- a->sym = linksym(s);
- break;
-
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- fatal("naddr: const %lT", n->type);
- break;
- case CTFLT:
- a->type = TYPE_FCONST;
- a->u.dval = mpgetflt(n->val.u.fval);
- break;
- case CTINT:
- case CTRUNE:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = mpgetfix(n->val.u.xval);
- break;
- case CTSTR:
- datagostring(n->val.u.sval, a);
- break;
- case CTBOOL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = n->val.u.bval;
- break;
- case CTNIL:
- a->sym = nil;
- a->type = TYPE_CONST;
- a->offset = 0;
- break;
- }
- break;
-
- case OREGISTER:
- a->type = TYPE_REG;
- a->reg = n->val.u.reg;
- a->sym = nil;
- break;
-
- case OINDREG:
- a->type = TYPE_MEM;
- a->reg = n->val.u.reg;
- a->sym = linksym(n->sym);
- a->offset = n->xoffset;
- if(a->offset != (int32)a->offset)
- yyerror("offset %lld too large for OINDREG", a->offset);
- break;
-
- case OPARAM:
- // n->left is PHEAP ONAME for stack parameter.
- // compute address of actual parameter on stack.
- a->etype = simtype[n->left->type->etype];
- a->width = n->left->type->width;
- a->offset = n->xoffset;
- a->sym = linksym(n->left->sym);
- a->type = TYPE_MEM;
- a->name = NAME_PARAM;
- a->node = n->left->orig;
- break;
-
- case OCLOSUREVAR:
- if(!curfn->needctxt)
- fatal("closurevar without needctxt");
- a->type = TYPE_MEM;
- a->reg = REGENV;
- a->offset = n->xoffset;
- a->sym = nil;
- break;
-
- case OCFUNC:
- naddr(n->left, a, canemitcode);
- a->sym = linksym(n->left->sym);
- break;
-
- case OITAB:
- // itable of interface value
- naddr(n->left, a, canemitcode);
- a->etype = simtype[tptr];
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // itab(nil)
- a->width = widthptr;
- break;
-
- case OSPTR:
- // pointer in a string or slice
- naddr(n->left, a, canemitcode);
- a->etype = simtype[tptr];
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // ptr(nil)
- a->offset += Array_array;
- a->width = widthptr;
- break;
-
- case OLEN:
- // len of string or slice
- naddr(n->left, a, canemitcode);
- a->etype = simtype[TINT];
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // len(nil)
- a->offset += Array_nel;
- a->width = widthint;
- break;
-
- case OCAP:
- // cap of string or slice
- naddr(n->left, a, canemitcode);
- a->etype = simtype[TINT];
- if(a->type == TYPE_CONST && a->offset == 0)
- break; // cap(nil)
- a->offset += Array_cap;
- a->width = widthint;
- break;
-
- case OADDR:
- naddr(n->left, a, canemitcode);
- a->etype = tptr;
- switch(a->type) {
- case TYPE_MEM:
- a->type = TYPE_ADDR;
- break;
-
- case TYPE_REG:
- case TYPE_CONST:
- break;
-
- default:
- fatal("naddr: OADDR %d\n", a->type);
- }
- break;
- }
-}
-
-/*
* return Axxx for Oxxx on type t.
*/
int
@@ -1700,6 +1152,7 @@ int
sudoaddable(int as, Node *n, Addr *a)
{
// TODO(minux)
- USED(as); USED(n); USED(a);
+ USED(as); USED(n);
+ memset(a, 0, sizeof *a);
return 0;
}
diff --git a/src/cmd/9g/opt.h b/src/cmd/9g/opt.h
index 25b6703279..79a34fb1f0 100644
--- a/src/cmd/9g/opt.h
+++ b/src/cmd/9g/opt.h
@@ -1,175 +1,6 @@
-// Derived from Inferno utils/6c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-#define Z N
-#define Adr Addr
-
-#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
-#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
-#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
-#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
-
-#define CLOAD 5
-#define CREF 5
-#define CINF 1000
-#define LOOP 3
-
-typedef struct Reg Reg;
-typedef struct Rgn Rgn;
-
-/*c2go
-extern Node *Z;
-enum
-{
- CLOAD = 5,
- CREF = 5,
- CINF = 1000,
- LOOP = 3,
-};
-
-uint32 BLOAD(Reg*);
-uint32 BSTORE(Reg*);
-uint32 LOAD(Reg*);
-uint32 STORE(Reg*);
-*/
-
-// A Reg is a wrapper around a single Prog (one instruction) that holds
-// register optimization information while the optimizer runs.
-// r->prog is the instruction.
-// r->prog->opt points back to r.
-struct Reg
-{
- Flow f;
-
- Bits set; // regopt variables written by this instruction.
- Bits use1; // regopt variables read by prog->from.
- Bits use2; // regopt variables read by prog->to.
-
- // refahead/refbehind are the regopt variables whose current
- // value may be used in the following/preceding instructions
- // up to a CALL (or the value is clobbered).
- Bits refbehind;
- Bits refahead;
- // calahead/calbehind are similar, but for variables in
- // instructions that are reachable after hitting at least one
- // CALL.
- Bits calbehind;
- Bits calahead;
- Bits regdiff;
- Bits act;
-
- uint64 regu; // register used bitmap
-};
-#define R ((Reg*)0)
-/*c2go extern Reg *R; */
-
-#define NRGN 600
-/*c2go enum { NRGN = 600 }; */
-
-// A Rgn represents a single regopt variable over a region of code
-// where a register could potentially be dedicated to that variable.
-// The code encompassed by a Rgn is defined by the flow graph,
-// starting at enter, flood-filling forward while varno is refahead
-// and backward while varno is refbehind, and following branches. A
-// single variable may be represented by multiple disjoint Rgns and
-// each Rgn may choose a different register for that variable.
-// Registers are allocated to regions greedily in order of descending
-// cost.
-struct Rgn
-{
- Reg* enter;
- short cost;
- short varno;
- short regno;
-};
-
-EXTERN int32 exregoffset; // not set
-EXTERN int32 exfregoffset; // not set
-EXTERN Reg zreg;
-EXTERN Rgn region[NRGN];
-EXTERN Rgn* rgp;
-EXTERN int nregion;
-EXTERN int nvar;
-EXTERN int32 regbits;
-EXTERN int32 exregbits; // TODO(austin) not used; remove
-EXTERN Bits externs;
-EXTERN Bits params;
-EXTERN Bits consts;
-EXTERN Bits addrs;
-EXTERN Bits ivar;
-EXTERN Bits ovar;
-EXTERN int change;
-EXTERN int32 maxnr;
-
-EXTERN struct
-{
- int32 ncvtreg;
- int32 nspill;
- int32 ndelmov;
- int32 nvar;
-} ostats;
-
-/*
- * reg.c
- */
-int rcmp(const void*, const void*);
-void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Adr*);
-void prop(Reg*, Bits, Bits);
-void synch(Reg*, Bits);
-uint64 allreg(uint64, Rgn*);
-void paint1(Reg*, int);
-uint64 paint2(Reg*, int, int);
-void paint3(Reg*, int, uint64, int);
-void addreg(Adr*, int);
-void dumpone(Flow*, int);
-void dumpit(char*, Flow*, int);
-
-/*
- * peep.c
- */
-void peep(Prog*);
-void excise(Flow*);
-int copyu(Prog*, Adr*, Adr*);
-
-uint64 RtoB(int);
-uint64 FtoB(int);
-int BtoR(uint64);
-int BtoF(uint64);
-
-/*
- * prog.c
- */
-void proginfo(ProgInfo*, Prog*);
+// Copyright 2014 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.
// Many Power ISA arithmetic and logical instructions come in four
// standard variants. These bits let us map between variants.
diff --git a/src/cmd/9g/peep.c b/src/cmd/9g/peep.c
index 95ff0b4d58..cf96d5dcda 100644
--- a/src/cmd/9g/peep.c
+++ b/src/cmd/9g/peep.c
@@ -31,6 +31,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
+#include "../gc/popt.h"
#include "opt.h"
static int regzer(Addr *a);
@@ -42,6 +43,7 @@ static int copyau(Addr*, Addr*);
static int copysub(Addr*, Addr*, Addr*, int);
static int copysub1(Prog*, Addr*, Addr*, int);
static int copyau1(Prog *p, Addr *v);
+static int copyu(Prog *p, Addr *v, Addr *s);
static uint32 gactive;
@@ -53,7 +55,7 @@ peep(Prog *firstp)
Prog *p, *p1;
int t;
- g = flowstart(firstp, sizeof(Flow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
gactive = 0;
@@ -568,12 +570,12 @@ copy1(Addr *v1, Addr *v2, Flow *r, int f)
// 4 if v is set in one address and used in another (so addresses
// can be rewritten independently)
// 0 otherwise (not touched)
-int
+static int
copyu(Prog *p, Addr *v, Addr *s)
{
if(p->from3.type != TYPE_NONE)
// 9g never generates a from3
- print("copyu: from3 (%D) not implemented\n", p->from3);
+ print("copyu: from3 (%D) not implemented\n", &p->from3);
switch(p->as) {
diff --git a/src/cmd/9g/prog.c b/src/cmd/9g/prog.c
index 1775993a97..561249c358 100644
--- a/src/cmd/9g/prog.c
+++ b/src/cmd/9g/prog.c
@@ -5,6 +5,7 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
+#include "../gc/popt.h"
#include "opt.h"
enum {
diff --git a/src/cmd/9g/reg.c b/src/cmd/9g/reg.c
index a7ee07e547..84e1747e8d 100644
--- a/src/cmd/9g/reg.c
+++ b/src/cmd/9g/reg.c
@@ -31,56 +31,12 @@
#include <u.h>
#include <libc.h>
#include "gg.h"
-#include "opt.h"
+#include "../gc/popt.h"
-#define NREGVAR 64 /* 32 general + 32 floating */
-#define REGBITS ((uint64)0xffffffffffffffffull)
-/*c2go enum {
- NREGVAR = 64,
- REGBITS = 0xffffffffffffffff,
+enum {
+ NREGVAR = 64, /* 32 general + 32 floating */
};
-*/
-static Reg* firstr;
-static int first = 1;
-
-int
-rcmp(const void *a1, const void *a2)
-{
- Rgn *p1, *p2;
- int c1, c2;
-
- p1 = (Rgn*)a1;
- p2 = (Rgn*)a2;
- c1 = p2->cost;
- c2 = p1->cost;
- if(c1 -= c2)
- return c1;
- return p2->varno - p1->varno;
-}
-
-static void
-setaddrs(Bits bit)
-{
- int i, n;
- Var *v;
- Node *node;
-
- while(bany(&bit)) {
- // convert each bit to a variable
- i = bnum(bit);
- node = var[i].node;
- n = var[i].name;
- biclr(&bit, i);
-
- // disable all pieces of that variable
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node && v->name == n)
- v->addr = 2;
- }
- }
-}
static char* regname[] = {
".R0",
@@ -149,1059 +105,32 @@ static char* regname[] = {
".F31",
};
-static Node* regnodes[NREGVAR];
-
-static void walkvardef(Node *n, Reg *r, int active);
-
-void
-regopt(Prog *firstp)
+char**
+regnames(int *n)
{
- Reg *r, *r1;
- Prog *p;
- Graph *g;
- ProgInfo info;
- int i, z, active;
- uint64 vreg, usedreg;
- Bits bit;
-
- if(first) {
- fmtinstall('Q', Qconv);
- first = 0;
- }
-
- mergetemp(firstp);
+ *n = NREGVAR;
+ return regname;
+}
- /*
- * control flow is more complicated in generated go code
- * than in generated c code. define pseudo-variables for
- * registers, so we have complete register usage information.
- */
- nvar = NREGVAR;
- memset(var, 0, NREGVAR*sizeof var[0]);
- for(i=0; i<NREGVAR; i++) {
- if(regnodes[i] == N)
- regnodes[i] = newname(lookup(regname[i]));
- var[i].node = regnodes[i];
- }
+uint64
+excludedregs(void)
+{
+ uint64 regbits;
// Exclude registers with fixed functions
regbits = (1<<0)|RtoB(REGSP)|RtoB(REGG)|RtoB(REGTLS);
// Also exclude floating point registers with fixed constants
regbits |= RtoB(REG_F27)|RtoB(REG_F28)|RtoB(REG_F29)|RtoB(REG_F30)|RtoB(REG_F31);
- externs = zbits;
- params = zbits;
- consts = zbits;
- addrs = zbits;
- ivar = zbits;
- ovar = zbits;
-
- /*
- * pass 1
- * build aux data structure
- * allocate pcs
- * find use and set of variables
- */
- g = flowstart(firstp, sizeof(Reg));
- if(g == nil) {
- for(i=0; i<nvar; i++)
- var[i].node->opt = nil;
- return;
- }
-
- firstr = (Reg*)g->start;
-
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- p = r->f.prog;
- if(p->as == AVARDEF || p->as == AVARKILL)
- continue;
- proginfo(&info, p);
-
- // Avoid making variables for direct-called functions.
- if(p->as == ABL && p->to.name == NAME_EXTERN)
- continue;
-
- // from vs to doesn't matter for registers
- r->use1.b[0] |= info.reguse | info.regindex;
- r->set.b[0] |= info.regset;
-
- // Compute used register for from
- bit = mkvar(r, &p->from);
- if(info.flags & LeftAddr)
- setaddrs(bit);
- if(info.flags & LeftRead)
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
-
- // Compute used register for reg
- if(info.flags & RegRead)
- r->use1.b[0] |= RtoB(p->reg);
-
- // Currently we never generate three register forms.
- // If we do, this will need to change.
- if(p->from3.type != TYPE_NONE)
- fatal("regopt not implemented for from3");
-
- // Compute used register for to
- bit = mkvar(r, &p->to);
- if(info.flags & RightAddr)
- setaddrs(bit);
- if(info.flags & RightRead)
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- if(info.flags & RightWrite)
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- }
-
- for(i=0; i<nvar; i++) {
- Var *v = var+i;
- if(v->addr) {
- bit = blsh(i);
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
- }
-
- if(debug['R'] && debug['v'])
- print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
- i, v->addr, v->etype, v->width, v->node, v->offset);
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass1", &firstr->f, 1);
-
- /*
- * pass 2
- * find looping structure
- */
- flowrpo(g);
-
- if(debug['R'] && debug['v'])
- dumpit("pass2", &firstr->f, 1);
-
- /*
- * pass 2.5
- * iterate propagating fat vardef covering forward
- * r->act records vars with a VARDEF since the last CALL.
- * (r->act will be reused in pass 5 for something else,
- * but we'll be done with it by then.)
- */
- active = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- r->f.active = 0;
- r->act = zbits;
- }
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- p = r->f.prog;
- if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
- active++;
- walkvardef(p->to.node, r, active);
- }
- }
-
- /*
- * pass 3
- * iterate propagating usage
- * back until flow graph is complete
- */
-loop1:
- change = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->f.active = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- if(r->f.prog->as == ARET)
- prop(r, zbits, zbits);
-loop11:
- /* pick up unreachable code */
- i = 0;
- for(r = firstr; r != R; r = r1) {
- r1 = (Reg*)r->f.link;
- if(r1 && r1->f.active && !r->f.active) {
- prop(r, zbits, zbits);
- i = 1;
- }
- }
- if(i)
- goto loop11;
- if(change)
- goto loop1;
-
- if(debug['R'] && debug['v'])
- dumpit("pass3", &firstr->f, 1);
-
- /*
- * pass 4
- * iterate propagating register/variable synchrony
- * forward until graph is complete
- */
-loop2:
- change = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->f.active = 0;
- synch(firstr, zbits);
- if(change)
- goto loop2;
-
- if(debug['R'] && debug['v'])
- dumpit("pass4", &firstr->f, 1);
-
- /*
- * pass 4.5
- * move register pseudo-variables into regu.
- */
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
-
- r->set.b[0] &= ~REGBITS;
- r->use1.b[0] &= ~REGBITS;
- r->use2.b[0] &= ~REGBITS;
- r->refbehind.b[0] &= ~REGBITS;
- r->refahead.b[0] &= ~REGBITS;
- r->calbehind.b[0] &= ~REGBITS;
- r->calahead.b[0] &= ~REGBITS;
- r->regdiff.b[0] &= ~REGBITS;
- r->act.b[0] &= ~REGBITS;
- }
-
- if(debug['R'] && debug['v'])
- dumpit("pass4.5", &firstr->f, 1);
-
- /*
- * pass 5
- * isolate regions
- * calculate costs (paint1)
- */
- r = firstr;
- if(r) {
- for(z=0; z<BITS; z++)
- bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
- ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
- if(bany(&bit) && !r->f.refset) {
- // should never happen - all variables are preset
- if(debug['w'])
- print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
- r->f.refset = 1;
- }
- }
- for(r = firstr; r != R; r = (Reg*)r->f.link)
- r->act = zbits;
- rgp = region;
- nregion = 0;
- for(r = firstr; r != R; r = (Reg*)r->f.link) {
- for(z=0; z<BITS; z++)
- bit.b[z] = r->set.b[z] &
- ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
- if(bany(&bit) && !r->f.refset) {
- if(debug['w'])
- print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
- r->f.refset = 1;
- excise(&r->f);
- }
- for(z=0; z<BITS; z++)
- bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
- while(bany(&bit)) {
- i = bnum(bit);
- rgp->enter = r;
- rgp->varno = i;
- change = 0;
- paint1(r, i);
- biclr(&bit, i);
- if(change <= 0)
- continue;
- rgp->cost = change;
- nregion++;
- if(nregion >= NRGN) {
- if(debug['R'] && debug['v'])
- print("too many regions\n");
- goto brk;
- }
- rgp++;
- }
- }
-brk:
- qsort(region, nregion, sizeof(region[0]), rcmp);
-
- if(debug['R'] && debug['v'])
- dumpit("pass5", &firstr->f, 1);
-
- /*
- * pass 6
- * determine used registers (paint2)
- * replace code (paint3)
- */
- rgp = region;
- if(debug['R'] && debug['v'])
- print("\nregisterizing\n");
- for(i=0; i<nregion; i++) {
- if(debug['R'] && debug['v'])
- print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
- bit = blsh(rgp->varno);
- usedreg = paint2(rgp->enter, rgp->varno, 0);
- vreg = allreg(usedreg, rgp);
- if(rgp->regno != 0) {
- if(debug['R'] && debug['v']) {
- Var *v;
-
- v = var + rgp->varno;
- print("registerize %N+%lld (bit=%2d et=%2E) in %R usedreg=%llx vreg=%llx\n",
- v->node, v->offset, rgp->varno, v->etype, rgp->regno, usedreg, vreg);
- }
- paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
- }
- rgp++;
- }
-
- /*
- * free aux structures. peep allocates new ones.
- */
- for(i=0; i<nvar; i++)
- var[i].node->opt = nil;
- flowend(g);
- firstr = R;
-
- if(debug['R'] && debug['v']) {
- // Rebuild flow graph, since we inserted instructions
- g = flowstart(firstp, sizeof(Reg));
- firstr = (Reg*)g->start;
- dumpit("pass6", &firstr->f, 1);
- flowend(g);
- firstr = R;
- }
-
- /*
- * pass 7
- * peep-hole on basic block
- */
- if(!debug['R'] || debug['P'])
- peep(firstp);
-
- /*
- * eliminate nops
- */
- for(p=firstp; p!=P; p=p->link) {
- while(p->link != P && p->link->as == ANOP)
- p->link = p->link->link;
- if(p->to.type == TYPE_BRANCH)
- while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
- p->to.u.branch = p->to.u.branch->link;
- }
-
- if(debug['R']) {
- if(ostats.ncvtreg ||
- ostats.nspill ||
- ostats.ndelmov ||
- ostats.nvar ||
- 0)
- print("\nstats\n");
-
- if(ostats.ncvtreg)
- print(" %4d cvtreg\n", ostats.ncvtreg);
- if(ostats.nspill)
- print(" %4d spill\n", ostats.nspill);
- if(ostats.ndelmov)
- print(" %4d delmov\n", ostats.ndelmov);
- if(ostats.nvar)
- print(" %4d var\n", ostats.nvar);
-
- memset(&ostats, 0, sizeof(ostats));
- }
-
- return;
-}
-
-static void
-walkvardef(Node *n, Reg *r, int active)
-{
- Reg *r1, *r2;
- int bn;
- Var *v;
-
- for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
- if(r1->f.active == active)
- break;
- r1->f.active = active;
- if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
- break;
- for(v=n->opt; v!=nil; v=v->nextinnode) {
- bn = v - var;
- biset(&r1->act, bn);
- }
- if(r1->f.prog->as == ABL)
- break;
- }
-
- for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
- if(r2->f.s2 != nil)
- walkvardef(n, (Reg*)r2->f.s2, active);
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
- Prog *p, *p1, *p2;
- Adr *a;
- Var *v;
-
- p1 = mal(sizeof(*p1));
- *p1 = zprog;
- p = r->f.prog;
-
- // If there's a stack fixup coming (ADD $n,R1 after BL newproc or BL deferproc),
- // delay the load until after the fixup.
- p2 = p->link;
- if(p2 && p2->as == AADD && p2->to.reg == REGSP && p2->to.type == TYPE_REG)
- p = p2;
-
- p1->link = p->link;
- p->link = p1;
- p1->lineno = p->lineno;
-
- v = var + bn;
-
- a = &p1->to;
- a->name = v->name;
- a->node = v->node;
- a->sym = linksym(v->node->sym);
- a->offset = v->offset;
- a->etype = v->etype;
- a->type = TYPE_MEM;
- if(a->etype == TARRAY)
- a->type = TYPE_ADDR;
- else if(a->sym == nil)
- a->type = TYPE_CONST;
-
- if(v->addr)
- fatal("addmove: shouldn't be doing this %A\n", a);
-
- switch(v->etype) {
- default:
- print("What is this %E\n", v->etype);
-
- case TINT8:
- p1->as = AMOVB;
- break;
- case TBOOL:
- case TUINT8:
-//print("movbu %E %d %S\n", v->etype, bn, v->sym);
- p1->as = AMOVBZ;
- break;
- case TINT16:
- p1->as = AMOVH;
- break;
- case TUINT16:
- p1->as = AMOVHZ;
- break;
- case TINT32:
- p1->as = AMOVW;
- break;
- case TUINT32:
- case TPTR32:
- p1->as = AMOVWZ;
- break;
- case TINT64:
- case TUINT64:
- case TPTR64:
- p1->as = AMOVD;
- break;
- case TFLOAT32:
- p1->as = AFMOVS;
- break;
- case TFLOAT64:
- p1->as = AFMOVD;
- break;
- }
-
- p1->from.type = TYPE_REG;
- p1->from.reg = rn;
- if(!f) {
- p1->from = *a;
- *a = zprog.from;
- a->type = TYPE_REG;
- a->reg = rn;
- if(v->etype == TUINT8 || v->etype == TBOOL)
- p1->as = AMOVBZ;
- if(v->etype == TUINT16)
- p1->as = AMOVHZ;
- }
- if(debug['R'])
- print("%P\t.a%P\n", p, p1);
- ostats.nspill++;
-}
-
-static int
-overlap(int64 o1, int w1, int64 o2, int w2)
-{
- int64 t1, t2;
-
- t1 = o1+w1;
- t2 = o2+w2;
-
- if(!(t1 > o2 && t2 > o1))
- return 0;
-
- return 1;
-}
-
-Bits
-mkvar(Reg *r, Adr *a)
-{
- USED(r);
- Var *v;
- int i, t, n, et, z, flag;
- int64 w;
- int64 o;
- Bits bit;
- Node *node;
-
- // mark registers used
- t = a->type;
- switch(t) {
- default:
- print("type %d %d %D\n", t, a->name, a);
- goto none;
-
- case TYPE_NONE:
- goto none;
-
- case TYPE_BRANCH:
- case TYPE_CONST:
- case TYPE_FCONST:
- case TYPE_SCONST:
- case TYPE_MEM:
- case TYPE_ADDR:
- break;
-
- case TYPE_REG:
- if(a->reg != 0) {
- bit = zbits;
- bit.b[0] = RtoB(a->reg);
- return bit;
- }
- break;
- }
-
- switch(a->name) {
- default:
- goto none;
-
- case NAME_EXTERN:
- case NAME_STATIC:
- case NAME_AUTO:
- case NAME_PARAM:
- n = a->name;
- break;
- }
-
- node = a->node;
- if(node == N || node->op != ONAME || node->orig == N)
- goto none;
- node = node->orig;
- if(node->orig != node)
- fatal("%D: bad node", a);
- if(node->sym == S || node->sym->name[0] == '.')
- goto none;
- et = a->etype;
- o = a->offset;
- w = a->width;
- if(w < 0)
- fatal("bad width %lld for %D", w, a);
-
- flag = 0;
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node && v->name == n) {
- if(v->offset == o)
- if(v->etype == et)
- if(v->width == w)
- return blsh(i);
-
- // if they overlap, disable both
- if(overlap(v->offset, v->width, o, w)) {
- v->addr = 1;
- flag = 1;
- }
- }
- }
-
- switch(et) {
- case 0:
- case TFUNC:
- goto none;
- }
-
- if(nvar >= NVAR) {
- if(debug['w'] > 1 && node != N)
- fatal("variable not optimized: %#N", node);
-
- // If we're not tracking a word in a variable, mark the rest as
- // having its address taken, so that we keep the whole thing
- // live at all calls. otherwise we might optimize away part of
- // a variable but not all of it.
- for(i=0; i<nvar; i++) {
- v = var+i;
- if(v->node == node)
- v->addr = 1;
- }
- goto none;
- }
-
- i = nvar;
- nvar++;
- v = var+i;
- v->offset = o;
- v->name = n;
- v->etype = et;
- v->width = w;
- v->addr = flag; // funny punning
- v->node = node;
-
- // node->opt is the head of a linked list
- // of Vars within the given Node, so that
- // we can start at a Var and find all the other
- // Vars in the same Go variable.
- v->nextinnode = node->opt;
- node->opt = v;
-
- bit = blsh(i);
- if(n == NAME_EXTERN || n == NAME_STATIC)
- for(z=0; z<BITS; z++)
- externs.b[z] |= bit.b[z];
- if(n == NAME_PARAM)
- for(z=0; z<BITS; z++)
- params.b[z] |= bit.b[z];
-
- if(node->class == PPARAM)
- for(z=0; z<BITS; z++)
- ivar.b[z] |= bit.b[z];
- if(node->class == PPARAMOUT)
- for(z=0; z<BITS; z++)
- ovar.b[z] |= bit.b[z];
-
- // Treat values with their address taken as live at calls,
- // because the garbage collector's liveness analysis in ../gc/plive.c does.
- // These must be consistent or else we will elide stores and the garbage
- // collector will see uninitialized data.
- // The typical case where our own analysis is out of sync is when the
- // node appears to have its address taken but that code doesn't actually
- // get generated and therefore doesn't show up as an address being
- // taken when we analyze the instruction stream.
- // One instance of this case is when a closure uses the same name as
- // an outer variable for one of its own variables declared with :=.
- // The parser flags the outer variable as possibly shared, and therefore
- // sets addrtaken, even though it ends up not being actually shared.
- // If we were better about _ elision, _ = &x would suffice too.
- // The broader := in a closure problem is mentioned in a comment in
- // closure.c:/^typecheckclosure and dcl.c:/^oldname.
- if(node->addrtaken)
- v->addr = 1;
-
- // Disable registerization for globals, because:
- // (1) we might panic at any time and we want the recovery code
- // to see the latest values (issue 1304).
- // (2) we don't know what pointers might point at them and we want
- // loads via those pointers to see updated values and vice versa (issue 7995).
- //
- // Disable registerization for results if using defer, because the deferred func
- // might recover and return, causing the current values to be used.
- if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
- v->addr = 1;
-
- if(debug['R'])
- print("bit=%2d et=%2E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
- ostats.nvar++;
-
- return bit;
-
-none:
- return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
- Reg *r1, *r2;
- int z, i, j;
- Var *v, *v1;
-
- for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
- for(z=0; z<BITS; z++) {
- ref.b[z] |= r1->refahead.b[z];
- if(ref.b[z] != r1->refahead.b[z]) {
- r1->refahead.b[z] = ref.b[z];
- change++;
- }
- cal.b[z] |= r1->calahead.b[z];
- if(cal.b[z] != r1->calahead.b[z]) {
- r1->calahead.b[z] = cal.b[z];
- change++;
- }
- }
- switch(r1->f.prog->as) {
- case ABL:
- if(noreturn(r1->f.prog))
- break;
-
- // Mark all input variables (ivar) as used, because that's what the
- // liveness bitmaps say. The liveness bitmaps say that so that a
- // panic will not show stale values in the parameter dump.
- // Mark variables with a recent VARDEF (r1->act) as used,
- // so that the optimizer flushes initializations to memory,
- // so that if a garbage collection happens during this CALL,
- // the collector will see initialized memory. Again this is to
- // match what the liveness bitmaps say.
- for(z=0; z<BITS; z++) {
- cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
- ref.b[z] = 0;
- }
-
- // cal.b is the current approximation of what's live across the call.
- // Every bit in cal.b is a single stack word. For each such word,
- // find all the other tracked stack words in the same Go variable
- // (struct/slice/string/interface) and mark them live too.
- // This is necessary because the liveness analysis for the garbage
- // collector works at variable granularity, not at word granularity.
- // It is fundamental for slice/string/interface: the garbage collector
- // needs the whole value, not just some of the words, in order to
- // interpret the other bits correctly. Specifically, slice needs a consistent
- // ptr and cap, string needs a consistent ptr and len, and interface
- // needs a consistent type word and data word.
- for(z=0; z<BITS; z++) {
- if(cal.b[z] == 0)
- continue;
- for(i=0; i<64; i++) {
- if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
- continue;
- v = var+z*64+i;
- if(v->node->opt == nil) // v represents fixed register, not Go variable
- continue;
-
- // v->node->opt is the head of a linked list of Vars
- // corresponding to tracked words from the Go variable v->node.
- // Walk the list and set all the bits.
- // For a large struct this could end up being quadratic:
- // after the first setting, the outer loop (for z, i) would see a 1 bit
- // for all of the remaining words in the struct, and for each such
- // word would go through and turn on all the bits again.
- // To avoid the quadratic behavior, we only turn on the bits if
- // v is the head of the list or if the head's bit is not yet turned on.
- // This will set the bits at most twice, keeping the overall loop linear.
- v1 = v->node->opt;
- j = v1 - var;
- if(v == v1 || !btest(&cal, j)) {
- for(; v1 != nil; v1 = v1->nextinnode) {
- j = v1 - var;
- biset(&cal, j);
- }
- }
- }
- }
- break;
-
- case ATEXT:
- for(z=0; z<BITS; z++) {
- cal.b[z] = 0;
- ref.b[z] = 0;
- }
- break;
-
- case ARET:
- for(z=0; z<BITS; z++) {
- cal.b[z] = externs.b[z] | ovar.b[z];
- ref.b[z] = 0;
- }
- break;
- }
- for(z=0; z<BITS; z++) {
- ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
- r1->use1.b[z] | r1->use2.b[z];
- cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
- r1->refbehind.b[z] = ref.b[z];
- r1->calbehind.b[z] = cal.b[z];
- }
- if(r1->f.active)
- break;
- r1->f.active = 1;
- }
- for(; r != r1; r = (Reg*)r->f.p1)
- for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
- prop(r2, r->refbehind, r->calbehind);
-}
-
-void
-synch(Reg *r, Bits dif)
-{
- Reg *r1;
- int z;
-
- for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
- for(z=0; z<BITS; z++) {
- dif.b[z] = (dif.b[z] &
- ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
- r1->set.b[z] | r1->regdiff.b[z];
- if(dif.b[z] != r1->regdiff.b[z]) {
- r1->regdiff.b[z] = dif.b[z];
- change++;
- }
- }
- if(r1->f.active)
- break;
- r1->f.active = 1;
- for(z=0; z<BITS; z++)
- dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
- if(r1->f.s2 != nil)
- synch((Reg*)r1->f.s2, dif);
- }
+ return regbits;
}
uint64
-allreg(uint64 b, Rgn *r)
+doregbits(int r)
{
- Var *v;
- int i;
-
- v = var + r->varno;
- r->regno = 0;
- switch(v->etype) {
-
- default:
- fatal("unknown etype %d/%E", bitno(b), v->etype);
- break;
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TBOOL:
- case TPTR32:
- case TPTR64:
- i = BtoR(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
-
- case TFLOAT32:
- case TFLOAT64:
- i = BtoF(~b);
- if(i && r->cost > 0) {
- r->regno = i;
- return RtoB(i);
- }
- break;
- }
+ USED(r);
return 0;
}
-void
-paint1(Reg *r, int bn)
-{
- Reg *r1;
- int z;
- uint64 bb;
-
- z = bn/64;
- bb = 1LL<<(bn%64);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
- change -= CLOAD * r->f.loop;
- }
- for(;;) {
- r->act.b[z] |= bb;
-
- if(r->f.prog->as != ANOP) { // don't give credit for NOPs
- if(r->use1.b[z] & bb)
- change += CREF * r->f.loop;
- if((r->use2.b[z]|r->set.b[z]) & bb)
- change += CREF * r->f.loop;
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb) {
- change -= CLOAD * r->f.loop;
- }
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- paint1(r1, bn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint1(r1, bn);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-uint64
-paint2(Reg *r, int bn, int depth)
-{
- Reg *r1;
- int z;
- uint64 bb, vreg;
-
- z = bn/64;
- bb = 1LL << (bn%64);
- vreg = regbits;
- if(!(r->act.b[z] & bb))
- return vreg;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(!(r1->act.b[z] & bb))
- break;
- r = r1;
- }
- for(;;) {
- if(debug['R'] && debug['v'])
- print(" paint2 %d %P\n", depth, r->f.prog);
-
- r->act.b[z] &= ~bb;
-
- vreg |= r->regu;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- vreg |= paint2(r1, bn, depth+1);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- vreg |= paint2(r1, bn, depth+1);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(!(r->act.b[z] & bb))
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
- return vreg;
-}
-
-void
-paint3(Reg *r, int bn, uint64 rb, int rn)
-{
- Reg *r1;
- Prog *p;
- int z;
- uint64 bb;
-
- z = bn/64;
- bb = 1LL << (bn%64);
- if(r->act.b[z] & bb)
- return;
- for(;;) {
- if(!(r->refbehind.b[z] & bb))
- break;
- r1 = (Reg*)r->f.p1;
- if(r1 == R)
- break;
- if(!(r1->refahead.b[z] & bb))
- break;
- if(r1->act.b[z] & bb)
- break;
- r = r1;
- }
-
- if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
- addmove(r, bn, rn, 0);
- for(;;) {
- r->act.b[z] |= bb;
- p = r->f.prog;
-
- if(r->use1.b[z] & bb) {
- if(debug['R'] && debug['v'])
- print("%P", p);
- addreg(&p->from, rn);
- if(debug['R'] && debug['v'])
- print(" ===change== %P\n", p);
- }
- if((r->use2.b[z]|r->set.b[z]) & bb) {
- if(debug['R'] && debug['v'])
- print("%P", p);
- addreg(&p->to, rn);
- if(debug['R'] && debug['v'])
- print(" ===change== %P\n", p);
- }
-
- if(STORE(r) & r->regdiff.b[z] & bb)
- addmove(r, bn, rn, 1);
- r->regu |= rb;
-
- if(r->refbehind.b[z] & bb)
- for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
- if(r1->refahead.b[z] & bb)
- paint3(r1, bn, rb, rn);
-
- if(!(r->refahead.b[z] & bb))
- break;
- r1 = (Reg*)r->f.s2;
- if(r1 != R)
- if(r1->refbehind.b[z] & bb)
- paint3(r1, bn, rb, rn);
- r = (Reg*)r->f.s1;
- if(r == R)
- break;
- if(r->act.b[z] & bb)
- break;
- if(!(r->refbehind.b[z] & bb))
- break;
- }
-}
-
-void
-addreg(Adr *a, int rn)
-{
- a->sym = nil;
- a->node = nil;
- a->name = NAME_NONE;
- a->type = TYPE_REG;
- a->reg = rn;
-
- ostats.ncvtreg++;
-}
-
/*
* track register variables including external registers:
* bit reg
@@ -1241,78 +170,3 @@ BtoF(uint64 b)
return 0;
return bitno(b) + REG_F0;
}
-
-void
-dumpone(Flow *f, int isreg)
-{
- int z;
- Bits bit;
- Reg *r;
-
- print("%d:%P", f->loop, f->prog);
- if(isreg) {
- r = (Reg*)f;
- for(z=0; z<BITS; z++)
- bit.b[z] =
- r->set.b[z] |
- r->use1.b[z] |
- r->use2.b[z] |
- r->refbehind.b[z] |
- r->refahead.b[z] |
- r->calbehind.b[z] |
- r->calahead.b[z] |
- r->regdiff.b[z] |
- r->act.b[z] |
- 0;
- if(bany(&bit)) {
- print("\t");
- if(bany(&r->set))
- print(" s:%Q", r->set);
- if(bany(&r->use1))
- print(" u1:%Q", r->use1);
- if(bany(&r->use2))
- print(" u2:%Q", r->use2);
- if(bany(&r->refbehind))
- print(" rb:%Q ", r->refbehind);
- if(bany(&r->refahead))
- print(" ra:%Q ", r->refahead);
- if(bany(&r->calbehind))
- print(" cb:%Q ", r->calbehind);
- if(bany(&r->calahead))
- print(" ca:%Q ", r->calahead);
- if(bany(&r->regdiff))
- print(" d:%Q ", r->regdiff);
- if(bany(&r->act))
- print(" a:%Q ", r->act);
- }
- }
- print("\n");
-}
-
-
-void
-dumpit(char *str, Flow *r0, int isreg)
-{
- Flow *r, *r1;
-
- print("\n%s\n", str);
- for(r = r0; r != nil; r = r->link) {
- dumpone(r, isreg);
- r1 = r->p2;
- if(r1 != nil) {
- print(" pred:");
- for(; r1 != nil; r1 = r1->p2link)
- print(" %.4ud", (int)r1->prog->pc);
- print("\n");
- }
- // Print successors if it's not just the next one
- if(r->s1 != r->link || r->s2 != nil) {
- print(" succ:");
- if(r->s1 != nil)
- print(" %.4ud", (int)r->s1->prog->pc);
- if(r->s2 != nil)
- print(" %.4ud", (int)r->s2->prog->pc);
- print("\n");
- }
- }
-}
diff --git a/src/cmd/9l/9.out.h b/src/cmd/9l/9.out.h
index b99e7e6f4d..6e95698db9 100644
--- a/src/cmd/9l/9.out.h
+++ b/src/cmd/9l/9.out.h
@@ -204,7 +204,7 @@ enum
REGRT1 = REG_R3, /* reserved for runtime, duffzero and duffcopy */
REGRT2 = REG_R4, /* reserved for runtime, duffcopy */
REGMIN = REG_R7, /* register variables allocated from here to REGMAX */
- REGENV = REG_R11, /* environment for closures */
+ REGCTXT = REG_R11, /* context for closures */
REGTLS = REG_R13, /* C ABI TLS base pointer */
REGMAX = REG_R27,
REGEXT = REG_R30, /* external registers allocated from here down */
diff --git a/src/cmd/9l/asm.c b/src/cmd/9l/asm.c
index 391f9562cf..01e17aaa09 100644
--- a/src/cmd/9l/asm.c
+++ b/src/cmd/9l/asm.c
@@ -35,15 +35,6 @@
#include "../ld/elf.h"
#include "../ld/dwarf.h"
-
-// TODO(austin): ABI v1 uses /usr/lib/ld.so.1
-char linuxdynld[] = "/lib64/ld64.so.1";
-char freebsddynld[] = "XXX";
-char openbsddynld[] = "XXX";
-char netbsddynld[] = "XXX";
-char dragonflydynld[] = "XXX";
-char solarisdynld[] = "XXX";
-
static int
needlib(char *name)
{
@@ -64,8 +55,6 @@ needlib(char *name)
return 0;
}
-int nelfsym = 1;
-
static void gencallstub(int abicase, LSym *stub, LSym *targ);
static void addpltsym(Link*, LSym*);
static LSym* ensureglinkresolver(void);
@@ -129,7 +118,7 @@ gentext(void)
// This assumes "case 1" from the ABI, where the caller needs
// us to save and restore the TOC pointer.
pprevtextp = &ctxt->textp;
- for(s=*pprevtextp; s!=S; pprevtextp=&s->next, s=*pprevtextp) {
+ for(s=*pprevtextp; s!=nil; pprevtextp=&s->next, s=*pprevtextp) {
for(r=s->r; r<s->r+s->nr; r++) {
if(!(r->type == 256 + R_PPC64_REL24 &&
r->sym->type == SDYNIMPORT))
@@ -797,14 +786,14 @@ asmb(void)
switch(HEADTYPE) {
default:
case Hplan9: /* plan 9 */
- LPUT(0x647); /* magic */
- LPUT(segtext.filelen); /* sizes */
- LPUT(segdata.filelen);
- LPUT(segdata.len - segdata.filelen);
- LPUT(symsize); /* nsyms */
- LPUT(entryvalue()); /* va of entry */
- LPUT(0L);
- LPUT(lcsize);
+ thearch.lput(0x647); /* magic */
+ thearch.lput(segtext.filelen); /* sizes */
+ thearch.lput(segdata.filelen);
+ thearch.lput(segdata.len - segdata.filelen);
+ thearch.lput(symsize); /* nsyms */
+ thearch.lput(entryvalue()); /* va of entry */
+ thearch.lput(0L);
+ thearch.lput(lcsize);
break;
case Hlinux:
case Hfreebsd:
@@ -824,18 +813,3 @@ asmb(void)
print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize);
}
}
-
-vlong
-rnd(vlong v, int32 r)
-{
- vlong c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
diff --git a/src/cmd/9l/l.h b/src/cmd/9l/l.h
index 9d8a4fae2c..a634cf80b4 100644
--- a/src/cmd/9l/l.h
+++ b/src/cmd/9l/l.h
@@ -44,55 +44,21 @@ enum
IntSize = 8,
RegSize = 8,
MaxAlign = 32, // max data alignment
- FuncAlign = 8
-};
-
-#define P ((Prog*)0)
-#define S ((LSym*)0)
-
-enum
-{
- FPCHIP = 1,
- STRINGSZ = 200,
- MAXHIST = 20, /* limit of path elements for history symbols */
- DATBLK = 1024,
- NHASH = 10007,
- NHUNK = 100000,
- MINSIZ = 64,
- NENT = 100,
- NSCHED = 20,
+ FuncAlign = 8,
MINLC = 4,
-
- Roffset = 22, /* no. bits for offset in relocation address */
- Rindex = 10 /* no. bits for index in relocation address */
};
-EXTERN int32 autosize;
-EXTERN LSym* datap;
-EXTERN int debug[128];
-EXTERN int32 lcsize;
-EXTERN char literal[32];
-EXTERN int nerrors;
-EXTERN vlong instoffset;
-EXTERN char* rpath;
-EXTERN vlong pc;
-EXTERN int32 symsize;
-EXTERN int32 staticgen;
-EXTERN Prog* lastp;
-EXTERN vlong textsize;
-
-void asmb(void);
void adddynlib(char *lib);
void adddynrel(LSym *s, Reloc *r);
+void adddynrela(LSym *rela, LSym *s, Reloc *r);
void adddynsym(Link *ctxt, LSym *s);
int archreloc(Reloc *r, LSym *s, vlong *val);
vlong archrelocvariant(Reloc *r, LSym *s, vlong t);
+void asmb(void);
+int elfreloc1(Reloc *r, vlong sectoff);
+void elfsetupplt(void);
void listinit(void);
-vlong rnd(vlong, int32);
-
-#define LPUT(a) (ctxt->arch->endian == BigEndian ? lputb(a):lputl(a))
-#define WPUT(a) (ctxt->arch->endian == BigEndian ? wputb(a):wputl(a))
-#define VPUT(a) (ctxt->arch->endian == BigEndian ? vputb(a):vputl(a))
+int machoreloc1(Reloc *r, vlong sectoff);
/* Used by ../ld/dwarf.c */
enum
diff --git a/src/cmd/9l/obj.c b/src/cmd/9l/obj.c
index 77f665e5a2..17dd5caacd 100644
--- a/src/cmd/9l/obj.c
+++ b/src/cmd/9l/obj.c
@@ -36,8 +36,12 @@
#include "../ld/dwarf.h"
#include <ar.h>
-char *thestring = "ppc64";
-LinkArch *thelinkarch;
+void
+main(int argc, char **argv)
+{
+ linkarchinit();
+ ldmain(argc, argv);
+}
void
linkarchinit(void)
@@ -47,6 +51,45 @@ linkarchinit(void)
thelinkarch = &linkppc64le;
else
thelinkarch = &linkppc64;
+
+ thearch.thechar = thechar;
+ thearch.ptrsize = thelinkarch->ptrsize;
+ thearch.intsize = thelinkarch->ptrsize;
+ thearch.regsize = thelinkarch->regsize;
+ thearch.funcalign = FuncAlign;
+ thearch.maxalign = MaxAlign;
+ thearch.minlc = MINLC;
+ thearch.dwarfregsp = DWARFREGSP;
+
+ thearch.adddynlib = adddynlib;
+ thearch.adddynrel = adddynrel;
+ thearch.adddynsym = adddynsym;
+ thearch.archinit = archinit;
+ thearch.archreloc = archreloc;
+ thearch.archrelocvariant = archrelocvariant;
+ thearch.asmb = asmb;
+ thearch.elfreloc1 = elfreloc1;
+ thearch.elfsetupplt = elfsetupplt;
+ thearch.gentext = gentext;
+ thearch.listinit = listinit;
+ thearch.machoreloc1 = machoreloc1;
+ if(thelinkarch == &linkppc64le) {
+ thearch.lput = lputl;
+ thearch.wput = wputl;
+ thearch.vput = vputl;
+ } else {
+ thearch.lput = lputb;
+ thearch.wput = wputb;
+ thearch.vput = vputb;
+ }
+
+ // TODO(austin): ABI v1 uses /usr/lib/ld.so.1
+ thearch.linuxdynld = "/lib64/ld64.so.1";
+ thearch.freebsddynld = "XXX";
+ thearch.openbsddynld = "XXX";
+ thearch.netbsddynld = "XXX";
+ thearch.dragonflydynld = "XXX";
+ thearch.solarisdynld = "XXX";
}
void
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 1519d96ccc..85988e3bb7 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -107,22 +107,12 @@ func setContexts() {
}
}
-var (
- internalPkg = regexp.MustCompile(`(^|/)internal($|/)`)
- hashRx = regexp.MustCompile(`^[0-9a-f]{7,40}$`)
-)
-
-func isDevelVersion(v string) bool {
- if strings.Contains(v, "devel") {
- return true
- }
- return hashRx.MatchString(v)
-}
+var internalPkg = regexp.MustCompile(`(^|/)internal($|/)`)
func main() {
flag.Parse()
- if v := runtime.Version(); !strings.Contains(v, "weekly") && !isDevelVersion(v) {
+ if !strings.Contains(runtime.Version(), "weekly") && !strings.Contains(runtime.Version(), "devel") {
if *nextFile != "" {
fmt.Printf("Go version is %q, ignoring -next %s\n", runtime.Version(), *nextFile)
*nextFile = ""
@@ -293,7 +283,7 @@ func compareAPI(w io.Writer, features, required, optional, exception []string) (
delete(optionalSet, newFeature)
} else {
fmt.Fprintf(w, "+%s\n", newFeature)
- if !*allowNew || !isDevelVersion(runtime.Version()) {
+ if !*allowNew || !strings.Contains(runtime.Version(), "devel") {
ok = false // we're in lock-down mode for next release
}
}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index a4bd5579d3..346ae94546 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -636,7 +636,7 @@ func (p *Package) writeExports(fgo2, fm io.Writer) {
fgcc := creat(*objDir + "_cgo_export.c")
fgcch := creat(*objDir + "_cgo_export.h")
- fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n/* This file is arch-specific. */\n")
fmt.Fprintf(fgcch, "%s\n", p.Preamble)
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
@@ -1310,6 +1310,10 @@ typedef double GoFloat64;
typedef __complex float GoComplex64;
typedef __complex double GoComplex128;
+// static assertion to make sure the file is being used on architecture
+// at least with matching size of GoInt.
+typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
+
typedef struct { char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 5cfc47ce84..81249d4645 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -32,7 +32,6 @@ var (
workdir string
tooldir string
gochar string
- goversion string
oldgoos string
oldgoarch string
oldgochar string
@@ -225,8 +224,6 @@ func xinit() {
os.Setenv("LANG", "C")
os.Setenv("LANGUAGE", "en_US.UTF8")
- goversion = findgoversion()
-
workdir = xworkdir()
xatexit(rmworkdir)
@@ -428,6 +425,7 @@ func setup() {
}
// For release, make sure excluded things are excluded.
+ goversion := findgoversion()
if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) {
for _, dir := range unreleased {
if p := pathf("%s/%s", goroot, dir); isdir(p) {
@@ -533,16 +531,16 @@ var deptab = []struct {
"$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
}},
{"cmd/5l", []string{
- "../ld/*",
+ "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a",
}},
{"cmd/6l", []string{
- "../ld/*",
+ "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a",
}},
{"cmd/8l", []string{
- "../ld/*",
+ "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a",
}},
{"cmd/9l", []string{
- "../ld/*",
+ "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a",
}},
{"cmd/go", []string{
"zdefaultcc.go",
@@ -619,7 +617,7 @@ func install(dir string) {
}
// disable word wrapping in error messages
gccargs = append(gccargs, "-fmessage-length=0")
- if gohostos == "darwin" {
+ if gohostos == "darwin" && gohostarch != "arm" {
// golang.org/issue/5261
gccargs = append(gccargs, "-mmacosx-version-min=10.6")
}
@@ -634,7 +632,7 @@ func install(dir string) {
// Legacy C exceptions.
switch dir {
- case "lib9", "libbio", "liblink", "cmd/gc":
+ case "lib9", "libbio", "liblink", "cmd/gc", "cmd/ld":
islib = true
isgo = false
case "cmd/5a", "cmd/5g", "cmd/5l",
@@ -914,7 +912,7 @@ func install(dir string) {
"-D", fmt.Sprintf("GOHOSTOS=%q", gohostos),
"-D", fmt.Sprintf("GOHOSTARCH=%q", gohostarch),
"-D", fmt.Sprintf("GOROOT=%q", goroot_final),
- "-D", fmt.Sprintf("GOVERSION=%q", goversion),
+ "-D", fmt.Sprintf("GOVERSION=%q", findgoversion()),
"-D", fmt.Sprintf("GOARM=%q", goarm),
"-D", fmt.Sprintf("GO386=%q", go386),
"-D", fmt.Sprintf("GO_EXTLINK_ENABLED=%q", goextlinkenabled),
@@ -1117,6 +1115,7 @@ var buildorder = []string{
"liblink",
"cmd/gc", // must be before g
+ "cmd/ld", // must be before l
"cmd/%sl", // must be before a, g
"cmd/%sa",
"cmd/%sg",
@@ -1505,5 +1504,5 @@ func cmdbanner() {
// Version prints the Go version.
func cmdversion() {
xflagparse(0)
- xprintf("%s\n", goversion)
+ xprintf("%s\n", findgoversion())
}
diff --git a/src/cmd/dist/buildgc.go b/src/cmd/dist/buildgc.go
index bc1898e04e..b59aa5b5a4 100644
--- a/src/cmd/dist/buildgc.go
+++ b/src/cmd/dist/buildgc.go
@@ -87,7 +87,7 @@ func mkanames(dir, file string) {
line = line[:i]
}
line = line[2:]
- fmt.Fprintf(&out, "\t\"%s\",\n", line)
+ fmt.Fprintf(&out, "\t\"%s\",\n", strings.TrimSpace(line))
}
}
fmt.Fprintf(&out, "};\n")
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
index ff2a489b55..1f8276468e 100644
--- a/src/cmd/dist/buildruntime.go
+++ b/src/cmd/dist/buildruntime.go
@@ -28,7 +28,7 @@ func mkzversion(dir, file string) {
"const defaultGoroot = `%s`\n"+
"const theVersion = `%s`\n"+
"const goexperiment = `%s`\n"+
- "var buildVersion = theVersion\n", goroot_final, goversion, os.Getenv("GOEXPERIMENT"))
+ "var buildVersion = theVersion\n", goroot_final, findgoversion(), os.Getenv("GOEXPERIMENT"))
writefile(out, file, 0)
}
@@ -56,7 +56,7 @@ func mkzbootstrap(file string) {
"const defaultGOARCH = `%s`\n"+
"const version = `%s`\n"+
"const goexperiment = `%s`\n",
- goroot_final, goarm, gohostos, gohostarch, goversion, os.Getenv("GOEXPERIMENT"))
+ goroot_final, goarm, gohostos, gohostarch, findgoversion(), os.Getenv("GOEXPERIMENT"))
writefile(out, file, 0)
}
diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go
index decbb0ffd2..df3e8154e2 100644
--- a/src/cmd/dist/util.go
+++ b/src/cmd/dist/util.go
@@ -414,7 +414,7 @@ func main() {
if gohostarch == "" {
// Default Unix system.
- out := run("", CheckExit, "uname", "-m")
+ out := run("", CheckExit, "uname", "-m", "-v")
switch {
case strings.Contains(out, "x86_64"), strings.Contains(out, "amd64"):
gohostarch = "amd64"
@@ -426,6 +426,10 @@ func main() {
gohostarch = "ppc64le"
case strings.Contains(out, "ppc64"):
gohostarch = "ppc64"
+ case gohostos == "darwin":
+ if strings.Contains(out, "RELEASE_ARM_") {
+ gohostarch = "arm"
+ }
default:
fatal("unknown architecture: %s", out)
}
@@ -491,6 +495,12 @@ func xgetgoarm() string {
// NaCl guarantees VFPv3 and is always cross-compiled.
return "7"
}
+ if goos == "darwin" {
+ // Assume all darwin/arm devices are have VFPv3. This
+ // port is also mostly cross-compiled, so it makes little
+ // sense to auto-detect the setting.
+ return "7"
+ }
if gohostarch != "arm" || goos != gohostos {
// Conservative default for cross-compilation.
return "5"
@@ -499,24 +509,38 @@ func xgetgoarm() string {
// FreeBSD has broken VFP support.
return "5"
}
- if xtryexecfunc(useVFPv3) {
+ if goos != "linux" {
+ // All other arm platforms that we support
+ // require ARMv7.
return "7"
}
- if xtryexecfunc(useVFPv1) {
- return "6"
- }
- return "5"
-}
+ cpuinfo := readfile("/proc/cpuinfo")
+ goarm := "5"
+ for _, line := range splitlines(cpuinfo) {
+ line := strings.SplitN(line, ":", 2)
+ if len(line) < 2 {
+ continue
+ }
+ if strings.TrimSpace(line[0]) != "Features" {
+ continue
+ }
+ features := splitfields(line[1])
+ sort.Strings(features) // so vfpv3 sorts after vfp
-func xtryexecfunc(f func()) bool {
- // TODO(rsc): Implement.
- // The C cmd/dist used this to test whether certain assembly
- // sequences could be executed properly. It used signals and
- // timers and sigsetjmp, which is basically not possible in Go.
- // We probably have to invoke ourselves as a subprocess instead,
- // to contain the fault/timeout.
- return false
+ // Infer GOARM value from the vfp features available
+ // on this host. Values of GOARM detected are:
+ // 5: no vfp support was found
+ // 6: vfp (v1) support was detected, but no higher
+ // 7: vfpv3 support was detected.
+ // This matches the assertions in runtime.checkarm.
+ for _, f := range features {
+ switch f {
+ case "vfp":
+ goarm = "6"
+ case "vfpv3":
+ goarm = "7"
+ }
+ }
+ }
+ return goarm
}
-
-func useVFPv1()
-func useVFPv3()
diff --git a/src/cmd/dist/vfp_arm.s b/src/cmd/dist/vfp_arm.s
deleted file mode 100644
index 39052dbb30..0000000000
--- a/src/cmd/dist/vfp_arm.s
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2015 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 "textflag.h"
-
-// try to run "vmov.f64 d0, d0" instruction
-TEXT ·useVFPv1(SB),NOSPLIT,$0
- WORD $0xeeb00b40 // vmov.f64 d0, d0
- RET
-
-// try to run VFPv3-only "vmov.f64 d0, #112" instruction
-TEXT ·useVFPv3(SB),NOSPLIT,$0
- WORD $0xeeb70b00 // vmov.f64 d0, #112
- RET
diff --git a/src/cmd/dist/vfp_default.s b/src/cmd/dist/vfp_default.s
deleted file mode 100644
index c795b357f7..0000000000
--- a/src/cmd/dist/vfp_default.s
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2015 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.
-
-// +build !arm
-
-#include "textflag.h"
-
-TEXT ·useVFPv1(SB),NOSPLIT,$0
- RET
-
-TEXT ·useVFPv3(SB),NOSPLIT,$0
- RET
-
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index 26d72e87fc..59ff0abf73 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -35,7 +35,7 @@ offmod(Type *t)
fatal("offmod: not TFIELD: %lT", f);
f->width = o;
o += widthptr;
- if(o >= arch.MAXWIDTH) {
+ if(o >= thearch.MAXWIDTH) {
yyerror("interface too large");
o = widthptr;
}
@@ -86,7 +86,7 @@ widstruct(Type *errtype, Type *t, vlong o, int flag)
if(w == 0)
lastzero = o;
o += w;
- if(o >= arch.MAXWIDTH) {
+ if(o >= thearch.MAXWIDTH) {
yyerror("type %lT too large", errtype);
o = 8; // small but nonzero
}
@@ -260,7 +260,7 @@ dowidth(Type *t)
dowidth(t->type);
if(t->type->width != 0) {
- cap = (arch.MAXWIDTH-1) / t->type->width;
+ cap = (thearch.MAXWIDTH-1) / t->type->width;
if(t->bound > cap)
yyerror("type %lT larger than address space", t);
}
@@ -613,15 +613,15 @@ typeinit(void)
simtype[TFUNC] = tptr;
simtype[TUNSAFEPTR] = tptr;
- /* pick up the backend arch.typedefs */
- for(i=0; arch.typedefs[i].name; i++) {
- s = lookup(arch.typedefs[i].name);
- s1 = pkglookup(arch.typedefs[i].name, builtinpkg);
+ /* pick up the backend thearch.typedefs */
+ for(i=0; thearch.typedefs[i].name; i++) {
+ s = lookup(thearch.typedefs[i].name);
+ s1 = pkglookup(thearch.typedefs[i].name, builtinpkg);
- etype = arch.typedefs[i].etype;
+ etype = thearch.typedefs[i].etype;
if(etype < 0 || etype >= nelem(types))
fatal("typeinit: %s bad etype", s->name);
- sameas = arch.typedefs[i].sameas;
+ sameas = thearch.typedefs[i].sameas;
if(sameas < 0 || sameas >= nelem(types))
fatal("typeinit: %s bad sameas", s->name);
simtype[etype] = sameas;
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
index f154ae70b1..1178f622e5 100644
--- a/src/cmd/gc/builtin.c
+++ b/src/cmd/gc/builtin.c
@@ -1,4 +1,7 @@
// AUTO-GENERATED by mkbuiltin; DO NOT EDIT
+#include <u.h>
+#include <libc.h>
+#include "go.h"
char *runtimeimport =
"package runtime\n"
"import runtime \"runtime\"\n"
@@ -36,10 +39,10 @@ char *runtimeimport =
"func @\"\".intstring (? *[4]byte, ? int64) (? string)\n"
"func @\"\".slicebytetostring (? *[32]byte, ? []byte) (? string)\n"
"func @\"\".slicebytetostringtmp (? []byte) (? string)\n"
- "func @\"\".slicerunetostring (? []rune) (? string)\n"
- "func @\"\".stringtoslicebyte (? string) (? []byte)\n"
+ "func @\"\".slicerunetostring (? *[32]byte, ? []rune) (? string)\n"
+ "func @\"\".stringtoslicebyte (? *[32]byte, ? string) (? []byte)\n"
"func @\"\".stringtoslicebytetmp (? string) (? []byte)\n"
- "func @\"\".stringtoslicerune (? string) (? []rune)\n"
+ "func @\"\".stringtoslicerune (? *[32]rune, ? string) (? []rune)\n"
"func @\"\".stringiter (? string, ? int) (? int)\n"
"func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n"
"func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n"
@@ -65,7 +68,7 @@ char *runtimeimport =
"func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n"
"func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
"func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
- "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64) (@\"\".hmap·1 map[any]any)\n"
+ "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *any, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n"
"func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n"
"func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
"func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
index 5d25ffe4ad..0391ece379 100644
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -105,6 +105,7 @@ typecheckclosure(Node *func, int top)
oldfn = curfn;
typecheck(&func->ntype, Etype);
func->type = func->ntype->type;
+ func->top = top;
// Type check the body now, but only if we're inside a function.
// At top level (in a variable initialization: curfn==nil) we're not
@@ -119,9 +120,6 @@ typecheckclosure(Node *func, int top)
curfn = oldfn;
}
- // Remember closure context for capturevars.
- func->etype = (top & (Ecall|Eproc)) == Ecall;
-
// Create top-level function
xtop = list(xtop, makeclosure(func));
}
@@ -172,22 +170,17 @@ makeclosure(Node *func)
// It decides whether each variable captured by a closure should be captured
// by value or by reference.
// We use value capturing for values <= 128 bytes that are never reassigned
-// after declaration.
+// after capturing (effectively constant).
void
capturevars(Node *xfunc)
{
- Node *func, *v, *addr, *cv, *outer;
- NodeList *l, *body;
- char *p;
- vlong offset;
- int nvar, lno;
+ Node *func, *v, *outer;
+ NodeList *l;
+ int lno;
lno = lineno;
lineno = xfunc->lineno;
- nvar = 0;
- body = nil;
- offset = widthptr;
func = xfunc->closure;
func->enter = nil;
for(l=func->cvars; l; l=l->next) {
@@ -202,7 +195,6 @@ capturevars(Node *xfunc)
v->op = OXXX;
continue;
}
- nvar++;
// type check the & of closed variables outside the closure,
// so that the outer frame also grabs them and knows they escape.
@@ -213,53 +205,150 @@ capturevars(Node *xfunc)
if(outer->class != PPARAMOUT && !v->closure->addrtaken && !v->closure->assigned && v->type->width <= 128)
v->byval = 1;
else {
+ v->closure->addrtaken = 1;
outer = nod(OADDR, outer, N);
- // For a closure that is called in place, but not
- // inside a go statement, avoid moving variables to the heap.
- outer->etype = func->etype;
}
- if(debug['m'] > 1)
+ if(debug['m'] > 1) {
+ Sym *name;
+ char *how;
+ name = nil;
+ if(v->curfn && v->curfn->nname)
+ name = v->curfn->nname->sym;
+ how = "ref";
+ if(v->byval)
+ how = "value";
warnl(v->lineno, "%S capturing by %s: %S (addr=%d assign=%d width=%d)",
- (v->curfn && v->curfn->nname) ? v->curfn->nname->sym : S, v->byval ? "value" : "ref",
+ name, how,
v->sym, v->closure->addrtaken, v->closure->assigned, (int32)v->type->width);
+ }
typecheck(&outer, Erv);
func->enter = list(func->enter, outer);
+ }
+
+ lineno = lno;
+}
+
+// transformclosure is called in a separate phase after escape analysis.
+// It transform closure bodies to properly reference captured variables.
+void
+transformclosure(Node *xfunc)
+{
+ Node *func, *cv, *addr, *v, *f;
+ NodeList *l, *body;
+ Type **param, *fld;
+ vlong offset;
+ int lno, nvar;
+
+ lno = lineno;
+ lineno = xfunc->lineno;
+ func = xfunc->closure;
- // declare variables holding addresses taken from closure
- // and initialize in entry prologue.
- addr = nod(ONAME, N, N);
- p = smprint("&%s", v->sym->name);
- addr->sym = lookup(p);
- free(p);
- addr->ntype = nod(OIND, typenod(v->type), N);
- addr->class = PAUTO;
- addr->addable = 1;
- addr->ullman = 1;
- addr->used = 1;
- addr->curfn = xfunc;
- xfunc->dcl = list(xfunc->dcl, addr);
- v->heapaddr = addr;
- cv = nod(OCLOSUREVAR, N, N);
- if(v->byval) {
+ if(func->top&Ecall) {
+ // If the closure is directly called, we transform it to a plain function call
+ // with variables passed as args. This avoids allocation of a closure object.
+ // Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
+ // will complete the transformation later.
+ // For illustration, the following closure:
+ // func(a int) {
+ // println(byval)
+ // byref++
+ // }(42)
+ // becomes:
+ // func(a int, byval int, &byref *int) {
+ // println(byval)
+ // (*&byref)++
+ // }(42, byval, &byref)
+
+ // f is ONAME of the actual function.
+ f = xfunc->nname;
+ // Get pointer to input arguments and rewind to the end.
+ // We are going to append captured variables to input args.
+ param = &getinargx(f->type)->type;
+ for(; *param; param = &(*param)->down) {
+ }
+ for(l=func->cvars; l; l=l->next) {
+ v = l->n;
+ if(v->op == OXXX)
+ continue;
+ fld = typ(TFIELD);
+ fld->funarg = 1;
+ if(v->byval) {
+ // If v is captured by value, we merely downgrade it to PPARAM.
+ v->class = PPARAM;
+ v->ullman = 1;
+ fld->nname = v;
+ } else {
+ // If v of type T is captured by reference,
+ // we introduce function param &v *T
+ // and v remains PPARAMREF with &v heapaddr
+ // (accesses will implicitly deref &v).
+ snprint(namebuf, sizeof namebuf, "&%s", v->sym->name);
+ addr = newname(lookup(namebuf));
+ addr->type = ptrto(v->type);
+ addr->class = PPARAM;
+ v->heapaddr = addr;
+ fld->nname = addr;
+ }
+ fld->type = fld->nname->type;
+ fld->sym = fld->nname->sym;
+ // Declare the new param and append it to input arguments.
+ xfunc->dcl = list(xfunc->dcl, fld->nname);
+ *param = fld;
+ param = &fld->down;
+ }
+ // Recalculate param offsets.
+ if(f->type->width > 0)
+ fatal("transformclosure: width is already calculated");
+ dowidth(f->type);
+ xfunc->type = f->type; // update type of ODCLFUNC
+ } else {
+ // The closure is not called, so it is going to stay as closure.
+ nvar = 0;
+ body = nil;
+ offset = widthptr;
+ for(l=func->cvars; l; l=l->next) {
+ v = l->n;
+ if(v->op == OXXX)
+ continue;
+ nvar++;
+ // cv refers to the field inside of closure OSTRUCTLIT.
+ cv = nod(OCLOSUREVAR, N, N);
cv->type = v->type;
- offset = rnd(offset, v->type->align);
+ if(!v->byval)
+ cv->type = ptrto(v->type);
+ offset = rnd(offset, cv->type->align);
cv->xoffset = offset;
- offset += v->type->width;
- body = list(body, nod(OAS, addr, nod(OADDR, cv, N)));
- } else {
- v->closure->addrtaken = 1;
- cv->type = ptrto(v->type);
- offset = rnd(offset, widthptr);
- cv->xoffset = offset;
- offset += widthptr;
- body = list(body, nod(OAS, addr, cv));
+ offset += cv->type->width;
+
+ if(v->byval && v->type->width <= 2*widthptr && thearch.thechar == '6') {
+ // If it is a small variable captured by value, downgrade it to PAUTO.
+ // This optimization is currently enabled only for amd64, see:
+ // https://github.com/golang/go/issues/9865
+ v->class = PAUTO;
+ v->ullman = 1;
+ xfunc->dcl = list(xfunc->dcl, v);
+ body = list(body, nod(OAS, v, cv));
+ } else {
+ // Declare variable holding addresses taken from closure
+ // and initialize in entry prologue.
+ snprint(namebuf, sizeof namebuf, "&%s", v->sym->name);
+ addr = newname(lookup(namebuf));
+ addr->ntype = nod(OIND, typenod(v->type), N);
+ addr->class = PAUTO;
+ addr->used = 1;
+ addr->curfn = xfunc;
+ xfunc->dcl = list(xfunc->dcl, addr);
+ v->heapaddr = addr;
+ if(v->byval)
+ cv = nod(OADDR, cv, N);
+ body = list(body, nod(OAS, addr, cv));
+ }
}
+ typechecklist(body, Etop);
+ walkstmtlist(body);
+ xfunc->enter = body;
+ xfunc->needctxt = nvar > 0;
}
- typechecklist(body, Etop);
- walkstmtlist(body);
- xfunc->enter = body;
- xfunc->needctxt = nvar > 0;
- func->etype = 0;
lineno = lno;
}
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index e418b9c561..50accb93a3 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -696,14 +696,7 @@ evconst(Node *n)
// run op
switch(TUP(n->op, v.ctype)) {
default:
- illegal:
- if(!n->diag) {
- yyerror("illegal constant expression: %T %O %T",
- nl->type, n->op, nr->type);
- n->diag = 1;
- }
- return;
-
+ goto illegal;
case TUP(OADD, CTINT):
case TUP(OADD, CTRUNE):
mpaddfixfix(v.u.xval, rv.u.xval, 0);
@@ -1036,6 +1029,14 @@ setfalse:
*n = *nodbool(0);
n->orig = norig;
return;
+
+illegal:
+ if(!n->diag) {
+ yyerror("illegal constant expression: %T %O %T",
+ nl->type, n->op, nr->type);
+ n->diag = 1;
+ }
+ return;
}
Node*
@@ -1214,28 +1215,31 @@ defaultlit(Node **np, Type *t)
case CTCPLX:
t1 = types[TCOMPLEX128];
goto num;
- num:
- if(t != T) {
- if(isint[t->etype]) {
- t1 = t;
- n->val = toint(n->val);
- }
- else
- if(isfloat[t->etype]) {
- t1 = t;
- n->val = toflt(n->val);
- }
- else
- if(iscomplex[t->etype]) {
- t1 = t;
- n->val = tocplx(n->val);
- }
+ }
+ lineno = lno;
+ return;
+
+num:
+ if(t != T) {
+ if(isint[t->etype]) {
+ t1 = t;
+ n->val = toint(n->val);
+ }
+ else
+ if(isfloat[t->etype]) {
+ t1 = t;
+ n->val = toflt(n->val);
+ }
+ else
+ if(iscomplex[t->etype]) {
+ t1 = t;
+ n->val = tocplx(n->val);
}
- overflow(n->val, t1);
- convlit(np, t1);
- break;
}
+ overflow(n->val, t1);
+ convlit(np, t1);
lineno = lno;
+ return;
}
/*
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
index d3fb952558..26c21df82a 100644
--- a/src/cmd/gc/cplx.c
+++ b/src/cmd/gc/cplx.c
@@ -78,8 +78,8 @@ complexmove(Node *f, Node *t)
subnode(&n1, &n2, f);
subnode(&n3, &n4, t);
- arch.cgen(&n1, &n3);
- arch.cgen(&n2, &n4);
+ thearch.cgen(&n1, &n3);
+ thearch.cgen(&n2, &n4);
break;
}
}
@@ -151,9 +151,9 @@ complexgen(Node *n, Node *res)
if(res->addable) {
subnode(&n1, &n2, res);
tempname(&tmp, n1.type);
- arch.cgen(n->left, &tmp);
- arch.cgen(n->right, &n2);
- arch.cgen(&tmp, &n1);
+ thearch.cgen(n->left, &tmp);
+ thearch.cgen(n->right, &n2);
+ thearch.cgen(&tmp, &n1);
return;
}
break;
@@ -168,10 +168,10 @@ complexgen(Node *n, Node *res)
}
subnode(&n1, &n2, nl);
if(n->op == OREAL) {
- arch.cgen(&n1, res);
+ thearch.cgen(&n1, res);
return;
}
- arch.cgen(&n2, res);
+ thearch.cgen(&n2, res);
return;
}
@@ -191,9 +191,9 @@ complexgen(Node *n, Node *res)
}
if(!res->addable) {
- arch.igen(res, &n1, N);
- arch.cgen(n, &n1);
- arch.regfree(&n1);
+ thearch.igen(res, &n1, N);
+ thearch.cgen(n, &n1);
+ thearch.regfree(&n1);
return;
}
if(n->addable) {
@@ -214,9 +214,9 @@ complexgen(Node *n, Node *res)
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
- arch.igen(n, &n1, res);
+ thearch.igen(n, &n1, res);
complexmove(&n1, res);
- arch.regfree(&n1);
+ thearch.regfree(&n1);
return;
case OCONV:
@@ -239,18 +239,18 @@ complexgen(Node *n, Node *res)
if(nr != N) {
if(nl->ullman > nr->ullman && !nl->addable) {
tempname(&tnl, nl->type);
- arch.cgen(nl, &tnl);
+ thearch.cgen(nl, &tnl);
nl = &tnl;
}
if(!nr->addable) {
tempname(&tnr, nr->type);
- arch.cgen(nr, &tnr);
+ thearch.cgen(nr, &tnr);
nr = &tnr;
}
}
if(!nl->addable) {
tempname(&tnl, nl->type);
- arch.cgen(nl, &tnl);
+ thearch.cgen(nl, &tnl);
nl = &tnl;
}
@@ -289,18 +289,18 @@ complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to)
if(nr != N) {
if(nl->ullman > nr->ullman && !nl->addable) {
tempname(&tnl, nl->type);
- arch.cgen(nl, &tnl);
+ thearch.cgen(nl, &tnl);
nl = &tnl;
}
if(!nr->addable) {
tempname(&tnr, nr->type);
- arch.cgen(nr, &tnr);
+ thearch.cgen(nr, &tnr);
nr = &tnr;
}
}
if(!nl->addable) {
tempname(&tnl, nl->type);
- arch.cgen(nl, &tnl);
+ thearch.cgen(nl, &tnl);
nl = &tnl;
}
@@ -331,7 +331,7 @@ complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to)
if(op == ONE)
true = !true;
- arch.bgen(&na, true, likely, to);
+ thearch.bgen(&na, true, likely, to);
}
void
@@ -387,7 +387,7 @@ minus(Node *nl, Node *res)
ra.op = OMINUS;
ra.left = nl;
ra.type = nl->type;
- arch.cgen(&ra, res);
+ thearch.cgen(&ra, res);
}
// build and execute tree
@@ -424,14 +424,14 @@ complexadd(int op, Node *nl, Node *nr, Node *res)
ra.left = &n1;
ra.right = &n3;
ra.type = n1.type;
- arch.cgen(&ra, &n5);
+ thearch.cgen(&ra, &n5);
memset(&ra, 0, sizeof(ra));
ra.op = op;
ra.left = &n2;
ra.right = &n4;
ra.type = n2.type;
- arch.cgen(&ra, &n6);
+ thearch.cgen(&ra, &n6);
}
// build and execute tree
@@ -467,7 +467,7 @@ complexmul(Node *nl, Node *nr, Node *res)
ra.left = &rm1;
ra.right = &rm2;
ra.type = rm1.type;
- arch.cgen(&ra, &tmp);
+ thearch.cgen(&ra, &tmp);
// imag part
memset(&rm1, 0, sizeof(rm1));
@@ -487,8 +487,8 @@ complexmul(Node *nl, Node *nr, Node *res)
ra.left = &rm1;
ra.right = &rm2;
ra.type = rm1.type;
- arch.cgen(&ra, &n6);
+ thearch.cgen(&ra, &n6);
// tmp ->real part
- arch.cgen(&tmp, &n5);
+ thearch.cgen(&tmp, &n5);
}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index f47ca2b50e..9a6c0023f5 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -1435,7 +1435,7 @@ addmethod(Sym *sf, Type *t, int local, int nointerface)
}
void
-funccompile(Node *n, int isclosure)
+funccompile(Node *n)
{
stksize = BADWIDTH;
maxarg = 0;
@@ -1449,20 +1449,6 @@ funccompile(Node *n, int isclosure)
// assign parameter offsets
checkwidth(n->type);
- // record offset to actual frame pointer.
- // for closure, have to skip over leading pointers and PC slot.
- // TODO(rsc): this is the old jit closure handling code.
- // with the new closures, isclosure is always 0; delete this block.
- nodfp->xoffset = 0;
- if(isclosure) {
- NodeList *l;
- for(l=n->nname->ntype->list; l; l=l->next) {
- nodfp->xoffset += widthptr;
- if(l->n->left == N) // found slot for PC
- break;
- }
- }
-
if(curfn)
fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym);
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
index 4f77983926..5b09c0b7fb 100644
--- a/src/cmd/gc/esc.c
+++ b/src/cmd/gc/esc.c
@@ -693,12 +693,10 @@ esc(EscState *e, Node *n, Node *up)
case OMAKEMAP:
case OMAKESLICE:
case ONEW:
- n->escloopdepth = e->loopdepth;
- n->esc = EscNone; // until proven otherwise
- e->noesc = list(e->noesc, n);
- break;
-
+ case OARRAYRUNESTR:
case OARRAYBYTESTR:
+ case OSTRARRAYRUNE:
+ case OSTRARRAYBYTE:
case ORUNESTR:
n->escloopdepth = e->loopdepth;
n->esc = EscNone; // until proven otherwise
@@ -824,7 +822,10 @@ escassign(EscState *e, Node *dst, Node *src)
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
+ case OARRAYRUNESTR:
case OARRAYBYTESTR:
+ case OSTRARRAYRUNE:
+ case OSTRARRAYBYTE:
case OADDSTR:
case ONEW:
case OCLOSURE:
@@ -1249,7 +1250,10 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
+ case OARRAYRUNESTR:
case OARRAYBYTESTR:
+ case OSTRARRAYRUNE:
+ case OSTRARRAYBYTE:
case OADDSTR:
case OMAPLIT:
case ONEW:
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
index 8685aa0def..91f4957dc2 100644
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -538,7 +538,7 @@ dumpasmhdr(void)
b = Bopen(asmhdr, OWRITE);
if(b == nil)
fatal("open %s: %r", asmhdr);
- Bprint(b, "// generated by %cg -asmhdr from package %s\n\n", arch.thechar, localpkg->name);
+ Bprint(b, "// generated by %cg -asmhdr from package %s\n\n", thearch.thechar, localpkg->name);
for(l=asmlist; l; l=l->next) {
n = l->n;
if(isblanksym(n->sym))
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
index f9eb0ba2b3..bd0a29f6e1 100644
--- a/src/cmd/gc/fmt.c
+++ b/src/cmd/gc/fmt.c
@@ -171,7 +171,7 @@ goopnames[] =
};
// Fmt "%O": Node opcodes
-static int
+int
Oconv(Fmt *fp)
{
int o;
@@ -1558,7 +1558,7 @@ Sconv(Fmt *fp)
// Flags: 'l' print definition, not name
// 'h' omit 'func' and receiver from function types, short type names
// 'u' package name, not prefix (FTypeId mode, sticky)
-static int
+int
Tconv(Fmt *fp)
{
Type *t;
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index 20c17bd46a..72bcc492a5 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -265,7 +265,7 @@ gen(Node *n)
//dump("gen", n);
lno = setlineno(n);
- wasregalloc = arch.anyregalloc();
+ wasregalloc = thearch.anyregalloc();
if(n == N)
goto ret;
@@ -304,8 +304,8 @@ gen(Node *n)
// if there are pending gotos, resolve them all to the current pc.
for(p1=lab->gotopc; p1; p1=p2) {
- p2 = arch.unpatch(p1);
- arch.patch(p1, pc);
+ p2 = unpatch(p1);
+ patch(p1, pc);
}
lab->gotopc = P;
if(lab->labelpc == P)
@@ -332,9 +332,9 @@ gen(Node *n)
// of the label in the OLABEL case above.)
lab = newlab(n);
if(lab->labelpc != P)
- arch.gjmp(lab->labelpc);
+ gjmp(lab->labelpc);
else
- lab->gotopc = arch.gjmp(lab->gotopc);
+ lab->gotopc = gjmp(lab->gotopc);
break;
case OBREAK:
@@ -349,14 +349,14 @@ gen(Node *n)
yyerror("invalid break label %S", n->left->sym);
break;
}
- arch.gjmp(lab->breakpc);
+ gjmp(lab->breakpc);
break;
}
if(breakpc == P) {
yyerror("break is not in a loop");
break;
}
- arch.gjmp(breakpc);
+ gjmp(breakpc);
break;
case OCONTINUE:
@@ -371,20 +371,20 @@ gen(Node *n)
yyerror("invalid continue label %S", n->left->sym);
break;
}
- arch.gjmp(lab->continpc);
+ gjmp(lab->continpc);
break;
}
if(continpc == P) {
yyerror("continue is not in a loop");
break;
}
- arch.gjmp(continpc);
+ gjmp(continpc);
break;
case OFOR:
sbreak = breakpc;
- p1 = arch.gjmp(P); // goto test
- breakpc = arch.gjmp(P); // break: goto done
+ p1 = gjmp(P); // goto test
+ breakpc = gjmp(P); // break: goto done
scontin = continpc;
continpc = pc;
@@ -394,11 +394,11 @@ gen(Node *n)
lab->continpc = continpc;
}
gen(n->nincr); // contin: incr
- arch.patch(p1, pc); // test:
- arch.bgen(n->ntest, 0, -1, breakpc); // if(!test) goto break
+ patch(p1, pc); // test:
+ thearch.bgen(n->ntest, 0, -1, breakpc); // if(!test) goto break
genlist(n->nbody); // body
- arch.gjmp(continpc);
- arch.patch(breakpc, pc); // done:
+ gjmp(continpc);
+ patch(breakpc, pc); // done:
continpc = scontin;
breakpc = sbreak;
if(lab) {
@@ -408,29 +408,29 @@ gen(Node *n)
break;
case OIF:
- p1 = arch.gjmp(P); // goto test
- p2 = arch.gjmp(P); // p2: goto else
- arch.patch(p1, pc); // test:
- arch.bgen(n->ntest, 0, -n->likely, p2); // if(!test) goto p2
+ p1 = gjmp(P); // goto test
+ p2 = gjmp(P); // p2: goto else
+ patch(p1, pc); // test:
+ thearch.bgen(n->ntest, 0, -n->likely, p2); // if(!test) goto p2
genlist(n->nbody); // then
- p3 = arch.gjmp(P); // goto done
- arch.patch(p2, pc); // else:
+ p3 = gjmp(P); // goto done
+ patch(p2, pc); // else:
genlist(n->nelse); // else
- arch.patch(p3, pc); // done:
+ patch(p3, pc); // done:
break;
case OSWITCH:
sbreak = breakpc;
- p1 = arch.gjmp(P); // goto test
- breakpc = arch.gjmp(P); // break: goto done
+ p1 = gjmp(P); // goto test
+ breakpc = gjmp(P); // break: goto done
// define break label
if((lab = stmtlabel(n)) != L)
lab->breakpc = breakpc;
- arch.patch(p1, pc); // test:
+ patch(p1, pc); // test:
genlist(n->nbody); // switch(test) body
- arch.patch(breakpc, pc); // done:
+ patch(breakpc, pc); // done:
breakpc = sbreak;
if(lab != L)
lab->breakpc = P;
@@ -438,25 +438,21 @@ gen(Node *n)
case OSELECT:
sbreak = breakpc;
- p1 = arch.gjmp(P); // goto test
- breakpc = arch.gjmp(P); // break: goto done
+ p1 = gjmp(P); // goto test
+ breakpc = gjmp(P); // break: goto done
// define break label
if((lab = stmtlabel(n)) != L)
lab->breakpc = breakpc;
- arch.patch(p1, pc); // test:
+ patch(p1, pc); // test:
genlist(n->nbody); // select() body
- arch.patch(breakpc, pc); // done:
+ patch(breakpc, pc); // done:
breakpc = sbreak;
if(lab != L)
lab->breakpc = P;
break;
- case OASOP:
- arch.cgen_asop(n);
- break;
-
case ODCL:
cgen_dcl(n->left);
break;
@@ -472,11 +468,11 @@ gen(Node *n)
break;
case OCALLINTER:
- arch.cgen_callinter(n, N, 0);
+ thearch.cgen_callinter(n, N, 0);
break;
case OCALLFUNC:
- arch.cgen_call(n, 0);
+ thearch.cgen_call(n, 0);
break;
case OPROC:
@@ -489,7 +485,7 @@ gen(Node *n)
case ORETURN:
case ORETJMP:
- arch.cgen_ret(n);
+ thearch.cgen_ret(n);
break;
case OCHECKNIL:
@@ -502,7 +498,7 @@ gen(Node *n)
}
ret:
- if(arch.anyregalloc() != wasregalloc) {
+ if(thearch.anyregalloc() != wasregalloc) {
dump("node", n);
fatal("registers left allocated");
}
@@ -536,7 +532,7 @@ cgen_callmeth(Node *n, int proc)
if(n2.left->op == ONAME)
n2.left->class = PFUNC;
- arch.cgen_call(&n2, proc);
+ thearch.cgen_call(&n2, proc);
}
/*
@@ -554,11 +550,11 @@ cgen_proc(Node *n, int proc)
break;
case OCALLINTER:
- arch.cgen_callinter(n->left, N, proc);
+ thearch.cgen_callinter(n->left, N, proc);
break;
case OCALLFUNC:
- arch.cgen_call(n->left, proc);
+ thearch.cgen_call(n->left, proc);
break;
}
@@ -601,7 +597,7 @@ cgen_discard(Node *nr)
switch(nr->op) {
case ONAME:
if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
- arch.gused(nr);
+ gused(nr);
break;
// unary
@@ -643,7 +639,7 @@ cgen_discard(Node *nr)
default:
tempname(&tmp, nr->type);
cgen_as(&tmp, nr);
- arch.gused(&tmp);
+ gused(&tmp);
}
}
@@ -705,7 +701,7 @@ clearslim(Node *n)
}
ullmancalc(&z);
- arch.cgen(&z, n);
+ thearch.cgen(&z, n);
}
/*
@@ -739,10 +735,10 @@ cgen_as(Node *nl, Node *nr)
tl = nl->type;
if(tl == T)
return;
- if(arch.isfat(tl)) {
+ if(isfat(tl)) {
if(nl->op == ONAME)
gvardef(nl);
- arch.clearfat(nl);
+ thearch.clearfat(nl);
return;
}
clearslim(nl);
@@ -753,7 +749,7 @@ cgen_as(Node *nl, Node *nr)
if(tl == T)
return;
- arch.cgen(nr, nl);
+ thearch.cgen(nr, nl);
}
/*
@@ -773,17 +769,17 @@ cgen_eface(Node *n, Node *res)
Node *tmp;
tmp = temp(types[tptr]);
- arch.cgen(n->right, tmp);
+ thearch.cgen(n->right, tmp);
gvardef(res);
dst = *res;
dst.type = types[tptr];
dst.xoffset += widthptr;
- arch.cgen(tmp, &dst);
+ thearch.cgen(tmp, &dst);
dst.xoffset -= widthptr;
- arch.cgen(n->left, &dst);
+ thearch.cgen(n->left, &dst);
}
/*
@@ -824,7 +820,7 @@ cgen_slice(Node *n, Node *res)
if(isnil(n->left)) {
tempname(&src, n->left->type);
- arch.cgen(n->left, &src);
+ thearch.cgen(n->left, &src);
} else
src = *n->left;
if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR)
@@ -833,11 +829,11 @@ cgen_slice(Node *n, Node *res)
if(n->op == OSLICEARR || n->op == OSLICE3ARR) {
if(!isptr[n->left->type->etype])
fatal("slicearr is supposed to work on pointer: %+N\n", n);
- arch.cgen(&src, base);
+ thearch.cgen(&src, base);
cgen_checknil(base);
} else {
src.type = types[tptr];
- arch.cgen(&src, base);
+ thearch.cgen(&src, base);
}
// committed to the update
@@ -846,9 +842,9 @@ cgen_slice(Node *n, Node *res)
// compute len and cap.
// len = n-i, cap = m-i, and offs = i*width.
// computing offs last lets the multiply overwrite i.
- arch.cgen(len, tmplen);
+ thearch.cgen(len, tmplen);
if(n->op != OSLICESTR)
- arch.cgen(cap, tmpcap);
+ thearch.cgen(cap, tmpcap);
// if new cap != 0 { base += add }
// This avoids advancing base past the end of the underlying array/string,
@@ -857,40 +853,40 @@ cgen_slice(Node *n, Node *res)
// In essence we are replacing x[i:j:k] where i == j == k
// or x[i:j] where i == j == cap(x) with x[0:0:0].
if(offs != N) {
- p1 = arch.gjmp(P);
- p2 = arch.gjmp(P);
- arch.patch(p1, pc);
+ p1 = gjmp(P);
+ p2 = gjmp(P);
+ patch(p1, pc);
nodconst(&con, tmpcap->type, 0);
cmp = nod(OEQ, tmpcap, &con);
typecheck(&cmp, Erv);
- arch.bgen(cmp, 1, -1, p2);
+ thearch.bgen(cmp, 1, -1, p2);
add = nod(OADD, base, offs);
typecheck(&add, Erv);
- arch.cgen(add, base);
+ thearch.cgen(add, base);
- arch.patch(p2, pc);
+ patch(p2, pc);
}
// dst.array = src.array [ + lo *width ]
dst = *res;
dst.xoffset += Array_array;
dst.type = types[tptr];
- arch.cgen(base, &dst);
+ thearch.cgen(base, &dst);
// dst.len = hi [ - lo ]
dst = *res;
dst.xoffset += Array_nel;
dst.type = types[simtype[TUINT]];
- arch.cgen(tmplen, &dst);
+ thearch.cgen(tmplen, &dst);
if(n->op != OSLICESTR) {
// dst.cap = cap [ - lo ]
dst = *res;
dst.xoffset += Array_cap;
dst.type = types[simtype[TUINT]];
- arch.cgen(tmpcap, &dst);
+ thearch.cgen(tmpcap, &dst);
}
}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 2aa7838c93..c5ef74586d 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -331,6 +331,7 @@ struct Node
// ONAME closure param with PPARAMREF
Node* outer; // outer PPARAMREF in nested closure
Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF
+ int top; // top context (Ecall, Eproc, etc)
// ONAME substitute while inlining
Node* inlvar;
@@ -598,7 +599,7 @@ enum
OCHECKNIL, // emit code to ensure pointer/interface not nil
OVARKILL, // variable is dead
- // arch-specific registers
+ // thearch-specific registers
OREGISTER, // a register, such as AX.
OINDREG, // offset plus indirect of a register, such as 8(SP).
@@ -742,6 +743,7 @@ struct Var
Node* node;
Var* nextinnode;
int width;
+ int id;
char name;
char etype;
char addr;
@@ -1075,6 +1077,7 @@ Node* closurebody(NodeList *body);
void closurehdr(Node *ntype);
void typecheckclosure(Node *func, int top);
void capturevars(Node *func);
+void transformclosure(Node *func);
Node* walkclosure(Node *func, NodeList **init);
void typecheckpartialcall(Node*, Node*);
Node* walkpartialcall(Node*, NodeList**);
@@ -1128,7 +1131,7 @@ void dumpdcl(char *st);
Node* embedded(Sym *s, Pkg *pkg);
Node* fakethis(void);
void funcbody(Node *n);
-void funccompile(Node *n, int isclosure);
+void funccompile(Node *n);
void funchdr(Node *n);
Type* functype(Node *this, NodeList *in, NodeList *out);
void ifacedcl(Node *n);
@@ -1321,7 +1324,9 @@ Sym* typenamesym(Type *t);
Sym* tracksym(Type *t);
Sym* typesymprefix(char *prefix, Type *t);
int haspointers(Type *t);
+Type* hmap(Type *t);
Type* hiter(Type* t);
+Type* mapbucket(Type *t);
/*
* select.c
@@ -1444,6 +1449,7 @@ void warn(char *fmt, ...);
void warnl(int line, char *fmt, ...);
void yyerror(char *fmt, ...);
void yyerrorl(int line, char *fmt, ...);
+void adderrorname(Node*);
/*
* swt.c
@@ -1492,7 +1498,7 @@ Node* outervalue(Node*);
void usefield(Node*);
/*
- * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c
+ * thearch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c
*/
#define P ((Prog*)0)
@@ -1514,7 +1520,6 @@ void gvarkill(Node*);
void movelarge(NodeList*);
void liveness(Node*, Prog*, Sym*, Sym*);
void twobitwalktype1(Type*, vlong*, Bvec*);
-void nopout(Prog*);
#pragma varargck type "B" Mpint*
#pragma varargck type "E" int
@@ -1558,9 +1563,12 @@ struct Flow {
int32 active; // usable by client
+ int32 id; // sequence number in flow graph
int32 rpo; // reverse post ordering
uint16 loop; // x5 for every loop
uchar refset; // diagnostic generated
+
+ void* data; // for use by client
};
struct Graph
@@ -1659,61 +1667,83 @@ struct Arch
LinkArch *thelinkarch;
Typedef *typedefs;
+ int REGSP;
+ int REGCTXT;
vlong MAXWIDTH;
- void (*afunclit)(Addr*, Node*);
int (*anyregalloc)(void);
void (*betypeinit)(void);
void (*bgen)(Node*, int, int, Prog*);
void (*cgen)(Node*, Node*);
- void (*cgen_asop)(Node*);
void (*cgen_call)(Node*, int);
void (*cgen_callinter)(Node*, Node*, int);
void (*cgen_ret)(Node*);
void (*clearfat)(Node*);
- void (*clearp)(Prog*);
void (*defframe)(Prog*);
- int (*dgostringptr)(Sym*, int, char*);
- int (*dgostrlitptr)(Sym*, int, Strlit*);
- int (*dsname)(Sym*, int, char*, int);
- int (*dsymptr)(Sym*, int, Sym*, int);
- void (*dumpdata)(void);
- void (*dumpit)(char*, Flow*, int);
void (*excise)(Flow*);
void (*expandchecks)(Prog*);
- void (*fixautoused)(Prog*);
void (*gclean)(void);
- void (*gdata)(Node*, Node*, int);
- void (*gdatacomplex)(Node*, Mpcplx*);
- void (*gdatastring)(Node*, Strlit*);
- void (*ggloblnod)(Node*);
- void (*ggloblsym)(Sym*, int32, int8);
void (*ginit)(void);
Prog* (*gins)(int, Node*, Node*);
void (*ginscall)(Node*, int);
- Prog* (*gjmp)(Prog*);
- void (*gtrack)(Sym*);
- void (*gused)(Node*);
void (*igen)(Node*, Node*, Node*);
- int (*isfat)(Type*);
void (*linkarchinit)(void);
- void (*markautoused)(Prog*);
- void (*naddr)(Node*, Addr*, int);
- Plist* (*newplist)(void);
- Node* (*nodarg)(Type*, int);
- void (*patch)(Prog*, Prog*);
+ void (*peep)(Prog*);
void (*proginfo)(ProgInfo*, Prog*);
void (*regalloc)(Node*, Type*, Node*);
void (*regfree)(Node*);
- void (*regopt)(Prog*);
int (*regtyp)(Addr*);
int (*sameaddr)(Addr*, Addr*);
int (*smallindir)(Addr*, Addr*);
int (*stackaddr)(Addr*);
- Prog* (*unpatch)(Prog*);
+ uint64 (*excludedregs)(void);
+ uint64 (*RtoB)(int);
+ uint64 (*FtoB)(int);
+ int (*BtoR)(uint64);
+ int (*BtoF)(uint64);
+ int (*optoas)(int, Type*);
+ uint64 (*doregbits)(int);
+ char **(*regnames)(int*);
};
-EXTERN Arch arch;
+void afunclit(Addr*, Node*);
+void clearp(Prog*);
+int dgostringptr(Sym*, int, char*);
+int dgostrlitptr(Sym*, int, Strlit*);
+int dsname(Sym*, int, char*, int);
+int dsymptr(Sym*, int, Sym*, int);
+void dumpdata(void);
+void fixautoused(Prog*);
+void gdata(Node*, Node*, int);
+void gdatacomplex(Node*, Mpcplx*);
+void gdatastring(Node*, Strlit*);
+void ggloblnod(Node*);
+void ggloblsym(Sym*, int32, int8);
+Prog* gjmp(Prog*);
+void gtrack(Sym*);
+void gused(Node*);
+int isfat(Type*);
+void markautoused(Prog*);
+void naddr(Node*, Addr*, int);
+Plist* newplist(void);
+Node* nodarg(Type*, int);
+void patch(Prog*, Prog*);
+Prog* unpatch(Prog*);
+void datagostring(Strlit *sval, Addr *a);
+int ismem(Node*);
+int samereg(Node*, Node*);
+void regopt(Prog*);
+int Tconv(Fmt*);
+int Oconv(Fmt*);
+Prog* gbranch(int as, Type *t, int likely);
+void nodindreg(Node *n, Type *t, int r);
+void nodreg(Node *n, Type *t, int r);
+Prog* prog(int as);
+void datastring(char*, int, Addr*);
+
+EXTERN int32 pcloc;
+
+EXTERN Arch thearch;
EXTERN Node *newproc;
EXTERN Node *deferproc;
diff --git a/src/cmd/gc/gsubr.c b/src/cmd/gc/gsubr.c
new file mode 100644
index 0000000000..5175ae34f5
--- /dev/null
+++ b/src/cmd/gc/gsubr.c
@@ -0,0 +1,654 @@
+// Derived from Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+#include "../../runtime/funcdata.h"
+#include "../ld/textflag.h"
+
+void
+ggloblnod(Node *nam)
+{
+ Prog *p;
+
+ p = thearch.gins(AGLOBL, nam, N);
+ p->lineno = nam->lineno;
+ p->from.sym->gotype = linksym(ngotype(nam));
+ p->to.sym = nil;
+ p->to.type = TYPE_CONST;
+ p->to.offset = nam->type->width;
+ if(nam->readonly)
+ p->from3.offset = RODATA;
+ if(nam->type != T && !haspointers(nam->type))
+ p->from3.offset |= NOPTR;
+}
+
+void
+gtrack(Sym *s)
+{
+ Prog *p;
+
+ p = thearch.gins(AUSEFIELD, N, N);
+ p->from.type = TYPE_MEM;
+ p->from.name = NAME_EXTERN;
+ p->from.sym = linksym(s);
+}
+
+void
+ggloblsym(Sym *s, int32 width, int8 flags)
+{
+ Prog *p;
+
+ p = thearch.gins(AGLOBL, N, N);
+ p->from.type = TYPE_MEM;
+ p->from.name = NAME_EXTERN;
+ p->from.sym = linksym(s);
+ p->to.type = TYPE_CONST;
+ p->to.offset = width;
+ p->from3.offset = flags;
+}
+
+void
+clearp(Prog *p)
+{
+ nopout(p);
+ p->as = AEND;
+ p->pc = pcloc;
+ pcloc++;
+}
+
+static int ddumped;
+static Prog *dfirst;
+static Prog *dpc;
+
+/*
+ * generate and return proc with p->as = as,
+ * linked into program. pc is next instruction.
+ */
+Prog*
+prog(int as)
+{
+ Prog *p;
+
+ if(as == ADATA || as == AGLOBL) {
+ if(ddumped)
+ fatal("already dumped data");
+ if(dpc == nil) {
+ dpc = mal(sizeof(*dpc));
+ dfirst = dpc;
+ }
+ p = dpc;
+ dpc = mal(sizeof(*dpc));
+ p->link = dpc;
+ } else {
+ p = pc;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p->link = pc;
+ }
+
+ if(lineno == 0) {
+ if(debug['K'])
+ warn("prog: line 0");
+ }
+
+ p->as = as;
+ p->lineno = lineno;
+ return p;
+}
+
+void
+dumpdata(void)
+{
+ ddumped = 1;
+ if(dfirst == nil)
+ return;
+ newplist();
+ *pc = *dfirst;
+ pc = dpc;
+ clearp(pc);
+}
+
+/*
+ * generate a branch.
+ * t is ignored.
+ * likely values are for branch prediction:
+ * -1 unlikely
+ * 0 no opinion
+ * +1 likely
+ */
+Prog*
+gbranch(int as, Type *t, int likely)
+{
+ Prog *p;
+
+ USED(t);
+
+ p = prog(as);
+ p->to.type = TYPE_BRANCH;
+ p->to.u.branch = P;
+ if(as != AJMP && likely != 0 && thearch.thechar != '9') {
+ p->from.type = TYPE_CONST;
+ p->from.offset = likely > 0;
+ }
+ return p;
+}
+
+/*
+ * patch previous branch to jump to to.
+ */
+void
+patch(Prog *p, Prog *to)
+{
+ if(p->to.type != TYPE_BRANCH)
+ fatal("patch: not a branch");
+ p->to.u.branch = to;
+ p->to.offset = to->pc;
+}
+
+Prog*
+unpatch(Prog *p)
+{
+ Prog *q;
+
+ if(p->to.type != TYPE_BRANCH)
+ fatal("unpatch: not a branch");
+ q = p->to.u.branch;
+ p->to.u.branch = P;
+ p->to.offset = 0;
+ return q;
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+newplist(void)
+{
+ Plist *pl;
+
+ pl = linknewplist(ctxt);
+
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ pl->firstpc = pc;
+
+ return pl;
+}
+
+void
+gused(Node *n)
+{
+ thearch.gins(ANOP, n, N); // used
+}
+
+Prog*
+gjmp(Prog *to)
+{
+ Prog *p;
+
+ p = gbranch(AJMP, T, 0);
+ if(to != P)
+ patch(p, to);
+ return p;
+}
+
+int
+isfat(Type *t)
+{
+ if(t != T)
+ switch(t->etype) {
+ case TSTRUCT:
+ case TARRAY:
+ case TSTRING:
+ case TINTER: // maybe remove later
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ */
+void
+afunclit(Addr *a, Node *n)
+{
+ if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
+ a->type = TYPE_MEM;
+ a->sym = linksym(n->sym);
+ }
+}
+
+/*
+ * initialize n to be register r of type t.
+ */
+void
+nodreg(Node *n, Type *t, int r)
+{
+ if(t == T)
+ fatal("nodreg: t nil");
+
+ memset(n, 0, sizeof(*n));
+ n->op = OREGISTER;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.u.reg = r;
+ n->type = t;
+}
+
+/*
+ * initialize n to be indirect of register r; n is type t.
+ */
+void
+nodindreg(Node *n, Type *t, int r)
+{
+ nodreg(n, t, r);
+ n->op = OINDREG;
+}
+
+/*
+ * Is this node a memory operand?
+ */
+int
+ismem(Node *n)
+{
+ switch(n->op) {
+ case OITAB:
+ case OSPTR:
+ case OLEN:
+ case OCAP:
+ case OINDREG:
+ case ONAME:
+ case OPARAM:
+ case OCLOSUREVAR:
+ return 1;
+ case OADDR:
+ return thearch.thechar == '6' || thearch.thechar == '9'; // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
+ }
+ return 0;
+}
+
+// Sweep the prog list to mark any used nodes.
+void
+markautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
+ continue;
+
+ if (p->from.node)
+ ((Node*)(p->from.node))->used = 1;
+
+ if (p->to.node)
+ ((Node*)(p->to.node))->used = 1;
+ }
+}
+
+// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
+void
+fixautoused(Prog *p)
+{
+ Prog **lp;
+
+ for (lp=&p; (p=*lp) != P; ) {
+ if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
+ *lp = p->link;
+ continue;
+ }
+ if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
+ // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
+ // VARDEFs are interspersed with other code, and a jump might be using the
+ // VARDEF as a target. Replace with a no-op instead. A later pass will remove
+ // the no-ops.
+ nopout(p);
+ continue;
+ }
+ if (p->from.name == NAME_AUTO && p->from.node)
+ p->from.offset += ((Node*)(p->from.node))->stkdelta;
+
+ if (p->to.name == NAME_AUTO && p->to.node)
+ p->to.offset += ((Node*)(p->to.node))->stkdelta;
+
+ lp = &p->link;
+ }
+}
+
+int
+samereg(Node *a, Node *b)
+{
+ if(a == N || b == N)
+ return 0;
+ if(a->op != OREGISTER)
+ return 0;
+ if(b->op != OREGISTER)
+ return 0;
+ if(a->val.u.reg != b->val.u.reg)
+ return 0;
+ return 1;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+ Node *n;
+ NodeList *l;
+ Type *first;
+ Iter savet;
+
+ // entire argument struct, not just one arg
+ if(t->etype == TSTRUCT && t->funarg) {
+ n = nod(ONAME, N, N);
+ n->sym = lookup(".args");
+ n->type = t;
+ first = structfirst(&savet, &t);
+ if(first == nil)
+ fatal("nodarg: bad struct");
+ if(first->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = first->width;
+ n->addable = 1;
+ goto fp;
+ }
+
+ if(t->etype != TFIELD)
+ fatal("nodarg: not field %T", t);
+
+ if(fp == 1) {
+ for(l=curfn->dcl; l; l=l->next) {
+ n = l->n;
+ if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
+ return n;
+ }
+ }
+
+ n = nod(ONAME, N, N);
+ n->type = t->type;
+ n->sym = t->sym;
+
+ if(t->width == BADWIDTH)
+ fatal("nodarg: offset not computed for %T", t);
+ n->xoffset = t->width;
+ n->addable = 1;
+ n->orig = t->nname;
+
+fp:
+ // Rewrite argument named _ to __,
+ // or else the assignment to _ will be
+ // discarded during code generation.
+ if(isblank(n))
+ n->sym = lookup("__");
+
+ switch(fp) {
+ case 0: // output arg
+ n->op = OINDREG;
+ n->val.u.reg = thearch.REGSP;
+ if(thearch.thechar == '5')
+ n->xoffset += 4;
+ if(thearch.thechar == '9')
+ n->xoffset += 8;
+ break;
+
+ case 1: // input arg
+ n->class = PPARAM;
+ break;
+
+ case 2: // offset output arg
+fatal("shouldn't be used");
+ n->op = OINDREG;
+ n->val.u.reg = thearch.REGSP;
+ n->xoffset += types[tptr]->width;
+ break;
+ }
+ n->typecheck = 1;
+ return n;
+}
+
+/*
+ * generate code to compute n;
+ * make a refer to result.
+ */
+void
+naddr(Node *n, Addr *a, int canemitcode)
+{
+ Sym *s;
+
+ *a = zprog.from;
+ if(n == N)
+ return;
+
+ if(n->type != T && n->type->etype != TIDEAL) {
+ // TODO(rsc): This is undone by the selective clearing of width below,
+ // to match architectures that were not as aggressive in setting width
+ // during naddr. Those widths must be cleared to avoid triggering
+ // failures in gins when it detects real but heretofore latent (and one
+ // hopes innocuous) type mismatches.
+ // The type mismatches should be fixed and the clearing below removed.
+ dowidth(n->type);
+ a->width = n->type->width;
+ }
+
+ switch(n->op) {
+ default:
+ fatal("naddr: bad %O %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ a->type = TYPE_REG;
+ a->reg = n->val.u.reg;
+ a->sym = nil;
+ if(thearch.thechar == '8') // TODO(rsc): Never clear a->width.
+ a->width = 0;
+ break;
+
+ case OINDREG:
+ a->type = TYPE_MEM;
+ a->reg = n->val.u.reg;
+ a->sym = linksym(n->sym);
+ a->offset = n->xoffset;
+ if(a->offset != (int32)a->offset)
+ yyerror("offset %lld too large for OINDREG", a->offset);
+ if(thearch.thechar == '8') // TODO(rsc): Never clear a->width.
+ a->width = 0;
+ break;
+
+ case OPARAM:
+ // n->left is PHEAP ONAME for stack parameter.
+ // compute address of actual parameter on stack.
+ a->etype = simtype[n->left->type->etype];
+ a->width = n->left->type->width;
+ a->offset = n->xoffset;
+ a->sym = linksym(n->left->sym);
+ a->type = TYPE_MEM;
+ a->name = NAME_PARAM;
+ a->node = n->left->orig;
+ break;
+
+ case OCLOSUREVAR:
+ if(!curfn->needctxt)
+ fatal("closurevar without needctxt");
+ a->type = TYPE_MEM;
+ a->reg = thearch.REGCTXT;
+ a->sym = nil;
+ a->offset = n->xoffset;
+ break;
+
+ case OCFUNC:
+ naddr(n->left, a, canemitcode);
+ a->sym = linksym(n->left->sym);
+ break;
+
+ case ONAME:
+ a->etype = 0;
+ if(n->type != T)
+ a->etype = simtype[n->type->etype];
+ a->offset = n->xoffset;
+ s = n->sym;
+ a->node = n->orig;
+ //if(a->node >= (Node*)&n)
+ // fatal("stack node");
+ if(s == S)
+ s = lookup(".noname");
+ if(n->method) {
+ if(n->type != T)
+ if(n->type->sym != S)
+ if(n->type->sym->pkg != nil)
+ s = pkglookup(s->name, n->type->sym->pkg);
+ }
+
+ a->type = TYPE_MEM;
+ switch(n->class) {
+ default:
+ fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+ case PEXTERN:
+ a->name = NAME_EXTERN;
+ break;
+ case PAUTO:
+ a->name = NAME_AUTO;
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ a->name = NAME_PARAM;
+ break;
+ case PFUNC:
+ a->name = NAME_EXTERN;
+ a->type = TYPE_ADDR;
+ a->width = widthptr;
+ s = funcsym(s);
+ break;
+ }
+ a->sym = linksym(s);
+ break;
+
+ case OLITERAL:
+ if(thearch.thechar == '8')
+ a->width = 0;
+ switch(n->val.ctype) {
+ default:
+ fatal("naddr: const %lT", n->type);
+ break;
+ case CTFLT:
+ a->type = TYPE_FCONST;
+ a->u.dval = mpgetflt(n->val.u.fval);
+ break;
+ case CTINT:
+ case CTRUNE:
+ a->sym = nil;
+ a->type = TYPE_CONST;
+ a->offset = mpgetfix(n->val.u.xval);
+ break;
+ case CTSTR:
+ datagostring(n->val.u.sval, a);
+ break;
+ case CTBOOL:
+ a->sym = nil;
+ a->type = TYPE_CONST;
+ a->offset = n->val.u.bval;
+ break;
+ case CTNIL:
+ a->sym = nil;
+ a->type = TYPE_CONST;
+ a->offset = 0;
+ break;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a, canemitcode);
+ a->etype = tptr;
+ if(thearch.thechar != '5' && thearch.thechar != '9') // TODO(rsc): Do this even for arm, ppc64.
+ a->width = widthptr;
+ if(a->type != TYPE_MEM)
+ fatal("naddr: OADDR %D (from %O)", a, n->left->op);
+ a->type = TYPE_ADDR;
+ break;
+
+ case OITAB:
+ // itable of interface value
+ naddr(n->left, a, canemitcode);
+ if(a->type == TYPE_CONST && a->offset == 0)
+ break; // itab(nil)
+ a->etype = tptr;
+ a->width = widthptr;
+ break;
+
+ case OSPTR:
+ // pointer in a string or slice
+ naddr(n->left, a, canemitcode);
+ if(a->type == TYPE_CONST && a->offset == 0)
+ break; // ptr(nil)
+ a->etype = simtype[tptr];
+ a->offset += Array_array;
+ a->width = widthptr;
+ break;
+
+ case OLEN:
+ // len of string or slice
+ naddr(n->left, a, canemitcode);
+ if(a->type == TYPE_CONST && a->offset == 0)
+ break; // len(nil)
+ a->etype = simtype[TUINT];
+ if(thearch.thechar == '9')
+ a->etype = simtype[TINT];
+ a->offset += Array_nel;
+ if(thearch.thechar != '5') // TODO(rsc): Do this even on arm.
+ a->width = widthint;
+ break;
+
+ case OCAP:
+ // cap of string or slice
+ naddr(n->left, a, canemitcode);
+ if(a->type == TYPE_CONST && a->offset == 0)
+ break; // cap(nil)
+ a->etype = simtype[TUINT];
+ if(thearch.thechar == '9')
+ a->etype = simtype[TINT];
+ a->offset += Array_cap;
+ if(thearch.thechar != '5') // TODO(rsc): Do this even on arm.
+ a->width = widthint;
+ break;
+
+// case OADD:
+// if(n->right->op == OLITERAL) {
+// v = n->right->vconst;
+// naddr(n->left, a, canemitcode);
+// } else
+// if(n->left->op == OLITERAL) {
+// v = n->left->vconst;
+// naddr(n->right, a, canemitcode);
+// } else
+// goto bad;
+// a->offset += v;
+// break;
+
+ }
+}
diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c
index 918d37180b..c769ec27f0 100644
--- a/src/cmd/gc/init.c
+++ b/src/cmd/gc/init.c
@@ -191,5 +191,5 @@ fninit(NodeList *n)
typecheck(&fn, Etop);
typechecklist(r, Etop);
curfn = nil;
- funccompile(fn, 0);
+ funccompile(fn);
}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 042099bd5e..a4b832aa0b 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -95,7 +95,7 @@ enum
void
usage(void)
{
- print("usage: %cg [options] file.go...\n", arch.thechar);
+ print("usage: %cg [options] file.go...\n", thearch.thechar);
flagprint(1);
exits("usage");
}
@@ -140,7 +140,7 @@ doversion(void)
sep = "";
if(*p)
sep = " ";
- print("%cg version %s%s%s\n", arch.thechar, getgoversion(), sep, p);
+ print("%cg version %s%s%s\n", thearch.thechar, getgoversion(), sep, p);
exits(0);
}
@@ -161,15 +161,15 @@ gcmain(int argc, char *argv[])
// Tell the FPU to handle all exceptions.
setfcr(FPPDBL|FPRNR);
#endif
- // Allow GOARCH=arch.thestring or GOARCH=arch.thestringsuffix,
+ // Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix,
// but not other values.
p = getgoarch();
- if(strncmp(p, arch.thestring, strlen(arch.thestring)) != 0)
- sysfatal("cannot use %cg with GOARCH=%s", arch.thechar, p);
+ if(strncmp(p, thearch.thestring, strlen(thearch.thestring)) != 0)
+ sysfatal("cannot use %cg with GOARCH=%s", thearch.thechar, p);
goarch = p;
- arch.linkarchinit();
- ctxt = linknew(arch.thelinkarch);
+ thearch.linkarchinit();
+ ctxt = linknew(thearch.thelinkarch);
ctxt->diag = yyerror;
ctxt->bso = &bstdout;
Binit(&bstdout, 1, OWRITE);
@@ -179,6 +179,7 @@ gcmain(int argc, char *argv[])
// pseudo-package, for scoping
builtinpkg = mkpkg(newstrlit("go.builtin"));
+ builtinpkg->prefix = "go.builtin"; // not go%2ebuiltin
// pseudo-package, accessed by import "unsafe"
unsafepkg = mkpkg(newstrlit("unsafe"));
@@ -267,7 +268,7 @@ gcmain(int argc, char *argv[])
flagcount("wb", "enable write barrier", &use_writebarrier);
flagcount("x", "debug lexer", &debug['x']);
flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']);
- if(arch.thechar == '6')
+ if(thearch.thechar == '6')
flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
flagparse(&argc, &argv, usage);
@@ -308,7 +309,7 @@ gcmain(int argc, char *argv[])
if(debug['l'] <= 1)
debug['l'] = 1 - debug['l'];
- if(arch.thechar == '8') {
+ if(thearch.thechar == '8') {
p = getgo386();
if(strcmp(p, "387") == 0)
use_sse = 0;
@@ -319,7 +320,7 @@ gcmain(int argc, char *argv[])
}
fmtinstallgo();
- arch.betypeinit();
+ thearch.betypeinit();
if(widthptr == 0)
fatal("betypeinit failed");
@@ -404,8 +405,9 @@ gcmain(int argc, char *argv[])
}
}
- // Phase 4: Decide how to capture variables
- // and transform closure bodies accordingly.
+ // Phase 4: Decide how to capture closed variables.
+ // This needs to run before escape analysis,
+ // because variables captured by value do not escape.
for(l=xtop; l; l=l->next) {
if(l->n->op == ODCLFUNC && l->n->closure) {
curfn = l->n;
@@ -456,15 +458,26 @@ gcmain(int argc, char *argv[])
// Move large values off stack too.
movelarge(xtop);
- // Phase 7: Compile top level functions.
+ // Phase 7: Transform closure bodies to properly reference captured variables.
+ // This needs to happen before walk, because closures must be transformed
+ // before walk reaches a call of a closure.
+ for(l=xtop; l; l=l->next) {
+ if(l->n->op == ODCLFUNC && l->n->closure) {
+ curfn = l->n;
+ transformclosure(l->n);
+ }
+ }
+ curfn = N;
+
+ // Phase 8: Compile top level functions.
for(l=xtop; l; l=l->next)
if(l->n->op == ODCLFUNC)
- funccompile(l->n, 0);
+ funccompile(l->n);
if(nsavederrors+nerrors == 0)
fninit(xtop);
- // Phase 8: Check external declarations.
+ // Phase 9: Check external declarations.
for(l=externdcl; l; l=l->next)
if(l->n->op == ONAME)
typecheck(&l->n, Erv);
@@ -588,7 +601,7 @@ findpkg(Strlit *name)
snprint(namebuf, sizeof(namebuf), "%Z.a", name);
if(access(namebuf, 0) >= 0)
return 1;
- snprint(namebuf, sizeof(namebuf), "%Z.%c", name, arch.thechar);
+ snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thearch.thechar);
if(access(namebuf, 0) >= 0)
return 1;
return 0;
@@ -610,7 +623,7 @@ findpkg(Strlit *name)
snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
if(access(namebuf, 0) >= 0)
return 1;
- snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, arch.thechar);
+ snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thearch.thechar);
if(access(namebuf, 0) >= 0)
return 1;
}
@@ -627,7 +640,7 @@ findpkg(Strlit *name)
snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.a", goroot, goos, goarch, suffixsep, suffix, name);
if(access(namebuf, 0) >= 0)
return 1;
- snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.%c", goroot, goos, goarch, suffixsep, suffix, name, arch.thechar);
+ snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.%c", goroot, goos, goarch, suffixsep, suffix, name, thearch.thechar);
if(access(namebuf, 0) >= 0)
return 1;
}
@@ -647,7 +660,7 @@ importfile(Val *f, int line)
Biobuf *imp;
char *file, *p, *q, *tag;
int32 c;
- int len;
+ int n;
Strlit *path;
char *cleanbuf, *prefix;
@@ -745,8 +758,8 @@ importfile(Val *f, int line)
}
file = strdup(namebuf);
- len = strlen(namebuf);
- if(len > 2 && namebuf[len-2] == '.' && namebuf[len-1] == 'a') {
+ n = strlen(namebuf);
+ if(n > 2 && namebuf[n-2] == '.' && namebuf[n-1] == 'a') {
if(!skiptopkgdef(imp)) {
yyerror("import %s: not a package file", file);
errorexit();
@@ -770,7 +783,7 @@ importfile(Val *f, int line)
// assume files move (get installed)
// so don't record the full path.
- linehist(file + len - path->len - 2, -1, 1); // acts as #pragma lib
+ linehist(file + n - path->len - 2, -1, 1); // acts as #pragma lib
/*
* position the input right
@@ -974,17 +987,7 @@ l0:
rune = c;
clen += runetochar(cp+clen, &rune);
}
-
- strlit:
- *(int32*)cp = clen-sizeof(int32); // length
- do {
- cp[clen++] = 0;
- } while(clen & MAXALIGN);
- yylval.val.u.sval = (Strlit*)cp;
- yylval.val.ctype = CTSTR;
- DBG("lex: string literal\n");
- strcpy(litbuf, "string literal");
- return LLITERAL;
+ goto strlit;
case '\'':
/* '.' */
@@ -1279,7 +1282,7 @@ talph:
if(c >= Runeself) {
ungetc(c);
rune = getr();
- // 0xb7 · is used for internal names
+ // 0xb7 · is used for internal names
if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
yyerror("invalid identifier character U+%04x", rune);
cp += runetochar(cp, &rune);
@@ -1467,6 +1470,17 @@ caseout:
strcpy(litbuf, "literal ");
strcat(litbuf, lexbuf);
return LLITERAL;
+
+strlit:
+ *(int32*)cp = clen-sizeof(int32); // length
+ do {
+ cp[clen++] = 0;
+ } while(clen & MAXALIGN);
+ yylval.val.u.sval = (Strlit*)cp;
+ yylval.val.ctype = CTSTR;
+ DBG("lex: string literal\n");
+ strcpy(litbuf, "string literal");
+ return LLITERAL;
}
static void pragcgo(char*);
@@ -2270,10 +2284,10 @@ lexfini(void)
}
// backend-specific builtin types (e.g. int).
- for(i=0; arch.typedefs[i].name; i++) {
- s = lookup(arch.typedefs[i].name);
+ for(i=0; thearch.typedefs[i].name; i++) {
+ s = lookup(thearch.typedefs[i].name);
if(s->def == N) {
- s->def = typenod(types[arch.typedefs[i].etype]);
+ s->def = typenod(types[thearch.typedefs[i].etype]);
s->origpkg = builtinpkg;
}
}
@@ -2571,6 +2585,6 @@ mkpackage(char* pkgname)
p = strrchr(namebuf, '.');
if(p != nil)
*p = 0;
- outfile = smprint("%s.%c", namebuf, arch.thechar);
+ outfile = smprint("%s.%c", namebuf, thearch.thechar);
}
}
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
index 1dab1c9a05..696aa82424 100755
--- a/src/cmd/gc/mkbuiltin
+++ b/src/cmd/gc/mkbuiltin
@@ -20,6 +20,10 @@ GC=${GOCHAR}g
gcc -o mkbuiltin1 mkbuiltin1.c
rm -f _builtin.c
echo "// AUTO-GENERATED by mkbuiltin; DO NOT EDIT" >>_builtin.c
+echo "#include <u.h>" >>_builtin.c
+echo "#include <libc.h>" >>_builtin.c
+echo '#include "go.h"' >>_builtin.c
+
for i in runtime unsafe
do
go tool $GC -A $i.go
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
index d33a81e09d..6a0eb2d6d9 100644
--- a/src/cmd/gc/mparith1.c
+++ b/src/cmd/gc/mparith1.c
@@ -235,9 +235,9 @@ mppow10flt(Mpflt *a, int p)
static void
mphextofix(Mpint *a, char *s, int n)
{
- char *hexdigitp, *end, c;
+ char c;
long d;
- int bit;
+ int bit, hexdigitp, end;
while(*s == '0') {
s++;
@@ -250,9 +250,9 @@ mphextofix(Mpint *a, char *s, int n)
return;
}
- end = s+n-1;
- for(hexdigitp=end; hexdigitp>=s; hexdigitp--) {
- c = *hexdigitp;
+ end = n-1;
+ for(hexdigitp=end; hexdigitp>=0; hexdigitp--) {
+ c = s[hexdigitp];
if(c >= '0' && c <= '9')
d = c-'0';
else if(c >= 'A' && c <= 'F')
@@ -334,18 +334,24 @@ mpatoflt(Mpflt *a, char *as)
break;
}
}
- if(start == nil)
+ if(start == nil) {
+ yyerror("malformed hex constant: %s", as);
goto bad;
+ }
mphextofix(&a->val, start, s-start);
- if(a->val.ovf)
+ if(a->val.ovf) {
+ yyerror("constant too large: %s", as);
goto bad;
+ }
a->exp = 0;
mpnorm(a);
}
for(;;) {
- switch(c = *s++) {
+ c = *s++;
+ switch(c) {
default:
+ yyerror("malformed constant: %s (at %c)", as, c);
goto bad;
case '-':
@@ -357,8 +363,10 @@ mpatoflt(Mpflt *a, char *as)
continue;
case '.':
- if(base == 16)
+ if(base == 16) {
+ yyerror("decimal point in hex constant: %s", as);
goto bad;
+ }
dp = 1;
continue;
@@ -414,8 +422,10 @@ mpatoflt(Mpflt *a, char *as)
}
if(eb) {
- if(dp)
+ if(dp) {
+ yyerror("decimal point and binary point in constant: %s", as);
goto bad;
+ }
mpsetexp(a, a->exp+ex);
goto out;
}
@@ -444,7 +454,6 @@ out:
return;
bad:
- yyerror("constant too large: %s", as);
mpmovecflt(a, 0.0);
}
@@ -483,6 +492,7 @@ mpatofix(Mpint *a, char *as)
c = *s++;
continue;
}
+ yyerror("malformed decimal constant: %s", as);
goto bad;
}
goto out;
@@ -498,6 +508,7 @@ oct:
c = *s++;
continue;
}
+ yyerror("malformed octal constant: %s", as);
goto bad;
}
goto out;
@@ -511,11 +522,14 @@ hex:
c = *s;
continue;
}
+ yyerror("malformed hex constant: %s", as);
goto bad;
}
mphextofix(a, s0, s-s0);
- if(a->ovf)
+ if(a->ovf) {
+ yyerror("constant too large: %s", as);
goto bad;
+ }
out:
if(f)
@@ -523,14 +537,14 @@ out:
return;
bad:
- yyerror("constant too large: %s", as);
mpmovecfix(a, 0);
}
int
Bconv(Fmt *fp)
{
- char buf[500], *p;
+ char buf[500];
+ int p;
Mpint *xval, q, r, ten, sixteen;
int f, digit;
@@ -542,8 +556,8 @@ Bconv(Fmt *fp)
mpnegfix(&q);
}
- p = &buf[sizeof(buf)];
- *--p = 0;
+ p = sizeof(buf);
+ buf[--p] = 0;
if(fp->flags & FmtSharp) {
// Hexadecimal
mpmovecfix(&sixteen, 16);
@@ -551,27 +565,27 @@ Bconv(Fmt *fp)
mpdivmodfixfix(&q, &r, &q, &sixteen);
digit = mpgetfix(&r);
if(digit < 10)
- *--p = digit + '0';
+ buf[--p] = digit + '0';
else
- *--p = digit - 10 + 'A';
+ buf[--p] = digit - 10 + 'A';
if(mptestfix(&q) <= 0)
break;
}
- *--p = 'x';
- *--p = '0';
+ buf[--p] = 'x';
+ buf[--p] = '0';
} else {
// Decimal
mpmovecfix(&ten, 10);
for(;;) {
mpdivmodfixfix(&q, &r, &q, &ten);
- *--p = mpgetfix(&r) + '0';
+ buf[--p] = mpgetfix(&r) + '0';
if(mptestfix(&q) <= 0)
break;
}
}
if(f)
- *--p = '-';
- return fmtstrcpy(fp, p);
+ buf[--p] = '-';
+ return fmtstrcpy(fp, &buf[p]);
}
int
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
index fd9f591cea..37aafbb5f5 100644
--- a/src/cmd/gc/mparith2.c
+++ b/src/cmd/gc/mparith2.c
@@ -14,12 +14,10 @@ static int
mplen(Mpint *a)
{
int i, n;
- long *a1;
n = -1;
- a1 = &a->a[0];
for(i=0; i<Mpprec; i++) {
- if(*a1++ != 0)
+ if(a->a[i] != 0)
n = i;
}
return n+1;
@@ -32,19 +30,18 @@ mplen(Mpint *a)
static void
mplsh(Mpint *a, int quiet)
{
- long *a1, x;
+ long x;
int i, c;
c = 0;
- a1 = &a->a[0];
for(i=0; i<Mpprec; i++) {
- x = (*a1 << 1) + c;
+ x = (a->a[i] << 1) + c;
c = 0;
if(x >= Mpbase) {
x -= Mpbase;
c = 1;
}
- *a1++ = x;
+ a->a[i] = x;
}
a->ovf = c;
if(a->ovf && !quiet)
@@ -58,20 +55,17 @@ mplsh(Mpint *a, int quiet)
static void
mplshw(Mpint *a, int quiet)
{
- long *a1;
int i;
- a1 = &a->a[Mpprec-1];
- if(*a1) {
+ i = Mpprec-1;
+ if(a->a[i]) {
a->ovf = 1;
if(!quiet)
yyerror("constant shift overflow");
}
- for(i=1; i<Mpprec; i++) {
- a1[0] = a1[-1];
- a1--;
- }
- a1[0] = 0;
+ for(; i > 0; i--)
+ a->a[i] = a->a[i-1];
+ a->a[i] = 0;
}
//
@@ -81,15 +75,14 @@ mplshw(Mpint *a, int quiet)
static void
mprsh(Mpint *a)
{
- long *a1, x, lo;
+ long x, lo;
int i, c;
c = 0;
lo = a->a[0] & 1;
- a1 = &a->a[Mpprec];
- for(i=0; i<Mpprec; i++) {
- x = *--a1;
- *a1 = (x + c) >> 1;
+ for(i=Mpprec-1; i>=0; i--) {
+ x = a->a[i];
+ a->a[i] = (x + c) >> 1;
c = 0;
if(x & 1)
c = Mpbase;
@@ -105,16 +98,14 @@ mprsh(Mpint *a)
static void
mprshw(Mpint *a)
{
- long *a1, lo;
+ long lo;
int i;
lo = a->a[0];
- a1 = &a->a[0];
- for(i=1; i<Mpprec; i++) {
- a1[0] = a1[1];
- a1++;
+ for(i=0; i<Mpprec-1; i++) {
+ a->a[i] = a->a[i+1];
}
- a1[0] = 0;
+ a->a[i] = 0;
if(a->neg && lo != 0)
mpaddcfix(a, -1);
}
@@ -125,7 +116,7 @@ mprshw(Mpint *a)
static int
mpcmp(Mpint *a, Mpint *b)
{
- long x, *a1, *b1;
+ long x;
int i;
if(a->ovf || b->ovf) {
@@ -134,11 +125,8 @@ mpcmp(Mpint *a, Mpint *b)
return 0;
}
- a1 = &a->a[0] + Mpprec;
- b1 = &b->a[0] + Mpprec;
-
- for(i=0; i<Mpprec; i++) {
- x = *--a1 - *--b1;
+ for(i=Mpprec-1; i>=0; i--) {
+ x = a->a[i] - b->a[i];
if(x > 0)
return +1;
if(x < 0)
@@ -154,19 +142,18 @@ mpcmp(Mpint *a, Mpint *b)
static void
mpneg(Mpint *a)
{
- long x, *a1;
+ long x;
int i, c;
- a1 = &a->a[0];
c = 0;
for(i=0; i<Mpprec; i++) {
- x = -*a1 -c;
+ x = -a->a[i] -c;
c = 0;
if(x < 0) {
x += Mpbase;
c = 1;
}
- *a1++ = x;
+ a->a[i] = x;
}
}
@@ -202,7 +189,7 @@ void
mpaddfixfix(Mpint *a, Mpint *b, int quiet)
{
int i, c;
- long x, *a1, *b1;
+ long x;
if(a->ovf || b->ovf) {
if(nsavederrors+nerrors == 0)
@@ -212,20 +199,18 @@ mpaddfixfix(Mpint *a, Mpint *b, int quiet)
}
c = 0;
- a1 = &a->a[0];
- b1 = &b->a[0];
if(a->neg != b->neg)
goto sub;
// perform a+b
for(i=0; i<Mpprec; i++) {
- x = *a1 + *b1++ + c;
+ x = a->a[i] + b->a[i] + c;
c = 0;
if(x >= Mpbase) {
x -= Mpbase;
c = 1;
}
- *a1++ = x;
+ a->a[i] = x;
}
a->ovf = c;
if(a->ovf && !quiet)
@@ -242,26 +227,26 @@ sub:
case 1:
for(i=0; i<Mpprec; i++) {
- x = *a1 - *b1++ - c;
+ x = a->a[i] - b->a[i] - c;
c = 0;
if(x < 0) {
x += Mpbase;
c = 1;
}
- *a1++ = x;
+ a->a[i] = x;
}
break;
case -1:
a->neg ^= 1;
for(i=0; i<Mpprec; i++) {
- x = *b1++ - *a1 - c;
+ x = b->a[i] - a->a[i] - c;
c = 0;
if(x < 0) {
x += Mpbase;
c = 1;
}
- *a1++ = x;
+ a->a[i] = x;
}
break;
}
@@ -272,8 +257,9 @@ mpmulfixfix(Mpint *a, Mpint *b)
{
int i, j, na, nb;
- long *a1, x;
+ long x;
Mpint s, q;
+ Mpint *c;
if(a->ovf || b->ovf) {
if(nsavederrors+nerrors == 0)
@@ -288,17 +274,17 @@ mpmulfixfix(Mpint *a, Mpint *b)
nb = mplen(b);
if(na > nb) {
mpmovefixfix(&s, a);
- a1 = &b->a[0];
+ c = b;
na = nb;
} else {
mpmovefixfix(&s, b);
- a1 = &a->a[0];
+ c = a;
}
s.neg = 0;
mpmovecfix(&q, 0);
for(i=0; i<na; i++) {
- x = *a1++;
+ x = c->a[i];
for(j=0; j<Mpscale; j++) {
if(x & 1) {
if(s.ovf) {
@@ -326,7 +312,7 @@ mpmulfract(Mpint *a, Mpint *b)
{
int i, j;
- long *a1, x;
+ long x;
Mpint s, q;
if(a->ovf || b->ovf) {
@@ -337,16 +323,16 @@ mpmulfract(Mpint *a, Mpint *b)
}
mpmovefixfix(&s, b);
- a1 = &a->a[Mpprec];
s.neg = 0;
mpmovecfix(&q, 0);
- x = *--a1;
+ i = Mpprec-1;
+ x = a->a[i];
if(x != 0)
yyerror("mpmulfract not normal");
- for(i=0; i<Mpprec-1; i++) {
- x = *--a1;
+ for(i--; i >= 0; i--) {
+ x = a->a[i];
if(x == 0) {
mprshw(&s);
continue;
@@ -369,7 +355,7 @@ void
mporfixfix(Mpint *a, Mpint *b)
{
int i;
- long x, *a1, *b1;
+ long x;
x = 0;
if(a->ovf || b->ovf) {
@@ -386,11 +372,9 @@ mporfixfix(Mpint *a, Mpint *b)
if(b->neg)
mpneg(b);
- a1 = &a->a[0];
- b1 = &b->a[0];
for(i=0; i<Mpprec; i++) {
- x = *a1 | *b1++;
- *a1++ = x;
+ x = a->a[i] | b->a[i];
+ a->a[i] = x;
}
if(b->neg)
@@ -405,7 +389,7 @@ void
mpandfixfix(Mpint *a, Mpint *b)
{
int i;
- long x, *a1, *b1;
+ long x;
x = 0;
if(a->ovf || b->ovf) {
@@ -422,11 +406,9 @@ mpandfixfix(Mpint *a, Mpint *b)
if(b->neg)
mpneg(b);
- a1 = &a->a[0];
- b1 = &b->a[0];
for(i=0; i<Mpprec; i++) {
- x = *a1 & *b1++;
- *a1++ = x;
+ x = a->a[i] & b->a[i];
+ a->a[i] = x;
}
if(b->neg)
@@ -441,7 +423,7 @@ void
mpandnotfixfix(Mpint *a, Mpint *b)
{
int i;
- long x, *a1, *b1;
+ long x;
x = 0;
if(a->ovf || b->ovf) {
@@ -458,11 +440,9 @@ mpandnotfixfix(Mpint *a, Mpint *b)
if(b->neg)
mpneg(b);
- a1 = &a->a[0];
- b1 = &b->a[0];
for(i=0; i<Mpprec; i++) {
- x = *a1 & ~*b1++;
- *a1++ = x;
+ x = a->a[i] & ~b->a[i];
+ a->a[i] = x;
}
if(b->neg)
@@ -477,7 +457,7 @@ void
mpxorfixfix(Mpint *a, Mpint *b)
{
int i;
- long x, *a1, *b1;
+ long x;
x = 0;
if(a->ovf || b->ovf) {
@@ -494,11 +474,9 @@ mpxorfixfix(Mpint *a, Mpint *b)
if(b->neg)
mpneg(b);
- a1 = &a->a[0];
- b1 = &b->a[0];
for(i=0; i<Mpprec; i++) {
- x = *a1 ^ *b1++;
- *a1++ = x;
+ x = a->a[i] ^ b->a[i];
+ a->a[i] = x;
}
if(b->neg)
@@ -585,7 +563,6 @@ void
mpmovecfix(Mpint *a, vlong c)
{
int i;
- long *a1;
vlong x;
a->neg = 0;
@@ -597,9 +574,8 @@ mpmovecfix(Mpint *a, vlong c)
x = -(uvlong)x;
}
- a1 = &a->a[0];
for(i=0; i<Mpprec; i++) {
- *a1++ = x&Mpmask;
+ a->a[i] = x&Mpmask;
x >>= Mpscale;
}
}
@@ -658,13 +634,11 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
static int
mpiszero(Mpint *a)
{
- long *a1;
int i;
- a1 = &a->a[0] + Mpprec;
- for(i=0; i<Mpprec; i++) {
- if(*--a1 != 0)
+
+ for(i=Mpprec-1; i>=0; i--)
+ if(a->a[i] != 0)
return 0;
- }
return 1;
}
@@ -673,16 +647,15 @@ mpdivfract(Mpint *a, Mpint *b)
{
Mpint n, d;
int i, j, neg;
- long *a1, x;
+ long x;
mpmovefixfix(&n, a); // numerator
mpmovefixfix(&d, b); // denominator
- a1 = &a->a[Mpprec]; // quotient
neg = n.neg ^ d.neg;
n.neg = 0;
d.neg = 0;
- for(i=0; i<Mpprec; i++) {
+ for(i=Mpprec-1; i >= 0; i--) {
x = 0;
for(j=0; j<Mpscale; j++) {
x <<= 1;
@@ -693,7 +666,7 @@ mpdivfract(Mpint *a, Mpint *b)
}
mprsh(&d);
}
- *--a1 = x;
+ a->a[i] = x;
}
a->neg = neg;
}
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index a4d470615a..3983f99d6d 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -95,9 +95,9 @@ dumpobj(void)
externdcl = tmp;
zero = pkglookup("zerovalue", runtimepkg);
- arch.ggloblsym(zero, zerosize, DUPOK|RODATA);
+ ggloblsym(zero, zerosize, DUPOK|RODATA);
- arch.dumpdata();
+ dumpdata();
writeobj(ctxt, bout);
if(writearchive) {
@@ -106,7 +106,7 @@ dumpobj(void)
if(size&1)
Bputc(bout, 0);
Bseek(bout, startobj - ArhdrSize, 0);
- snprint(namebuf, sizeof namebuf, "_go_.%c", arch.thechar);
+ snprint(namebuf, sizeof namebuf, "_go_.%c", thearch.thechar);
formathdr(arhdr, namebuf, size);
Bwrite(bout, arhdr, ArhdrSize);
}
@@ -133,13 +133,13 @@ dumpglobls(void)
continue;
dowidth(n->type);
- arch.ggloblnod(n);
+ ggloblnod(n);
}
for(l=funcsyms; l; l=l->next) {
n = l->n;
- arch.dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
- arch.ggloblsym(n->sym, widthptr, DUPOK|RODATA);
+ dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
+ ggloblsym(n->sym, widthptr, DUPOK|RODATA);
}
// Do not reprocess funcsyms on next dumpglobls call.
@@ -250,7 +250,7 @@ stringsym(char *s, int len)
off = 0;
// string header
- off = arch.dsymptr(sym, off, sym, widthptr+widthint);
+ off = dsymptr(sym, off, sym, widthptr+widthint);
off = duintxx(sym, off, len, widthint);
// string data
@@ -258,11 +258,11 @@ stringsym(char *s, int len)
m = 8;
if(m > len-n)
m = len-n;
- off = arch.dsname(sym, off, s+n, m);
+ off = dsname(sym, off, s+n, m);
}
off = duint8(sym, off, 0); // terminating NUL for runtime
off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment
- arch.ggloblsym(sym, off, DUPOK|RODATA);
+ ggloblsym(sym, off, DUPOK|RODATA);
return sym;
}
@@ -283,14 +283,216 @@ slicebytes(Node *nam, char *s, int len)
m = 8;
if(m > len-n)
m = len-n;
- off = arch.dsname(sym, off, s+n, m);
+ off = dsname(sym, off, s+n, m);
}
- arch.ggloblsym(sym, off, NOPTR);
+ ggloblsym(sym, off, NOPTR);
if(nam->op != ONAME)
fatal("slicebytes %N", nam);
off = nam->xoffset;
- off = arch.dsymptr(nam->sym, off, sym, 0);
+ off = dsymptr(nam->sym, off, sym, 0);
off = duintxx(nam->sym, off, len, widthint);
duintxx(nam->sym, off, len, widthint);
}
+
+int
+dsname(Sym *s, int off, char *t, int n)
+{
+ Prog *p;
+
+ p = thearch.gins(ADATA, N, N);
+ p->from.type = TYPE_MEM;
+ p->from.name = NAME_EXTERN;
+ p->from.offset = off;
+ p->from.sym = linksym(s);
+ p->from3.type = TYPE_CONST;
+ p->from3.offset = n;
+
+ p->to.type = TYPE_SCONST;
+ memmove(p->to.u.sval, t, n);
+ return off + n;
+}
+
+/*
+ * make a refer to the data s, s+len
+ * emitting DATA if needed.
+ */
+void
+datastring(char *s, int len, Addr *a)
+{
+ Sym *sym;
+
+ sym = stringsym(s, len);
+ a->type = TYPE_MEM;
+ a->name = NAME_EXTERN;
+ a->sym = linksym(sym);
+ a->node = sym->def;
+ a->offset = widthptr+widthint; // skip header
+ a->etype = simtype[TINT];
+}
+
+/*
+ * make a refer to the string sval,
+ * emitting DATA if needed.
+ */
+void
+datagostring(Strlit *sval, Addr *a)
+{
+ Sym *sym;
+
+ sym = stringsym(sval->s, sval->len);
+ a->type = TYPE_MEM;
+ a->name = NAME_EXTERN;
+ a->sym = linksym(sym);
+ a->node = sym->def;
+ a->offset = 0; // header
+ a->etype = TSTRING;
+}
+
+void
+gdata(Node *nam, Node *nr, int wid)
+{
+ Prog *p;
+
+ if(nr->op == OLITERAL) {
+ switch(nr->val.ctype) {
+ case CTCPLX:
+ gdatacomplex(nam, nr->val.u.cval);
+ return;
+ case CTSTR:
+ gdatastring(nam, nr->val.u.sval);
+ return;
+ }
+ }
+ p = thearch.gins(ADATA, nam, nr);
+ p->from3.type = TYPE_CONST;
+ p->from3.offset = wid;
+}
+
+void
+gdatacomplex(Node *nam, Mpcplx *cval)
+{
+ Prog *p;
+ int w;
+
+ w = cplxsubtype(nam->type->etype);
+ w = types[w]->width;
+
+ p = thearch.gins(ADATA, nam, N);
+ p->from3.type = TYPE_CONST;
+ p->from3.offset = w;
+ p->to.type = TYPE_FCONST;
+ p->to.u.dval = mpgetflt(&cval->real);
+
+ p = thearch.gins(ADATA, nam, N);
+ p->from3.type = TYPE_CONST;
+ p->from3.offset = w;
+ p->from.offset += w;
+ p->to.type = TYPE_FCONST;
+ p->to.u.dval = mpgetflt(&cval->imag);
+}
+
+void
+gdatastring(Node *nam, Strlit *sval)
+{
+ Prog *p;
+ Node nod1;
+
+ p = thearch.gins(ADATA, nam, N);
+ datastring(sval->s, sval->len, &p->to);
+ p->from3.type = TYPE_CONST;
+ p->from3.offset = types[tptr]->width;
+ p->to.type = TYPE_ADDR;
+//print("%P\n", p);
+
+ nodconst(&nod1, types[TINT], sval->len);
+ p = thearch.gins(ADATA, nam, &nod1);
+ p->from3.type = TYPE_CONST;
+ p->from3.offset = widthint;
+ p->from.offset += widthptr;
+}
+
+int
+dstringptr(Sym *s, int off, char *str)
+{
+ Prog *p;
+
+ off = rnd(off, widthptr);
+ p = thearch.gins(ADATA, N, N);
+ p->from.type = TYPE_MEM;
+ p->from.name = NAME_EXTERN;
+ p->from.sym = linksym(s);
+ p->from.offset = off;
+ p->from3.type = TYPE_CONST;
+ p->from3.offset = widthptr;
+
+ datastring(str, strlen(str)+1, &p->to);
+ p->to.type = TYPE_ADDR;
+ p->to.etype = simtype[TINT];
+ off += widthptr;
+
+ return off;
+}
+
+int
+dgostrlitptr(Sym *s, int off, Strlit *lit)
+{
+ Prog *p;
+
+ if(lit == nil)
+ return duintptr(s, off, 0);
+
+ off = rnd(off, widthptr);
+ p = thearch.gins(ADATA, N, N);
+ p->from.type = TYPE_MEM;
+ p->from.name = NAME_EXTERN;
+ p->from.sym = linksym(s);
+ p->from.offset = off;
+ p->from3.type = TYPE_CONST;
+ p->from3.offset = widthptr;
+ datagostring(lit, &p->to);
+ p->to.type = TYPE_ADDR;
+ p->to.etype = simtype[TINT];
+ off += widthptr;
+
+ return off;
+}
+
+int
+dgostringptr(Sym *s, int off, char *str)
+{
+ int n;
+ Strlit *lit;
+
+ if(str == nil)
+ return duintptr(s, off, 0);
+
+ n = strlen(str);
+ lit = mal(sizeof *lit + n);
+ strcpy(lit->s, str);
+ lit->len = n;
+ return dgostrlitptr(s, off, lit);
+}
+
+int
+dsymptr(Sym *s, int off, Sym *x, int xoff)
+{
+ Prog *p;
+
+ off = rnd(off, widthptr);
+
+ p = thearch.gins(ADATA, N, N);
+ p->from.type = TYPE_MEM;
+ p->from.name = NAME_EXTERN;
+ p->from.sym = linksym(s);
+ p->from.offset = off;
+ p->from3.type = TYPE_CONST;
+ p->from3.offset = widthptr;
+ p->to.type = TYPE_ADDR;
+ p->to.name = NAME_EXTERN;
+ p->to.sym = linksym(x);
+ p->to.offset = xoff;
+ off += widthptr;
+
+ return off;
+}
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index ec1628651e..3df78e7f9a 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -30,7 +30,7 @@ makefuncdatasym(char *namefmt, int64 funcdatakind)
pnod = newname(sym);
pnod->class = PEXTERN;
nodconst(&nod, types[TINT32], funcdatakind);
- arch.gins(AFUNCDATA, &nod, pnod);
+ thearch.gins(AFUNCDATA, &nod, pnod);
return sym;
}
@@ -39,7 +39,7 @@ makefuncdatasym(char *namefmt, int64 funcdatakind)
// where a complete initialization (definition) of a variable begins.
// Since the liveness analysis can see initialization of single-word
// variables quite easy, gvardef is usually only called for multi-word
-// or 'fat' variables, those satisfying arch.isfat(n->type).
+// or 'fat' variables, those satisfying isfat(n->type).
// However, gvardef is also called when a non-fat variable is initialized
// via a block move; the only time this happens is when you have
// return f()
@@ -103,7 +103,7 @@ gvardefx(Node *n, int as)
case PAUTO:
case PPARAM:
case PPARAMOUT:
- arch.gins(as, N, n);
+ thearch.gins(as, N, n);
}
}
@@ -161,6 +161,7 @@ compile(Node *fn)
Iter save;
vlong oldstksize;
NodeList *l;
+ Node *nam;
Sym *gcargs;
Sym *gclocals;
@@ -223,13 +224,16 @@ compile(Node *fn)
continpc = P;
breakpc = P;
- pl = arch.newplist();
+ pl = newplist();
pl->name = linksym(curfn->nname->sym);
setlineno(curfn);
nodconst(&nod1, types[TINT32], 0);
- ptxt = arch.gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
+ nam = curfn->nname;
+ if(isblank(nam))
+ nam = N;
+ ptxt = thearch.gins(ATEXT, nam, &nod1);
if(fn->dupok)
ptxt->from3.offset |= DUPOK;
if(fn->wrapper)
@@ -247,15 +251,15 @@ compile(Node *fn)
ptxt->from3.offset |= WRAPPER;
}
- arch.afunclit(&ptxt->from, curfn->nname);
+ afunclit(&ptxt->from, curfn->nname);
- arch.ginit();
+ thearch.ginit();
gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
for(t=curfn->paramfld; t; t=t->down)
- arch.gtrack(tracksym(t->type));
+ gtrack(tracksym(t->type));
for(l=fn->dcl; l; l=l->next) {
n = l->n;
@@ -266,7 +270,7 @@ compile(Node *fn)
case PPARAM:
case PPARAMOUT:
nodconst(&nod1, types[TUINTPTR], l->n->type->width);
- p = arch.gins(ATYPE, l->n, &nod1);
+ p = thearch.gins(ATYPE, l->n, &nod1);
p->from.gotype = linksym(ngotype(l->n));
break;
}
@@ -274,7 +278,7 @@ compile(Node *fn)
genlist(curfn->enter);
genlist(curfn->nbody);
- arch.gclean();
+ thearch.gclean();
checklabels();
if(nerrors != 0)
goto ret;
@@ -282,18 +286,18 @@ compile(Node *fn)
lineno = curfn->endlineno;
if(curfn->type->outtuple != 0)
- arch.ginscall(throwreturn, 0);
+ thearch.ginscall(throwreturn, 0);
- arch.ginit();
+ thearch.ginit();
// TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
- arch.cgen_ret(nil);
+ thearch.cgen_ret(nil);
if(hasdefer) {
// deferreturn pretends to have one uintptr argument.
// Reserve space for it so stack scanner is happy.
if(maxarg < widthptr)
maxarg = widthptr;
}
- arch.gclean();
+ thearch.gclean();
if(nerrors != 0)
goto ret;
@@ -302,10 +306,10 @@ compile(Node *fn)
fixjmp(ptxt);
if(!debug['N'] || debug['R'] || debug['P']) {
- arch.regopt(ptxt);
+ regopt(ptxt);
nilopt(ptxt);
}
- arch.expandchecks(ptxt);
+ thearch.expandchecks(ptxt);
oldstksize = stksize;
allocauto(ptxt);
@@ -325,9 +329,9 @@ compile(Node *fn)
gcsymdup(gcargs);
gcsymdup(gclocals);
- arch.defframe(ptxt);
+ thearch.defframe(ptxt);
- if(0)
+ if(debug['f'])
frame(0);
// Remove leftover instrumentation from the instruction stream.
@@ -369,7 +373,7 @@ emitptrargsmap(void)
for(j = 0; j < bv->n; j += 32)
off = duint32(sym, off, bv->b[j/32]);
}
- arch.ggloblsym(sym, off, RODATA);
+ ggloblsym(sym, off, RODATA);
free(bv);
}
@@ -438,7 +442,7 @@ allocauto(Prog* ptxt)
if (ll->n->class == PAUTO)
ll->n->used = 0;
- arch.markautoused(ptxt);
+ markautoused(ptxt);
listsort(&curfn->dcl, cmpstackvar);
@@ -448,7 +452,7 @@ allocauto(Prog* ptxt)
if (n->class == PAUTO && n->op == ONAME && !n->used) {
// No locals used at all
curfn->dcl = nil;
- arch.fixautoused(ptxt);
+ fixautoused(ptxt);
return;
}
@@ -469,13 +473,13 @@ allocauto(Prog* ptxt)
dowidth(n->type);
w = n->type->width;
- if(w >= arch.MAXWIDTH || w < 0)
+ if(w >= thearch.MAXWIDTH || w < 0)
fatal("bad width");
stksize += w;
stksize = rnd(stksize, n->type->align);
if(haspointers(n->type))
stkptrsize = stksize;
- if(arch.thechar == '5' || arch.thechar == '9')
+ if(thearch.thechar == '5' || thearch.thechar == '9')
stksize = rnd(stksize, widthptr);
if(stksize >= (1ULL<<31)) {
setlineno(curfn);
@@ -486,7 +490,7 @@ allocauto(Prog* ptxt)
stksize = rnd(stksize, widthreg);
stkptrsize = rnd(stkptrsize, widthreg);
- arch.fixautoused(ptxt);
+ fixautoused(ptxt);
// The debug information needs accurate offsets on the symbols.
for(ll = curfn->dcl; ll != nil; ll=ll->next) {
@@ -532,12 +536,12 @@ cgen_checknil(Node *n)
dump("checknil", n);
fatal("bad checknil");
}
- if(((arch.thechar == '5' || arch.thechar == '9') && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
- arch.regalloc(&reg, types[tptr], n);
- arch.cgen(n, &reg);
- arch.gins(ACHECKNIL, &reg, N);
- arch.regfree(&reg);
+ if(((thearch.thechar == '5' || thearch.thechar == '9') && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
+ thearch.regalloc(&reg, types[tptr], n);
+ thearch.cgen(n, &reg);
+ thearch.gins(ACHECKNIL, &reg, N);
+ thearch.regfree(&reg);
return;
}
- arch.gins(ACHECKNIL, n, N);
+ thearch.gins(ACHECKNIL, n, N);
}
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
index 0461085b5b..c0d1e57932 100644
--- a/src/cmd/gc/plive.c
+++ b/src/cmd/gc/plive.c
@@ -677,7 +677,7 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
bvresetall(varkill);
bvresetall(avarinit);
- arch.proginfo(&info, prog);
+ thearch.proginfo(&info, prog);
if(prog->as == ARET) {
// Return instructions implicitly read all the arguments. For
// the sake of correctness, out arguments must be read. For the
@@ -701,7 +701,7 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
// If we added it to uevar too, we'd not see any kill
// and decide that the varible was live entry, which it is not.
// So only use uevar in the non-addrtaken case.
- // The p->to.type == arch.D_NONE limits the bvset to
+ // The p->to.type == thearch.D_NONE limits the bvset to
// non-tail-call return instructions; see note above
// the for loop for details.
if(!node->addrtaken && prog->to.type == TYPE_NONE)
@@ -744,7 +744,7 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
if(info.flags & (LeftRead | LeftAddr))
bvset(uevar, pos);
if(info.flags & LeftWrite)
- if(from->node != nil && !arch.isfat(((Node*)(from->node))->type))
+ if(from->node != nil && !isfat(((Node*)(from->node))->type))
bvset(varkill, pos);
}
}
@@ -780,7 +780,7 @@ Next:
if((info.flags & RightRead) || (info.flags & (RightAddr|RightWrite)) == RightAddr)
bvset(uevar, pos);
if(info.flags & RightWrite)
- if(to->node != nil && (!arch.isfat(((Node*)(to->node))->type) || prog->as == AVARDEF))
+ if(to->node != nil && (!isfat(((Node*)(to->node))->type) || prog->as == AVARDEF))
bvset(varkill, pos);
}
}
@@ -1218,7 +1218,7 @@ unlinkedprog(int as)
Prog *p;
p = mal(sizeof(*p));
- arch.clearp(p);
+ clearp(p);
p->as = as;
return p;
}
@@ -1235,8 +1235,8 @@ newpcdataprog(Prog *prog, int32 index)
nodconst(&to, types[TINT32], index);
pcdata = unlinkedprog(APCDATA);
pcdata->lineno = prog->lineno;
- arch.naddr(&from, &pcdata->from, 0);
- arch.naddr(&to, &pcdata->to, 0);
+ naddr(&from, &pcdata->from, 0);
+ naddr(&to, &pcdata->to, 0);
return pcdata;
}
@@ -1909,15 +1909,15 @@ static void
twobitwritesymbol(Array *arr, Sym *sym)
{
Bvec *bv;
- int off, i, j, len;
+ int off, i, j, n;
uint32 word;
- len = arraylength(arr);
+ n = arraylength(arr);
off = 0;
off += 4; // number of bitmaps, to fill in later
bv = *(Bvec**)arrayget(arr, 0);
off = duint32(sym, off, bv->n); // number of bits in each bitmap
- for(i = 0; i < len; i++) {
+ for(i = 0; i < n; i++) {
// bitmap words
bv = *(Bvec**)arrayget(arr, i);
if(bv == nil)
@@ -1932,7 +1932,7 @@ twobitwritesymbol(Array *arr, Sym *sym)
}
}
duint32(sym, 0, i); // number of bitmaps
- arch.ggloblsym(sym, off, RODATA);
+ ggloblsym(sym, off, RODATA);
}
static void
diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c
index f71702431a..b02d58e663 100644
--- a/src/cmd/gc/popt.c
+++ b/src/cmd/gc/popt.c
@@ -35,6 +35,7 @@
#include <u.h>
#include <libc.h>
#include "go.h"
+#include "popt.h"
// p is a call instruction. Does the call fail to return?
int
@@ -202,7 +203,7 @@ fixjmp(Prog *firstp)
// Control flow analysis. The Flow structures hold predecessor and successor
// information as well as basic loop analysis.
//
-// graph = flowstart(firstp, sizeof(Flow));
+// graph = flowstart(firstp, 0);
// ... use flow graph ...
// flowend(graph); // free graph
//
@@ -214,25 +215,26 @@ fixjmp(Prog *firstp)
// f->p1 and this list:
//
// for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
-//
-// Often the Flow struct is embedded as the first field inside a larger struct S.
-// In that case casts are needed to convert Flow* to S* in many places but the
-// idea is the same. Pass sizeof(S) instead of sizeof(Flow) to flowstart.
+//
+// The size argument to flowstart specifies an amount of zeroed memory
+// to allocate in every f->data field, for use by the client.
+// If size == 0, f->data will be nil.
Graph*
flowstart(Prog *firstp, int size)
{
- int nf;
+ int id, nf;
Flow *f, *f1, *start, *last;
Graph *graph;
Prog *p;
ProgInfo info;
+ char *data;
// Count and mark instructions to annotate.
nf = 0;
for(p = firstp; p != P; p = p->link) {
p->opt = nil; // should be already, but just in case
- arch.proginfo(&info, p);
+ thearch.proginfo(&info, p);
if(info.flags & Skip)
continue;
p->opt = (void*)1;
@@ -248,12 +250,16 @@ flowstart(Prog *firstp, int size)
}
// Allocate annotations and assign to instructions.
- graph = calloc(sizeof *graph + size*nf, 1);
+ graph = calloc(sizeof *graph + sizeof(Flow)*nf + size*nf, 1);
if(graph == nil)
fatal("out of memory");
start = (Flow*)(graph+1);
last = nil;
f = start;
+ data = (char*)(f+nf);
+ if(size == 0)
+ data = nil;
+ id = 0;
for(p = firstp; p != P; p = p->link) {
if(p->opt == nil)
continue;
@@ -262,14 +268,17 @@ flowstart(Prog *firstp, int size)
if(last)
last->link = f;
last = f;
-
- f = (Flow*)((uchar*)f + size);
+ f->data = data;
+ f->id = id;
+ f++;
+ id++;
+ data += size;
}
// Fill in pred/succ information.
for(f = start; f != nil; f = f->link) {
p = f->prog;
- arch.proginfo(&info, p);
+ thearch.proginfo(&info, p);
if(!(info.flags & Break)) {
f1 = f->link;
f->s1 = f1;
@@ -383,10 +392,6 @@ loophead(int32 *idom, Flow *r)
return 0;
}
-enum {
- LOOP = 3,
-};
-
static void
loopmark(Flow **rpo2r, int32 head, Flow *r)
{
@@ -498,13 +503,12 @@ uniqs(Flow *r)
// ACM TOPLAS 1999.
typedef struct TempVar TempVar;
-typedef struct TempFlow TempFlow;
struct TempVar
{
Node *node;
- TempFlow *def; // definition of temp var
- TempFlow *use; // use list, chained through TempFlow.uselink
+ Flow *def; // definition of temp var
+ Flow *use; // use list, chained through Flow.data
TempVar *freelink; // next free temp in Type.opt list
TempVar *merge; // merge var with this one
vlong start; // smallest Prog.pc in live range
@@ -513,12 +517,6 @@ struct TempVar
uchar removed; // removed from program
};
-struct TempFlow
-{
- Flow f;
- TempFlow *uselink;
-};
-
static int
startcmp(const void *va, const void *vb)
{
@@ -531,6 +529,14 @@ startcmp(const void *va, const void *vb)
return -1;
if(a->start > b->start)
return +1;
+ // Order what's left by id or symbol name,
+ // just so that sort is forced into a specific ordering,
+ // so that the result of the sort does not depend on
+ // the sort implementation.
+ if(a->def != b->def)
+ return a->def->id - b->def->id;
+ if(a->node != b->node)
+ return strcmp(a->node->sym->name, b->node->sym->name);
return 0;
}
@@ -541,15 +547,15 @@ canmerge(Node *n)
return n->class == PAUTO && strncmp(n->sym->name, "autotmp", 7) == 0;
}
-static void mergewalk(TempVar*, TempFlow*, uint32);
-static void varkillwalk(TempVar*, TempFlow*, uint32);
+static void mergewalk(TempVar*, Flow*, uint32);
+static void varkillwalk(TempVar*, Flow*, uint32);
void
mergetemp(Prog *firstp)
{
int i, j, nvar, ninuse, nfree, nkill;
TempVar *var, *v, *v1, **bystart, **inuse;
- TempFlow *r;
+ Flow *f;
NodeList *l, **lp;
Node *n;
Prog *p, *p1;
@@ -558,9 +564,9 @@ mergetemp(Prog *firstp)
int32 gen;
Graph *g;
- enum { Debug = 0 };
+ enum { debugmerge = 1 };
- g = flowstart(firstp, sizeof(TempFlow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
@@ -585,9 +591,9 @@ mergetemp(Prog *firstp)
// We assume that the earliest reference to a temporary is its definition.
// This is not true of variables in general but our temporaries are all
// single-use (that's why we have so many!).
- for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
- p = r->f.prog;
- arch.proginfo(&info, p);
+ for(f = g->start; f != nil; f = f->link) {
+ p = f->prog;
+ thearch.proginfo(&info, p);
if(p->from.node != N && ((Node*)(p->from.node))->opt && p->to.node != N && ((Node*)(p->to.node))->opt)
fatal("double node %P", p);
@@ -598,32 +604,33 @@ mergetemp(Prog *firstp)
v = n->opt;
if(v != nil) {
if(v->def == nil)
- v->def = r;
- r->uselink = v->use;
- v->use = r;
+ v->def = f;
+ f->data = v->use;
+ v->use = f;
if(n == p->from.node && (info.flags & LeftAddr))
v->addr = 1;
}
}
- if(Debug > 1)
- arch.dumpit("before", g->start, 0);
+ if(debugmerge > 1 && debug['v'])
+ dumpit("before", g->start, 0);
nkill = 0;
// Special case.
- for(v = var; v < var+nvar; v++) {
+ for(i = 0; i < nvar; i++) {
+ v = &var[i];
if(v->addr)
continue;
// Used in only one instruction, which had better be a write.
- if((r = v->use) != nil && r->uselink == nil) {
- p = r->f.prog;
- arch.proginfo(&info, p);
+ if((f = v->use) != nil && (Flow*)f->data == nil) {
+ p = f->prog;
+ thearch.proginfo(&info, p);
if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) {
p->as = ANOP;
p->to = zprog.to;
v->removed = 1;
- if(Debug)
+ if(debugmerge > 0 && debug['v'])
print("drop write-only %S\n", v->node->sym);
} else
fatal("temp used and not set: %P", p);
@@ -633,11 +640,11 @@ mergetemp(Prog *firstp)
// Written in one instruction, read in the next, otherwise unused,
// no jumps to the next instruction. Happens mainly in 386 compiler.
- if((r = v->use) != nil && r->f.link == &r->uselink->f && r->uselink->uselink == nil && uniqp(r->f.link) == &r->f) {
- p = r->f.prog;
- arch.proginfo(&info, p);
- p1 = r->f.link->prog;
- arch.proginfo(&info1, p1);
+ if((f = v->use) != nil && f->link == (Flow*)f->data && (Flow*)((Flow*)f->data)->data == nil && uniqp(f->link) == f) {
+ p = f->prog;
+ thearch.proginfo(&info, p);
+ p1 = f->link->prog;
+ thearch.proginfo(&info1, p1);
enum {
SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD,
};
@@ -645,9 +652,9 @@ mergetemp(Prog *firstp)
!((info.flags|info1.flags) & (LeftAddr|RightAddr)) &&
(info.flags & SizeAny) == (info1.flags & SizeAny)) {
p1->from = p->from;
- arch.excise(&r->f);
+ thearch.excise(f);
v->removed = 1;
- if(Debug)
+ if(debugmerge > 0 && debug['v'])
print("drop immediate-use %S\n", v->node->sym);
}
nkill++;
@@ -657,16 +664,17 @@ mergetemp(Prog *firstp)
// Traverse live range of each variable to set start, end.
// Each flood uses a new value of gen so that we don't have
- // to clear all the r->f.active words after each variable.
+ // to clear all the r->active words after each variable.
gen = 0;
- for(v = var; v < var+nvar; v++) {
+ for(i = 0; i < nvar; i++) {
+ v = &var[i];
gen++;
- for(r = v->use; r != nil; r = r->uselink)
- mergewalk(v, r, gen);
+ for(f = v->use; f != nil; f = (Flow*)f->data)
+ mergewalk(v, f, gen);
if(v->addr) {
gen++;
- for(r = v->use; r != nil; r = r->uselink)
- varkillwalk(v, r, gen);
+ for(f = v->use; f != nil; f = (Flow*)f->data)
+ varkillwalk(v, f, gen);
}
}
@@ -687,6 +695,9 @@ mergetemp(Prog *firstp)
nfree = nvar;
for(i=0; i<nvar; i++) {
v = bystart[i];
+ if(debugmerge > 0 && debug['v'])
+ print("consider %#N: removed=%d\n", v->node, v->removed);
+
if(v->removed)
continue;
@@ -696,10 +707,14 @@ mergetemp(Prog *firstp)
inuse[--nfree] = v1;
}
+ if(debugmerge > 0 && debug['v'])
+ print("consider %#N: removed=%d nfree=%d nvar=%d\n", v->node, v->removed, nfree, nvar);
// Find old temp to reuse if possible.
t = v->node->type;
for(j=nfree; j<nvar; j++) {
v1 = inuse[j];
+ if(debugmerge > 0 && debug['v'])
+ print("consider %#N: maybe %#N: type=%T,%T addrtaken=%d,%d\n", v->node, v1->node, t, v1->node->type, v->node->addrtaken, v1->node->addrtaken);
// Require the types to match but also require the addrtaken bits to match.
// If a variable's address is taken, that disables registerization for the individual
// words of the variable (for example, the base,len,cap of a slice).
@@ -725,9 +740,10 @@ mergetemp(Prog *firstp)
inuse[j] = v;
}
- if(Debug) {
+ if(debugmerge > 0 && debug['v']) {
print("%S [%d - %d]\n", curfn->nname->sym, nvar, nkill);
- for(v=var; v<var+nvar; v++) {
+ for(i = 0; i < nvar; i++) {
+ v = &var[i];
print("var %#N %T %lld-%lld", v->node, v->node->type, v->start, v->end);
if(v->addr)
print(" addr=1");
@@ -735,18 +751,18 @@ mergetemp(Prog *firstp)
print(" dead=1");
if(v->merge)
print(" merge %#N", v->merge->node);
- if(v->start == v->end)
- print(" %P", v->def->f.prog);
+ if(v->start == v->end && v->def != nil)
+ print(" %P", v->def->prog);
print("\n");
}
- if(Debug > 1)
- arch.dumpit("after", g->start, 0);
+ if(debugmerge > 1 && debug['v'])
+ dumpit("after", g->start, 0);
}
// Update node references to use merged temporaries.
- for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
- p = r->f.prog;
+ for(f = g->start; f != nil; f = f->link) {
+ p = f->prog;
if((n = p->from.node) != N && (v = n->opt) != nil && v->merge != nil)
p->from.node = v->merge->node;
if((n = p->to.node) != N && (v = n->opt) != nil && v->merge != nil)
@@ -766,8 +782,9 @@ mergetemp(Prog *firstp)
}
// Clear aux structures.
- for(v=var; v<var+nvar; v++)
- v->node->opt = nil;
+ for(i = 0; i < nvar; i++)
+ var[i].node->opt = nil;
+
free(var);
free(bystart);
free(inuse);
@@ -775,40 +792,40 @@ mergetemp(Prog *firstp)
}
static void
-mergewalk(TempVar *v, TempFlow *r0, uint32 gen)
+mergewalk(TempVar *v, Flow *f0, uint32 gen)
{
Prog *p;
- TempFlow *r1, *r, *r2;
+ Flow *f1, *f, *f2;
- for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.p1) {
- if(r1->f.active == gen)
+ for(f1 = f0; f1 != nil; f1 = f1->p1) {
+ if(f1->active == gen)
break;
- r1->f.active = gen;
- p = r1->f.prog;
+ f1->active = gen;
+ p = f1->prog;
if(v->end < p->pc)
v->end = p->pc;
- if(r1 == v->def) {
+ if(f1 == v->def) {
v->start = p->pc;
break;
}
}
- for(r = r0; r != r1; r = (TempFlow*)r->f.p1)
- for(r2 = (TempFlow*)r->f.p2; r2 != nil; r2 = (TempFlow*)r2->f.p2link)
- mergewalk(v, r2, gen);
+ for(f = f0; f != f1; f = f->p1)
+ for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
+ mergewalk(v, f2, gen);
}
static void
-varkillwalk(TempVar *v, TempFlow *r0, uint32 gen)
+varkillwalk(TempVar *v, Flow *f0, uint32 gen)
{
Prog *p;
- TempFlow *r1, *r;
+ Flow *f1, *f;
- for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.s1) {
- if(r1->f.active == gen)
+ for(f1 = f0; f1 != nil; f1 = f1->s1) {
+ if(f1->active == gen)
break;
- r1->f.active = gen;
- p = r1->f.prog;
+ f1->active = gen;
+ p = f1->prog;
if(v->end < p->pc)
v->end = p->pc;
if(v->start > p->pc)
@@ -817,8 +834,8 @@ varkillwalk(TempVar *v, TempFlow *r0, uint32 gen)
break;
}
- for(r = r0; r != r1; r = (TempFlow*)r->f.s1)
- varkillwalk(v, (TempFlow*)r->f.s2, gen);
+ for(f = f0; f != f1; f = f->s1)
+ varkillwalk(v, f->s2, gen);
}
// Eliminate redundant nil pointer checks.
@@ -836,62 +853,58 @@ varkillwalk(TempVar *v, TempFlow *r0, uint32 gen)
// each load.
typedef struct NilVar NilVar;
-typedef struct NilFlow NilFlow;
-struct NilFlow {
- Flow f;
- int kill;
-};
+static void nilwalkback(Flow *rcheck);
+static void nilwalkfwd(Flow *rcheck);
-static void nilwalkback(NilFlow *rcheck);
-static void nilwalkfwd(NilFlow *rcheck);
+static int killed; // f->data is either nil or &killed
void
nilopt(Prog *firstp)
{
- NilFlow *r;
+ Flow *f;
Prog *p;
Graph *g;
int ncheck, nkill;
- g = flowstart(firstp, sizeof(NilFlow));
+ g = flowstart(firstp, 0);
if(g == nil)
return;
if(debug_checknil > 1 /* || strcmp(curfn->nname->sym->name, "f1") == 0 */)
- arch.dumpit("nilopt", g->start, 0);
+ dumpit("nilopt", g->start, 0);
ncheck = 0;
nkill = 0;
- for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
- p = r->f.prog;
- if(p->as != ACHECKNIL || !arch.regtyp(&p->from))
+ for(f = g->start; f != nil; f = f->link) {
+ p = f->prog;
+ if(p->as != ACHECKNIL || !thearch.regtyp(&p->from))
continue;
ncheck++;
- if(arch.stackaddr(&p->from)) {
+ if(thearch.stackaddr(&p->from)) {
if(debug_checknil && p->lineno > 1)
warnl(p->lineno, "removed nil check of SP address");
- r->kill = 1;
+ f->data = &killed;
continue;
}
- nilwalkfwd(r);
- if(r->kill) {
+ nilwalkfwd(f);
+ if(f->data != nil) {
if(debug_checknil && p->lineno > 1)
warnl(p->lineno, "removed nil check before indirect");
continue;
}
- nilwalkback(r);
- if(r->kill) {
+ nilwalkback(f);
+ if(f->data != nil) {
if(debug_checknil && p->lineno > 1)
warnl(p->lineno, "removed repeated nil check");
continue;
}
}
- for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
- if(r->kill) {
+ for(f = g->start; f != nil; f = f->link) {
+ if(f->data != nil) {
nkill++;
- arch.excise(&r->f);
+ thearch.excise(f);
}
}
@@ -902,72 +915,72 @@ nilopt(Prog *firstp)
}
static void
-nilwalkback(NilFlow *rcheck)
+nilwalkback(Flow *fcheck)
{
Prog *p;
ProgInfo info;
- NilFlow *r;
+ Flow *f;
- for(r = rcheck; r != nil; r = (NilFlow*)uniqp(&r->f)) {
- p = r->f.prog;
- arch.proginfo(&info, p);
- if((info.flags & RightWrite) && arch.sameaddr(&p->to, &rcheck->f.prog->from)) {
+ for(f = fcheck; f != nil; f = uniqp(f)) {
+ p = f->prog;
+ thearch.proginfo(&info, p);
+ if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
// Found initialization of value we're checking for nil.
// without first finding the check, so this one is unchecked.
return;
}
- if(r != rcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from)) {
- rcheck->kill = 1;
+ if(f != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from)) {
+ fcheck->data = &killed;
return;
}
}
// Here is a more complex version that scans backward across branches.
- // It assumes rcheck->kill = 1 has been set on entry, and its job is to find a reason
- // to keep the check (setting rcheck->kill = 0).
+ // It assumes fcheck->kill = 1 has been set on entry, and its job is to find a reason
+ // to keep the check (setting fcheck->kill = 0).
// It doesn't handle copying of aggregates as well as I would like,
// nor variables with their address taken,
// and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3.
/*
- for(r1 = r0; r1 != nil; r1 = (NilFlow*)r1->f.p1) {
- if(r1->f.active == gen)
+ for(f1 = f0; f1 != nil; f1 = f1->p1) {
+ if(f1->active == gen)
break;
- r1->f.active = gen;
- p = r1->f.prog;
+ f1->active = gen;
+ p = f1->prog;
// If same check, stop this loop but still check
// alternate predecessors up to this point.
- if(r1 != rcheck && p->as == ACHECKNIL && arch.sameaddr(&p->from, &rcheck->f.prog->from))
+ if(f1 != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from))
break;
- arch.proginfo(&info, p);
- if((info.flags & RightWrite) && arch.sameaddr(&p->to, &rcheck->f.prog->from)) {
+ thearch.proginfo(&info, p);
+ if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
// Found initialization of value we're checking for nil.
// without first finding the check, so this one is unchecked.
- rcheck->kill = 0;
+ fcheck->kill = 0;
return;
}
- if(r1->f.p1 == nil && r1->f.p2 == nil) {
- print("lost pred for %P\n", rcheck->f.prog);
- for(r1=r0; r1!=nil; r1=(NilFlow*)r1->f.p1) {
- arch.proginfo(&info, r1->f.prog);
- print("\t%P %d %d %D %D\n", r1->f.prog, info.flags&RightWrite, arch.sameaddr(&r1->f.prog->to, &rcheck->f.prog->from), &r1->f.prog->to, &rcheck->f.prog->from);
+ if(f1->p1 == nil && f1->p2 == nil) {
+ print("lost pred for %P\n", fcheck->prog);
+ for(f1=f0; f1!=nil; f1=f1->p1) {
+ thearch.proginfo(&info, f1->prog);
+ print("\t%P %d %d %D %D\n", r1->prog, info.flags&RightWrite, thearch.sameaddr(&f1->prog->to, &fcheck->prog->from), &f1->prog->to, &fcheck->prog->from);
}
fatal("lost pred trail");
}
}
- for(r = r0; r != r1; r = (NilFlow*)r->f.p1)
- for(r2 = (NilFlow*)r->f.p2; r2 != nil; r2 = (NilFlow*)r2->f.p2link)
- nilwalkback(rcheck, r2, gen);
+ for(f = f0; f != f1; f = f->p1)
+ for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
+ nilwalkback(fcheck, f2, gen);
*/
}
static void
-nilwalkfwd(NilFlow *rcheck)
+nilwalkfwd(Flow *fcheck)
{
- NilFlow *r, *last;
+ Flow *f, *last;
Prog *p;
ProgInfo info;
@@ -979,16 +992,16 @@ nilwalkfwd(NilFlow *rcheck)
// _ = *x // should panic
// for {} // no writes but infinite loop may be considered visible
last = nil;
- for(r = (NilFlow*)uniqs(&rcheck->f); r != nil; r = (NilFlow*)uniqs(&r->f)) {
- p = r->f.prog;
- arch.proginfo(&info, p);
+ for(f = uniqs(fcheck); f != nil; f = uniqs(f)) {
+ p = f->prog;
+ thearch.proginfo(&info, p);
- if((info.flags & LeftRead) && arch.smallindir(&p->from, &rcheck->f.prog->from)) {
- rcheck->kill = 1;
+ if((info.flags & LeftRead) && thearch.smallindir(&p->from, &fcheck->prog->from)) {
+ fcheck->data = &killed;
return;
}
- if((info.flags & (RightRead|RightWrite)) && arch.smallindir(&p->to, &rcheck->f.prog->from)) {
- rcheck->kill = 1;
+ if((info.flags & (RightRead|RightWrite)) && thearch.smallindir(&p->to, &fcheck->prog->from)) {
+ fcheck->data = &killed;
return;
}
@@ -996,17 +1009,14 @@ nilwalkfwd(NilFlow *rcheck)
if(p->as == ACHECKNIL)
return;
// Stop if value is lost.
- if((info.flags & RightWrite) && arch.sameaddr(&p->to, &rcheck->f.prog->from))
+ if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from))
return;
// Stop if memory write.
- if((info.flags & RightWrite) && !arch.regtyp(&p->to))
+ if((info.flags & RightWrite) && !thearch.regtyp(&p->to))
return;
// Stop if we jump backward.
- // This test is valid because all the NilFlow* are pointers into
- // a single contiguous array. We will need to add an explicit
- // numbering when the code is converted to Go.
- if(last != nil && r <= last)
+ if(last != nil && f->id <= last->id)
return;
- last = r;
+ last = f;
}
}
diff --git a/src/cmd/6g/opt.h b/src/cmd/gc/popt.h
index 11befb6ad1..0a30e81f55 100644
--- a/src/cmd/6g/opt.h
+++ b/src/cmd/gc/popt.h
@@ -28,38 +28,28 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-
#define Z N
#define Adr Addr
-#define D_HI TYPE_NONE
-#define D_LO TYPE_NONE
-
#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
-#define CLOAD 5
-#define CREF 5
-#define CINF 1000
-#define LOOP 3
-
-typedef struct Reg Reg;
-typedef struct Rgn Rgn;
-
-/*c2go
-extern Node *Z;
enum
{
- D_HI = TYPE_NONE,
- D_LO = TYPE_NONE,
CLOAD = 5,
CREF = 5,
CINF = 1000,
LOOP = 3,
};
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+/*c2go
+extern Node *Z;
+
uint32 BLOAD(Reg*);
uint32 BSTORE(Reg*);
uint64 LOAD(Reg*);
@@ -69,11 +59,8 @@ uint64 STORE(Reg*);
// A Reg is a wrapper around a single Prog (one instruction) that holds
// register optimization information while the optimizer runs.
// r->prog is the instruction.
-// r->prog->opt points back to r.
struct Reg
{
- Flow f;
-
Bits set; // regopt variables written by this instruction.
Bits use1; // regopt variables read by prog->from.
Bits use2; // regopt variables read by prog->to.
@@ -91,7 +78,7 @@ struct Reg
Bits regdiff;
Bits act;
- int32 regu; // register used bitmap
+ uint64 regu; // register used bitmap
};
#define R ((Reg*)0)
/*c2go extern Reg *R; */
@@ -110,21 +97,18 @@ struct Reg
// cost.
struct Rgn
{
- Reg* enter;
+ Flow* enter;
short cost;
short varno;
short regno;
};
-EXTERN int32 exregoffset; // not set
-EXTERN int32 exfregoffset; // not set
EXTERN Reg zreg;
EXTERN Rgn region[NRGN];
EXTERN Rgn* rgp;
EXTERN int nregion;
EXTERN int nvar;
-EXTERN int32 regbits;
-EXTERN int32 exregbits;
+EXTERN uint64 regbits;
EXTERN Bits externs;
EXTERN Bits params;
EXTERN Bits consts;
@@ -147,34 +131,19 @@ EXTERN struct
/*
* reg.c
*/
-int rcmp(const void*, const void*);
void regopt(Prog*);
-void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Adr*);
-void prop(Reg*, Bits, Bits);
-void synch(Reg*, Bits);
-uint32 allreg(uint32, Rgn*);
-void paint1(Reg*, int);
-uint32 paint2(Reg*, int, int);
-void paint3(Reg*, int, uint32, int);
-void addreg(Adr*, int);
void dumpone(Flow*, int);
void dumpit(char*, Flow*, int);
/*
* peep.c
- */
void peep(Prog*);
void excise(Flow*);
int copyu(Prog*, Adr*, Adr*);
-
-uint32 RtoB(int);
-uint32 FtoB(int);
-int BtoR(uint32);
-int BtoF(uint32);
+ */
/*
* prog.c
- */
void proginfo(ProgInfo*, Prog*);
+ */
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
index f3134dab23..3aa7e36386 100644
--- a/src/cmd/gc/racewalk.c
+++ b/src/cmd/gc/racewalk.c
@@ -24,7 +24,6 @@ static void racewalknode(Node **np, NodeList **init, int wr, int skip);
static int callinstr(Node **n, NodeList **init, int wr, int skip);
static Node* uintptraddr(Node *n);
static void makeaddable(Node *n);
-static Node* basenod(Node *n);
static void foreach(Node *n, void(*f)(Node*, void*), void *c);
static void hascallspred(Node *n, void *c);
static void appendinit(Node **np, NodeList *init);
@@ -155,12 +154,8 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
default:
fatal("racewalk: unknown node type %O", n->op);
- case OASOP:
case OAS:
- case OAS2:
- case OAS2RECV:
case OAS2FUNC:
- case OAS2MAPR:
racewalknode(&n->left, init, 1, 0);
racewalknode(&n->right, init, 0, 0);
goto ret;
@@ -210,6 +205,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
case OCALLFUNC:
// Instrument dst argument of runtime.writebarrier* calls
// as we do not instrument runtime code.
+ // typedslicecopy is instrumented in runtime.
if(n->left->sym != S && n->left->sym->pkg == runtimepkg &&
(strncmp(n->left->sym->name, "writebarrier", 12) == 0 || strcmp(n->left->sym->name, "typedmemmove") == 0)) {
// Find the dst argument.
@@ -350,7 +346,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
goto ret;
case OEFACE:
- racewalknode(&n->left, init, 0, 0);
+ // n->left is Type* which is not interesting.
racewalknode(&n->right, init, 0, 0);
goto ret;
@@ -393,6 +389,10 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
case OARRAYLIT: // lowered to assignments
case OMAPLIT:
case OSTRUCTLIT:
+ case OAS2:
+ case OAS2RECV:
+ case OAS2MAPR:
+ case OASOP:
yyerror("racewalk: %O must be lowered by now", n->op);
goto ret;
@@ -489,7 +489,7 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
if(isartificial(n))
return 0;
- b = basenod(n);
+ b = outervalue(n);
// it skips e.g. stores to ... parameter array
if(isartificial(b))
return 0;
@@ -499,7 +499,7 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
// that has got a pointer inside. Whether it points to
// the heap or not is impossible to know at compile time
if((class&PHEAP) || class == PPARAMREF || class == PEXTERN
- || b->op == OINDEX || b->op == ODOTPTR || b->op == OIND || b->op == OXDOT) {
+ || b->op == OINDEX || b->op == ODOTPTR || b->op == OIND) {
hascalls = 0;
foreach(n, hascallspred, &hascalls);
if(hascalls) {
@@ -568,25 +568,6 @@ uintptraddr(Node *n)
return r;
}
-// basenod returns the simplest child node of n pointing to the same
-// memory area.
-static Node*
-basenod(Node *n)
-{
- for(;;) {
- if(n->op == ODOT || n->op == OXDOT || n->op == OCONVNOP || n->op == OCONV || n->op == OPAREN) {
- n = n->left;
- continue;
- }
- if(n->op == OINDEX && isfixedarray(n->type)) {
- n = n->left;
- continue;
- }
- break;
- }
- return n;
-}
-
static Node*
detachexpr(Node *n, NodeList **init)
{
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index ff05820b58..ff9de6c349 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -13,6 +13,7 @@
void
typecheckrange(Node *n)
{
+ int toomany;
char *why;
Type *t, *t1, *t2;
Node *v1, *v2;
@@ -41,6 +42,7 @@ typecheckrange(Node *n)
t = t->type;
n->type = t;
+ toomany = 0;
switch(t->etype) {
default:
yyerror("cannot range over %lN", n->right);
@@ -64,7 +66,7 @@ typecheckrange(Node *n)
t1 = t->type;
t2 = nil;
if(count(n->list) == 2)
- goto toomany;
+ toomany = 1;
break;
case TSTRING:
@@ -73,10 +75,8 @@ typecheckrange(Node *n)
break;
}
- if(count(n->list) > 2) {
- toomany:
+ if(count(n->list) > 2 || toomany)
yyerror("too many variables in range");
- }
v1 = N;
if(n->list)
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 61a63c0528..14a1f13e33 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -117,16 +117,29 @@ enum {
};
static Type*
+makefield(char *name, Type *t)
+{
+ Type *f;
+
+ f = typ(TFIELD);
+ f->type = t;
+ f->sym = mal(sizeof(Sym));
+ f->sym->name = name;
+ return f;
+}
+
+Type*
mapbucket(Type *t)
{
Type *keytype, *valtype;
- Type *bucket;
- Type *overflowfield, *keysfield, *valuesfield;
- int32 offset;
+ Type *bucket, *arr;
+ Type *field[4];
+ int32 n;
if(t->bucket != T)
return t->bucket;
+ bucket = typ(TSTRUCT);
keytype = t->down;
valtype = t->type;
dowidth(keytype);
@@ -136,119 +149,74 @@ mapbucket(Type *t)
if(valtype->width > MAXVALSIZE)
valtype = ptrto(valtype);
- bucket = typ(TSTRUCT);
- bucket->noalg = 1;
-
// The first field is: uint8 topbits[BUCKETSIZE].
- // We don't need to encode it as GC doesn't care about it.
- offset = BUCKETSIZE * 1;
-
- keysfield = typ(TFIELD);
- keysfield->type = typ(TARRAY);
- keysfield->type->type = keytype;
- keysfield->type->bound = BUCKETSIZE;
- keysfield->type->width = BUCKETSIZE * keytype->width;
- keysfield->width = offset;
- keysfield->sym = mal(sizeof(Sym));
- keysfield->sym->name = "keys";
- offset += BUCKETSIZE * keytype->width;
+ arr = typ(TARRAY);
+ arr->type = types[TUINT8];
+ arr->bound = BUCKETSIZE;
+ field[0] = makefield("topbits", arr);
+ arr = typ(TARRAY);
+ arr->type = keytype;
+ arr->bound = BUCKETSIZE;
+ field[1] = makefield("keys", arr);
+ arr = typ(TARRAY);
+ arr->type = valtype;
+ arr->bound = BUCKETSIZE;
+ field[2] = makefield("values", arr);
+ field[3] = makefield("overflow", ptrto(bucket));
- valuesfield = typ(TFIELD);
- valuesfield->type = typ(TARRAY);
- valuesfield->type->type = valtype;
- valuesfield->type->bound = BUCKETSIZE;
- valuesfield->type->width = BUCKETSIZE * valtype->width;
- valuesfield->width = offset;
- valuesfield->sym = mal(sizeof(Sym));
- valuesfield->sym->name = "values";
- offset += BUCKETSIZE * valtype->width;
+ // link up fields
+ bucket->noalg = 1;
+ bucket->local = t->local;
+ bucket->type = field[0];
+ for(n = 0; n < nelem(field)-1; n++)
+ field[n]->down = field[n+1];
+ field[nelem(field)-1]->down = T;
+ dowidth(bucket);
- overflowfield = typ(TFIELD);
- overflowfield->type = ptrto(bucket);
- overflowfield->width = offset; // "width" is offset in structure
- overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name
- overflowfield->sym->name = "overflow";
- offset += widthptr;
-
// Pad to the native integer alignment.
- // This is usually the same as widthptr; the exception (as usual) is nacl/amd64.
+ // This is usually the same as widthptr; the exception (as usual) is amd64p32.
if(widthreg > widthptr)
- offset += widthreg - widthptr;
-
- // link up fields
- bucket->type = keysfield;
- keysfield->down = valuesfield;
- valuesfield->down = overflowfield;
- overflowfield->down = T;
+ bucket->width += widthreg - widthptr;
// See comment on hmap.overflow in ../../runtime/hashmap.go.
if(!haspointers(t->type) && !haspointers(t->down))
bucket->haspointers = 1; // no pointers
- bucket->width = offset;
- bucket->local = t->local;
t->bucket = bucket;
bucket->map = t;
return bucket;
}
-// Builds a type respresenting a Hmap structure for
-// the given map type. This type is not visible to users -
-// we include only enough information to generate a correct GC
-// program for it.
+// Builds a type representing a Hmap structure for the given map type.
// Make sure this stays in sync with ../../runtime/hashmap.go!
-static Type*
+Type*
hmap(Type *t)
{
Type *h, *bucket;
- Type *bucketsfield, *oldbucketsfield, *overflowfield;
- int32 offset;
+ Type *field[8];
+ int32 n;
if(t->hmap != T)
return t->hmap;
bucket = mapbucket(t);
+ field[0] = makefield("count", types[TINT]);
+ field[1] = makefield("flags", types[TUINT8]);
+ field[2] = makefield("B", types[TUINT8]);
+ field[3] = makefield("hash0", types[TUINT32]);
+ field[4] = makefield("buckets", ptrto(bucket));
+ field[5] = makefield("oldbuckets", ptrto(bucket));
+ field[6] = makefield("nevacuate", types[TUINTPTR]);
+ field[7] = makefield("overflow", types[TUNSAFEPTR]);
+
h = typ(TSTRUCT);
h->noalg = 1;
-
- offset = widthint; // count
- offset += 1; // flags
- offset += 1; // B
- offset += 2; // padding
- offset += 4; // hash0
- offset = (offset + widthptr - 1) / widthptr * widthptr;
-
- bucketsfield = typ(TFIELD);
- bucketsfield->type = ptrto(bucket);
- bucketsfield->width = offset;
- bucketsfield->sym = mal(sizeof(Sym));
- bucketsfield->sym->name = "buckets";
- offset += widthptr;
-
- oldbucketsfield = typ(TFIELD);
- oldbucketsfield->type = ptrto(bucket);
- oldbucketsfield->width = offset;
- oldbucketsfield->sym = mal(sizeof(Sym));
- oldbucketsfield->sym->name = "oldbuckets";
- offset += widthptr;
-
- offset += widthptr; // nevacuate
-
- overflowfield = typ(TFIELD);
- overflowfield->type = types[TUNSAFEPTR];
- overflowfield->width = offset;
- overflowfield->sym = mal(sizeof(Sym));
- overflowfield->sym->name = "overflow";
- offset += widthptr;
-
- // link up fields
- h->type = bucketsfield;
- bucketsfield->down = oldbucketsfield;
- oldbucketsfield->down = overflowfield;
- overflowfield->down = T;
-
- h->width = offset;
h->local = t->local;
+ h->type = field[0];
+ for(n = 0; n < nelem(field)-1; n++)
+ field[n]->down = field[n+1];
+ field[nelem(field)-1]->down = T;
+ dowidth(h);
t->hmap = h;
h->map = t;
return h;
@@ -257,8 +225,8 @@ hmap(Type *t)
Type*
hiter(Type *t)
{
- int32 n, off;
- Type *field[9];
+ int32 n;
+ Type *field[12];
Type *i;
if(t->hiter != T)
@@ -272,73 +240,37 @@ hiter(Type *t)
// h *Hmap
// buckets *Bucket
// bptr *Bucket
- // overflow unsafe.Pointer
- // other [4]uintptr
+ // overflow0 unsafe.Pointer
+ // overflow1 unsafe.Pointer
+ // startBucket uintptr
+ // stuff uintptr
+ // bucket uintptr
+ // checkBucket uintptr
// }
// must match ../../runtime/hashmap.c:hash_iter.
- field[0] = typ(TFIELD);
- field[0]->type = ptrto(t->down);
- field[0]->sym = mal(sizeof(Sym));
- field[0]->sym->name = "key";
-
- field[1] = typ(TFIELD);
- field[1]->type = ptrto(t->type);
- field[1]->sym = mal(sizeof(Sym));
- field[1]->sym->name = "val";
-
- field[2] = typ(TFIELD);
- field[2]->type = ptrto(types[TUINT8]); // TODO: is there a Type type?
- field[2]->sym = mal(sizeof(Sym));
- field[2]->sym->name = "t";
-
- field[3] = typ(TFIELD);
- field[3]->type = ptrto(hmap(t));
- field[3]->sym = mal(sizeof(Sym));
- field[3]->sym->name = "h";
-
- field[4] = typ(TFIELD);
- field[4]->type = ptrto(mapbucket(t));
- field[4]->sym = mal(sizeof(Sym));
- field[4]->sym->name = "buckets";
-
- field[5] = typ(TFIELD);
- field[5]->type = ptrto(mapbucket(t));
- field[5]->sym = mal(sizeof(Sym));
- field[5]->sym->name = "bptr";
-
- field[6] = typ(TFIELD);
- field[6]->type = types[TUNSAFEPTR];
- field[6]->sym = mal(sizeof(Sym));
- field[6]->sym->name = "overflow0";
-
- field[7] = typ(TFIELD);
- field[7]->type = types[TUNSAFEPTR];
- field[7]->sym = mal(sizeof(Sym));
- field[7]->sym->name = "overflow1";
-
- // all other non-pointer fields
- field[8] = typ(TFIELD);
- field[8]->type = typ(TARRAY);
- field[8]->type->type = types[TUINTPTR];
- field[8]->type->bound = 4;
- field[8]->type->width = 4 * widthptr;
- field[8]->sym = mal(sizeof(Sym));
- field[8]->sym->name = "other";
+ field[0] = makefield("key", ptrto(t->down));
+ field[1] = makefield("val", ptrto(t->type));
+ field[2] = makefield("t", ptrto(types[TUINT8]));
+ field[3] = makefield("h", ptrto(hmap(t)));
+ field[4] = makefield("buckets", ptrto(mapbucket(t)));
+ field[5] = makefield("bptr", ptrto(mapbucket(t)));
+ field[6] = makefield("overflow0", types[TUNSAFEPTR]);
+ field[7] = makefield("overflow1", types[TUNSAFEPTR]);
+ field[8] = makefield("startBucket", types[TUINTPTR]);
+ field[9] = makefield("stuff", types[TUINTPTR]); // offset+wrapped+B+I
+ field[10] = makefield("bucket", types[TUINTPTR]);
+ field[11] = makefield("checkBucket", types[TUINTPTR]);
// build iterator struct holding the above fields
i = typ(TSTRUCT);
i->noalg = 1;
i->type = field[0];
- off = 0;
- for(n = 0; n < nelem(field)-1; n++) {
+ for(n = 0; n < nelem(field)-1; n++)
field[n]->down = field[n+1];
- field[n]->width = off;
- off += field[n]->type->width;
- }
field[nelem(field)-1]->down = T;
- off += field[nelem(field)-1]->type->width;
- if(off != 12 * widthptr)
- yyerror("hash_iter size not correct %d %d", off, 11 * widthptr);
+ dowidth(i);
+ if(i->width != 12 * widthptr)
+ yyerror("hash_iter size not correct %d %d", i->width, 12 * widthptr);
t->hiter = i;
i->map = t;
return i;
@@ -547,15 +479,15 @@ dimportpath(Pkg *p)
n->xoffset = 0;
p->pathsym = n->sym;
- arch.gdatastring(n, p->path);
- arch.ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA);
+ gdatastring(n, p->path);
+ ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA);
}
static int
dgopkgpath(Sym *s, int ot, Pkg *pkg)
{
if(pkg == nil)
- return arch.dgostringptr(s, ot, nil);
+ return dgostringptr(s, ot, nil);
// Emit reference to go.importpath.""., which 6l will
// rewrite using the correct import path. Every package
@@ -565,11 +497,11 @@ dgopkgpath(Sym *s, int ot, Pkg *pkg)
if(ns == nil)
ns = pkglookup("importpath.\"\".", mkpkg(newstrlit("go")));
- return arch.dsymptr(s, ot, ns, 0);
+ return dsymptr(s, ot, ns, 0);
}
dimportpath(pkg);
- return arch.dsymptr(s, ot, pkg->pathsym, 0);
+ return dsymptr(s, ot, pkg->pathsym, 0);
}
/*
@@ -589,7 +521,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
// fill in *extraType pointer in header
off = rnd(off, widthptr);
- arch.dsymptr(sym, ptroff, sym, off);
+ dsymptr(sym, ptroff, sym, off);
n = 0;
for(a=m; a; a=a->link) {
@@ -600,18 +532,18 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
ot = off;
s = sym;
if(t->sym) {
- ot = arch.dgostringptr(s, ot, t->sym->name);
+ ot = dgostringptr(s, ot, t->sym->name);
if(t != types[t->etype] && t != errortype)
ot = dgopkgpath(s, ot, t->sym->pkg);
else
- ot = arch.dgostringptr(s, ot, nil);
+ ot = dgostringptr(s, ot, nil);
} else {
- ot = arch.dgostringptr(s, ot, nil);
- ot = arch.dgostringptr(s, ot, nil);
+ ot = dgostringptr(s, ot, nil);
+ ot = dgostringptr(s, ot, nil);
}
// slice header
- ot = arch.dsymptr(s, ot, s, ot + widthptr + 2*widthint);
+ ot = dsymptr(s, ot, s, ot + widthptr + 2*widthint);
ot = duintxx(s, ot, n, widthint);
ot = duintxx(s, ot, n, widthint);
@@ -619,16 +551,16 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
for(a=m; a; a=a->link) {
// method
// ../../runtime/type.go:/method
- ot = arch.dgostringptr(s, ot, a->name);
+ ot = dgostringptr(s, ot, a->name);
ot = dgopkgpath(s, ot, a->pkg);
- ot = arch.dsymptr(s, ot, dtypesym(a->mtype), 0);
- ot = arch.dsymptr(s, ot, dtypesym(a->type), 0);
+ ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
+ ot = dsymptr(s, ot, dtypesym(a->type), 0);
if(a->isym)
- ot = arch.dsymptr(s, ot, a->isym, 0);
+ ot = dsymptr(s, ot, a->isym, 0);
else
ot = duintptr(s, ot, 0);
if(a->tsym)
- ot = arch.dsymptr(s, ot, a->tsym, 0);
+ ot = dsymptr(s, ot, a->tsym, 0);
else
ot = duintptr(s, ot, 0);
}
@@ -816,43 +748,43 @@ dcommontype(Sym *s, int ot, Type *t)
i |= KindGCProg;
ot = duint8(s, ot, i); // kind
if(algsym == S)
- ot = arch.dsymptr(s, ot, algarray, alg*sizeofAlg);
+ ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
else
- ot = arch.dsymptr(s, ot, algsym, 0);
+ ot = dsymptr(s, ot, algsym, 0);
// gc
if(gcprog) {
gengcprog(t, &gcprog0, &gcprog1);
if(gcprog0 != S)
- ot = arch.dsymptr(s, ot, gcprog0, 0);
+ ot = dsymptr(s, ot, gcprog0, 0);
else
ot = duintptr(s, ot, 0);
- ot = arch.dsymptr(s, ot, gcprog1, 0);
+ ot = dsymptr(s, ot, gcprog1, 0);
} else {
gengcmask(t, gcmask);
x1 = 0;
for(i=0; i<8; i++)
x1 = x1<<8 | gcmask[i];
if(widthptr == 4) {
- p = smprint("gcbits.%#016llux", x1);
+ p = smprint("gcbits.0x%016llux", x1);
} else {
x2 = 0;
for(i=0; i<8; i++)
x2 = x2<<8 | gcmask[i+8];
- p = smprint("gcbits.%#016llux%016llux", x1, x2);
+ p = smprint("gcbits.0x%016llux%016llux", x1, x2);
}
sbits = pkglookup(p, runtimepkg);
if((sbits->flags & SymUniq) == 0) {
sbits->flags |= SymUniq;
for(i = 0; i < 2*widthptr; i++)
duint8(sbits, i, gcmask[i]);
- arch.ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
+ ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
}
- ot = arch.dsymptr(s, ot, sbits, 0);
+ ot = dsymptr(s, ot, sbits, 0);
ot = duintptr(s, ot, 0);
}
p = smprint("%-uT", t);
//print("dcommontype: %s\n", p);
- ot = arch.dgostringptr(s, ot, p); // string
+ ot = dgostringptr(s, ot, p); // string
free(p);
// skip pointer to extraType,
@@ -861,8 +793,8 @@ dcommontype(Sym *s, int ot, Type *t)
// otherwise linker will assume 0.
ot += widthptr;
- ot = arch.dsymptr(s, ot, sptr, 0); // ptrto type
- ot = arch.dsymptr(s, ot, zero, 0); // ptr to zero value
+ ot = dsymptr(s, ot, sptr, 0); // ptrto type
+ ot = dsymptr(s, ot, zero, 0); // ptr to zero value
return ot;
}
@@ -1092,15 +1024,15 @@ ok:
s2 = dtypesym(t2);
ot = dcommontype(s, ot, t);
xt = ot - 3*widthptr;
- ot = arch.dsymptr(s, ot, s1, 0);
- ot = arch.dsymptr(s, ot, s2, 0);
+ ot = dsymptr(s, ot, s1, 0);
+ ot = dsymptr(s, ot, s2, 0);
ot = duintptr(s, ot, t->bound);
} else {
// ../../runtime/type.go:/SliceType
s1 = dtypesym(t->type);
ot = dcommontype(s, ot, t);
xt = ot - 3*widthptr;
- ot = arch.dsymptr(s, ot, s1, 0);
+ ot = dsymptr(s, ot, s1, 0);
}
break;
@@ -1109,7 +1041,7 @@ ok:
s1 = dtypesym(t->type);
ot = dcommontype(s, ot, t);
xt = ot - 3*widthptr;
- ot = arch.dsymptr(s, ot, s1, 0);
+ ot = dsymptr(s, ot, s1, 0);
ot = duintptr(s, ot, t->chan);
break;
@@ -1130,21 +1062,21 @@ ok:
// two slice headers: in and out.
ot = rnd(ot, widthptr);
- ot = arch.dsymptr(s, ot, s, ot+2*(widthptr+2*widthint));
+ ot = dsymptr(s, ot, s, ot+2*(widthptr+2*widthint));
n = t->thistuple + t->intuple;
ot = duintxx(s, ot, n, widthint);
ot = duintxx(s, ot, n, widthint);
- ot = arch.dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr);
+ ot = dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr);
ot = duintxx(s, ot, t->outtuple, widthint);
ot = duintxx(s, ot, t->outtuple, widthint);
// slice data
for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
- ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
- ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
- ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
break;
case TINTER:
@@ -1158,14 +1090,14 @@ ok:
// ../../runtime/type.go:/InterfaceType
ot = dcommontype(s, ot, t);
xt = ot - 3*widthptr;
- ot = arch.dsymptr(s, ot, s, ot+widthptr+2*widthint);
+ ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
ot = duintxx(s, ot, n, widthint);
ot = duintxx(s, ot, n, widthint);
for(a=m; a; a=a->link) {
// ../../runtime/type.go:/imethod
- ot = arch.dgostringptr(s, ot, a->name);
+ ot = dgostringptr(s, ot, a->name);
ot = dgopkgpath(s, ot, a->pkg);
- ot = arch.dsymptr(s, ot, dtypesym(a->type), 0);
+ ot = dsymptr(s, ot, dtypesym(a->type), 0);
}
break;
@@ -1177,10 +1109,10 @@ ok:
s4 = dtypesym(hmap(t));
ot = dcommontype(s, ot, t);
xt = ot - 3*widthptr;
- ot = arch.dsymptr(s, ot, s1, 0);
- ot = arch.dsymptr(s, ot, s2, 0);
- ot = arch.dsymptr(s, ot, s3, 0);
- ot = arch.dsymptr(s, ot, s4, 0);
+ ot = dsymptr(s, ot, s1, 0);
+ ot = dsymptr(s, ot, s2, 0);
+ ot = dsymptr(s, ot, s3, 0);
+ ot = dsymptr(s, ot, s4, 0);
if(t->down->width > MAXKEYSIZE) {
ot = duint8(s, ot, widthptr);
ot = duint8(s, ot, 1); // indirect
@@ -1210,7 +1142,7 @@ ok:
s1 = dtypesym(t->type);
ot = dcommontype(s, ot, t);
xt = ot - 3*widthptr;
- ot = arch.dsymptr(s, ot, s1, 0);
+ ot = dsymptr(s, ot, s1, 0);
break;
case TSTRUCT:
@@ -1223,32 +1155,32 @@ ok:
}
ot = dcommontype(s, ot, t);
xt = ot - 3*widthptr;
- ot = arch.dsymptr(s, ot, s, ot+widthptr+2*widthint);
+ ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
ot = duintxx(s, ot, n, widthint);
ot = duintxx(s, ot, n, widthint);
for(t1=t->type; t1!=T; t1=t1->down) {
// ../../runtime/type.go:/structField
if(t1->sym && !t1->embedded) {
- ot = arch.dgostringptr(s, ot, t1->sym->name);
+ ot = dgostringptr(s, ot, t1->sym->name);
if(exportname(t1->sym->name))
- ot = arch.dgostringptr(s, ot, nil);
+ ot = dgostringptr(s, ot, nil);
else
ot = dgopkgpath(s, ot, t1->sym->pkg);
} else {
- ot = arch.dgostringptr(s, ot, nil);
+ ot = dgostringptr(s, ot, nil);
if(t1->type->sym != S && t1->type->sym->pkg == builtinpkg)
ot = dgopkgpath(s, ot, localpkg);
else
- ot = arch.dgostringptr(s, ot, nil);
+ ot = dgostringptr(s, ot, nil);
}
- ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
- ot = arch.dgostrlitptr(s, ot, t1->note);
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+ ot = dgostrlitptr(s, ot, t1->note);
ot = duintptr(s, ot, t1->width); // field offset
}
break;
}
ot = dextratype(s, ot, t, xt);
- arch.ggloblsym(s, ot, dupok|RODATA);
+ ggloblsym(s, ot, dupok|RODATA);
// generate typelink.foo pointing at s = type.foo.
// The linker will leave a table of all the typelinks for
@@ -1261,8 +1193,8 @@ ok:
case TCHAN:
case TMAP:
slink = typelinksym(t);
- arch.dsymptr(slink, 0, s, 0);
- arch.ggloblsym(slink, widthptr, dupok|RODATA);
+ dsymptr(slink, 0, s, 0);
+ ggloblsym(slink, widthptr, dupok|RODATA);
}
}
@@ -1354,18 +1286,18 @@ dalgsym(Type *t)
hashfunc = pkglookup(p, typepkg);
free(p);
ot = 0;
- ot = arch.dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0);
+ ot = dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0);
ot = duintxx(hashfunc, ot, t->width, widthptr); // size encoded in closure
- arch.ggloblsym(hashfunc, ot, DUPOK|RODATA);
+ ggloblsym(hashfunc, ot, DUPOK|RODATA);
// make equality closure
p = smprint(".eqfunc%lld", t->width);
eqfunc = pkglookup(p, typepkg);
free(p);
ot = 0;
- ot = arch.dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0);
+ ot = dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0);
ot = duintxx(eqfunc, ot, t->width, widthptr);
- arch.ggloblsym(eqfunc, ot, DUPOK|RODATA);
+ ggloblsym(eqfunc, ot, DUPOK|RODATA);
} else {
// generate an alg table specific to this type
s = typesymprefix(".alg", t);
@@ -1378,16 +1310,16 @@ dalgsym(Type *t)
geneq(eq, t);
// make Go funcs (closures) for calling hash and equal from Go
- arch.dsymptr(hashfunc, 0, hash, 0);
- arch.ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
- arch.dsymptr(eqfunc, 0, eq, 0);
- arch.ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
+ dsymptr(hashfunc, 0, hash, 0);
+ ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
+ dsymptr(eqfunc, 0, eq, 0);
+ ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
}
// ../../runtime/alg.go:/typeAlg
ot = 0;
- ot = arch.dsymptr(s, ot, hashfunc, 0);
- ot = arch.dsymptr(s, ot, eqfunc, 0);
- arch.ggloblsym(s, ot, DUPOK|RODATA);
+ ot = dsymptr(s, ot, hashfunc, 0);
+ ot = dsymptr(s, ot, eqfunc, 0);
+ ggloblsym(s, ot, DUPOK|RODATA);
return s;
}
@@ -1417,7 +1349,7 @@ usegcprog(Type *t)
// Generates sparse GC bitmask (4 bits per word).
static void
-gengcmask(Type *t, uint8 gcmask[16])
+gengcmask(Type *t, uint8 *gcmask)
{
Bvec *vec;
vlong xoffset, nptr, i, j;
@@ -1570,7 +1502,7 @@ gengcprog(Type *t, Sym **pgc0, Sym **pgc1)
// Don't generate it if it's too large, runtime will unroll directly into GC bitmap.
if(size <= MaxGCMask) {
gc0 = typesymprefix(".gc", t);
- arch.ggloblsym(gc0, size, DUPOK|NOPTR);
+ ggloblsym(gc0, size, DUPOK|NOPTR);
*pgc0 = gc0;
}
@@ -1580,7 +1512,7 @@ gengcprog(Type *t, Sym **pgc0, Sym **pgc1)
xoffset = 0;
gengcprog1(&g, t, &xoffset);
ot = proggenfini(&g);
- arch.ggloblsym(gc1, ot, DUPOK|RODATA);
+ ggloblsym(gc1, ot, DUPOK|RODATA);
*pgc1 = gc1;
}
diff --git a/src/cmd/gc/reg.c b/src/cmd/gc/reg.c
new file mode 100644
index 0000000000..67409c2127
--- /dev/null
+++ b/src/cmd/gc/reg.c
@@ -0,0 +1,1233 @@
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+#include "popt.h"
+
+static Flow* firstf;
+static int first = 1;
+
+static void addmove(Flow*, int, int, int);
+static Bits mkvar(Flow*, Adr*);
+static void prop(Flow*, Bits, Bits);
+static void synch(Flow*, Bits);
+static uint64 allreg(uint64, Rgn*);
+static void paint1(Flow*, int);
+static uint64 paint2(Flow*, int, int);
+static void paint3(Flow*, int, uint64, int);
+static void addreg(Adr*, int);
+
+static int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ if(p1->cost != p2->cost)
+ return p2->cost - p1->cost;
+ if(p1->varno != p2->varno)
+ return p2->varno - p1->varno;
+ if(p1->enter != p2->enter)
+ return p2->enter->id - p1->enter->id;
+ return 0;
+}
+
+static void
+setaddrs(Bits bit)
+{
+ int i, n;
+ Var *v;
+ Node *node;
+
+ while(bany(&bit)) {
+ // convert each bit to a variable
+ i = bnum(bit);
+ node = var[i].node;
+ n = var[i].name;
+ biclr(&bit, i);
+
+ // disable all pieces of that variable
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->node == node && v->name == n)
+ v->addr = 2;
+ }
+ }
+}
+
+static Node* regnodes[64];
+
+static void walkvardef(Node *n, Flow *r, int active);
+
+void
+regopt(Prog *firstp)
+{
+ Flow *f, *f1;
+ Reg *r;
+ Prog *p;
+ Graph *g;
+ ProgInfo info;
+ int i, z, active;
+ uint64 vreg, usedreg;
+ uint64 mask;
+ int nreg;
+ char **regnames;
+ Bits bit;
+ Rgn *rgp;
+
+ if(first) {
+ fmtinstall('Q', Qconv);
+ first = 0;
+ }
+
+ mergetemp(firstp);
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ regnames = thearch.regnames(&nreg);
+ nvar = nreg;
+ memset(var, 0, nreg*sizeof var[0]);
+ for(i=0; i<nreg; i++) {
+ if(regnodes[i] == N)
+ regnodes[i] = newname(lookup(regnames[i]));
+ var[i].node = regnodes[i];
+ }
+
+ regbits = thearch.excludedregs();
+ externs = zbits;
+ params = zbits;
+ consts = zbits;
+ addrs = zbits;
+ ivar = zbits;
+ ovar = zbits;
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ g = flowstart(firstp, sizeof(Reg));
+ if(g == nil) {
+ for(i=0; i<nvar; i++)
+ var[i].node->opt = nil;
+ return;
+ }
+
+ firstf = g->start;
+
+ for(f = firstf; f != nil; f = f->link) {
+ p = f->prog;
+ if(p->as == AVARDEF || p->as == AVARKILL)
+ continue;
+ thearch.proginfo(&info, p);
+
+ // Avoid making variables for direct-called functions.
+ if(p->as == ACALL && p->to.type == TYPE_MEM && p->to.name == NAME_EXTERN)
+ continue;
+
+ // from vs to doesn't matter for registers.
+ r = (Reg*)f->data;
+ r->use1.b[0] |= info.reguse | info.regindex;
+ r->set.b[0] |= info.regset;
+
+ bit = mkvar(f, &p->from);
+ if(bany(&bit)) {
+ if(info.flags & LeftAddr)
+ setaddrs(bit);
+ if(info.flags & LeftRead)
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ if(info.flags & LeftWrite)
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ }
+
+ // Compute used register for reg
+ if(info.flags & RegRead)
+ r->use1.b[0] |= thearch.RtoB(p->reg);
+
+ // Currently we never generate three register forms.
+ // If we do, this will need to change.
+ if(p->from3.type != TYPE_NONE)
+ fatal("regopt not implemented for from3");
+
+ bit = mkvar(f, &p->to);
+ if(bany(&bit)) {
+ if(info.flags & RightAddr)
+ setaddrs(bit);
+ if(info.flags & RightRead)
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ if(info.flags & RightWrite)
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ }
+ }
+
+ for(i=0; i<nvar; i++) {
+ Var *v;
+ v = var+i;
+ if(v->addr) {
+ bit = blsh(i);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ }
+
+ if(debug['R'] && debug['v'])
+ print("bit=%2d addr=%d et=%E w=%-2d s=%N + %lld\n",
+ i, v->addr, v->etype, v->width, v->node, v->offset);
+ }
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass1", firstf, 1);
+
+ /*
+ * pass 2
+ * find looping structure
+ */
+ flowrpo(g);
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass2", firstf, 1);
+
+ /*
+ * pass 2.5
+ * iterate propagating fat vardef covering forward
+ * r->act records vars with a VARDEF since the last CALL.
+ * (r->act will be reused in pass 5 for something else,
+ * but we'll be done with it by then.)
+ */
+ active = 0;
+ for(f = firstf; f != nil; f = f->link) {
+ f->active = 0;
+ r = (Reg*)f->data;
+ r->act = zbits;
+ }
+ for(f = firstf; f != nil; f = f->link) {
+ p = f->prog;
+ if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) {
+ active++;
+ walkvardef(p->to.node, f, active);
+ }
+ }
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(f = firstf; f != nil; f = f->link)
+ f->active = 0;
+ for(f = firstf; f != nil; f = f->link)
+ if(f->prog->as == ARET)
+ prop(f, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(f = firstf; f != nil; f = f1) {
+ f1 = f->link;
+ if(f1 && f1->active && !f->active) {
+ prop(f, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass3", firstf, 1);
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(f = firstf; f != nil; f = f->link)
+ f->active = 0;
+ synch(firstf, zbits);
+ if(change)
+ goto loop2;
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass4", firstf, 1);
+
+ /*
+ * pass 4.5
+ * move register pseudo-variables into regu.
+ */
+ if(nreg == 64)
+ mask = ~0ULL; // can't rely on C to shift by 64
+ else
+ mask = (1ULL<<nreg) - 1;
+ for(f = firstf; f != nil; f = f->link) {
+ r = (Reg*)f->data;
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & mask;
+ r->set.b[0] &= ~mask;
+ r->use1.b[0] &= ~mask;
+ r->use2.b[0] &= ~mask;
+ r->refbehind.b[0] &= ~mask;
+ r->refahead.b[0] &= ~mask;
+ r->calbehind.b[0] &= ~mask;
+ r->calahead.b[0] &= ~mask;
+ r->regdiff.b[0] &= ~mask;
+ r->act.b[0] &= ~mask;
+ }
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass4.5", firstf, 1);
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ f = firstf;
+ if(f) {
+ r = (Reg*)f->data;
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit) && !f->refset) {
+ // should never happen - all variables are preset
+ if(debug['w'])
+ print("%L: used and not set: %Q\n", f->prog->lineno, bit);
+ f->refset = 1;
+ }
+ }
+ for(f = firstf; f != nil; f = f->link)
+ ((Reg*)f->data)->act = zbits;
+ nregion = 0;
+ for(f = firstf; f != nil; f = f->link) {
+ r = (Reg*)f->data;
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit) && !f->refset) {
+ if(debug['w'])
+ print("%L: set and not used: %Q\n", f->prog->lineno, bit);
+ f->refset = 1;
+ thearch.excise(f);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ change = 0;
+ paint1(f, i);
+ biclr(&bit, i);
+ if(change <= 0)
+ continue;
+ if(nregion >= NRGN) {
+ if(debug['R'] && debug['v'])
+ print("too many regions\n");
+ goto brk;
+ }
+ rgp = &region[nregion];
+ rgp->enter = f;
+ rgp->varno = i;
+ rgp->cost = change;
+ nregion++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ if(debug['R'] && debug['v'])
+ dumpit("pass5", firstf, 1);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ if(debug['R'] && debug['v'])
+ print("\nregisterizing\n");
+ for(i=0; i<nregion; i++) {
+ rgp = &region[i];
+ if(debug['R'] && debug['v'])
+ print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->prog->pc);
+ bit = blsh(rgp->varno);
+ usedreg = paint2(rgp->enter, rgp->varno, 0);
+ vreg = allreg(usedreg, rgp);
+ if(rgp->regno != 0) {
+ if(debug['R'] && debug['v']) {
+ Var *v;
+
+ v = var + rgp->varno;
+ print("registerize %N+%lld (bit=%2d et=%E) in %R usedreg=%#llx vreg=%#llx\n",
+ v->node, v->offset, rgp->varno, v->etype, rgp->regno, usedreg, vreg);
+ }
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ }
+ }
+
+ /*
+ * free aux structures. peep allocates new ones.
+ */
+ for(i=0; i<nvar; i++)
+ var[i].node->opt = nil;
+ flowend(g);
+ firstf = nil;
+
+ if(debug['R'] && debug['v']) {
+ // Rebuild flow graph, since we inserted instructions
+ g = flowstart(firstp, 0);
+ firstf = g->start;
+ dumpit("pass6", firstf, 0);
+ flowend(g);
+ firstf = nil;
+ }
+
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ thearch.peep(firstp);
+
+ /*
+ * eliminate nops
+ */
+ for(p=firstp; p!=P; p=p->link) {
+ while(p->link != P && p->link->as == ANOP)
+ p->link = p->link->link;
+ if(p->to.type == TYPE_BRANCH)
+ while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
+ p->to.u.branch = p->to.u.branch->link;
+ }
+
+ if(debug['R']) {
+ if(ostats.ncvtreg ||
+ ostats.nspill ||
+ ostats.nreload ||
+ ostats.ndelmov ||
+ ostats.nvar ||
+ ostats.naddr ||
+ 0)
+ print("\nstats\n");
+
+ if(ostats.ncvtreg)
+ print(" %4d cvtreg\n", ostats.ncvtreg);
+ if(ostats.nspill)
+ print(" %4d spill\n", ostats.nspill);
+ if(ostats.nreload)
+ print(" %4d reload\n", ostats.nreload);
+ if(ostats.ndelmov)
+ print(" %4d delmov\n", ostats.ndelmov);
+ if(ostats.nvar)
+ print(" %4d var\n", ostats.nvar);
+ if(ostats.naddr)
+ print(" %4d addr\n", ostats.naddr);
+
+ memset(&ostats, 0, sizeof(ostats));
+ }
+}
+
+static void
+walkvardef(Node *n, Flow *f, int active)
+{
+ Flow *f1, *f2;
+ int bn;
+ Var *v;
+
+ for(f1=f; f1!=nil; f1=f1->s1) {
+ if(f1->active == active)
+ break;
+ f1->active = active;
+ if(f1->prog->as == AVARKILL && f1->prog->to.node == n)
+ break;
+ for(v=n->opt; v!=nil; v=v->nextinnode) {
+ bn = v->id;
+ biset(&((Reg*)f1->data)->act, bn);
+ }
+ if(f1->prog->as == ACALL)
+ break;
+ }
+
+ for(f2=f; f2!=f1; f2=f2->s1)
+ if(f2->s2 != nil)
+ walkvardef(n, f2->s2, active);
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+static void
+addmove(Flow *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = mal(sizeof(*p1));
+ clearp(p1);
+ p1->pc = 9999;
+
+ p = r->prog;
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = TYPE_MEM;
+ a->name = v->name;
+ a->node = v->node;
+ a->sym = linksym(v->node->sym);
+ /* NOTE(rsc): 9g did
+ if(a->etype == TARRAY)
+ a->type = TYPE_ADDR;
+ else if(a->sym == nil)
+ a->type = TYPE_CONST;
+ */
+
+ p1->as = thearch.optoas(OAS, types[(uchar)v->etype]);
+ // TODO(rsc): Remove special case here.
+ if((thearch.thechar == '9' || thearch.thechar == '5') && v->etype == TBOOL)
+ p1->as = thearch.optoas(OAS, types[TUINT8]);
+ p1->from.type = TYPE_REG;
+ p1->from.reg = rn;
+ p1->from.name = NAME_NONE;
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = TYPE_REG;
+ a->reg = rn;
+ }
+ if(debug['R'] && debug['v'])
+ print("%P ===add=== %P\n", p, p1);
+ ostats.nspill++;
+}
+
+static int
+overlap(int64 o1, int w1, int64 o2, int w2)
+{
+ int64 t1, t2;
+
+ t1 = o1+w1;
+ t2 = o2+w2;
+
+ if(!(t1 > o2 && t2 > o1))
+ return 0;
+
+ return 1;
+}
+
+static Bits
+mkvar(Flow *f, Adr *a)
+{
+ Var *v;
+ int i, n, et, z, flag;
+ int64 w;
+ uint64 regu;
+ int64 o;
+ Bits bit;
+ Node *node;
+ Reg *r;
+
+
+ /*
+ * mark registers used
+ */
+ if(a->type == TYPE_NONE)
+ goto none;
+
+ r = (Reg*)f->data;
+ r->use1.b[0] |= thearch.doregbits(a->index); // TODO: Use RtoB
+
+ switch(a->type) {
+ default:
+ regu = thearch.doregbits(a->reg) | thearch.RtoB(a->reg); // TODO: Use RtoB
+ if(regu == 0)
+ goto none;
+ bit = zbits;
+ bit.b[0] = regu;
+ return bit;
+
+ case TYPE_ADDR:
+ // TODO(rsc): Remove special case here.
+ if(thearch.thechar == '9' || thearch.thechar == '5')
+ goto memcase;
+ a->type = TYPE_MEM;
+ bit = mkvar(f, a);
+ setaddrs(bit);
+ a->type = TYPE_ADDR;
+ ostats.naddr++;
+ goto none;
+
+ case TYPE_MEM:
+ memcase:
+ if(r != R) {
+ r->use1.b[0] |= thearch.RtoB(a->reg);
+ /* NOTE: 5g did
+ if(r->f.prog->scond & (C_PBIT|C_WBIT))
+ r->set.b[0] |= RtoB(a->reg);
+ */
+ }
+ switch(a->name) {
+ default:
+ goto none;
+ case NAME_EXTERN:
+ case NAME_STATIC:
+ case NAME_PARAM:
+ case NAME_AUTO:
+ n = a->name;
+ break;
+ }
+ }
+
+ node = a->node;
+ if(node == N || node->op != ONAME || node->orig == N)
+ goto none;
+ node = node->orig;
+ if(node->orig != node)
+ fatal("%D: bad node", a);
+ if(node->sym == S || node->sym->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ w = a->width;
+ if(w < 0)
+ fatal("bad width %lld for %D", w, a);
+
+ flag = 0;
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->node == node && v->name == n) {
+ if(v->offset == o)
+ if(v->etype == et)
+ if(v->width == w) {
+ // TODO(rsc): Remove special case for arm here.
+ if(!flag || thearch.thechar != '5')
+ return blsh(i);
+ }
+
+ // if they overlap, disable both
+ if(overlap(v->offset, v->width, o, w)) {
+// print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
+ v->addr = 1;
+ flag = 1;
+ }
+ }
+ }
+
+ switch(et) {
+ case 0:
+ case TFUNC:
+ goto none;
+ }
+
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && node != N)
+ fatal("variable not optimized: %#N", node);
+
+ // If we're not tracking a word in a variable, mark the rest as
+ // having its address taken, so that we keep the whole thing
+ // live at all calls. otherwise we might optimize away part of
+ // a variable but not all of it.
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->node == node)
+ v->addr = 1;
+ }
+ goto none;
+ }
+
+ i = nvar;
+ nvar++;
+ v = var+i;
+ v->id = i;
+ v->offset = o;
+ v->name = n;
+ v->etype = et;
+ v->width = w;
+ v->addr = flag; // funny punning
+ v->node = node;
+
+ // node->opt is the head of a linked list
+ // of Vars within the given Node, so that
+ // we can start at a Var and find all the other
+ // Vars in the same Go variable.
+ v->nextinnode = node->opt;
+ node->opt = v;
+
+ bit = blsh(i);
+ if(n == NAME_EXTERN || n == NAME_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == NAME_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+
+ if(node->class == PPARAM)
+ for(z=0; z<BITS; z++)
+ ivar.b[z] |= bit.b[z];
+ if(node->class == PPARAMOUT)
+ for(z=0; z<BITS; z++)
+ ovar.b[z] |= bit.b[z];
+
+ // Treat values with their address taken as live at calls,
+ // because the garbage collector's liveness analysis in ../gc/plive.c does.
+ // These must be consistent or else we will elide stores and the garbage
+ // collector will see uninitialized data.
+ // The typical case where our own analysis is out of sync is when the
+ // node appears to have its address taken but that code doesn't actually
+ // get generated and therefore doesn't show up as an address being
+ // taken when we analyze the instruction stream.
+ // One instance of this case is when a closure uses the same name as
+ // an outer variable for one of its own variables declared with :=.
+ // The parser flags the outer variable as possibly shared, and therefore
+ // sets addrtaken, even though it ends up not being actually shared.
+ // If we were better about _ elision, _ = &x would suffice too.
+ // The broader := in a closure problem is mentioned in a comment in
+ // closure.c:/^typecheckclosure and dcl.c:/^oldname.
+ if(node->addrtaken)
+ v->addr = 1;
+
+ // Disable registerization for globals, because:
+ // (1) we might panic at any time and we want the recovery code
+ // to see the latest values (issue 1304).
+ // (2) we don't know what pointers might point at them and we want
+ // loads via those pointers to see updated values and vice versa (issue 7995).
+ //
+ // Disable registerization for results if using defer, because the deferred func
+ // might recover and return, causing the current values to be used.
+ if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
+ v->addr = 1;
+
+ if(debug['R'])
+ print("bit=%2d et=%E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
+ ostats.nvar++;
+
+ return bit;
+
+none:
+ return zbits;
+}
+
+static void
+prop(Flow *f, Bits ref, Bits cal)
+{
+ Flow *f1, *f2;
+ Reg *r, *r1;
+ int z, i;
+ Var *v, *v1;
+
+ for(f1 = f; f1 != nil; f1 = f1->p1) {
+ r1 = (Reg*)f1->data;
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(f1->prog->as) {
+ case ACALL:
+ if(noreturn(f1->prog))
+ break;
+
+ // Mark all input variables (ivar) as used, because that's what the
+ // liveness bitmaps say. The liveness bitmaps say that so that a
+ // panic will not show stale values in the parameter dump.
+ // Mark variables with a recent VARDEF (r1->act) as used,
+ // so that the optimizer flushes initializations to memory,
+ // so that if a garbage collection happens during this CALL,
+ // the collector will see initialized memory. Again this is to
+ // match what the liveness bitmaps say.
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
+ ref.b[z] = 0;
+ }
+
+ // cal.b is the current approximation of what's live across the call.
+ // Every bit in cal.b is a single stack word. For each such word,
+ // find all the other tracked stack words in the same Go variable
+ // (struct/slice/string/interface) and mark them live too.
+ // This is necessary because the liveness analysis for the garbage
+ // collector works at variable granularity, not at word granularity.
+ // It is fundamental for slice/string/interface: the garbage collector
+ // needs the whole value, not just some of the words, in order to
+ // interpret the other bits correctly. Specifically, slice needs a consistent
+ // ptr and cap, string needs a consistent ptr and len, and interface
+ // needs a consistent type word and data word.
+ for(z=0; z<BITS; z++) {
+ if(cal.b[z] == 0)
+ continue;
+ for(i=0; i<64; i++) {
+ if(z*64+i >= nvar || ((cal.b[z]>>i)&1) == 0)
+ continue;
+ v = var+z*64+i;
+ if(v->node->opt == nil) // v represents fixed register, not Go variable
+ continue;
+
+ // v->node->opt is the head of a linked list of Vars
+ // corresponding to tracked words from the Go variable v->node.
+ // Walk the list and set all the bits.
+ // For a large struct this could end up being quadratic:
+ // after the first setting, the outer loop (for z, i) would see a 1 bit
+ // for all of the remaining words in the struct, and for each such
+ // word would go through and turn on all the bits again.
+ // To avoid the quadratic behavior, we only turn on the bits if
+ // v is the head of the list or if the head's bit is not yet turned on.
+ // This will set the bits at most twice, keeping the overall loop linear.
+ v1 = v->node->opt;
+ if(v == v1 || !btest(&cal, v1->id)) {
+ for(; v1 != nil; v1 = v1->nextinnode) {
+ biset(&cal, v1->id);
+ }
+ }
+ }
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z] | ovar.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(f1->active)
+ break;
+ f1->active = 1;
+ }
+
+ for(; f != f1; f = f->p1) {
+ r = (Reg*)f->data;
+ for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
+ prop(f2, r->refbehind, r->calbehind);
+ }
+}
+
+static void
+synch(Flow *f, Bits dif)
+{
+ Flow *f1;
+ Reg *r1;
+ int z;
+
+ for(f1 = f; f1 != nil; f1 = f1->s1) {
+ r1 = (Reg*)f1->data;
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(f1->active)
+ break;
+ f1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(f1->s2 != nil)
+ synch(f1->s2, dif);
+ }
+}
+
+static uint64
+allreg(uint64 b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ fatal("unknown etype %d/%E", bitno(b), v->etype);
+ break;
+
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TBOOL:
+ case TPTR32:
+ case TPTR64:
+ i = thearch.BtoR(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return thearch.RtoB(i);
+ }
+ break;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ i = thearch.BtoF(~b);
+ if(i && r->cost > 0) {
+ r->regno = i;
+ return thearch.FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+static void
+paint1(Flow *f, int bn)
+{
+ Flow *f1;
+ Reg *r, *r1;
+ int z;
+ uint64 bb;
+
+ z = bn/64;
+ bb = 1LL<<(bn%64);
+ r = (Reg*)f->data;
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ f1 = f->p1;
+ if(f1 == nil)
+ break;
+ r1 = (Reg*)f1->data;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ f = f1;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * f->loop;
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+
+ if(f->prog->as != ANOP) { // don't give credit for NOPs
+ if(r->use1.b[z] & bb)
+ change += CREF * f->loop;
+ if((r->use2.b[z]|r->set.b[z]) & bb)
+ change += CREF * f->loop;
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * f->loop;
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
+ if(((Reg*)f1->data)->refahead.b[z] & bb)
+ paint1(f1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ f1 = f->s2;
+ if(f1 != nil)
+ if(((Reg*)f1->data)->refbehind.b[z] & bb)
+ paint1(f1, bn);
+ f = f->s1;
+ if(f == nil)
+ break;
+ r = (Reg*)f->data;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+static uint64
+paint2(Flow *f, int bn, int depth)
+{
+ Flow *f1;
+ Reg *r, *r1;
+ int z;
+ uint64 bb, vreg;
+
+ z = bn/64;
+ bb = 1LL << (bn%64);
+ vreg = regbits;
+ r = (Reg*)f->data;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ f1 = f->p1;
+ if(f1 == nil)
+ break;
+ r1 = (Reg*)f1->data;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ f = f1;
+ r = r1;
+ }
+ for(;;) {
+ if(debug['R'] && debug['v'])
+ print(" paint2 %d %P\n", depth, f->prog);
+
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
+ if(((Reg*)f1->data)->refahead.b[z] & bb)
+ vreg |= paint2(f1, bn, depth+1);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ f1 = f->s2;
+ if(f1 != nil)
+ if(((Reg*)f1->data)->refbehind.b[z] & bb)
+ vreg |= paint2(f1, bn, depth+1);
+ f = f->s1;
+ if(f == nil)
+ break;
+ r = (Reg*)f->data;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+
+ return vreg;
+}
+
+static void
+paint3(Flow *f, int bn, uint64 rb, int rn)
+{
+ Flow *f1;
+ Reg *r, *r1;
+ Prog *p;
+ int z;
+ uint64 bb;
+
+ z = bn/64;
+ bb = 1LL << (bn%64);
+ r = (Reg*)f->data;
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ f1 = f->p1;
+ if(f1 == nil)
+ break;
+ r1 = (Reg*)f1->data;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ f = f1;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(f, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = f->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'] && debug['v'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'] && debug['v'])
+ print(" ===change== %P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'] && debug['v'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'] && debug['v'])
+ print(" ===change== %P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(f, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(f1 = f->p2; f1 != nil; f1 = f1->p2link)
+ if(((Reg*)f1->data)->refahead.b[z] & bb)
+ paint3(f1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ f1 = f->s2;
+ if(f1 != nil)
+ if(((Reg*)f1->data)->refbehind.b[z] & bb)
+ paint3(f1, bn, rb, rn);
+ f = f->s1;
+ if(f == nil)
+ break;
+ r = (Reg*)f->data;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+static void
+addreg(Adr *a, int rn)
+{
+ a->sym = nil;
+ a->node = nil;
+ a->offset = 0;
+ a->type = TYPE_REG;
+ a->reg = rn;
+ a->name = 0;
+
+ ostats.ncvtreg++;
+}
+
+void
+dumpone(Flow *f, int isreg)
+{
+ int z;
+ Bits bit;
+ Reg *r;
+
+ print("%d:%P", f->loop, f->prog);
+ if(isreg) {
+ r = (Reg*)f->data;
+ for(z=0; z<BITS; z++)
+ bit.b[z] =
+ r->set.b[z] |
+ r->use1.b[z] |
+ r->use2.b[z] |
+ r->refbehind.b[z] |
+ r->refahead.b[z] |
+ r->calbehind.b[z] |
+ r->calahead.b[z] |
+ r->regdiff.b[z] |
+ r->act.b[z] |
+ 0;
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->set))
+ print(" s:%Q", r->set);
+ if(bany(&r->use1))
+ print(" u1:%Q", r->use1);
+ if(bany(&r->use2))
+ print(" u2:%Q", r->use2);
+ if(bany(&r->refbehind))
+ print(" rb:%Q ", r->refbehind);
+ if(bany(&r->refahead))
+ print(" ra:%Q ", r->refahead);
+ if(bany(&r->calbehind))
+ print(" cb:%Q ", r->calbehind);
+ if(bany(&r->calahead))
+ print(" ca:%Q ", r->calahead);
+ if(bany(&r->regdiff))
+ print(" d:%Q ", r->regdiff);
+ if(bany(&r->act))
+ print(" a:%Q ", r->act);
+ }
+ }
+ print("\n");
+}
+
+void
+dumpit(char *str, Flow *r0, int isreg)
+{
+ Flow *r, *r1;
+
+ print("\n%s\n", str);
+ for(r = r0; r != nil; r = r->link) {
+ dumpone(r, isreg);
+ r1 = r->p2;
+ if(r1 != nil) {
+ print(" pred:");
+ for(; r1 != nil; r1 = r1->p2link)
+ print(" %.4ud", (int)r1->prog->pc);
+ if(r->p1 != nil)
+ print(" (and %.4ud)", (int)r->p1->prog->pc);
+ else
+ print(" (only)");
+ print("\n");
+ }
+ // Print successors if it's not just the next one
+ if(r->s1 != r->link || r->s2 != nil) {
+ print(" succ:");
+ if(r->s1 != nil)
+ print(" %.4ud", (int)r->s1->prog->pc);
+ if(r->s2 != nil)
+ print(" %.4ud", (int)r->s2->prog->pc);
+ print("\n");
+ }
+ }
+}
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 80550f856d..0a4c1b8cbb 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -50,10 +50,10 @@ func eqstring(string, string) bool
func intstring(*[4]byte, int64) string
func slicebytetostring(*[32]byte, []byte) string
func slicebytetostringtmp([]byte) string
-func slicerunetostring([]rune) string
-func stringtoslicebyte(string) []byte
+func slicerunetostring(*[32]byte, []rune) string
+func stringtoslicebyte(*[32]byte, string) []byte
func stringtoslicebytetmp(string) []byte
-func stringtoslicerune(string) []rune
+func stringtoslicerune(*[32]rune, string) []rune
func stringiter(string, int) int
func stringiter2(string, int) (retk int, retv rune)
func slicecopy(to any, fr any, wid uintptr) int
@@ -86,7 +86,7 @@ func ifacethash(i1 any) (ret uint32)
func efacethash(i1 any) (ret uint32)
// *byte is really *runtime.Type
-func makemap(mapType *byte, hint int64) (hmap map[any]any)
+func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any)
func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any)
func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index 5d3b71164a..537d0ca928 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -133,18 +133,16 @@ walkselect(Node *sel)
break;
case OSELRECV:
- ch = n->right->left;
- Selrecv1:
- if(n->left == N)
- n = n->right;
- else
- n->op = OAS;
- break;
-
case OSELRECV2:
ch = n->right->left;
- if(n->ntest == N)
- goto Selrecv1;
+ if(n->op == OSELRECV || n->ntest == N) {
+ if(n->left == N)
+ n = n->right;
+ else
+ n->op = OAS;
+ break;
+ }
+
if(n->left == N) {
typecheck(&nblank, Erv | Easgn);
n->left = nblank;
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 3d303eda09..1015950e41 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -302,13 +302,13 @@ staticcopy(Node *l, Node *r, NodeList **out)
case OLITERAL:
if(iszero(r))
return 1;
- arch.gdata(l, r, l->type->width);
+ gdata(l, r, l->type->width);
return 1;
case OADDR:
switch(r->left->op) {
case ONAME:
- arch.gdata(l, r, l->type->width);
+ gdata(l, r, l->type->width);
return 1;
}
break;
@@ -322,7 +322,7 @@ staticcopy(Node *l, Node *r, NodeList **out)
case OSTRUCTLIT:
case OMAPLIT:
// copy pointer
- arch.gdata(l, nod(OADDR, r->nname, N), l->type->width);
+ gdata(l, nod(OADDR, r->nname, N), l->type->width);
return 1;
}
break;
@@ -333,11 +333,11 @@ staticcopy(Node *l, Node *r, NodeList **out)
a = r->nname;
n1 = *l;
n1.xoffset = l->xoffset + Array_array;
- arch.gdata(&n1, nod(OADDR, a, N), widthptr);
+ gdata(&n1, nod(OADDR, a, N), widthptr);
n1.xoffset = l->xoffset + Array_nel;
- arch.gdata(&n1, r->right, widthint);
+ gdata(&n1, r->right, widthint);
n1.xoffset = l->xoffset + Array_cap;
- arch.gdata(&n1, r->right, widthint);
+ gdata(&n1, r->right, widthint);
return 1;
}
// fall through
@@ -349,7 +349,7 @@ staticcopy(Node *l, Node *r, NodeList **out)
n1.xoffset = l->xoffset + e->xoffset;
n1.type = e->expr->type;
if(e->expr->op == OLITERAL)
- arch.gdata(&n1, e->expr, n1.type->width);
+ gdata(&n1, e->expr, n1.type->width);
else {
ll = nod(OXXX, N, N);
*ll = n1;
@@ -394,14 +394,14 @@ staticassign(Node *l, Node *r, NodeList **out)
case OLITERAL:
if(iszero(r))
return 1;
- arch.gdata(l, r, l->type->width);
+ gdata(l, r, l->type->width);
return 1;
case OADDR:
if(stataddr(&nam, r->left)) {
n1 = *r;
n1.left = &nam;
- arch.gdata(l, &n1, l->type->width);
+ gdata(l, &n1, l->type->width);
return 1;
}
@@ -417,7 +417,7 @@ staticassign(Node *l, Node *r, NodeList **out)
// Init pointer.
a = staticname(r->left->type, 1);
r->nname = a;
- arch.gdata(l, nod(OADDR, a, N), l->type->width);
+ gdata(l, nod(OADDR, a, N), l->type->width);
// Init underlying literal.
if(!staticassign(a, r->left, out))
*out = list(*out, nod(OAS, a, r->left));
@@ -444,11 +444,11 @@ staticassign(Node *l, Node *r, NodeList **out)
r->nname = a;
n1 = *l;
n1.xoffset = l->xoffset + Array_array;
- arch.gdata(&n1, nod(OADDR, a, N), widthptr);
+ gdata(&n1, nod(OADDR, a, N), widthptr);
n1.xoffset = l->xoffset + Array_nel;
- arch.gdata(&n1, r->right, widthint);
+ gdata(&n1, r->right, widthint);
n1.xoffset = l->xoffset + Array_cap;
- arch.gdata(&n1, r->right, widthint);
+ gdata(&n1, r->right, widthint);
// Fall through to init underlying array.
l = a;
}
@@ -462,7 +462,7 @@ staticassign(Node *l, Node *r, NodeList **out)
n1.xoffset = l->xoffset + e->xoffset;
n1.type = e->expr->type;
if(e->expr->op == OLITERAL)
- arch.gdata(&n1, e->expr, n1.type->width);
+ gdata(&n1, e->expr, n1.type->width);
else {
a = nod(OXXX, N, N);
*a = n1;
@@ -1223,7 +1223,7 @@ stataddr(Node *nam, Node *n)
if(l < 0)
break;
// Check for overflow.
- if(n->type->width != 0 && arch.MAXWIDTH/n->type->width <= l)
+ if(n->type->width != 0 && thearch.MAXWIDTH/n->type->width <= l)
break;
nam->xoffset += l*n->type->width;
nam->type = n->type;
@@ -1303,16 +1303,16 @@ gen_as_init(Node *n)
case TPTR64:
case TFLOAT32:
case TFLOAT64:
- arch.gdata(&nam, nr, nr->type->width);
+ gdata(&nam, nr, nr->type->width);
break;
case TCOMPLEX64:
case TCOMPLEX128:
- arch.gdatacomplex(&nam, nr->val.u.cval);
+ gdatacomplex(&nam, nr->val.u.cval);
break;
case TSTRING:
- arch.gdatastring(&nam, nr->val.u.sval);
+ gdatastring(&nam, nr->val.u.sval);
break;
}
@@ -1320,7 +1320,7 @@ yes:
return 1;
slice:
- arch.gused(N); // in case the data is the dest of a goto
+ gused(N); // in case the data is the dest of a goto
nl = nr;
if(nr == N || nr->op != OADDR)
goto no;
@@ -1333,14 +1333,14 @@ slice:
goto no;
nam.xoffset += Array_array;
- arch.gdata(&nam, nl, types[tptr]->width);
+ gdata(&nam, nl, types[tptr]->width);
nam.xoffset += Array_nel-Array_array;
nodconst(&nod1, types[TINT], nr->type->bound);
- arch.gdata(&nam, &nod1, widthint);
+ gdata(&nam, &nod1, widthint);
nam.xoffset += Array_cap-Array_nel;
- arch.gdata(&nam, &nod1, widthint);
+ gdata(&nam, &nod1, widthint);
goto yes;
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 3ed194ee8f..f739a72499 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -38,6 +38,19 @@ parserline(void)
return lineno;
}
+void
+adderrorname(Node *n)
+{
+ char *old;
+
+ if(n->op != ODOT)
+ return;
+ old = smprint("%L: undefined: %N\n", n->lineno, n->left);
+ if(nerr > 0 && err[nerr-1].lineno == n->lineno && strcmp(err[nerr-1].msg, old) == 0)
+ err[nerr-1].msg = smprint("%L: undefined: %N in %N\n", n->lineno, n->left, n);
+ free(old);
+}
+
static void
adderr(int line, char *fmt, va_list arg)
{
@@ -1211,7 +1224,7 @@ assignop(Type *src, Type *dst, char **why)
*why = "";
// TODO(rsc,lvd): This behaves poorly in the presence of inlining.
- // https://code.google.com/p/go/issues/detail?id=2795
+ // https://golang.org/issue/2795
if(safemode && importpkg == nil && src != T && src->etype == TUNSAFEPTR) {
yyerror("cannot use unsafe.Pointer");
errorexit();
@@ -1703,36 +1716,31 @@ ptrto(Type *t)
void
frame(int context)
{
- char *p;
NodeList *l;
Node *n;
- int flag;
+ vlong w;
- p = "stack";
- l = nil;
- if(curfn)
- l = curfn->dcl;
if(context) {
- p = "external";
+ print("--- external frame ---\n");
l = externdcl;
- }
+ } else if(curfn) {
+ print("--- %S frame ---\n", curfn->nname->sym);
+ l = curfn->dcl;
+ } else
+ return;
- flag = 1;
for(; l; l=l->next) {
n = l->n;
+ w = -1;
+ if(n->type)
+ w = n->type->width;
switch(n->op) {
case ONAME:
- if(flag)
- print("--- %s frame ---\n", p);
- print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type);
- flag = 0;
+ print("%O %S G%d %T width=%lld\n", n->op, n->sym, n->vargen, n->type, w);
break;
case OTYPE:
- if(flag)
- print("--- %s frame ---\n", p);
- print("%O %T\n", n->op, n->type);
- flag = 0;
+ print("%O %T width=%lld\n", n->op, n->type, w);
break;
}
}
@@ -2121,10 +2129,10 @@ setmaxarg(Type *t, int32 extra)
dowidth(t);
w = t->argwid;
- if(w >= arch.MAXWIDTH)
+ if(w >= thearch.MAXWIDTH)
fatal("bad argwid %T", t);
w += extra;
- if(w >= arch.MAXWIDTH)
+ if(w >= thearch.MAXWIDTH)
fatal("bad argwid %d + %T", extra, t);
if(w > maxarg)
maxarg = w;
@@ -2628,7 +2636,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
inl_nonlocal = 0;
curfn = nil;
- funccompile(fn, 0);
+ funccompile(fn);
}
static Node*
@@ -2876,7 +2884,7 @@ genhash(Sym *sym, Type *t)
// an unexported field of type unsafe.Pointer.
old_safemode = safemode;
safemode = 0;
- funccompile(fn, 0);
+ funccompile(fn);
safemode = old_safemode;
}
@@ -3096,7 +3104,7 @@ geneq(Sym *sym, Type *t)
// an unexported field of type unsafe.Pointer.
old_safemode = safemode;
safemode = 0;
- funccompile(fn, 0);
+ funccompile(fn);
safemode = old_safemode;
}
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
index ca5455d479..0dc0065ed9 100644
--- a/src/cmd/gc/swt.c
+++ b/src/cmd/gc/swt.c
@@ -454,31 +454,22 @@ exprbsw(Case *c0, int ncase, int arg)
n = c0->node;
lno = setlineno(n);
- if(assignop(n->left->type, exprname->type, nil) == OCONVIFACE ||
- assignop(exprname->type, n->left->type, nil) == OCONVIFACE)
- goto snorm;
-
- switch(arg) {
- case Strue:
+ if((arg != Strue && arg != Sfalse) ||
+ assignop(n->left->type, exprname->type, nil) == OCONVIFACE ||
+ assignop(exprname->type, n->left->type, nil) == OCONVIFACE) {
a = nod(OIF, N, N);
- a->ntest = n->left; // if val
+ a->ntest = nod(OEQ, exprname, n->left); // if name == val
+ typecheck(&a->ntest, Erv);
a->nbody = list1(n->right); // then goto l
- break;
-
- case Sfalse:
+ } else if(arg == Strue) {
a = nod(OIF, N, N);
- a->ntest = nod(ONOT, n->left, N); // if !val
- typecheck(&a->ntest, Erv);
+ a->ntest = n->left; // if val
a->nbody = list1(n->right); // then goto l
- break;
-
- default:
- snorm:
+ } else { // arg == Sfalse
a = nod(OIF, N, N);
- a->ntest = nod(OEQ, exprname, n->left); // if name == val
+ a->ntest = nod(ONOT, n->left, N); // if !val
typecheck(&a->ntest, Erv);
a->nbody = list1(n->right); // then goto l
- break;
}
cas = list(cas, a);
@@ -503,7 +494,7 @@ exprbsw(Case *c0, int ncase, int arg)
/*
* normal (expression) switch.
- * rebulid case statements into if .. goto
+ * rebuild case statements into if .. goto
*/
static void
exprswitch(Node *sw)
@@ -533,12 +524,15 @@ exprswitch(Node *sw)
*/
exprname = N;
cas = nil;
- if(arg != Strue && arg != Sfalse) {
+ if(arg == Strue || arg == Sfalse)
+ exprname = nodbool(arg == Strue);
+ else if(consttype(sw->ntest) >= 0)
+ // leave constants to enable dead code elimination (issue 9608)
+ exprname = sw->ntest;
+ else {
exprname = temp(sw->ntest->type);
cas = list1(nod(OAS, exprname, sw->ntest));
typechecklist(cas, Etop);
- } else {
- exprname = nodbool(arg == Strue);
}
c0 = mkcaselist(sw, arg);
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 635d2c4170..649f1c5120 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -555,168 +555,7 @@ reswitch:
if(l->type == T || r->type == T)
goto error;
op = n->op;
- arith:
- if(op == OLSH || op == ORSH)
- goto shift;
- // ideal mixed with non-ideal
- defaultlit2(&l, &r, 0);
- n->left = l;
- n->right = r;
- if(l->type == T || r->type == T)
- goto error;
- t = l->type;
- if(t->etype == TIDEAL)
- t = r->type;
- et = t->etype;
- if(et == TIDEAL)
- et = TINT;
- if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- // comparison is okay as long as one side is
- // assignable to the other. convert so they have
- // the same type.
- //
- // the only conversion that isn't a no-op is concrete == interface.
- // in that case, check comparability of the concrete type.
- if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
- if(isinter(r->type) && !isinter(l->type) && algtype1(l->type, nil) == ANOEQ) {
- yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(l->type));
- goto error;
- }
- l = nod(aop, l, N);
- l->type = r->type;
- l->typecheck = 1;
- n->left = l;
- t = l->type;
- goto converted;
- }
- if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
- if(isinter(l->type) && !isinter(r->type) && algtype1(r->type, nil) == ANOEQ) {
- yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(r->type));
- goto error;
- }
- r = nod(aop, r, N);
- r->type = l->type;
- r->typecheck = 1;
- n->right = r;
- t = r->type;
- }
- converted:
- et = t->etype;
- }
- if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- defaultlit2(&l, &r, 1);
- if(n->op == OASOP && n->implicit) {
- yyerror("invalid operation: %N (non-numeric type %T)", n, l->type);
- goto error;
- }
- yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
- goto error;
- }
- if(!okfor[op][et]) {
- yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(t));
- goto error;
- }
- // okfor allows any array == array, map == map, func == func.
- // restrict to slice/map/func == nil and nil == slice/map/func.
- if(isfixedarray(l->type) && algtype1(l->type, nil) == ANOEQ) {
- yyerror("invalid operation: %N (%T cannot be compared)", n, l->type);
- goto error;
- }
- if(isslice(l->type) && !isnil(l) && !isnil(r)) {
- yyerror("invalid operation: %N (slice can only be compared to nil)", n);
- goto error;
- }
- if(l->type->etype == TMAP && !isnil(l) && !isnil(r)) {
- yyerror("invalid operation: %N (map can only be compared to nil)", n);
- goto error;
- }
- if(l->type->etype == TFUNC && !isnil(l) && !isnil(r)) {
- yyerror("invalid operation: %N (func can only be compared to nil)", n);
- goto error;
- }
- if(l->type->etype == TSTRUCT && algtype1(l->type, &badtype) == ANOEQ) {
- yyerror("invalid operation: %N (struct containing %T cannot be compared)", n, badtype);
- goto error;
- }
-
- t = l->type;
- if(iscmp[n->op]) {
- evconst(n);
- t = idealbool;
- if(n->op != OLITERAL) {
- defaultlit2(&l, &r, 1);
- n->left = l;
- n->right = r;
- }
- } else if(n->op == OANDAND || n->op == OOROR) {
- if(l->type == r->type)
- t = l->type;
- else if(l->type == idealbool)
- t = r->type;
- else if(r->type == idealbool)
- t = l->type;
- // non-comparison operators on ideal bools should make them lose their ideal-ness
- } else if(t == idealbool)
- t = types[TBOOL];
-
- if(et == TSTRING) {
- if(iscmp[n->op]) {
- n->etype = n->op;
- n->op = OCMPSTR;
- } else if(n->op == OADD) {
- // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
- n->op = OADDSTR;
- if(l->op == OADDSTR)
- n->list = l->list;
- else
- n->list = list1(l);
- if(r->op == OADDSTR)
- n->list = concat(n->list, r->list);
- else
- n->list = list(n->list, r);
- n->left = N;
- n->right = N;
- }
- }
- if(et == TINTER) {
- if(l->op == OLITERAL && l->val.ctype == CTNIL) {
- // swap for back end
- n->left = r;
- n->right = l;
- } else if(r->op == OLITERAL && r->val.ctype == CTNIL) {
- // leave alone for back end
- } else {
- n->etype = n->op;
- n->op = OCMPIFACE;
- }
- }
-
- if((op == ODIV || op == OMOD) && isconst(r, CTINT))
- if(mpcmpfixc(r->val.u.xval, 0) == 0) {
- yyerror("division by zero");
- goto error;
- }
-
- n->type = t;
- goto ret;
-
- shift:
- defaultlit(&r, types[TUINT]);
- n->right = r;
- t = r->type;
- if(!isint[t->etype] || issigned[t->etype]) {
- yyerror("invalid operation: %N (shift count type %T, must be unsigned integer)", n, r->type);
- goto error;
- }
- t = l->type;
- if(t != T && t->etype != TIDEAL && !isint[t->etype]) {
- yyerror("invalid operation: %N (shift of type %T)", n, t);
- goto error;
- }
- // no defaultlit for left
- // the outer context gives the type
- n->type = l->type;
- goto ret;
+ goto arith;
case OCOM:
case OMINUS:
@@ -776,12 +615,14 @@ reswitch:
case ODOT:
typecheck(&n->left, Erv|Etype);
defaultlit(&n->left, T);
- if((t = n->left->type) == T)
- goto error;
if(n->right->op != ONAME) {
yyerror("rhs of . must be a name"); // impossible
goto error;
}
+ if((t = n->left->type) == T) {
+ adderrorname(n);
+ goto error;
+ }
r = n->right;
if(n->left->op == OTYPE) {
@@ -1442,41 +1283,7 @@ reswitch:
goto ret;
case OCONV:
- doconv:
- ok |= Erv;
- saveorignode(n);
- typecheck(&n->left, Erv | (top & (Eindir | Eiota)));
- convlit1(&n->left, n->type, 1);
- if((t = n->left->type) == T || n->type == T)
- goto error;
- if((n->op = convertop(t, n->type, &why)) == 0) {
- if(!n->diag && !n->type->broke) {
- yyerror("cannot convert %lN to type %T%s", n->left, n->type, why);
- n->diag = 1;
- }
- n->op = OCONV;
- }
- switch(n->op) {
- case OCONVNOP:
- if(n->left->op == OLITERAL && n->type != types[TBOOL]) {
- r = nod(OXXX, N, N);
- n->op = OCONV;
- n->orig = r;
- *r = *n;
- n->op = OLITERAL;
- n->val = n->left->val;
- }
- break;
- case OSTRARRAYBYTE:
- // do not use stringtoarraylit.
- // generated code and compiler memory footprint is better without it.
- break;
- case OSTRARRAYRUNE:
- if(n->left->op == OLITERAL)
- stringtoarraylit(&n);
- break;
- }
- goto ret;
+ goto doconv;
case OMAKE:
ok |= Erv;
@@ -1494,13 +1301,14 @@ reswitch:
switch(t->etype) {
default:
- badmake:
yyerror("cannot make type %T", t);
goto error;
case TARRAY:
- if(!isslice(t))
- goto badmake;
+ if(!isslice(t)) {
+ yyerror("cannot make type %T", t);
+ goto error;
+ }
if(args == nil) {
yyerror("missing len argument to make(%T)", t);
goto error;
@@ -1793,6 +1601,216 @@ reswitch:
checkwidth(n->left->type);
goto ret;
}
+ goto ret;
+
+arith:
+ if(op == OLSH || op == ORSH)
+ goto shift;
+ // ideal mixed with non-ideal
+ defaultlit2(&l, &r, 0);
+ n->left = l;
+ n->right = r;
+ if(l->type == T || r->type == T)
+ goto error;
+ t = l->type;
+ if(t->etype == TIDEAL)
+ t = r->type;
+ et = t->etype;
+ if(et == TIDEAL)
+ et = TINT;
+ aop = 0;
+ if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) {
+ // comparison is okay as long as one side is
+ // assignable to the other. convert so they have
+ // the same type.
+ //
+ // the only conversion that isn't a no-op is concrete == interface.
+ // in that case, check comparability of the concrete type.
+ // The conversion allocates, so only do it if the concrete type is huge.
+ if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
+ if(isinter(r->type) && !isinter(l->type) && algtype1(l->type, nil) == ANOEQ) {
+ yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(l->type));
+ goto error;
+ }
+ dowidth(l->type);
+ if(isinter(r->type) == isinter(l->type) || l->type->width >= 1<<16) {
+ l = nod(aop, l, N);
+ l->type = r->type;
+ l->typecheck = 1;
+ n->left = l;
+ }
+ t = r->type;
+ goto converted;
+ }
+ if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
+ if(isinter(l->type) && !isinter(r->type) && algtype1(r->type, nil) == ANOEQ) {
+ yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(r->type));
+ goto error;
+ }
+ dowidth(r->type);
+ if(isinter(r->type) == isinter(l->type) || r->type->width >= 1<<16) {
+ r = nod(aop, r, N);
+ r->type = l->type;
+ r->typecheck = 1;
+ n->right = r;
+ }
+ t = l->type;
+ }
+ converted:
+ et = t->etype;
+ }
+ if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
+ defaultlit2(&l, &r, 1);
+ if(n->op == OASOP && n->implicit) {
+ yyerror("invalid operation: %N (non-numeric type %T)", n, l->type);
+ goto error;
+ }
+ if(isinter(r->type) == isinter(l->type) || aop == 0) {
+ yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
+ goto error;
+ }
+ }
+ if(!okfor[op][et]) {
+ yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(t));
+ goto error;
+ }
+ // okfor allows any array == array, map == map, func == func.
+ // restrict to slice/map/func == nil and nil == slice/map/func.
+ if(isfixedarray(l->type) && algtype1(l->type, nil) == ANOEQ) {
+ yyerror("invalid operation: %N (%T cannot be compared)", n, l->type);
+ goto error;
+ }
+ if(isslice(l->type) && !isnil(l) && !isnil(r)) {
+ yyerror("invalid operation: %N (slice can only be compared to nil)", n);
+ goto error;
+ }
+ if(l->type->etype == TMAP && !isnil(l) && !isnil(r)) {
+ yyerror("invalid operation: %N (map can only be compared to nil)", n);
+ goto error;
+ }
+ if(l->type->etype == TFUNC && !isnil(l) && !isnil(r)) {
+ yyerror("invalid operation: %N (func can only be compared to nil)", n);
+ goto error;
+ }
+ if(l->type->etype == TSTRUCT && algtype1(l->type, &badtype) == ANOEQ) {
+ yyerror("invalid operation: %N (struct containing %T cannot be compared)", n, badtype);
+ goto error;
+ }
+
+ t = l->type;
+ if(iscmp[n->op]) {
+ evconst(n);
+ t = idealbool;
+ if(n->op != OLITERAL) {
+ defaultlit2(&l, &r, 1);
+ n->left = l;
+ n->right = r;
+ }
+ } else if(n->op == OANDAND || n->op == OOROR) {
+ if(l->type == r->type)
+ t = l->type;
+ else if(l->type == idealbool)
+ t = r->type;
+ else if(r->type == idealbool)
+ t = l->type;
+ // non-comparison operators on ideal bools should make them lose their ideal-ness
+ } else if(t == idealbool)
+ t = types[TBOOL];
+
+ if(et == TSTRING) {
+ if(iscmp[n->op]) {
+ n->etype = n->op;
+ n->op = OCMPSTR;
+ } else if(n->op == OADD) {
+ // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
+ n->op = OADDSTR;
+ if(l->op == OADDSTR)
+ n->list = l->list;
+ else
+ n->list = list1(l);
+ if(r->op == OADDSTR)
+ n->list = concat(n->list, r->list);
+ else
+ n->list = list(n->list, r);
+ n->left = N;
+ n->right = N;
+ }
+ }
+ if(et == TINTER) {
+ if(l->op == OLITERAL && l->val.ctype == CTNIL) {
+ // swap for back end
+ n->left = r;
+ n->right = l;
+ } else if(r->op == OLITERAL && r->val.ctype == CTNIL) {
+ // leave alone for back end
+ } else if(isinter(r->type) == isinter(l->type)) {
+ n->etype = n->op;
+ n->op = OCMPIFACE;
+ }
+ }
+
+ if((op == ODIV || op == OMOD) && isconst(r, CTINT))
+ if(mpcmpfixc(r->val.u.xval, 0) == 0) {
+ yyerror("division by zero");
+ goto error;
+ }
+
+ n->type = t;
+ goto ret;
+
+shift:
+ defaultlit(&r, types[TUINT]);
+ n->right = r;
+ t = r->type;
+ if(!isint[t->etype] || issigned[t->etype]) {
+ yyerror("invalid operation: %N (shift count type %T, must be unsigned integer)", n, r->type);
+ goto error;
+ }
+ t = l->type;
+ if(t != T && t->etype != TIDEAL && !isint[t->etype]) {
+ yyerror("invalid operation: %N (shift of type %T)", n, t);
+ goto error;
+ }
+ // no defaultlit for left
+ // the outer context gives the type
+ n->type = l->type;
+ goto ret;
+
+doconv:
+ ok |= Erv;
+ saveorignode(n);
+ typecheck(&n->left, Erv | (top & (Eindir | Eiota)));
+ convlit1(&n->left, n->type, 1);
+ if((t = n->left->type) == T || n->type == T)
+ goto error;
+ if((n->op = convertop(t, n->type, &why)) == 0) {
+ if(!n->diag && !n->type->broke) {
+ yyerror("cannot convert %lN to type %T%s", n->left, n->type, why);
+ n->diag = 1;
+ }
+ n->op = OCONV;
+ }
+ switch(n->op) {
+ case OCONVNOP:
+ if(n->left->op == OLITERAL && n->type != types[TBOOL]) {
+ r = nod(OXXX, N, N);
+ n->op = OCONV;
+ n->orig = r;
+ *r = *n;
+ n->op = OLITERAL;
+ n->val = n->left->val;
+ }
+ break;
+ case OSTRARRAYBYTE:
+ // do not use stringtoarraylit.
+ // generated code and compiler memory footprint is better without it.
+ break;
+ case OSTRARRAYRUNE:
+ if(n->left->op == OLITERAL)
+ stringtoarraylit(&n);
+ break;
+ }
+ goto ret;
ret:
t = n->type;
@@ -1913,7 +1931,7 @@ checkdefergo(Node *n)
case OPRINTN:
case ORECOVER:
// ok
- break;
+ return;
case OAPPEND:
case OCAP:
case OCOMPLEX:
@@ -1927,23 +1945,21 @@ checkdefergo(Node *n)
case OREAL:
case OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
if(n->left->orig != N && n->left->orig->op == OCONV)
- goto conv;
- yyerror("%s discards result of %N", what, n->left);
- break;
- default:
- conv:
- // type is broken or missing, most likely a method call on a broken type
- // we will warn about the broken type elsewhere. no need to emit a potentially confusing error
- if(n->left->type == T || n->left->type->broke)
break;
+ yyerror("%s discards result of %N", what, n->left);
+ return;
+ }
- if(!n->diag) {
- // The syntax made sure it was a call, so this must be
- // a conversion.
- n->diag = 1;
- yyerror("%s requires function call, not conversion", what);
- }
- break;
+ // type is broken or missing, most likely a method call on a broken type
+ // we will warn about the broken type elsewhere. no need to emit a potentially confusing error
+ if(n->left->type == T || n->left->type->broke)
+ return;
+
+ if(!n->diag) {
+ // The syntax made sure it was a call, so this must be
+ // a conversion.
+ n->diag = 1;
+ yyerror("%s requires function call, not conversion", what);
}
}
@@ -3036,15 +3052,20 @@ typecheckas2(Node *n)
goto out;
switch(r->op) {
case OINDEXMAP:
- n->op = OAS2MAPR;
- goto common;
case ORECV:
- n->op = OAS2RECV;
- goto common;
case ODOTTYPE:
- n->op = OAS2DOTTYPE;
- r->op = ODOTTYPE2;
- common:
+ switch(r->op) {
+ case OINDEXMAP:
+ n->op = OAS2MAPR;
+ break;
+ case ORECV:
+ n->op = OAS2RECV;
+ break;
+ case ODOTTYPE:
+ n->op = OAS2DOTTYPE;
+ r->op = ODOTTYPE2;
+ break;
+ }
if(l->type != T)
checkassignto(r->type, l);
if(l->defn == n)
@@ -3293,6 +3314,8 @@ typecheckdef(Node *n)
n->diag = 1;
if(n->lineno != 0)
lineno = n->lineno;
+ // Note: adderrorname looks for this string and
+ // adds context about the outer expression
yyerror("undefined: %S", n->sym);
}
return n;
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index efb283a1b8..0e69f88b66 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -628,6 +628,26 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OCALLFUNC:
+ if(n->left->op == OCLOSURE) {
+ // Transform direct call of a closure to call of a normal function.
+ // transformclosure already did all preparation work.
+
+ // Append captured variables to argument list.
+ n->list = concat(n->list, n->left->enter);
+ n->left->enter = NULL;
+ // Replace OCLOSURE with ONAME/PFUNC.
+ n->left = n->left->closure->nname;
+ // Update type of OCALLFUNC node.
+ // Output arguments had not changed, but their offsets could.
+ if(n->left->type->outtuple == 1) {
+ t = getoutargx(n->left->type)->type;
+ if(t->etype == TFIELD)
+ t = t->type;
+ n->type = t;
+ } else
+ n->type = getoutargx(n->left->type);
+ }
+
t = n->left->type;
if(n->list && n->list->n->op == OAS)
goto ret;
@@ -927,7 +947,7 @@ walkexpr(Node **np, NodeList **init)
l->class = PEXTERN;
l->xoffset = 0;
sym->def = l;
- arch.ggloblsym(sym, widthptr, DUPOK|NOPTR);
+ ggloblsym(sym, widthptr, DUPOK|NOPTR);
}
l = nod(OADDR, sym->def, N);
l->addable = 1;
@@ -995,7 +1015,7 @@ walkexpr(Node **np, NodeList **init)
case OCONV:
case OCONVNOP:
- if(arch.thechar == '5') {
+ if(thearch.thechar == '5') {
if(isfloat[n->left->type->etype]) {
if(n->type->etype == TINT64) {
n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
@@ -1273,6 +1293,7 @@ walkexpr(Node **np, NodeList **init)
conv(n->right, types[TSTRING]));
// quick check of len before full compare for == or !=
+ // eqstring assumes that the lengths are equal
if(n->etype == OEQ) {
// len(left) == len(right) && eqstring(left, right)
r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
@@ -1329,12 +1350,32 @@ walkexpr(Node **np, NodeList **init)
t = n->type;
fn = syslook("makemap", 1);
- argtype(fn, t->down); // any-1
- argtype(fn, t->type); // any-2
- n = mkcall1(fn, n->type, init,
- typename(n->type),
- conv(n->left, types[TINT64]));
+ a = nodnil(); // hmap buffer
+ r = nodnil(); // bucket buffer
+ if(n->esc == EscNone) {
+ // Allocate hmap buffer on stack.
+ var = temp(hmap(t));
+ a = nod(OAS, var, N); // zero temp
+ typecheck(&a, Etop);
+ *init = list(*init, a);
+ a = nod(OADDR, var, N);
+
+ // Allocate one bucket on stack.
+ // Maximum key/value size is 128 bytes, larger objects
+ // are stored with an indirection. So max bucket size is 2048+eps.
+ var = temp(mapbucket(t));
+ r = nod(OAS, var, N); // zero temp
+ typecheck(&r, Etop);
+ *init = list(*init, r);
+ r = nod(OADDR, var, N);
+ }
+
+ argtype(fn, hmap(t)); // hmap buffer
+ argtype(fn, mapbucket(t)); // bucket buffer
+ argtype(fn, t->down); // key type
+ argtype(fn, t->type); // value type
+ n = mkcall1(fn, n->type, init, typename(n->type), conv(n->left, types[TINT64]), a, r);
goto ret;
case OMAKESLICE:
@@ -1397,13 +1438,25 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OARRAYRUNESTR:
- // slicerunetostring([]rune) string;
- n = mkcall("slicerunetostring", n->type, init, n->left);
+ // slicerunetostring(*[32]byte, []rune) string;
+ a = nodnil();
+ if(n->esc == EscNone) {
+ // Create temporary buffer for string on stack.
+ t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]);
+ a = nod(OADDR, temp(t), N);
+ }
+ n = mkcall("slicerunetostring", n->type, init, a, n->left);
goto ret;
case OSTRARRAYBYTE:
- // stringtoslicebyte(string) []byte;
- n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING]));
+ // stringtoslicebyte(*32[byte], string) []byte;
+ a = nodnil();
+ if(n->esc == EscNone) {
+ // Create temporary buffer for slice on stack.
+ t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]);
+ a = nod(OADDR, temp(t), N);
+ }
+ n = mkcall("stringtoslicebyte", n->type, init, a, conv(n->left, types[TSTRING]));
goto ret;
case OSTRARRAYBYTETMP:
@@ -1412,8 +1465,14 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OSTRARRAYRUNE:
- // stringtoslicerune(string) []rune
- n = mkcall("stringtoslicerune", n->type, init, n->left);
+ // stringtoslicerune(*[32]rune, string) []rune
+ a = nodnil();
+ if(n->esc == EscNone) {
+ // Create temporary buffer for slice on stack.
+ t = aindex(nodintconst(tmpstringbufsize), types[TINT32]);
+ a = nod(OADDR, temp(t), N);
+ }
+ n = mkcall("stringtoslicerune", n->type, init, a, n->left);
goto ret;
case OCMPIFACE:
@@ -1601,7 +1660,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
l = tmp;
}
- a = nod(OAS, l, arch.nodarg(r, fp));
+ a = nod(OAS, l, nodarg(r, fp));
a = convas(a, init);
ullmancalc(a);
if(a->ullman >= UINF) {
@@ -1654,7 +1713,7 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, Nod
walkexpr(&n, init);
}
- a = nod(OAS, arch.nodarg(l, fp), n);
+ a = nod(OAS, nodarg(l, fp), n);
nn = list(nn, convas(a, init));
return nn;
}
@@ -1734,7 +1793,7 @@ ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeL
if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
// optimization - can do block copy
if(eqtypenoname(r->type, *nl)) {
- a = arch.nodarg(*nl, fp);
+ a = nodarg(*nl, fp);
r = nod(OCONVNOP, r, N);
r->type = a->type;
nn = list1(convas(nod(OAS, a, r), init));
@@ -1771,7 +1830,7 @@ loop:
// argument to a ddd parameter then it is
// passed thru unencapsulated
if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) {
- a = nod(OAS, arch.nodarg(l, fp), r);
+ a = nod(OAS, nodarg(l, fp), r);
a = convas(a, init);
nn = list(nn, a);
goto ret;
@@ -1796,7 +1855,7 @@ loop:
goto ret;
}
- a = nod(OAS, arch.nodarg(l, fp), r);
+ a = nod(OAS, nodarg(l, fp), r);
a = convas(a, init);
nn = list(nn, a);
@@ -1944,8 +2003,7 @@ isstack(Node *n)
{
Node *defn;
- while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
- n = n->left;
+ n = outervalue(n);
// If n is *autotmp and autotmp = &foo, replace n with foo.
// We introduce such temps when initializing struct literals.
@@ -1976,8 +2034,7 @@ isstack(Node *n)
static int
isglobal(Node *n)
{
- while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
- n = n->left;
+ n = outervalue(n);
switch(n->op) {
case ONAME:
@@ -2336,7 +2393,9 @@ Node*
outervalue(Node *n)
{
for(;;) {
- if(n->op == ODOT || n->op == OPAREN) {
+ if(n->op == OXDOT)
+ fatal("OXDOT in walk");
+ if(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP) {
n = n->left;
continue;
}
@@ -2559,7 +2618,7 @@ paramstoheap(Type **argin, int out)
// Defer might stop a panic and show the
// return values as they exist at the time of panic.
// Make sure to zero them on entry to the function.
- nn = list(nn, nod(OAS, arch.nodarg(t, 1), N));
+ nn = list(nn, nod(OAS, nodarg(t, 1), N));
}
if(v == N || !(v->class & PHEAP))
continue;
@@ -3300,10 +3359,51 @@ static void
walkcompare(Node **np, NodeList **init)
{
Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr;
+ Node *x, *ok;
int andor, i, needsize;
Type *t, *t1;
n = *np;
+
+ // Given interface value l and concrete value r, rewrite
+ // l == r
+ // to
+ // x, ok := l.(type(r)); ok && x == r
+ // Handle != similarly.
+ // This avoids the allocation that would be required
+ // to convert r to l for comparison.
+ l = N;
+ r = N;
+ if(isinter(n->left->type) && !isinter(n->right->type)) {
+ l = n->left;
+ r = n->right;
+ } else if(!isinter(n->left->type) && isinter(n->right->type)) {
+ l = n->right;
+ r = n->left;
+ }
+ if(l != N) {
+ x = temp(r->type);
+ ok = temp(types[TBOOL]);
+
+ // l.(type(r))
+ a = nod(ODOTTYPE, l, N);
+ a->type = r->type;
+
+ // x, ok := l.(type(r))
+ expr = nod(OAS2, N, N);
+ expr->list = list1(x);
+ expr->list = list(expr->list, ok);
+ expr->rlist = list1(a);
+ typecheck(&expr, Etop);
+ walkexpr(&expr, init);
+
+ if(n->op == OEQ)
+ r = nod(OANDAND, ok, nod(OEQ, x, r));
+ else
+ r = nod(OOROR, nod(ONOT, ok, N), nod(ONE, x, r));
+ *init = list(*init, expr);
+ goto ret;
+ }
// Must be comparison of array or struct.
// Otherwise back end handles it.
@@ -3447,7 +3547,7 @@ walkrotate(Node **np)
Node *l, *r;
Node *n;
- if(arch.thechar == '9')
+ if(thearch.thechar == '9')
return;
n = *np;
@@ -3575,7 +3675,7 @@ walkdiv(Node **np, NodeList **init)
Magic m;
// TODO(minux)
- if(arch.thechar == '9')
+ if(thearch.thechar == '9')
return;
n = *np;
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index 398f83d113..7c92389767 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -14,32 +14,32 @@ Usage:
The commands are:
- build compile packages and dependencies
- clean remove object files
- env print Go environment information
- fix run go tool fix on packages
- fmt run gofmt on package sources
- generate generate Go files by processing source
- get download and install packages and dependencies
- install compile and install packages and dependencies
- list list packages
- run compile and run Go program
- test test packages
- tool run specified go tool
- version print Go version
- vet run go tool vet on packages
+ build compile packages and dependencies
+ clean remove object files
+ env print Go environment information
+ fix run go tool fix on packages
+ fmt run gofmt on package sources
+ generate generate Go files by processing source
+ get download and install packages and dependencies
+ install compile and install packages and dependencies
+ list list packages
+ run compile and run Go program
+ test test packages
+ tool run specified go tool
+ version print Go version
+ vet run go tool vet on packages
Use "go help [command]" for more information about a command.
Additional help topics:
- c calling between Go and C
- filetype file types
- gopath GOPATH environment variable
- importpath import path syntax
- packages description of package lists
- testflag description of testing flags
- testfunc description of testing functions
+ c calling between Go and C
+ filetype file types
+ gopath GOPATH environment variable
+ importpath import path syntax
+ packages description of package lists
+ testflag description of testing flags
+ testfunc description of testing functions
Use "go help [topic]" for more information about that topic.
@@ -310,6 +310,7 @@ The generator is run in the package's source directory.
Go generate accepts one specific flag:
-run=""
+ TODO: This flag is unimplemented.
if non-empty, specifies a regular expression to
select directives whose command matches the expression.
diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go
index 8c1e3ee230..3c0af8760b 100644
--- a/src/cmd/go/generate.go
+++ b/src/cmd/go/generate.go
@@ -106,6 +106,7 @@ The generator is run in the package's source directory.
Go generate accepts one specific flag:
-run=""
+ TODO: This flag is unimplemented.
if non-empty, specifies a regular expression to
select directives whose command matches the expression.
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 1482a39582..d5e86395a2 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -180,13 +180,13 @@ Usage:
The commands are:
{{range .}}{{if .Runnable}}
- {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+ {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [command]" for more information about a command.
Additional help topics:
{{range .}}{{if not .Runnable}}
- {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+ {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [topic]" for more information about that topic.
diff --git a/src/cmd/go/mkdoc.sh b/src/cmd/go/mkdoc.sh
index e15e8809ce..507a8aeddc 100755
--- a/src/cmd/go/mkdoc.sh
+++ b/src/cmd/go/mkdoc.sh
@@ -1,9 +1,12 @@
-#!/bin/sh
+#!/bin/bash
# Copyright 2012 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.
-go install # So the next line will produce updated documentation.
-go help documentation | sed 's; \*/; * /;' >doc.go
+set -e
+
+go build -o go.latest
+./go.latest help documentation | sed 's; \*/; * /;' >doc.go
gofmt -w doc.go
+rm go.latest
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index 60f6b16c9a..a8110f385d 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -346,11 +346,11 @@ func runTest(cmd *Command, args []string) {
// been given on the command line (implicit current directory)
// or when benchmarking.
// Also stream if we're showing output anyway with a
- // single package under test. In that case, streaming the
- // output produces the same result as not streaming,
- // just more immediately.
+ // single package under test or if parallelism is set to 1.
+ // In these cases, streaming the output produces the same result
+ // as not streaming, just more immediately.
testStreamOutput = len(pkgArgs) == 0 || testBench ||
- (len(pkgs) <= 1 && testShowPass)
+ (testShowPass && (len(pkgs) == 1 || buildP == 1))
var b builder
b.init()
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 3fc0439548..9d0cd32862 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -87,6 +87,13 @@ When invoked with -s gofmt will make the following source transformations where
for x, _ = range v {...}
will be simplified to:
for x = range v {...}
+
+ A range of the form:
+ for _ = range v {...}
+ will be simplified to:
+ for range v {...}
+
+This may result in changes that are incompatible with earlier versions of Go.
*/
package main
diff --git a/src/cmd/ld/Makefile b/src/cmd/ld/Makefile
new file mode 100644
index 0000000000..3f528d7517
--- /dev/null
+++ b/src/cmd/ld/Makefile
@@ -0,0 +1,5 @@
+# Copyright 2012 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 ../../Make.dist
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 0f287c202f..580d36f7e2 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -30,11 +30,14 @@
// Data layout and relocation.
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-#include "../ld/macho.h"
-#include "../ld/pe.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "lib.h"
+#include "elf.h"
+#include "macho.h"
+#include "pe.h"
#include "../../runtime/mgc0.h"
void dynreloc(void);
@@ -150,7 +153,7 @@ relocsym(LSym *s)
diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np);
continue;
}
- if(r->sym != S && ((r->sym->type & (SMASK | SHIDDEN)) == 0 || (r->sym->type & SMASK) == SXREF)) {
+ if(r->sym != nil && ((r->sym->type & (SMASK | SHIDDEN)) == 0 || (r->sym->type & SMASK) == SXREF)) {
diag("%s: not defined", r->sym->name);
continue;
}
@@ -160,9 +163,9 @@ relocsym(LSym *s)
continue;
// Solaris needs the ability to reference dynimport symbols.
- if(HEADTYPE != Hsolaris && r->sym != S && r->sym->type == SDYNIMPORT)
+ if(HEADTYPE != Hsolaris && r->sym != nil && r->sym->type == SDYNIMPORT)
diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type);
- if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable)
+ if(r->sym != nil && r->sym->type != STLSBSS && !r->sym->reachable)
diag("unreachable sym in relocation: %s %s", s->name, r->sym->name);
// Android emulates runtime.tlsg as a regular variable.
@@ -172,11 +175,11 @@ relocsym(LSym *s)
switch(r->type) {
default:
o = 0;
- if(archreloc(r, s, &o) < 0)
+ if(thearch.archreloc(r, s, &o) < 0)
diag("unknown reloc %d", r->type);
break;
case R_TLS:
- if(linkmode == LinkInternal && iself && thechar == '5') {
+ if(linkmode == LinkInternal && iself && thearch.thechar == '5') {
// On ELF ARM, the thread pointer is 8 bytes before
// the start of the thread-local data block, so add 8
// to the actual TLS offset (r->sym->value).
@@ -189,7 +192,7 @@ relocsym(LSym *s)
}
r->done = 0;
o = 0;
- if(thechar != '6')
+ if(thearch.thechar != '6')
o = r->add;
break;
case R_TLS_LE:
@@ -199,7 +202,7 @@ relocsym(LSym *s)
r->xsym = ctxt->tlsg;
r->xadd = r->add;
o = 0;
- if(thechar != '6')
+ if(thearch.thechar != '6')
o = r->add;
break;
}
@@ -213,7 +216,7 @@ relocsym(LSym *s)
r->xsym = ctxt->tlsg;
r->xadd = r->add;
o = 0;
- if(thechar != '6')
+ if(thearch.thechar != '6')
o = r->add;
break;
}
@@ -241,7 +244,7 @@ relocsym(LSym *s)
o = r->xadd;
if(iself) {
- if(thechar == '6')
+ if(thearch.thechar == '6')
o = 0;
} else if(HEADTYPE == Hdarwin) {
if(rs->type != SHOSTOBJ)
@@ -258,7 +261,7 @@ relocsym(LSym *s)
// fail at runtime. See http://golang.org/issue/7980.
// Instead of special casing only amd64, we treat this as an error on all
// 64-bit architectures so as to be future-proof.
- if((int32)o < 0 && PtrSize > 4 && siz == 4) {
+ if((int32)o < 0 && thearch.ptrsize > 4 && siz == 4) {
diag("non-pc-relative relocation address is too big: %#llux", o);
errorexit();
}
@@ -283,7 +286,7 @@ relocsym(LSym *s)
o = r->xadd;
if(iself) {
- if(thechar == '6')
+ if(thearch.thechar == '6')
o = 0;
} else if(HEADTYPE == Hdarwin) {
if(r->type == R_CALL) {
@@ -314,7 +317,7 @@ relocsym(LSym *s)
break;
}
if(r->variant != RV_NONE)
- o = archrelocvariant(r, s, o);
+ o = thearch.archrelocvariant(r, s, o);
//print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "<nil>", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o);
switch(siz) {
default:
@@ -363,9 +366,9 @@ reloc(void)
Bprint(&bso, "%5.2f reloc\n", cputime());
Bflush(&bso);
- for(s=ctxt->textp; s!=S; s=s->next)
+ for(s=ctxt->textp; s!=nil; s=s->next)
relocsym(s);
- for(s=datap; s!=S; s=s->next)
+ for(s=datap; s!=nil; s=s->next)
relocsym(s);
}
@@ -392,7 +395,7 @@ dynrelocsym(LSym *s)
r->add = targ->plt;
// jmp *addr
- if(thechar == '8') {
+ if(thearch.thechar == '8') {
adduint8(ctxt, rel, 0xff);
adduint8(ctxt, rel, 0x25);
addaddr(ctxt, rel, targ);
@@ -414,10 +417,10 @@ dynrelocsym(LSym *s)
}
for(r=s->r; r<s->r+s->nr; r++) {
- if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) {
- if(r->sym != S && !r->sym->reachable)
+ if(r->sym != nil && r->sym->type == SDYNIMPORT || r->type >= 256) {
+ if(r->sym != nil && !r->sym->reachable)
diag("internal inconsistency: dynamic symbol %s is not reachable.", r->sym->name);
- adddynrel(s, r);
+ thearch.adddynrel(s, r);
}
}
}
@@ -435,9 +438,9 @@ dynreloc(void)
Bprint(&bso, "%5.2f reloc\n", cputime());
Bflush(&bso);
- for(s=ctxt->textp; s!=S; s=s->next)
+ for(s=ctxt->textp; s!=nil; s=s->next)
dynrelocsym(s);
- for(s=datap; s!=S; s=s->next)
+ for(s=datap; s!=nil; s=s->next)
dynrelocsym(s);
if(iself)
elfdynhash();
@@ -650,7 +653,7 @@ addstrdata(char *name, char *value)
s->dupok = 1;
reachable = s->reachable;
addaddr(ctxt, s, sp);
- adduintxx(ctxt, s, strlen(value), PtrSize);
+ adduintxx(ctxt, s, strlen(value), thearch.ptrsize);
// addstring, addaddr, etc., mark the symbols as reachable.
// In this case that is not necessarily true, so stick to what
@@ -701,7 +704,7 @@ symalign(LSym *s)
if(s->align != 0)
return s->align;
- align = MaxAlign;
+ align = thearch.maxalign;
while(align > s->size && align > 1)
align >>= 1;
if(align < s->align)
@@ -723,7 +726,7 @@ maxalign(LSym *s, int type)
int32 align, max;
max = 0;
- for(; s != S && s->type <= type; s = s->next) {
+ for(; s != nil && s->type <= type; s = s->next) {
align = symalign(s);
if(max < align)
max = align;
@@ -789,7 +792,7 @@ proggenskip(ProgGen *g, vlong off, vlong v)
vlong i;
for(i = off; i < off+v; i++) {
- if((i%PtrSize) == 0)
+ if((i%thearch.ptrsize) == 0)
proggendata(g, BitsScalar);
}
}
@@ -802,7 +805,7 @@ proggenarray(ProgGen *g, vlong len)
proggendataflush(g);
proggenemit(g, insArray);
- for(i = 0; i < PtrSize; i++, len >>= 8)
+ for(i = 0; i < thearch.ptrsize; i++, len >>= 8)
proggenemit(g, len);
}
@@ -843,39 +846,39 @@ proggenaddsym(ProgGen *g, LSym *s)
// and not SDATA, but sometimes that doesn't happen.
// Leave debugging the SDATA issue for the Go rewrite.
- if(s->gotype == nil && s->size >= PtrSize && s->name[0] != '.') {
+ if(s->gotype == nil && s->size >= thearch.ptrsize && s->name[0] != '.') {
// conservative scan
diag("missing Go type information for global symbol: %s size %d", s->name, (int)s->size);
- if((s->size%PtrSize) || (g->pos%PtrSize))
+ if((s->size%thearch.ptrsize) || (g->pos%thearch.ptrsize))
diag("proggenaddsym: unaligned conservative symbol %s: size=%lld pos=%lld",
s->name, s->size, g->pos);
- size = (s->size+PtrSize-1)/PtrSize*PtrSize;
- if(size < 32*PtrSize) {
+ size = (s->size+thearch.ptrsize-1)/thearch.ptrsize*thearch.ptrsize;
+ if(size < 32*thearch.ptrsize) {
// Emit small symbols as data.
- for(i = 0; i < size/PtrSize; i++)
+ for(i = 0; i < size/thearch.ptrsize; i++)
proggendata(g, BitsPointer);
} else {
// Emit large symbols as array.
- proggenarray(g, size/PtrSize);
+ proggenarray(g, size/thearch.ptrsize);
proggendata(g, BitsPointer);
proggenarrayend(g);
}
g->pos = s->value + size;
- } else if(s->gotype == nil || decodetype_noptr(s->gotype) || s->size < PtrSize || s->name[0] == '.') {
+ } else if(s->gotype == nil || decodetype_noptr(s->gotype) || s->size < thearch.ptrsize || s->name[0] == '.') {
// no scan
- if(s->size < 32*PtrSize) {
+ if(s->size < 32*thearch.ptrsize) {
// Emit small symbols as data.
// This case also handles unaligned and tiny symbols, so tread carefully.
for(i = s->value; i < s->value+s->size; i++) {
- if((i%PtrSize) == 0)
+ if((i%thearch.ptrsize) == 0)
proggendata(g, BitsScalar);
}
} else {
// Emit large symbols as array.
- if((s->size%PtrSize) || (g->pos%PtrSize))
+ if((s->size%thearch.ptrsize) || (g->pos%thearch.ptrsize))
diag("proggenaddsym: unaligned noscan symbol %s: size=%lld pos=%lld",
s->name, s->size, g->pos);
- proggenarray(g, s->size/PtrSize);
+ proggenarray(g, s->size/thearch.ptrsize);
proggendata(g, BitsScalar);
proggenarrayend(g);
}
@@ -885,7 +888,7 @@ proggenaddsym(ProgGen *g, LSym *s)
proggendataflush(g);
gcprog = decodetype_gcprog(s->gotype);
size = decodetype_size(s->gotype);
- if((size%PtrSize) || (g->pos%PtrSize))
+ if((size%thearch.ptrsize) || (g->pos%thearch.ptrsize))
diag("proggenaddsym: unaligned gcprog symbol %s: size=%lld pos=%lld",
s->name, s->size, g->pos);
for(i = 0; i < gcprog->np-1; i++)
@@ -895,11 +898,11 @@ proggenaddsym(ProgGen *g, LSym *s)
// gc mask, it's small so emit as data
mask = decodetype_gcmask(s->gotype);
size = decodetype_size(s->gotype);
- if((size%PtrSize) || (g->pos%PtrSize))
+ if((size%thearch.ptrsize) || (g->pos%thearch.ptrsize))
diag("proggenaddsym: unaligned gcmask symbol %s: size=%lld pos=%lld",
s->name, s->size, g->pos);
- for(i = 0; i < size; i += PtrSize)
- proggendata(g, (mask[i/PtrSize/2]>>((i/PtrSize%2)*4+2))&BitsMask);
+ for(i = 0; i < size; i += thearch.ptrsize)
+ proggendata(g, (mask[i/thearch.ptrsize/2]>>((i/thearch.ptrsize%2)*4+2))&BitsMask);
g->pos = s->value + size;
}
}
@@ -935,7 +938,7 @@ dodata(void)
last = nil;
datap = nil;
- for(s=ctxt->allsym; s!=S; s=s->allsym) {
+ for(s=ctxt->allsym; s!=nil; s=s->allsym) {
if(!s->reachable || s->special)
continue;
if(STEXT < s->type && s->type < SXREF) {
@@ -1134,7 +1137,7 @@ dodata(void)
if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) {
sect = addsection(&segdata, ".tbss", 06);
- sect->align = PtrSize;
+ sect->align = thearch.ptrsize;
sect->vaddr = 0;
datsize = 0;
for(; s != nil && s->type == STLSBSS; s = s->next) {
@@ -1311,9 +1314,9 @@ textaddress(void)
else
va = rnd(va, funcalign);
sym->value = 0;
- for(sub = sym; sub != S; sub = sub->sub)
+ for(sub = sym; sub != nil; sub = sub->sub)
sub->value += va;
- if(sym->size == 0 && sym->sub != S)
+ if(sym->size == 0 && sym->sub != nil)
ctxt->cursym = sym;
if(sym->size < MINFUNC)
va += MINFUNC; // spacing required for findfunctab
diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c
index eedb246789..c194a1f767 100644
--- a/src/cmd/ld/decodesym.c
+++ b/src/cmd/ld/decodesym.c
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "l.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
#include "lib.h"
#include "../../runtime/typekind.h"
@@ -70,42 +73,42 @@ decode_inuxi(uchar* p, int sz)
static int
commonsize(void)
{
- return 8*PtrSize + 8;
+ return 8*thearch.ptrsize + 8;
}
// Type.commonType.kind
uint8
decodetype_kind(LSym *s)
{
- return s->p[1*PtrSize + 7] & KindMask; // 0x13 / 0x1f
+ return s->p[1*thearch.ptrsize + 7] & KindMask; // 0x13 / 0x1f
}
// Type.commonType.kind
uint8
decodetype_noptr(LSym *s)
{
- return s->p[1*PtrSize + 7] & KindNoPointers; // 0x13 / 0x1f
+ return s->p[1*thearch.ptrsize + 7] & KindNoPointers; // 0x13 / 0x1f
}
// Type.commonType.kind
uint8
decodetype_usegcprog(LSym *s)
{
- return s->p[1*PtrSize + 7] & KindGCProg; // 0x13 / 0x1f
+ return s->p[1*thearch.ptrsize + 7] & KindGCProg; // 0x13 / 0x1f
}
// Type.commonType.size
vlong
decodetype_size(LSym *s)
{
- return decode_inuxi(s->p, PtrSize); // 0x8 / 0x10
+ return decode_inuxi(s->p, thearch.ptrsize); // 0x8 / 0x10
}
// Type.commonType.gc
LSym*
decodetype_gcprog(LSym *s)
{
- return decode_reloc_sym(s, 1*PtrSize + 8 + 2*PtrSize);
+ return decode_reloc_sym(s, 1*thearch.ptrsize + 8 + 2*thearch.ptrsize);
}
uint8*
@@ -113,7 +116,7 @@ decodetype_gcmask(LSym *s)
{
LSym *mask;
- mask = decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize);
+ mask = decode_reloc_sym(s, 1*thearch.ptrsize + 8 + 1*thearch.ptrsize);
return mask->p;
}
@@ -127,7 +130,7 @@ decodetype_arrayelem(LSym *s)
vlong
decodetype_arraylen(LSym *s)
{
- return decode_inuxi(s->p + commonsize()+2*PtrSize, PtrSize);
+ return decode_inuxi(s->p + commonsize()+2*thearch.ptrsize, thearch.ptrsize);
}
// Type.PtrType.elem
@@ -147,7 +150,7 @@ decodetype_mapkey(LSym *s)
LSym*
decodetype_mapvalue(LSym *s)
{
- return decode_reloc_sym(s, commonsize()+PtrSize); // 0x20 / 0x38
+ return decode_reloc_sym(s, commonsize()+thearch.ptrsize); // 0x20 / 0x38
}
// Type.ChanType.elem
@@ -168,13 +171,13 @@ decodetype_funcdotdotdot(LSym *s)
int
decodetype_funcincount(LSym *s)
{
- return decode_inuxi(s->p + commonsize()+2*PtrSize, IntSize);
+ return decode_inuxi(s->p + commonsize()+2*thearch.ptrsize, thearch.intsize);
}
int
decodetype_funcoutcount(LSym *s)
{
- return decode_inuxi(s->p + commonsize()+3*PtrSize + 2*IntSize, IntSize);
+ return decode_inuxi(s->p + commonsize()+3*thearch.ptrsize + 2*thearch.intsize, thearch.intsize);
}
LSym*
@@ -182,10 +185,10 @@ decodetype_funcintype(LSym *s, int i)
{
Reloc *r;
- r = decode_reloc(s, commonsize() + PtrSize);
+ r = decode_reloc(s, commonsize() + thearch.ptrsize);
if (r == nil)
return nil;
- return decode_reloc_sym(r->sym, r->add + i * PtrSize);
+ return decode_reloc_sym(r->sym, r->add + i * thearch.ptrsize);
}
LSym*
@@ -193,23 +196,23 @@ decodetype_funcouttype(LSym *s, int i)
{
Reloc *r;
- r = decode_reloc(s, commonsize() + 2*PtrSize + 2*IntSize);
+ r = decode_reloc(s, commonsize() + 2*thearch.ptrsize + 2*thearch.intsize);
if (r == nil)
return nil;
- return decode_reloc_sym(r->sym, r->add + i * PtrSize);
+ return decode_reloc_sym(r->sym, r->add + i * thearch.ptrsize);
}
// Type.StructType.fields.Slice::len
int
decodetype_structfieldcount(LSym *s)
{
- return decode_inuxi(s->p + commonsize() + PtrSize, IntSize);
+ return decode_inuxi(s->p + commonsize() + thearch.ptrsize, thearch.intsize);
}
static int
structfieldsize(void)
{
- return 5*PtrSize;
+ return 5*thearch.ptrsize;
}
// Type.StructType.fields[]-> name, typ and offset.
@@ -219,7 +222,7 @@ decodetype_structfieldname(LSym *s, int i)
Reloc *r;
// go.string."foo" 0x28 / 0x40
- s = decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize());
+ s = decode_reloc_sym(s, commonsize() + thearch.ptrsize + 2*thearch.intsize + i*structfieldsize());
if (s == nil) // embedded structs have a nil name.
return nil;
r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0
@@ -231,18 +234,18 @@ decodetype_structfieldname(LSym *s, int i)
LSym*
decodetype_structfieldtype(LSym *s, int i)
{
- return decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 2*PtrSize);
+ return decode_reloc_sym(s, commonsize() + thearch.ptrsize + 2*thearch.intsize + i*structfieldsize() + 2*thearch.ptrsize);
}
vlong
decodetype_structfieldoffs(LSym *s, int i)
{
- return decode_inuxi(s->p + commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 4*PtrSize, IntSize);
+ return decode_inuxi(s->p + commonsize() + thearch.ptrsize + 2*thearch.intsize + i*structfieldsize() + 4*thearch.ptrsize, thearch.intsize);
}
// InterfaceTYpe.methods.len
vlong
decodetype_ifacemethodcount(LSym *s)
{
- return decode_inuxi(s->p + commonsize() + PtrSize, IntSize);
+ return decode_inuxi(s->p + commonsize() + thearch.ptrsize, thearch.intsize);
}
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index 061171ea0b..53f0194b31 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -12,13 +12,16 @@
// - file:line info for variables
// - make strings a typedef so prettyprinters can see the underlying string type
//
-#include "l.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
#include "lib.h"
-#include "../ld/dwarf.h"
-#include "../ld/dwarf_defs.h"
-#include "../ld/elf.h"
-#include "../ld/macho.h"
-#include "../ld/pe.h"
+#include "dwarf.h"
+#include "dwarf_defs.h"
+#include "elf.h"
+#include "macho.h"
+#include "pe.h"
#include "../../runtime/typekind.h"
/*
@@ -75,12 +78,12 @@ static char gdbscript[1024];
static void
addrput(vlong addr)
{
- switch(PtrSize) {
+ switch(thearch.ptrsize) {
case 4:
- LPUT(addr);
+ thearch.lput(addr);
break;
case 8:
- VPUT(addr);
+ thearch.vput(addr);
break;
}
}
@@ -629,14 +632,14 @@ adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend)
r->type = R_ADDR;
r->add = addend;
r->xadd = addend;
- if(iself && thechar == '6')
+ if(iself && thearch.thechar == '6')
addend = 0;
switch(siz) {
case 4:
- LPUT(addend);
+ thearch.lput(addend);
break;
case 8:
- VPUT(addend);
+ thearch.vput(addend);
break;
default:
diag("bad size in adddwarfrel");
@@ -663,7 +666,7 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
case DW_FORM_addr: // address
if(linkmode == LinkExternal) {
value -= ((LSym*)data)->value;
- adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
+ adddwarfrel(infosec, (LSym*)data, infoo, thearch.ptrsize, value);
break;
}
addrput(value);
@@ -671,11 +674,11 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
case DW_FORM_block1: // block
if(cls == DW_CLS_ADDRESS) {
- cput(1+PtrSize);
+ cput(1+thearch.ptrsize);
cput(DW_OP_addr);
if(linkmode == LinkExternal) {
value -= ((LSym*)data)->value;
- adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
+ adddwarfrel(infosec, (LSym*)data, infoo, thearch.ptrsize, value);
break;
}
addrput(value);
@@ -689,14 +692,14 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
case DW_FORM_block2: // block
value &= 0xffff;
- WPUT(value);
+ thearch.wput(value);
while(value--)
cput(*data++);
break;
case DW_FORM_block4: // block
value &= 0xffffffff;
- LPUT(value);
+ thearch.lput(value);
while(value--)
cput(*data++);
break;
@@ -712,7 +715,7 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
break;
case DW_FORM_data2: // constant
- WPUT(value);
+ thearch.wput(value);
break;
case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
@@ -720,11 +723,11 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
adddwarfrel(infosec, linesym, infoo, 4, value);
break;
}
- LPUT(value);
+ thearch.lput(value);
break;
case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
- VPUT(value);
+ thearch.vput(value);
break;
case DW_FORM_sdata: // constant
@@ -750,16 +753,16 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
// (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
if (data == nil) {
diag("dwarf: null reference in %d", abbrev);
- if(PtrSize == 8)
- VPUT(0); // invalid dwarf, gdb will complain.
+ if(thearch.ptrsize == 8)
+ thearch.vput(0); // invalid dwarf, gdb will complain.
else
- LPUT(0); // invalid dwarf, gdb will complain.
+ thearch.lput(0); // invalid dwarf, gdb will complain.
} else {
off = ((DWDie*)data)->offs;
if (off == 0)
fwdcount++;
if(linkmode == LinkExternal) {
- adddwarfrel(infosec, infosym, infoo, PtrSize, off);
+ adddwarfrel(infosec, infosym, infoo, thearch.ptrsize, off);
break;
}
addrput(off);
@@ -1236,17 +1239,17 @@ synthesizemaptypes(DWDie *die)
// compute size info like hashmap.c does.
a = getattr(keytype, DW_AT_byte_size);
- keysize = a ? a->value : PtrSize; // We don't store size with Pointers
+ keysize = a ? a->value : thearch.ptrsize; // We don't store size with Pointers
a = getattr(valtype, DW_AT_byte_size);
- valsize = a ? a->value : PtrSize;
+ valsize = a ? a->value : thearch.ptrsize;
indirect_key = 0;
indirect_val = 0;
if(keysize > MaxKeySize) {
- keysize = PtrSize;
+ keysize = thearch.ptrsize;
indirect_key = 1;
}
if(valsize > MaxValSize) {
- valsize = PtrSize;
+ valsize = thearch.ptrsize;
indirect_val = 1;
}
@@ -1288,12 +1291,12 @@ synthesizemaptypes(DWDie *die)
fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow");
newrefattr(fld, DW_AT_type, defptrto(dwhb));
newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize));
- if(RegSize > PtrSize) {
+ if(thearch.regsize > thearch.ptrsize) {
fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad");
newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
- newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize) + PtrSize);
+ newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize) + thearch.ptrsize);
}
- newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize + BucketSize * keysize + BucketSize * valsize + RegSize, 0);
+ newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize + BucketSize * keysize + BucketSize * valsize + thearch.regsize, 0);
// Construct hash<K,V>
dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
@@ -1332,7 +1335,7 @@ synthesizechantypes(DWDie *die)
continue;
elemtype = (DWDie*) getattr(die, DW_AT_go_elem)->data;
a = getattr(elemtype, DW_AT_byte_size);
- elemsize = a ? a->value : PtrSize;
+ elemsize = a ? a->value : thearch.ptrsize;
// sudog<T>
dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
@@ -1414,7 +1417,7 @@ movetomodule(DWDie *parent)
die->link = parent->child;
}
-// If the pcln table contains runtime/string.goc, use that to set gdbscript path.
+// If the pcln table contains runtime/runtime.go, use that to set gdbscript path.
static void
finddebugruntimepath(LSym *s)
{
@@ -1427,7 +1430,7 @@ finddebugruntimepath(LSym *s)
for(i=0; i<s->pcln->nfile; i++) {
f = s->pcln->file[i];
- if((p = strstr(f->name, "runtime/string.goc")) != nil) {
+ if((p = strstr(f->name, "runtime/runtime.go")) != nil) {
*p = '\0';
snprint(gdbscript, sizeof gdbscript, "%sruntime/runtime-gdb.py", f->name);
*p = 'r';
@@ -1519,9 +1522,9 @@ flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_le
here = cpos();
cseek(unitstart);
- LPUT(here - unitstart - sizeof(int32)); // unit_length
- WPUT(2); // dwarf version
- LPUT(header_length); // header length starting here
+ thearch.lput(here - unitstart - sizeof(int32)); // unit_length
+ thearch.wput(2); // dwarf version
+ thearch.lput(header_length); // header length starting here
cseek(here);
}
}
@@ -1540,14 +1543,14 @@ writelines(void)
Pciter pcfile, pcline;
LSym **files, *f;
- if(linesec == S)
+ if(linesec == nil)
linesec = linklookup(ctxt, ".dwarfline", 0);
linesec->nr = 0;
unitstart = -1;
headerend = -1;
epc = 0;
- epcs = S;
+ epcs = nil;
lineo = cpos();
dwinfo = nil;
@@ -1565,9 +1568,9 @@ writelines(void)
// Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf
- LPUT(0); // unit_length (*), will be filled in by flushunit.
- WPUT(2); // dwarf version (appendix F)
- LPUT(0); // header_length (*), filled in by flushunit.
+ thearch.lput(0); // unit_length (*), will be filled in by flushunit.
+ thearch.wput(2); // dwarf version (appendix F)
+ thearch.lput(0); // header_length (*), filled in by flushunit.
// cpos == unitstart + 4 + 2 + 4
cput(1); // minimum_instruction_length
cput(1); // default_is_stmt
@@ -1598,14 +1601,14 @@ writelines(void)
headerend = cpos();
cput(0); // start extended opcode
- uleb128put(1 + PtrSize);
+ uleb128put(1 + thearch.ptrsize);
cput(DW_LNE_set_address);
pc = s->value;
line = 1;
file = 1;
if(linkmode == LinkExternal)
- adddwarfrel(linesec, s, lineo, PtrSize, 0);
+ adddwarfrel(linesec, s, lineo, thearch.ptrsize, 0);
else
addrput(pc);
@@ -1661,7 +1664,7 @@ writelines(void)
switch (a->name) {
case A_AUTO:
dt = DW_ABRV_AUTO;
- offs = a->aoffset - PtrSize;
+ offs = a->aoffset - thearch.ptrsize;
break;
case A_PARAM:
dt = DW_ABRV_PARAM;
@@ -1710,7 +1713,7 @@ writelines(void)
enum
{
CIERESERVE = 16,
- DATAALIGNMENTFACTOR = -4, // TODO -PtrSize?
+ DATAALIGNMENTFACTOR = -4, // TODO -thearch.ptrsize?
FAKERETURNCOLUMN = 16 // TODO gdb6 doesn't like > 15?
};
@@ -1727,10 +1730,10 @@ putpccfadelta(vlong deltapc, vlong cfa)
cput(deltapc);
} else if (deltapc < 0x10000) {
cput(DW_CFA_advance_loc2);
- WPUT(deltapc);
+ thearch.wput(deltapc);
} else {
cput(DW_CFA_advance_loc4);
- LPUT(deltapc);
+ thearch.lput(deltapc);
}
}
@@ -1742,14 +1745,14 @@ writeframes(void)
Pciter pcsp;
uint32 nextpc;
- if(framesec == S)
+ if(framesec == nil)
framesec = linklookup(ctxt, ".dwarfframe", 0);
framesec->nr = 0;
frameo = cpos();
// Emit the CIE, Section 6.4.1
- LPUT(CIERESERVE); // initial length, must be multiple of PtrSize
- LPUT(0xffffffff); // cid.
+ thearch.lput(CIERESERVE); // initial length, must be multiple of thearch.ptrsize
+ thearch.lput(0xffffffff); // cid.
cput(3); // dwarf version (appendix F)
cput(0); // augmentation ""
uleb128put(1); // code_alignment_factor
@@ -1757,11 +1760,11 @@ writeframes(void)
uleb128put(FAKERETURNCOLUMN); // return_address_register
cput(DW_CFA_def_cfa);
- uleb128put(DWARFREGSP); // register SP (**ABI-dependent, defined in l.h)
- uleb128put(PtrSize); // offset
+ uleb128put(thearch.dwarfregsp); // register SP (**ABI-dependent, defined in l.h)
+ uleb128put(thearch.ptrsize); // offset
cput(DW_CFA_offset + FAKERETURNCOLUMN); // return address
- uleb128put(-PtrSize / DATAALIGNMENTFACTOR); // at cfa - x*4
+ uleb128put(-thearch.ptrsize / DATAALIGNMENTFACTOR); // at cfa - x*4
// 4 is to exclude the length field.
pad = CIERESERVE + frameo + 4 - cpos();
@@ -1778,8 +1781,8 @@ writeframes(void)
fdeo = cpos();
// Emit a FDE, Section 6.4.1, starting wit a placeholder.
- LPUT(0); // length, must be multiple of PtrSize
- LPUT(0); // Pointer to the CIE above, at offset 0
+ thearch.lput(0); // length, must be multiple of thearch.ptrsize
+ thearch.lput(0); // Pointer to the CIE above, at offset 0
addrput(0); // initial location
addrput(0); // address range
@@ -1792,23 +1795,23 @@ writeframes(void)
if(nextpc < pcsp.pc)
continue;
}
- putpccfadelta(nextpc - pcsp.pc, PtrSize + pcsp.value);
+ putpccfadelta(nextpc - pcsp.pc, thearch.ptrsize + pcsp.value);
}
fdesize = cpos() - fdeo - 4; // exclude the length field.
- pad = rnd(fdesize, PtrSize) - fdesize;
+ pad = rnd(fdesize, thearch.ptrsize) - fdesize;
strnput("", pad);
fdesize += pad;
// Emit the FDE header for real, Section 6.4.1.
cseek(fdeo);
- LPUT(fdesize);
+ thearch.lput(fdesize);
if(linkmode == LinkExternal) {
adddwarfrel(framesec, framesym, frameo, 4, 0);
- adddwarfrel(framesec, s, frameo, PtrSize, 0);
+ adddwarfrel(framesec, s, frameo, thearch.ptrsize, 0);
}
else {
- LPUT(0);
+ thearch.lput(0);
addrput(s->value);
}
addrput(s->size);
@@ -1834,11 +1837,11 @@ writeinfo(void)
vlong unitstart, here;
fwdcount = 0;
- if (infosec == S)
+ if (infosec == nil)
infosec = linklookup(ctxt, ".dwarfinfo", 0);
infosec->nr = 0;
- if(arangessec == S)
+ if(arangessec == nil)
arangessec = linklookup(ctxt, ".dwarfaranges", 0);
arangessec->nr = 0;
@@ -1848,22 +1851,22 @@ writeinfo(void)
// Write .debug_info Compilation Unit Header (sec 7.5.1)
// Fields marked with (*) must be changed for 64-bit dwarf
// This must match COMPUNITHEADERSIZE above.
- LPUT(0); // unit_length (*), will be filled in later.
- WPUT(2); // dwarf version (appendix F)
+ thearch.lput(0); // unit_length (*), will be filled in later.
+ thearch.wput(2); // dwarf version (appendix F)
// debug_abbrev_offset (*)
if(linkmode == LinkExternal)
adddwarfrel(infosec, abbrevsym, infoo, 4, 0);
else
- LPUT(0);
+ thearch.lput(0);
- cput(PtrSize); // address_size
+ cput(thearch.ptrsize); // address_size
putdie(compunit);
here = cpos();
cseek(unitstart);
- LPUT(here - unitstart - 4); // exclude the length field.
+ thearch.lput(here - unitstart - 4); // exclude the length field.
cseek(here);
}
cflush();
@@ -1910,22 +1913,22 @@ writepub(int (*ispub)(DWDie*))
unitend = infoo + infosize;
// Write .debug_pubnames/types Header (sec 6.1.1)
- LPUT(0); // unit_length (*), will be filled in later.
- WPUT(2); // dwarf version (appendix F)
- LPUT(unitstart); // debug_info_offset (of the Comp unit Header)
- LPUT(unitend - unitstart); // debug_info_length
+ thearch.lput(0); // unit_length (*), will be filled in later.
+ thearch.wput(2); // dwarf version (appendix F)
+ thearch.lput(unitstart); // debug_info_offset (of the Comp unit Header)
+ thearch.lput(unitend - unitstart); // debug_info_length
for (die = compunit->child; die != nil; die = die->link) {
if (!ispub(die)) continue;
- LPUT(die->offs - unitstart);
+ thearch.lput(die->offs - unitstart);
dwa = getattr(die, DW_AT_name);
strnput(dwa->data, dwa->value + 1);
}
- LPUT(0);
+ thearch.lput(0);
here = cpos();
cseek(sectionstart);
- LPUT(here - sectionstart - 4); // exclude the length field.
+ thearch.lput(here - sectionstart - 4); // exclude the length field.
cseek(here);
}
@@ -1947,7 +1950,7 @@ writearanges(void)
vlong value;
sectionstart = cpos();
- headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself
+ headersize = rnd(4+2+4+1+1, thearch.ptrsize); // don't count unit_length field itself
for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
b = getattr(compunit, DW_AT_low_pc);
@@ -1958,21 +1961,21 @@ writearanges(void)
continue;
// Write .debug_aranges Header + entry (sec 6.1.2)
- LPUT(headersize + 4*PtrSize - 4); // unit_length (*)
- WPUT(2); // dwarf version (appendix F)
+ thearch.lput(headersize + 4*thearch.ptrsize - 4); // unit_length (*)
+ thearch.wput(2); // dwarf version (appendix F)
value = compunit->offs - COMPUNITHEADERSIZE; // debug_info_offset
if(linkmode == LinkExternal)
adddwarfrel(arangessec, infosym, sectionstart, 4, value);
else
- LPUT(value);
+ thearch.lput(value);
- cput(PtrSize); // address_size
+ cput(thearch.ptrsize); // address_size
cput(0); // segment_size
- strnput("", headersize - (4+2+4+1+1)); // align to PtrSize
+ strnput("", headersize - (4+2+4+1+1)); // align to thearch.ptrsize
if(linkmode == LinkExternal)
- adddwarfrel(arangessec, (LSym*)b->data, sectionstart, PtrSize, b->value-((LSym*)b->data)->value);
+ adddwarfrel(arangessec, (LSym*)b->data, sectionstart, thearch.ptrsize, b->value-((LSym*)b->data)->value);
else
addrput(b->value);
@@ -2016,9 +2019,9 @@ writedwarfreloc(LSym* s)
start = cpos();
for(r = s->r; r < s->r+s->nr; r++) {
if(iself)
- i = elfreloc1(r, r->off);
+ i = thearch.elfreloc1(r, r->off);
else if(HEADTYPE == Hdarwin)
- i = machoreloc1(r, r->off);
+ i = thearch.machoreloc1(r, r->off);
else
i = -1;
if(i < 0)
@@ -2062,7 +2065,7 @@ dwarfemitdebugsections(void)
die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr"); // needed for array size
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, thearch.ptrsize, 0);
newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, KindUintptr, 0);
// Needed by the prettyprinter code for interface inspection.
@@ -2196,7 +2199,7 @@ dwarfaddshstrings(LSym *shstrtab)
elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str");
elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts");
if(linkmode == LinkExternal) {
- if(thechar == '6' || thechar == '9') {
+ if(thearch.thechar == '6' || thearch.thechar == '9') {
elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rela.debug_info");
elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rela.debug_aranges");
elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rela.debug_line");
@@ -2251,17 +2254,17 @@ dwarfaddelfrelocheader(int elfstr, ElfShdr *shdata, vlong off, vlong size)
ElfShdr *sh;
sh = newElfShdr(elfstrdbg[elfstr]);
- if(thechar == '6' || thechar == '9') {
+ if(thearch.thechar == '6' || thearch.thechar == '9') {
sh->type = SHT_RELA;
} else {
sh->type = SHT_REL;
}
- sh->entsize = PtrSize*(2+(sh->type==SHT_RELA));
+ sh->entsize = thearch.ptrsize*(2+(sh->type==SHT_RELA));
sh->link = elfshname(".symtab")->shnum;
sh->info = shdata->shnum;
sh->off = off;
sh->size = size;
- sh->addralign = PtrSize;
+ sh->addralign = thearch.ptrsize;
}
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index 89a0a5e87f..12ced98107 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "l.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
#include "lib.h"
-#include "../ld/elf.h"
+#include "elf.h"
/*
* We use the 64-bit data structures on both 32- and 64-bit machines
@@ -15,6 +18,8 @@
int iself;
+int nelfsym = 1;
+
static int elf64;
static ElfEhdr hdr;
static ElfPhdr *phdr[NSECT];
@@ -42,7 +47,7 @@ elfinit(void)
{
iself = 1;
- switch(thechar) {
+ switch(thearch.thechar) {
// 64-bit architectures
case '9':
if(ctxt->arch->endian == BigEndian)
@@ -77,14 +82,14 @@ elfinit(void)
void
elf64phdr(ElfPhdr *e)
{
- LPUT(e->type);
- LPUT(e->flags);
- VPUT(e->off);
- VPUT(e->vaddr);
- VPUT(e->paddr);
- VPUT(e->filesz);
- VPUT(e->memsz);
- VPUT(e->align);
+ thearch.lput(e->type);
+ thearch.lput(e->flags);
+ thearch.vput(e->off);
+ thearch.vput(e->vaddr);
+ thearch.vput(e->paddr);
+ thearch.vput(e->filesz);
+ thearch.vput(e->memsz);
+ thearch.vput(e->align);
}
void
@@ -103,44 +108,44 @@ elf32phdr(ElfPhdr *e)
e->filesz += frag;
e->memsz += frag;
}
- LPUT(e->type);
- LPUT(e->off);
- LPUT(e->vaddr);
- LPUT(e->paddr);
- LPUT(e->filesz);
- LPUT(e->memsz);
- LPUT(e->flags);
- LPUT(e->align);
+ thearch.lput(e->type);
+ thearch.lput(e->off);
+ thearch.lput(e->vaddr);
+ thearch.lput(e->paddr);
+ thearch.lput(e->filesz);
+ thearch.lput(e->memsz);
+ thearch.lput(e->flags);
+ thearch.lput(e->align);
}
void
elf64shdr(ElfShdr *e)
{
- LPUT(e->name);
- LPUT(e->type);
- VPUT(e->flags);
- VPUT(e->addr);
- VPUT(e->off);
- VPUT(e->size);
- LPUT(e->link);
- LPUT(e->info);
- VPUT(e->addralign);
- VPUT(e->entsize);
+ thearch.lput(e->name);
+ thearch.lput(e->type);
+ thearch.vput(e->flags);
+ thearch.vput(e->addr);
+ thearch.vput(e->off);
+ thearch.vput(e->size);
+ thearch.lput(e->link);
+ thearch.lput(e->info);
+ thearch.vput(e->addralign);
+ thearch.vput(e->entsize);
}
void
elf32shdr(ElfShdr *e)
{
- LPUT(e->name);
- LPUT(e->type);
- LPUT(e->flags);
- LPUT(e->addr);
- LPUT(e->off);
- LPUT(e->size);
- LPUT(e->link);
- LPUT(e->info);
- LPUT(e->addralign);
- LPUT(e->entsize);
+ thearch.lput(e->name);
+ thearch.lput(e->type);
+ thearch.lput(e->flags);
+ thearch.lput(e->addr);
+ thearch.lput(e->off);
+ thearch.lput(e->size);
+ thearch.lput(e->link);
+ thearch.lput(e->info);
+ thearch.lput(e->addralign);
+ thearch.lput(e->entsize);
}
uint32
@@ -231,19 +236,19 @@ elf64writehdr(void)
for (i = 0; i < EI_NIDENT; i++)
cput(hdr.ident[i]);
- WPUT(hdr.type);
- WPUT(hdr.machine);
- LPUT(hdr.version);
- VPUT(hdr.entry);
- VPUT(hdr.phoff);
- VPUT(hdr.shoff);
- LPUT(hdr.flags);
- WPUT(hdr.ehsize);
- WPUT(hdr.phentsize);
- WPUT(hdr.phnum);
- WPUT(hdr.shentsize);
- WPUT(hdr.shnum);
- WPUT(hdr.shstrndx);
+ thearch.wput(hdr.type);
+ thearch.wput(hdr.machine);
+ thearch.lput(hdr.version);
+ thearch.vput(hdr.entry);
+ thearch.vput(hdr.phoff);
+ thearch.vput(hdr.shoff);
+ thearch.lput(hdr.flags);
+ thearch.wput(hdr.ehsize);
+ thearch.wput(hdr.phentsize);
+ thearch.wput(hdr.phnum);
+ thearch.wput(hdr.shentsize);
+ thearch.wput(hdr.shnum);
+ thearch.wput(hdr.shstrndx);
return ELF64HDRSIZE;
}
@@ -254,19 +259,19 @@ elf32writehdr(void)
for (i = 0; i < EI_NIDENT; i++)
cput(hdr.ident[i]);
- WPUT(hdr.type);
- WPUT(hdr.machine);
- LPUT(hdr.version);
- LPUT(hdr.entry);
- LPUT(hdr.phoff);
- LPUT(hdr.shoff);
- LPUT(hdr.flags);
- WPUT(hdr.ehsize);
- WPUT(hdr.phentsize);
- WPUT(hdr.phnum);
- WPUT(hdr.shentsize);
- WPUT(hdr.shnum);
- WPUT(hdr.shstrndx);
+ thearch.wput(hdr.type);
+ thearch.wput(hdr.machine);
+ thearch.lput(hdr.version);
+ thearch.lput(hdr.entry);
+ thearch.lput(hdr.phoff);
+ thearch.lput(hdr.shoff);
+ thearch.lput(hdr.flags);
+ thearch.wput(hdr.ehsize);
+ thearch.wput(hdr.phentsize);
+ thearch.wput(hdr.phnum);
+ thearch.wput(hdr.shentsize);
+ thearch.wput(hdr.shnum);
+ thearch.wput(hdr.shstrndx);
return ELF32HDRSIZE;
}
@@ -381,9 +386,9 @@ elfwritenotehdr(char *str, uint32 namesz, uint32 descsz, uint32 tag)
// Write Elf_Note header.
cseek(sh->off);
- LPUT(namesz);
- LPUT(descsz);
- LPUT(tag);
+ thearch.lput(namesz);
+ thearch.lput(descsz);
+ thearch.lput(tag);
return sh;
}
@@ -416,7 +421,7 @@ elfwritenetbsdsig(void)
// Followed by NetBSD string and version.
cwrite(ELF_NOTE_NETBSD_NAME, ELF_NOTE_NETBSD_NAMESZ + 1);
- LPUT(ELF_NOTE_NETBSD_VERSION);
+ thearch.lput(ELF_NOTE_NETBSD_VERSION);
return sh->size;
}
@@ -449,7 +454,7 @@ elfwriteopenbsdsig(void)
// Followed by OpenBSD string and version.
cwrite(ELF_NOTE_OPENBSD_NAME, ELF_NOTE_OPENBSD_NAMESZ);
- LPUT(ELF_NOTE_OPENBSD_VERSION);
+ thearch.lput(ELF_NOTE_OPENBSD_VERSION);
return sh->size;
}
@@ -525,7 +530,6 @@ elfwritebuildinfo(void)
return sh->size;
}
-extern int nelfsym;
int elfverneed;
typedef struct Elfaux Elfaux;
@@ -610,7 +614,7 @@ elfdynhash(void)
memset(need, 0, nsym * sizeof need[0]);
memset(chain, 0, nsym * sizeof chain[0]);
memset(buckets, 0, nbucket * sizeof buckets[0]);
- for(sy=ctxt->allsym; sy!=S; sy=sy->allsym) {
+ for(sy=ctxt->allsym; sy!=nil; sy=sy->allsym) {
if (sy->dynid <= 0)
continue;
@@ -690,7 +694,7 @@ elfdynhash(void)
elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0));
}
- if(thechar == '6' || thechar == '9') {
+ if(thearch.thechar == '6' || thearch.thechar == '9') {
sy = linklookup(ctxt, ".rela.plt", 0);
if(sy->size > 0) {
elfwritedynent(s, DT_PLTREL, DT_RELA);
@@ -816,7 +820,7 @@ elfshreloc(Section *sect)
if(strcmp(sect->name, ".shstrtab") == 0 || strcmp(sect->name, ".tbss") == 0)
return nil;
- if(thechar == '6' || thechar == '9') {
+ if(thearch.thechar == '6' || thearch.thechar == '9') {
prefix = ".rela";
typ = SHT_RELA;
} else {
@@ -827,12 +831,12 @@ elfshreloc(Section *sect)
snprint(buf, sizeof buf, "%s%s", prefix, sect->name);
sh = elfshname(buf);
sh->type = typ;
- sh->entsize = RegSize*(2+(typ==SHT_RELA));
+ sh->entsize = thearch.regsize*(2+(typ==SHT_RELA));
sh->link = elfshname(".symtab")->shnum;
sh->info = sect->elfsect->shnum;
sh->off = sect->reloff;
sh->size = sect->rellen;
- sh->addralign = RegSize;
+ sh->addralign = thearch.regsize;
return sh;
}
@@ -875,7 +879,7 @@ elfrelocsect(Section *sect, LSym *first)
}
if(r->xsym->elfsym == 0)
diag("reloc %d to non-elf symbol %s (outer=%s) %d", r->type, r->sym->name, r->xsym->name, r->sym->type);
- if(elfreloc1(r, sym->value+r->off - sect->vaddr) < 0)
+ if(thearch.elfreloc1(r, sym->value+r->off - sect->vaddr) < 0)
diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
}
}
@@ -943,7 +947,7 @@ doelf(void)
debug['s'] = 0;
debug['d'] = 1;
- if(thechar == '6' || thechar == '9') {
+ if(thearch.thechar == '6' || thearch.thechar == '9') {
addstring(shstrtab, ".rela.text");
addstring(shstrtab, ".rela.rodata");
addstring(shstrtab, ".rela.typelink");
@@ -966,7 +970,7 @@ doelf(void)
if(flag_shared) {
addstring(shstrtab, ".init_array");
- if(thechar == '6' || thechar == '9')
+ if(thearch.thechar == '6' || thearch.thechar == '9')
addstring(shstrtab, ".rela.init_array");
else
addstring(shstrtab, ".rel.init_array");
@@ -983,13 +987,13 @@ doelf(void)
addstring(shstrtab, ".interp");
addstring(shstrtab, ".hash");
addstring(shstrtab, ".got");
- if(thechar == '9')
+ if(thearch.thechar == '9')
addstring(shstrtab, ".glink");
addstring(shstrtab, ".got.plt");
addstring(shstrtab, ".dynamic");
addstring(shstrtab, ".dynsym");
addstring(shstrtab, ".dynstr");
- if(thechar == '6' || thechar == '9') {
+ if(thearch.thechar == '6' || thearch.thechar == '9') {
addstring(shstrtab, ".rela");
addstring(shstrtab, ".rela.plt");
} else {
@@ -1004,7 +1008,7 @@ doelf(void)
s = linklookup(ctxt, ".dynsym", 0);
s->type = SELFROSECT;
s->reachable = 1;
- if(thechar == '6' || thechar == '9')
+ if(thearch.thechar == '6' || thearch.thechar == '9')
s->size += ELF64SYMSIZE;
else
s->size += ELF32SYMSIZE;
@@ -1018,7 +1022,7 @@ doelf(void)
dynstr = s;
/* relocation table */
- if(thechar == '6' || thechar == '9')
+ if(thearch.thechar == '6' || thearch.thechar == '9')
s = linklookup(ctxt, ".rela", 0);
else
s = linklookup(ctxt, ".rel", 0);
@@ -1031,7 +1035,7 @@ doelf(void)
s->type = SELFGOT; // writable
/* ppc64 glink resolver */
- if(thechar == '9') {
+ if(thearch.thechar == '9') {
s = linklookup(ctxt, ".glink", 0);
s->reachable = 1;
s->type = SELFRXSECT;
@@ -1048,16 +1052,16 @@ doelf(void)
s = linklookup(ctxt, ".plt", 0);
s->reachable = 1;
- if(thechar == '9')
+ if(thearch.thechar == '9')
// In the ppc64 ABI, .plt is a data section
// written by the dynamic linker.
s->type = SELFSECT;
else
s->type = SELFRXSECT;
- elfsetupplt();
+ thearch.elfsetupplt();
- if(thechar == '6' || thechar == '9')
+ if(thearch.thechar == '6' || thearch.thechar == '9')
s = linklookup(ctxt, ".rela.plt", 0);
else
s = linklookup(ctxt, ".rel.plt", 0);
@@ -1082,13 +1086,13 @@ doelf(void)
*/
elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0));
- if(thechar == '6' || thechar == '9')
+ if(thearch.thechar == '6' || thearch.thechar == '9')
elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
else
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0));
elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0));
- if(thechar == '6' || thechar == '9') {
+ if(thearch.thechar == '6' || thearch.thechar == '9') {
elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0));
elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0));
elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
@@ -1100,12 +1104,12 @@ doelf(void)
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
- if(thechar == '9')
+ if(thearch.thechar == '9')
elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".plt", 0));
else
elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0));
- if(thechar == '9')
+ if(thearch.thechar == '9')
elfwritedynent(s, DT_PPC64_OPT, 0);
// Solaris dynamic linker can't handle an empty .rela.plt if
@@ -1167,7 +1171,7 @@ asmbelf(vlong symo)
Section *sect;
eh = getElfEhdr();
- switch(thechar) {
+ switch(thearch.thechar) {
default:
diag("unknown architecture in asmbelf");
errorexit();
@@ -1228,22 +1232,22 @@ asmbelf(vlong symo)
if(interpreter == nil) {
switch(HEADTYPE) {
case Hlinux:
- interpreter = linuxdynld;
+ interpreter = thearch.linuxdynld;
break;
case Hfreebsd:
- interpreter = freebsddynld;
+ interpreter = thearch.freebsddynld;
break;
case Hnetbsd:
- interpreter = netbsddynld;
+ interpreter = thearch.netbsddynld;
break;
case Hopenbsd:
- interpreter = openbsddynld;
+ interpreter = thearch.openbsddynld;
break;
case Hdragonfly:
- interpreter = dragonflydynld;
+ interpreter = thearch.dragonflydynld;
break;
case Hsolaris:
- interpreter = solarisdynld;
+ interpreter = thearch.solarisdynld;
break;
}
}
@@ -1304,7 +1308,7 @@ asmbelf(vlong symo)
sh->entsize = ELF64SYMSIZE;
else
sh->entsize = ELF32SYMSIZE;
- sh->addralign = RegSize;
+ sh->addralign = thearch.regsize;
sh->link = elfshname(".dynstr")->shnum;
// sh->info = index of first non-local symbol (number of local symbols)
shsym(sh, linklookup(ctxt, ".dynsym", 0));
@@ -1327,7 +1331,7 @@ asmbelf(vlong symo)
sh = elfshname(".gnu.version_r");
sh->type = SHT_GNU_VERNEED;
sh->flags = SHF_ALLOC;
- sh->addralign = RegSize;
+ sh->addralign = thearch.regsize;
sh->info = elfverneed;
sh->link = elfshname(".dynstr")->shnum;
shsym(sh, linklookup(ctxt, ".gnu.version_r", 0));
@@ -1340,7 +1344,7 @@ asmbelf(vlong symo)
sh->type = SHT_RELA;
sh->flags = SHF_ALLOC;
sh->entsize = ELF64RELASIZE;
- sh->addralign = RegSize;
+ sh->addralign = thearch.regsize;
sh->link = elfshname(".dynsym")->shnum;
sh->info = elfshname(".plt")->shnum;
shsym(sh, linklookup(ctxt, ".rela.plt", 0));
@@ -1402,15 +1406,15 @@ asmbelf(vlong symo)
sh = elfshname(".got");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = RegSize;
- sh->addralign = RegSize;
+ sh->entsize = thearch.regsize;
+ sh->addralign = thearch.regsize;
shsym(sh, linklookup(ctxt, ".got", 0));
sh = elfshname(".got.plt");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = RegSize;
- sh->addralign = RegSize;
+ sh->entsize = thearch.regsize;
+ sh->addralign = thearch.regsize;
shsym(sh, linklookup(ctxt, ".got.plt", 0));
}
@@ -1418,7 +1422,7 @@ asmbelf(vlong symo)
sh->type = SHT_HASH;
sh->flags = SHF_ALLOC;
sh->entsize = 4;
- sh->addralign = RegSize;
+ sh->addralign = thearch.regsize;
sh->link = elfshname(".dynsym")->shnum;
shsym(sh, linklookup(ctxt, ".hash", 0));
@@ -1426,8 +1430,8 @@ asmbelf(vlong symo)
sh = elfshname(".dynamic");
sh->type = SHT_DYNAMIC;
sh->flags = SHF_ALLOC+SHF_WRITE;
- sh->entsize = 2*RegSize;
- sh->addralign = RegSize;
+ sh->entsize = 2*thearch.regsize;
+ sh->addralign = thearch.regsize;
sh->link = elfshname(".dynstr")->shnum;
shsym(sh, linklookup(ctxt, ".dynamic", 0));
ph = newElfPhdr();
@@ -1446,7 +1450,7 @@ asmbelf(vlong symo)
ph->type = PT_TLS;
ph->flags = PF_R;
ph->memsz = -ctxt->tlsoffset;
- ph->align = RegSize;
+ ph->align = thearch.regsize;
}
}
@@ -1454,12 +1458,12 @@ asmbelf(vlong symo)
ph = newElfPhdr();
ph->type = PT_GNU_STACK;
ph->flags = PF_W+PF_R;
- ph->align = RegSize;
+ ph->align = thearch.regsize;
ph = newElfPhdr();
ph->type = PT_PAX_FLAGS;
ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled
- ph->align = RegSize;
+ ph->align = thearch.regsize;
}
elfobj:
@@ -1501,7 +1505,7 @@ elfobj:
if(linkmode == LinkInternal && !debug['d'] && HEADTYPE != Hopenbsd) {
sh = elfshname(".tbss");
sh->type = SHT_NOBITS;
- sh->addralign = RegSize;
+ sh->addralign = thearch.regsize;
sh->size = -ctxt->tlsoffset;
sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE;
}
@@ -1511,8 +1515,8 @@ elfobj:
sh->type = SHT_SYMTAB;
sh->off = symo;
sh->size = symsize;
- sh->addralign = RegSize;
- sh->entsize = 8+2*RegSize;
+ sh->addralign = thearch.regsize;
+ sh->entsize = 8+2*thearch.regsize;
sh->link = elfshname(".strtab")->shnum;
sh->info = elfglobalsymndx;
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index 16c052fcb5..85589bd70f 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -1021,12 +1021,6 @@ void dwarfaddelfsectionsyms(void);
void dwarfaddelfheaders(void);
void asmbelf(vlong symo);
void asmbelfsetup(void);
-extern char linuxdynld[];
-extern char freebsddynld[];
-extern char netbsddynld[];
-extern char openbsddynld[];
-extern char dragonflydynld[];
-extern char solarisdynld[];
int elfreloc1(Reloc*, vlong sectoff);
void putelfsectionsyms(void);
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index 9c296b740f..8b1123d3de 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -4,8 +4,11 @@
// go-specific code shared across loaders (5l, 6l, 8l).
-#include "l.h"
-#include "../ld/lib.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "lib.h"
// accumulate all type information from .6 files.
// check for inconsistencies.
@@ -401,7 +404,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
// allow #pragma dynimport _ _ "foo.so"
// to force a link of foo.so.
havedynamic = 1;
- adddynlib(lib);
+ thearch.adddynlib(lib);
continue;
}
@@ -518,7 +521,7 @@ static LSym *emarkq;
static void
mark1(LSym *s, LSym *parent)
{
- if(s == S || s->reachable)
+ if(s == nil || s->reachable)
return;
if(strncmp(s->name, "go.weak.", 8) == 0)
return;
@@ -544,7 +547,7 @@ markflood(void)
LSym *s;
int i;
- for(s=markq; s!=S; s=s->queue) {
+ for(s=markq; s!=nil; s=s->queue) {
if(s->type == STEXT) {
if(debug['v'] > 1)
Bprint(&bso, "marktext %s\n", s->name);
@@ -608,7 +611,7 @@ deadcode(void)
markflood();
// keep each beginning with 'typelink.' if the symbol it points at is being kept.
- for(s = ctxt->allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != nil; s = s->allsym) {
if(strncmp(s->name, "go.typelink.", 12) == 0)
s->reachable = s->nr==1 && s->r[0].sym->reachable;
}
@@ -630,7 +633,7 @@ deadcode(void)
else
last->next = nil;
- for(s = ctxt->allsym; s != S; s = s->allsym)
+ for(s = ctxt->allsym; s != nil; s = s->allsym)
if(strncmp(s->name, "go.weak.", 8) == 0) {
s->special = 1; // do not lay out in data segment
s->reachable = 1;
@@ -639,7 +642,7 @@ deadcode(void)
// record field tracking references
fmtstrinit(&fmt);
- for(s = ctxt->allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != nil; s = s->allsym) {
if(strncmp(s->name, "go.track.", 9) == 0) {
s->special = 1; // do not lay out in data segment
s->hide = 1;
@@ -668,7 +671,7 @@ doweak(void)
// resolve weak references only if
// target symbol will be in binary anyway.
- for(s = ctxt->allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != nil; s = s->allsym) {
if(strncmp(s->name, "go.weak.", 8) == 0) {
t = linkrlookup(ctxt, s->name+8, s->version);
if(t && t->type != 0 && t->reachable) {
@@ -693,7 +696,7 @@ addexport(void)
return;
for(i=0; i<ndynexp; i++)
- adddynsym(ctxt, dynexp[i]);
+ thearch.adddynsym(ctxt, dynexp[i]);
}
/* %Z from gc, for quoting import paths */
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index 29d32d283d..7beff337f2 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -25,9 +25,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
-#include "l.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
#include "lib.h"
-#include "../ld/elf.h"
+#include "elf.h"
enum
{
@@ -414,7 +417,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
return;
}
- switch(thechar) {
+ switch(thearch.thechar) {
default:
diag("%s: elf %s unimplemented", pn, thestring);
return;
@@ -590,7 +593,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
if(sym.shndx >= obj->nsect || sym.shndx == 0)
continue;
// even when we pass needSym == 1 to readsym, it might still return nil to skip some unwanted symbols
- if(sym.sym == S)
+ if(sym.sym == nil)
continue;
sect = obj->sect+sym.shndx;
if(sect->sym == nil) {
@@ -600,7 +603,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
continue;
}
s = sym.sym;
- if(s->outer != S) {
+ if(s->outer != nil) {
if(s->dupok)
continue;
diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
@@ -632,7 +635,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
// This keeps textp in increasing address order.
for(i=0; i<obj->nsect; i++) {
s = obj->sect[i].sym;
- if(s == S)
+ if(s == nil)
continue;
if(s->sub)
s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
@@ -645,7 +648,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
else
ctxt->textp = s;
ctxt->etextp = s;
- for(s = s->sub; s != S; s = s->sub) {
+ for(s = s->sub; s != nil; s = s->sub) {
if(s->onlist)
sysfatal("symbol %s listed multiple times", s->name);
s->onlist = 1;
@@ -700,7 +703,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
continue;
}
if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol
- rp->sym = S;
+ rp->sym = nil;
} else {
if(readsym(obj, info>>32, &sym, 0) < 0)
goto bad;
@@ -844,7 +847,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
}
break;
case ElfSymBindLocal:
- if(thechar == '5' && (strncmp(sym->name, "$a", 2) == 0 || strncmp(sym->name, "$d", 2) == 0)) {
+ if(thearch.thechar == '5' && (strncmp(sym->name, "$a", 2) == 0 || strncmp(sym->name, "$d", 2) == 0)) {
// binutils for arm generate these mapping
// symbols, ignore these
break;
@@ -905,7 +908,7 @@ rbyoff(const void *va, const void *vb)
static int
reltype(char *pn, int elftype, uchar *siz)
{
- switch(R(thechar, elftype)) {
+ switch(R(thearch.thechar, elftype)) {
default:
diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype);
case R('9', R_PPC64_TOC16):
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
index 71cfa63dec..4cbfa8d1ce 100644
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -25,7 +25,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
-#include "l.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
#include "lib.h"
enum {
@@ -477,7 +480,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
m->len = len;
m->name = pn;
- switch(thechar) {
+ switch(thearch.thechar) {
default:
diag("%s: mach-o %s unimplemented", pn, thestring);
return;
@@ -627,7 +630,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
werrstr("reference to invalid section %s/%s", sect->segname, sect->name);
continue;
}
- if(s->outer != S) {
+ if(s->outer != nil) {
if(s->dupok)
continue;
diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
@@ -652,13 +655,13 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
// This keeps textp in increasing address order.
for(i=0; i<c->seg.nsect; i++) {
sect = &c->seg.sect[i];
- if((s = sect->sym) == S)
+ if((s = sect->sym) == nil)
continue;
if(s->sub) {
s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
// assign sizes, now that we know symbols in sorted order.
- for(s1 = s->sub; s1 != S; s1 = s1->sub) {
+ for(s1 = s->sub; s1 != nil; s1 = s1->sub) {
if(s1->sub)
s1->size = s1->sub->value - s1->value;
else
@@ -674,7 +677,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
else
ctxt->textp = s;
ctxt->etextp = s;
- for(s1 = s->sub; s1 != S; s1 = s1->sub) {
+ for(s1 = s->sub; s1 != nil; s1 = s1->sub) {
if(s1->onlist)
sysfatal("symbol %s listed multiple times", s1->name);
s1->onlist = 1;
@@ -687,7 +690,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
// load relocations
for(i=0; i<c->seg.nsect; i++) {
sect = &c->seg.sect[i];
- if((s = sect->sym) == S)
+ if((s = sect->sym) == nil)
continue;
macholoadrel(m, sect);
if(sect->rel == nil)
@@ -700,7 +703,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
int k;
MachoSect *ks;
- if(thechar != '8') {
+ if(thearch.thechar != '8') {
// mach-o only uses scattered relocation on 32-bit platforms
diag("unexpected scattered relocation");
continue;
@@ -750,7 +753,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr);
goto bad;
foundk:
- if(ks->sym != S) {
+ if(ks->sym != nil) {
rp->sym = ks->sym;
rp->add += rel->value - ks->addr;
} else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) {
@@ -788,7 +791,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
rp->off = rel->addr;
// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
- if (thechar == '6' && rel->extrn == 0 && rel->type == 1) {
+ if (thearch.thechar == '6' && rel->extrn == 0 && rel->type == 1) {
// Calculate the addend as the offset into the section.
//
// The rip-relative offset stored in the object file is encoded
@@ -812,7 +815,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
// For i386 Mach-O PC-relative, the addend is written such that
// it *is* the PC being subtracted. Use that to make
// it match our version of PC-relative.
- if(rel->pcrel && thechar == '8')
+ if(rel->pcrel && thearch.thechar == '8')
rp->add += rp->off+rp->siz;
if(!rel->extrn) {
if(rel->symnum < 1 || rel->symnum > c->seg.nsect) {
@@ -828,7 +831,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
// include that information in the addend.
// We only care about the delta from the
// section base.
- if(thechar == '8')
+ if(thearch.thechar == '8')
rp->add -= c->seg.sect[rel->symnum-1].addr;
} else {
if(rel->symnum >= symtab->nsym) {
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index 4f5e51f2f1..da11a3ea18 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "l.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
#include "lib.h"
-#include "../ld/pe.h"
+#include "pe.h"
#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
@@ -363,7 +366,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
if(sect == nil)
return;
- if(s->outer != S) {
+ if(s->outer != nil) {
if(s->dupok)
continue;
diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
@@ -386,7 +389,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
// This keeps textp in increasing address order.
for(i=0; i<obj->nsect; i++) {
s = obj->sect[i].sym;
- if(s == S)
+ if(s == nil)
continue;
if(s->sub)
s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
@@ -399,7 +402,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
else
ctxt->textp = s;
ctxt->etextp = s;
- for(s = s->sub; s != S; s = s->sub) {
+ for(s = s->sub; s != nil; s = s->sub) {
if(s->onlist)
sysfatal("symbol %s listed multiple times", s->name);
s->onlist = 1;
@@ -458,7 +461,7 @@ readsym(PeObj *obj, int i, PeSym **y)
name = sym->name;
if(strncmp(name, "__imp_", 6) == 0)
name = &name[6]; // __imp_Name => Name
- if(thechar == '8' && name[0] == '_')
+ if(thearch.thechar == '8' && name[0] == '_')
name = &name[1]; // _Name => Name
}
// remove last @XXX
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index fa08bc5f03..72c903b4d2 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -29,10 +29,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-#include "l.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
#include "lib.h"
-#include "../ld/elf.h"
-#include "../ld/dwarf.h"
+#include "elf.h"
+#include "dwarf.h"
#include "../../runtime/stack.h"
#include "../../runtime/funcdata.h"
@@ -105,7 +108,7 @@ libinit(void)
{
char *suffix, *suffixsep;
- funcalign = FuncAlign;
+ funcalign = thearch.funcalign;
fmtinstall('i', iconv);
fmtinstall('Y', Yconv);
fmtinstall('Z', Zconv);
@@ -191,7 +194,7 @@ loadlib(void)
}
loadinternal("runtime");
- if(thechar == '5')
+ if(thearch.thechar == '5')
loadinternal("math");
if(flag_race)
loadinternal("runtime/race");
@@ -212,6 +215,14 @@ loadlib(void)
// Force external linking for android.
if(strcmp(goos, "android") == 0)
linkmode = LinkExternal;
+
+ // cgo on Darwin must use external linking
+ // we can always use external linking, but then there will be circular
+ // dependency problems when compiling natively (external linking requires
+ // runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
+ // compiled using external linking.)
+ if(thearch.thechar == '5' && HEADTYPE == Hdarwin && iscgo)
+ linkmode = LinkExternal;
}
if(linkmode == LinkExternal && !iscgo) {
@@ -243,7 +254,7 @@ loadlib(void)
if(linkmode == LinkInternal) {
// Drop all the cgo_import_static declarations.
// Turns out we won't be needing them.
- for(s = ctxt->allsym; s != S; s = s->allsym)
+ for(s = ctxt->allsym; s != nil; s = s->allsym)
if(s->type == SHOSTOBJ) {
// If a symbol was marked both
// cgo_import_static and cgo_import_dynamic,
@@ -257,8 +268,14 @@ loadlib(void)
}
tlsg = linklookup(ctxt, "runtime.tlsg", 0);
- tlsg->type = STLSBSS;
- tlsg->size = PtrSize;
+ // For most ports, runtime.tlsg is a placeholder symbol for TLS
+ // relocation. However, the Android and Darwin ports need it to
+ // be a real variable. Instead of hard-coding which platforms
+ // need it to be a real variable, we set the type to STLSBSS only
+ // when the runtime has not declared its type already.
+ if(tlsg->type == 0)
+ tlsg->type = STLSBSS;
+ tlsg->size = thearch.ptrsize;
tlsg->hide = 1;
tlsg->reachable = 1;
ctxt->tlsg = tlsg;
@@ -426,7 +443,7 @@ dowrite(int fd, char *p, int n)
while(n > 0) {
m = write(fd, p, n);
if(m <= 0) {
- ctxt->cursym = S;
+ ctxt->cursym = nil;
diag("write error: %r");
errorexit();
}
@@ -515,7 +532,7 @@ hostobjs(void)
h = &hostobj[i];
f = Bopen(h->file, OREAD);
if(f == nil) {
- ctxt->cursym = S;
+ ctxt->cursym = nil;
diag("cannot reopen %s: %r", h->pn);
errorexit();
}
@@ -589,7 +606,7 @@ hostlink(void)
if(extld == nil)
extld = "gcc";
argv[argc++] = extld;
- switch(thechar){
+ switch(thearch.thechar){
case '8':
argv[argc++] = "-m32";
break;
@@ -637,7 +654,7 @@ hostlink(void)
h = &hostobj[i];
f = Bopen(h->file, OREAD);
if(f == nil) {
- ctxt->cursym = S;
+ ctxt->cursym = nil;
diag("cannot reopen %s: %r", h->pn);
errorexit();
}
@@ -646,7 +663,7 @@ hostlink(void)
argv[argc++] = p;
w = create(p, 1, 0775);
if(w < 0) {
- ctxt->cursym = S;
+ ctxt->cursym = nil;
diag("cannot create %s: %r", p);
errorexit();
}
@@ -658,7 +675,7 @@ hostlink(void)
len -= n;
}
if(close(w) < 0) {
- ctxt->cursym = S;
+ ctxt->cursym = nil;
diag("cannot write %s: %r", p);
errorexit();
}
@@ -705,7 +722,7 @@ hostlink(void)
}
if(runcmd(argv) < 0) {
- ctxt->cursym = S;
+ ctxt->cursym = nil;
diag("%s: running %s failed: %r", argv0, argv[0]);
errorexit();
}
@@ -760,7 +777,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence)
line[n] = '\0';
if(strncmp(line, "go object ", 10) != 0) {
if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) {
- print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thechar, pn, thechar, thechar);
+ print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thearch.thechar, pn, thearch.thechar, thearch.thechar);
errorexit();
}
if(strcmp(line, thestring) == 0) {
@@ -846,7 +863,7 @@ mywhatsys(void)
goarch = getgoarch();
if(strncmp(goarch, thestring, strlen(thestring)) != 0)
- sysfatal("cannot use %cc with GOARCH=%s", thechar, goarch);
+ sysfatal("cannot use %cc with GOARCH=%s", thearch.thechar, goarch);
}
int
@@ -974,7 +991,7 @@ addsection(Segment *seg, char *name, int rwx)
sect->rwx = rwx;
sect->name = name;
sect->seg = seg;
- sect->align = PtrSize; // everything is at least pointer-aligned
+ sect->align = thearch.ptrsize; // everything is at least pointer-aligned
*l = sect;
return sect;
}
@@ -1032,20 +1049,21 @@ static void stkbroke(Chain*, int);
static LSym *morestack;
static LSym *newstack;
-enum
-{
- HasLinkRegister = (thechar == '5' || thechar == '9'),
-};
-
// TODO: Record enough information in new object files to
// allow stack checks here.
static int
+haslinkregister(void)
+{
+ return thearch.thechar == '5' || thearch.thechar == '9';
+}
+
+static int
callsize(void)
{
- if(HasLinkRegister)
+ if(haslinkregister())
return 0;
- return RegSize;
+ return thearch.regsize;
}
void
@@ -1166,8 +1184,8 @@ stkcheck(Chain *up, int depth)
// to StackLimit beyond the frame size.
if(strncmp(r->sym->name, "runtime.morestack", 17) == 0) {
limit = StackLimit + s->locals;
- if(HasLinkRegister)
- limit += RegSize;
+ if(haslinkregister())
+ limit += thearch.regsize;
}
break;
@@ -1215,8 +1233,8 @@ stkprint(Chain *ch, int limit)
else
print("\t%d\tguaranteed after split check in %s\n", ch->limit, name);
} else {
- stkprint(ch->up, ch->limit + (!HasLinkRegister)*RegSize);
- if(!HasLinkRegister)
+ stkprint(ch->up, ch->limit + callsize());
+ if(!haslinkregister())
print("\t%d\ton entry to %s\n", ch->limit, name);
}
if(ch->limit != limit)
@@ -1232,7 +1250,7 @@ Yconv(Fmt *fp)
char *str;
s = va_arg(fp->args, LSym*);
- if (s == S) {
+ if (s == nil) {
fmtprint(fp, "<nil>");
} else {
fmtstrinit(&fmt);
@@ -1317,7 +1335,7 @@ cwrite(void *buf, int n)
void
usage(void)
{
- fprint(2, "usage: %cl [options] main.%c\n", thechar, thechar);
+ fprint(2, "usage: %cl [options] main.%c\n", thearch.thechar, thearch.thechar);
flagprint(2);
exits("usage");
}
@@ -1346,7 +1364,7 @@ setinterp(char *s)
void
doversion(void)
{
- print("%cl version %s\n", thechar, getgoversion());
+ print("%cl version %s\n", thearch.thechar, getgoversion());
errorexit();
}
@@ -1366,7 +1384,7 @@ genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
if(s->type == STEXT)
put(s, s->name, 'T', s->value, s->size, s->version, 0);
- for(s=ctxt->allsym; s!=S; s=s->allsym) {
+ for(s=ctxt->allsym; s!=nil; s=s->allsym) {
if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0))
continue;
switch(s->type&SMASK) {
@@ -1406,7 +1424,7 @@ genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
// NOTE(ality): acid can't produce a stack trace without .frame symbols
- put(nil, ".frame", 'm', s->locals+PtrSize, 0, 0, 0);
+ put(nil, ".frame", 'm', s->locals+thearch.ptrsize, 0, 0, 0);
for(a=s->autom; a; a=a->link) {
// Emit a or p according to actual offset, even if label is wrong.
@@ -1418,7 +1436,7 @@ genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
if(a->name == A_PARAM)
off = a->aoffset;
else
- off = a->aoffset - PtrSize;
+ off = a->aoffset - thearch.ptrsize;
// FP
if(off >= 0) {
@@ -1427,8 +1445,8 @@ genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
}
// SP
- if(off <= -PtrSize) {
- put(nil, a->asym->name, 'a', -(off+PtrSize), 0, 0, a->gotype);
+ if(off <= -thearch.ptrsize) {
+ put(nil, a->asym->name, 'a', -(off+thearch.ptrsize), 0, 0, a->gotype);
continue;
}
@@ -1549,7 +1567,7 @@ diag(char *fmt, ...)
tn = "";
sep = "";
- if(ctxt->cursym != S) {
+ if(ctxt->cursym != nil) {
tn = ctxt->cursym->name;
sep = ": ";
}
@@ -1617,3 +1635,18 @@ checkgo(void)
}
}
}
+
+vlong
+rnd(vlong v, vlong r)
+{
+ vlong c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index fd84c8bccb..f6a89535da 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -28,6 +28,58 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Arch Arch;
+struct Arch {
+ int thechar;
+ int ptrsize;
+ int intsize;
+ int regsize;
+ int funcalign;
+ int maxalign;
+ int minlc;
+ int dwarfregsp;
+
+ char *linuxdynld;
+ char *freebsddynld;
+ char *netbsddynld;
+ char *openbsddynld;
+ char *dragonflydynld;
+ char *solarisdynld;
+
+ void (*adddynlib)(char*);
+ void (*adddynrel)(LSym*, Reloc*);
+ void (*adddynsym)(Link*, LSym*);
+ void (*archinit)(void);
+ int (*archreloc)(Reloc*, LSym*, vlong*);
+ vlong (*archrelocvariant)(Reloc*, LSym*, vlong);
+ void (*asmb)(void);
+ int (*elfreloc1)(Reloc*, vlong);
+ void (*elfsetupplt)(void);
+ void (*gentext)(void);
+ void (*listinit)(void);
+ int (*machoreloc1)(Reloc*, vlong);
+
+ void (*lput)(uint32);
+ void (*wput)(uint16);
+ void (*vput)(uint64);
+};
+
+vlong rnd(vlong, vlong);
+
+EXTERN Arch thearch;
+EXTERN LSym* datap;
+EXTERN int debug[128];
+EXTERN char literal[32];
+EXTERN int32 lcsize;
+EXTERN char* rpath;
+EXTERN int32 spsize;
+EXTERN LSym* symlist;
+EXTERN int32 symsize;
+
// Terrible but standard terminology.
// A segment describes a block of file to load into memory.
// A section further describes the pieces of that block for
@@ -71,8 +123,8 @@ struct Section
extern char symname[];
EXTERN char* INITENTRY;
-extern char* thestring;
-extern LinkArch* thelinkarch;
+EXTERN char* thestring;
+EXTERN LinkArch* thelinkarch;
EXTERN char* outfile;
EXTERN int ndynexp;
EXTERN LSym** dynexp;
@@ -82,6 +134,7 @@ EXTERN int havedynamic;
EXTERN int funcalign;
EXTERN int iscgo;
EXTERN int elfglobalsymndx;
+extern int nelfsym;
EXTERN char* flag_installsuffix;
EXTERN int flag_race;
EXTERN int flag_shared;
@@ -250,8 +303,8 @@ void libinit(void);
LSym* listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off);
void loadinternal(char *name);
void loadlib(void);
-void lputb(int32 l);
-void lputl(int32 l);
+void lputb(uint32 l);
+void lputl(uint32 l);
void* mal(uint32 n);
void mark(LSym *s);
void mywhatsys(void);
@@ -289,4 +342,8 @@ void zerosig(char *sp);
void archinit(void);
void diag(char *fmt, ...);
+void ldmain(int, char**);
+
#pragma varargck argpos diag 1
+
+#define SYMDEF "__.GOSYMDEF" \ No newline at end of file
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index ffb20b3a55..b9b341031b 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -5,10 +5,13 @@
// Mach-O file writing
// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
-#include "l.h"
-#include "../ld/dwarf.h"
-#include "../ld/lib.h"
-#include "../ld/macho.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "dwarf.h"
+#include "lib.h"
+#include "macho.h"
static int macho64;
static MachoHdr hdr;
@@ -41,7 +44,7 @@ static void machodysymtab(void);
void
machoinit(void)
{
- switch(thechar) {
+ switch(thearch.thechar) {
// 64-bit architectures
case '6':
case '9':
@@ -146,85 +149,85 @@ machowrite(void)
}
if(macho64)
- LPUT(0xfeedfacf);
+ thearch.lput(0xfeedfacf);
else
- LPUT(0xfeedface);
- LPUT(hdr.cpu);
- LPUT(hdr.subcpu);
+ thearch.lput(0xfeedface);
+ thearch.lput(hdr.cpu);
+ thearch.lput(hdr.subcpu);
if(linkmode == LinkExternal)
- LPUT(1); /* file type - mach object */
+ thearch.lput(1); /* file type - mach object */
else
- LPUT(2); /* file type - mach executable */
- LPUT(nload+nseg+ndebug);
- LPUT(loadsize);
- LPUT(1); /* flags - no undefines */
+ thearch.lput(2); /* file type - mach executable */
+ thearch.lput(nload+nseg+ndebug);
+ thearch.lput(loadsize);
+ thearch.lput(1); /* flags - no undefines */
if(macho64)
- LPUT(0); /* reserved */
+ thearch.lput(0); /* reserved */
for(i=0; i<nseg; i++) {
s = &seg[i];
if(macho64) {
- LPUT(25); /* segment 64 */
- LPUT(72+80*s->nsect);
+ thearch.lput(25); /* segment 64 */
+ thearch.lput(72+80*s->nsect);
strnput(s->name, 16);
- VPUT(s->vaddr);
- VPUT(s->vsize);
- VPUT(s->fileoffset);
- VPUT(s->filesize);
- LPUT(s->prot1);
- LPUT(s->prot2);
- LPUT(s->nsect);
- LPUT(s->flag);
+ thearch.vput(s->vaddr);
+ thearch.vput(s->vsize);
+ thearch.vput(s->fileoffset);
+ thearch.vput(s->filesize);
+ thearch.lput(s->prot1);
+ thearch.lput(s->prot2);
+ thearch.lput(s->nsect);
+ thearch.lput(s->flag);
} else {
- LPUT(1); /* segment 32 */
- LPUT(56+68*s->nsect);
+ thearch.lput(1); /* segment 32 */
+ thearch.lput(56+68*s->nsect);
strnput(s->name, 16);
- LPUT(s->vaddr);
- LPUT(s->vsize);
- LPUT(s->fileoffset);
- LPUT(s->filesize);
- LPUT(s->prot1);
- LPUT(s->prot2);
- LPUT(s->nsect);
- LPUT(s->flag);
+ thearch.lput(s->vaddr);
+ thearch.lput(s->vsize);
+ thearch.lput(s->fileoffset);
+ thearch.lput(s->filesize);
+ thearch.lput(s->prot1);
+ thearch.lput(s->prot2);
+ thearch.lput(s->nsect);
+ thearch.lput(s->flag);
}
for(j=0; j<s->nsect; j++) {
t = &s->sect[j];
if(macho64) {
strnput(t->name, 16);
strnput(t->segname, 16);
- VPUT(t->addr);
- VPUT(t->size);
- LPUT(t->off);
- LPUT(t->align);
- LPUT(t->reloc);
- LPUT(t->nreloc);
- LPUT(t->flag);
- LPUT(t->res1); /* reserved */
- LPUT(t->res2); /* reserved */
- LPUT(0); /* reserved */
+ thearch.vput(t->addr);
+ thearch.vput(t->size);
+ thearch.lput(t->off);
+ thearch.lput(t->align);
+ thearch.lput(t->reloc);
+ thearch.lput(t->nreloc);
+ thearch.lput(t->flag);
+ thearch.lput(t->res1); /* reserved */
+ thearch.lput(t->res2); /* reserved */
+ thearch.lput(0); /* reserved */
} else {
strnput(t->name, 16);
strnput(t->segname, 16);
- LPUT(t->addr);
- LPUT(t->size);
- LPUT(t->off);
- LPUT(t->align);
- LPUT(t->reloc);
- LPUT(t->nreloc);
- LPUT(t->flag);
- LPUT(t->res1); /* reserved */
- LPUT(t->res2); /* reserved */
+ thearch.lput(t->addr);
+ thearch.lput(t->size);
+ thearch.lput(t->off);
+ thearch.lput(t->align);
+ thearch.lput(t->reloc);
+ thearch.lput(t->nreloc);
+ thearch.lput(t->flag);
+ thearch.lput(t->res1); /* reserved */
+ thearch.lput(t->res2); /* reserved */
}
}
}
for(i=0; i<nload; i++) {
l = &load[i];
- LPUT(l->type);
- LPUT(4*(l->ndata+2));
+ thearch.lput(l->type);
+ thearch.lput(4*(l->ndata+2));
for(j=0; j<l->ndata; j++)
- LPUT(l->data[j]);
+ thearch.lput(l->data[j]);
}
return cpos() - o1;
@@ -353,10 +356,14 @@ asmbmacho(void)
/* apple MACH */
va = INITTEXT - HEADR;
mh = getMachoHdr();
- switch(thechar){
+ switch(thearch.thechar){
default:
diag("unknown mach architecture");
errorexit();
+ case '5':
+ mh->cpu = MACHO_CPU_ARM;
+ mh->subcpu = MACHO_SUBCPU_ARMV7;
+ break;
case '6':
mh->cpu = MACHO_CPU_AMD64;
mh->subcpu = MACHO_SUBCPU_X86;
@@ -412,10 +419,16 @@ asmbmacho(void)
machoshbits(ms, sect, "__DATA");
if(linkmode != LinkExternal) {
- switch(thechar) {
+ switch(thearch.thechar) {
default:
diag("unknown macho architecture");
errorexit();
+ case '5':
+ ml = newMachoLoad(5, 17+2); /* unix thread */
+ ml->data[0] = 1; /* thread type */
+ ml->data[1] = 17; /* word count */
+ ml->data[2+15] = entryvalue(); /* start pc */
+ break;
case '6':
ml = newMachoLoad(5, 42+2); /* unix thread */
ml->data[0] = 4; /* thread type */
@@ -605,7 +618,7 @@ machosymtab(void)
adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol
adduint8(ctxt, symtab, 0); // no section
adduint16(ctxt, symtab, 0); // desc
- adduintxx(ctxt, symtab, 0, PtrSize); // no value
+ adduintxx(ctxt, symtab, 0, thearch.ptrsize); // no value
} else {
if(s->cgoexport)
adduint8(ctxt, symtab, 0x0f);
@@ -620,7 +633,7 @@ machosymtab(void)
} else
adduint8(ctxt, symtab, o->sect->extnum);
adduint16(ctxt, symtab, 0); // desc
- adduintxx(ctxt, symtab, symaddr(s), PtrSize);
+ adduintxx(ctxt, symtab, symaddr(s), thearch.ptrsize);
}
}
}
@@ -746,7 +759,7 @@ machorelocsect(Section *sect, LSym *first)
for(r = sym->r; r < sym->r+sym->nr; r++) {
if(r->done)
continue;
- if(machoreloc1(r, sym->value+r->off - sect->vaddr) < 0)
+ if(thearch.machoreloc1(r, sym->value+r->off - sect->vaddr) < 0)
diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
}
}
diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h
index d759f4b0f8..d21109b38f 100644
--- a/src/cmd/ld/macho.h
+++ b/src/cmd/ld/macho.h
@@ -66,6 +66,9 @@ enum {
MACHO_CPU_AMD64 = (1<<24)|7,
MACHO_CPU_386 = 7,
MACHO_SUBCPU_X86 = 3,
+ MACHO_CPU_ARM = 12,
+ MACHO_SUBCPU_ARM = 0,
+ MACHO_SUBCPU_ARMV7 = 9,
MACHO32SYMSIZE = 12,
MACHO64SYMSIZE = 16,
@@ -80,6 +83,9 @@ enum {
MACHO_X86_64_RELOC_SIGNED_2 = 7,
MACHO_X86_64_RELOC_SIGNED_4 = 8,
+ MACHO_ARM_RELOC_VANILLA = 0,
+ MACHO_ARM_RELOC_BR24 = 5,
+
MACHO_GENERIC_RELOC_VANILLA = 0,
MACHO_FAKE_GOTPCREL = 100,
diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c
index f889b2c3ea..adb7661301 100644
--- a/src/cmd/ld/pcln.c
+++ b/src/cmd/ld/pcln.c
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "l.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
#include "lib.h"
#include "../../runtime/funcdata.h"
@@ -104,6 +107,15 @@ renumberfiles(Link *ctxt, LSym **files, int nfiles, Pcdata *d)
*d = out;
}
+static int
+container(LSym *s)
+{
+ // We want to generate func table entries only for the "lowest level" symbols,
+ // not containers of subsymbols.
+ if(s != nil && s->sub != nil)
+ return 1;
+ return 0;
+}
// pclntab initializes the pclntab symbol with
// runtime function and file name information.
@@ -111,7 +123,7 @@ void
pclntab(void)
{
int32 i, nfunc, start, funcstart;
- LSym *ftab, *s;
+ LSym *ftab, *s, *last;
int32 off, end, frameptrsize;
int64 funcdata_bytes;
Pcln *pcln;
@@ -125,35 +137,41 @@ pclntab(void)
// See golang.org/s/go12symtab for the format. Briefly:
// 8-byte header
- // nfunc [PtrSize bytes]
- // function table, alternating PC and offset to func struct [each entry PtrSize bytes]
- // end PC [PtrSize bytes]
+ // nfunc [thearch.ptrsize bytes]
+ // function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
+ // end PC [thearch.ptrsize bytes]
// offset to file table [4 bytes]
nfunc = 0;
- for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next)
- nfunc++;
- symgrow(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4);
+ for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
+ if(!container(ctxt->cursym))
+ nfunc++;
+ }
+ symgrow(ctxt, ftab, 8+thearch.ptrsize+nfunc*2*thearch.ptrsize+thearch.ptrsize+4);
setuint32(ctxt, ftab, 0, 0xfffffffb);
- setuint8(ctxt, ftab, 6, MINLC);
- setuint8(ctxt, ftab, 7, PtrSize);
- setuintxx(ctxt, ftab, 8, nfunc, PtrSize);
+ setuint8(ctxt, ftab, 6, thearch.minlc);
+ setuint8(ctxt, ftab, 7, thearch.ptrsize);
+ setuintxx(ctxt, ftab, 8, nfunc, thearch.ptrsize);
nfunc = 0;
- for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next, nfunc++) {
+ last = nil;
+ for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
+ last = ctxt->cursym;
+ if(container(ctxt->cursym))
+ continue;
pcln = ctxt->cursym->pcln;
if(pcln == nil)
pcln = &zpcln;
funcstart = ftab->np;
- funcstart += -ftab->np & (PtrSize-1);
+ funcstart += -ftab->np & (thearch.ptrsize-1);
- setaddr(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize, ctxt->cursym);
- setuintxx(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize);
+ setaddr(ctxt, ftab, 8+thearch.ptrsize+nfunc*2*thearch.ptrsize, ctxt->cursym);
+ setuintxx(ctxt, ftab, 8+thearch.ptrsize+nfunc*2*thearch.ptrsize+thearch.ptrsize, funcstart, thearch.ptrsize);
// fixed size of struct, checked below
off = funcstart;
- end = funcstart + PtrSize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*PtrSize;
- if(pcln->nfuncdata > 0 && (end&(PtrSize-1)))
+ end = funcstart + thearch.ptrsize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*thearch.ptrsize;
+ if(pcln->nfuncdata > 0 && (end&(thearch.ptrsize-1)))
end += 4;
symgrow(ctxt, ftab, end);
@@ -173,7 +191,7 @@ pclntab(void)
// when a called function doesn't have argument information.
// We need to make sure everything has argument information
// and then remove this.
- frameptrsize = PtrSize;
+ frameptrsize = thearch.ptrsize;
if(ctxt->cursym->leaf)
frameptrsize = 0;
off = setuint32(ctxt, ftab, off, ctxt->cursym->locals + frameptrsize);
@@ -203,38 +221,38 @@ pclntab(void)
// funcdata, must be pointer-aligned and we're only int32-aligned.
// Missing funcdata will be 0 (nil pointer).
if(pcln->nfuncdata > 0) {
- if(off&(PtrSize-1))
+ if(off&(thearch.ptrsize-1))
off += 4;
for(i=0; i<pcln->nfuncdata; i++) {
if(pcln->funcdata[i] == nil)
- setuintxx(ctxt, ftab, off+PtrSize*i, pcln->funcdataoff[i], PtrSize);
+ setuintxx(ctxt, ftab, off+thearch.ptrsize*i, pcln->funcdataoff[i], thearch.ptrsize);
else {
// TODO: Dedup.
funcdata_bytes += pcln->funcdata[i]->size;
- setaddrplus(ctxt, ftab, off+PtrSize*i, pcln->funcdata[i], pcln->funcdataoff[i]);
+ setaddrplus(ctxt, ftab, off+thearch.ptrsize*i, pcln->funcdata[i], pcln->funcdataoff[i]);
}
}
- off += pcln->nfuncdata*PtrSize;
+ off += pcln->nfuncdata*thearch.ptrsize;
}
if(off != end) {
- diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata, PtrSize);
+ diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata, thearch.ptrsize);
errorexit();
}
- // Final entry of table is just end pc.
- if(ctxt->cursym->next == nil)
- setaddrplus(ctxt, ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, ctxt->cursym, ctxt->cursym->size);
+ nfunc++;
}
+ // Final entry of table is just end pc.
+ setaddrplus(ctxt, ftab, 8+thearch.ptrsize+nfunc*2*thearch.ptrsize, last, last->size);
// Start file table.
start = ftab->np;
- start += -ftab->np & (PtrSize-1);
- setuint32(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start);
+ start += -ftab->np & (thearch.ptrsize-1);
+ setuint32(ctxt, ftab, 8+thearch.ptrsize+nfunc*2*thearch.ptrsize+thearch.ptrsize, start);
symgrow(ctxt, ftab, start+(ctxt->nhistfile+1)*4);
setuint32(ctxt, ftab, start, ctxt->nhistfile);
- for(s = ctxt->filesyms; s != S; s = s->next)
+ for(s = ctxt->filesyms; s != nil; s = s->next)
setuint32(ctxt, ftab, start + s->value*4, ftabaddstring(ftab, s->name));
ftab->size = ftab->np;
@@ -246,6 +264,8 @@ pclntab(void)
enum {
BUCKETSIZE = 256*MINFUNC,
SUBBUCKETS = 16,
+ SUBBUCKETSIZE = BUCKETSIZE/SUBBUCKETS,
+ NOIDX = 0x7fffffff
};
// findfunctab generates a lookup table to quickly find the containing
@@ -253,9 +273,10 @@ enum {
void
findfunctab(void)
{
- LSym *t, *s;
- int32 idx, bidx, i, j, nbuckets;
- vlong min, max;
+ LSym *t, *s, *e;
+ int32 idx, i, j, nbuckets, n, base;
+ vlong min, max, p, q;
+ int32 *indexes;
t = linklookup(ctxt, "runtime.findfunctab", 0);
t->type = SRODATA;
@@ -267,33 +288,60 @@ findfunctab(void)
for(s = ctxt->textp; s != nil; s = s->next)
max = s->value + s->size;
+ // for each subbucket, compute the minimum of all symbol indexes
+ // that map to that subbucket.
+ n = (max-min+SUBBUCKETSIZE-1)/SUBBUCKETSIZE;
+ indexes = (int32*)malloc(n*4);
+ if(indexes == nil) {
+ diag("out of memory");
+ errorexit();
+ }
+ for(i = 0; i < n; i++)
+ indexes[i] = NOIDX;
+ idx = 0;
+ for(s = ctxt->textp; s != nil; s = s->next) {
+ if(container(s))
+ continue;
+ p = s->value;
+ e = s->next;
+ while(container(e))
+ e = e->next;
+ if(e != nil)
+ q = e->value;
+ else
+ q = max;
+
+ //print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
+ for(; p < q; p += SUBBUCKETSIZE) {
+ i = (p - min) / SUBBUCKETSIZE;
+ if(indexes[i] > idx)
+ indexes[i] = idx;
+ }
+ i = (q - 1 - min) / SUBBUCKETSIZE;
+ if(indexes[i] > idx)
+ indexes[i] = idx;
+ idx++;
+ }
+
// allocate table
nbuckets = (max-min+BUCKETSIZE-1)/BUCKETSIZE;
- symgrow(ctxt, t, nbuckets * (4+SUBBUCKETS));
+ symgrow(ctxt, t, 4*nbuckets + n);
// fill in table
- s = ctxt->textp;
- idx = 0;
for(i = 0; i < nbuckets; i++) {
- // Find first function which overlaps this bucket.
- // Only do leaf symbols; skip symbols which are just containers (sub != nil but outer == nil).
- while(s != nil && (s->value+s->size <= min + i * BUCKETSIZE || s->sub != nil && s->outer == nil)) {
- s = s->next;
- idx++;
- }
- // record this function in bucket header
- setuint32(ctxt, t, i*(4+SUBBUCKETS), idx);
- bidx = idx;
-
- // compute SUBBUCKETS deltas
- for(j = 0; j < SUBBUCKETS; j++) {
- while(s != nil && (s->value+s->size <= min + i * BUCKETSIZE + j * (BUCKETSIZE/SUBBUCKETS) || s->sub != nil && s->outer == nil)) {
- s = s->next;
- idx++;
+ base = indexes[i*SUBBUCKETS];
+ if(base == NOIDX)
+ diag("hole in findfunctab");
+ setuint32(ctxt, t, i*(4+SUBBUCKETS), base);
+ for(j = 0; j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++) {
+ idx = indexes[i*SUBBUCKETS+j];
+ if(idx == NOIDX)
+ diag("hole in findfunctab");
+ if(idx - base >= 256) {
+ diag("too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base);
}
- if(idx - bidx >= 256)
- diag("too many functions in a findfunc bucket! %d %s", idx-bidx, s->name);
- setuint8(ctxt, t, i*(4+SUBBUCKETS)+4+j, idx-bidx);
+ setuint8(ctxt, t, i*(4+SUBBUCKETS)+4+j, idx-base);
}
}
+ free(indexes);
}
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index c26cd5264a..cb87778abd 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -5,10 +5,13 @@
// PE (Portable Executable) file writing
// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/pe.h"
-#include "../ld/dwarf.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "lib.h"
+#include "pe.h"
+#include "dwarf.h"
// DOS stub that prints out
// "This program cannot be run in DOS mode."
@@ -139,7 +142,7 @@ peinit(void)
{
int32 l;
- switch(thechar) {
+ switch(thearch.thechar) {
// 64-bit architectures
case '6':
pe64 = 1;
@@ -204,7 +207,7 @@ initdynimport(void)
dr = nil;
m = nil;
- for(s = ctxt->allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != nil; s = s->allsym) {
if(!s->reachable || s->type != SDYNIMPORT)
continue;
for(d = dr; d != nil; d = d->next) {
@@ -234,9 +237,9 @@ initdynimport(void)
m->s->sub = dynamic->sub;
dynamic->sub = m->s;
m->s->value = dynamic->size;
- dynamic->size += PtrSize;
+ dynamic->size += thearch.ptrsize;
}
- dynamic->size += PtrSize;
+ dynamic->size += thearch.ptrsize;
}
return dr;
@@ -344,7 +347,7 @@ initdynexport(void)
LSym *s;
nexport = 0;
- for(s = ctxt->allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != nil; s = s->allsym) {
if(!s->reachable || !(s->cgoexport & CgoExportDynamic))
continue;
if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
@@ -611,7 +614,7 @@ asmbpe(void)
{
IMAGE_SECTION_HEADER *t, *d;
- switch(thechar) {
+ switch(thearch.thechar) {
default:
diag("unknown PE architecture");
errorexit();
@@ -646,7 +649,9 @@ asmbpe(void)
addpersrc();
fh.NumberOfSections = nsect;
- fh.TimeDateStamp = time(0);
+ // Being able to produce identical output for identical input is
+ // much more beneficial than having build timestamp in the header.
+ fh.TimeDateStamp = 0;
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED;
if (pe64) {
diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c
index 8ecd18b817..0a48eb3a76 100644
--- a/src/cmd/ld/pobj.c
+++ b/src/cmd/ld/pobj.c
@@ -31,31 +31,33 @@
// Reading object files.
#define EXTERN
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
-#include "../ld/macho.h"
-#include "../ld/dwarf.h"
-#include "../ld/pe.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "lib.h"
+#include "elf.h"
+#include "macho.h"
+#include "dwarf.h"
+#include "pe.h"
#include <ar.h>
char *noname = "<none>";
char* paramspace = "FP";
void
-main(int argc, char *argv[])
+ldmain(int argc, char **argv)
{
int i;
- linkarchinit();
ctxt = linknew(thelinkarch);
- ctxt->thechar = thechar;
+ ctxt->thechar = thearch.thechar;
ctxt->thestring = thestring;
ctxt->diag = diag;
ctxt->bso = &bso;
Binit(&bso, 1, OWRITE);
- listinit();
+ thearch.listinit();
memset(debug, 0, sizeof(debug));
nerrors = 0;
outfile = nil;
@@ -73,30 +75,30 @@ main(int argc, char *argv[])
if(strcmp(argv[i], "-crash_for_testing") == 0)
*(volatile int*)0 = 0;
- if(thechar == '5' && ctxt->goarm == 5)
+ if(thearch.thechar == '5' && ctxt->goarm == 5)
debug['F'] = 1;
flagcount("1", "use alternate profiling code", &debug['1']);
- if(thechar == '6')
+ if(thearch.thechar == '6')
flagcount("8", "assume 64-bit addresses", &debug['8']);
flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
flagcount("C", "check Go calls to C code", &debug['C']);
flagint64("D", "addr: data address", &INITDAT);
flagstr("E", "sym: entry symbol", &INITENTRY);
- if(thechar == '5')
+ if(thearch.thechar == '5')
flagcount("G", "debug pseudo-ops", &debug['G']);
flagfn1("I", "interp: set ELF interp", setinterp);
flagfn1("L", "dir: add dir to library path", Lflag);
flagfn1("H", "head: header type", setheadtype);
flagcount("K", "add stack underflow checks", &debug['K']);
- if(thechar == '5')
+ if(thearch.thechar == '5')
flagcount("M", "disable software div/mod", &debug['M']);
flagcount("O", "print pc-line tables", &debug['O']);
flagcount("Q", "debug byte-register code gen", &debug['Q']);
- if(thechar == '5')
+ if(thearch.thechar == '5')
flagcount("P", "debug code generation", &debug['P']);
flagint32("R", "rnd: address rounding", &INITRND);
- flagcount("S", "check type signatures", &debug['S']);
+ flagcount("nil", "check type signatures", &debug['S']);
flagint64("T", "addr: text address", &INITTEXT);
flagfn0("V", "print version and exit", doversion);
flagcount("W", "disassemble input", &debug['W']);
@@ -117,7 +119,7 @@ main(int argc, char *argv[])
flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
flagcount("race", "enable race detector", &flag_race);
flagcount("s", "disable symbol table", &debug['s']);
- if(thechar == '5' || thechar == '6')
+ if(thearch.thechar == '5' || thearch.thechar == '6')
flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
flagstr("tmpdir", "dir: leave temporary files in this directory", &tmpdir);
flagcount("u", "reject unsafe packages", &debug['u']);
@@ -139,9 +141,9 @@ main(int argc, char *argv[])
if(outfile == nil) {
if(HEADTYPE == Hwindows)
- outfile = smprint("%c.out.exe", thechar);
+ outfile = smprint("%c.out.exe", thearch.thechar);
else
- outfile = smprint("%c.out", thechar);
+ outfile = smprint("%c.out", thearch.thechar);
}
libinit(); // creates outfile
@@ -151,7 +153,7 @@ main(int argc, char *argv[])
if(headstring == nil)
headstring = headstr(HEADTYPE);
- archinit();
+ thearch.archinit();
ctxt->debugfloat = debug['F'];
if(debug['v'])
@@ -165,7 +167,7 @@ main(int argc, char *argv[])
addlibpath(ctxt, "command line", "command line", argv[0], "main");
loadlib();
- if(thechar == '5') {
+ if(thearch.thechar == '5') {
// mark some functions that are only referenced after linker code editing
if(debug['F'])
mark(linkrlookup(ctxt, "_sfloat", 0));
@@ -184,7 +186,7 @@ main(int argc, char *argv[])
if(HEADTYPE == Hwindows)
dope();
addexport();
- gentext(); // trampolines, call stubs, etc.
+ thearch.gentext(); // trampolines, call stubs, etc.
textaddress();
pclntab();
findfunctab();
@@ -193,7 +195,7 @@ main(int argc, char *argv[])
address();
doweak();
reloc();
- asmb();
+ thearch.asmb();
undef();
hostlink();
if(debug['v']) {
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index c3a72c3cf6..55ef608c1d 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -30,9 +30,12 @@
// Symbol table.
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/elf.h"
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "lib.h"
+#include "elf.h"
static int maxelfstr;
@@ -76,24 +79,24 @@ putelfstr(char *s)
static void
putelfsyment(int off, vlong addr, vlong size, int info, int shndx, int other)
{
- switch(thechar) {
+ switch(thearch.thechar) {
case '6':
case '9':
- LPUT(off);
+ thearch.lput(off);
cput(info);
cput(other);
- WPUT(shndx);
- VPUT(addr);
- VPUT(size);
+ thearch.wput(shndx);
+ thearch.vput(addr);
+ thearch.vput(size);
symsize += ELF64SYMSIZE;
break;
default:
- LPUT(off);
- LPUT(addr);
- LPUT(size);
+ thearch.lput(off);
+ thearch.lput(addr);
+ thearch.lput(size);
cput(info);
cput(other);
- WPUT(shndx);
+ thearch.wput(shndx);
symsize += ELF32SYMSIZE;
break;
}
@@ -172,7 +175,7 @@ putelfsymshndx(vlong sympos, int shndx)
vlong here;
here = cpos();
- switch(thechar) {
+ switch(thearch.thechar) {
case '6':
cseek(sympos+6);
break;
@@ -180,7 +183,7 @@ putelfsymshndx(vlong sympos, int shndx)
cseek(sympos+14);
break;
}
- WPUT(shndx);
+ thearch.wput(shndx);
cseek(here);
}
@@ -218,7 +221,7 @@ asmelfsym(void)
elfglobalsymndx = numelfsym;
genasmsym(putelfsym);
- for(s=ctxt->allsym; s!=S; s=s->allsym) {
+ for(s=ctxt->allsym; s!=nil; s=s->allsym) {
if(s->type != SHOSTOBJ && !(s->type == SDYNIMPORT && s->reachable))
continue;
if(s->type == SDYNIMPORT)
@@ -253,7 +256,7 @@ putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
case 'Z':
case 'm':
l = 4;
- if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) {
+ if(HEADTYPE == Hplan9 && thearch.thechar == '6' && !debug['8']) {
lputb(addr>>32);
l = 8;
}
@@ -307,7 +310,7 @@ wputb(ushort w)
}
void
-lputb(int32 l)
+lputb(uint32 l)
{
cput(l>>24);
cput(l>>16);
@@ -316,7 +319,7 @@ lputb(int32 l)
}
void
-lputl(int32 l)
+lputl(uint32 l)
{
cput(l);
cput(l>>8);
@@ -408,7 +411,7 @@ symtab(void)
// within a type they sort by size, so the .* symbols
// just defined above will be first.
// hide the specific symbols.
- for(s = ctxt->allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != nil; s = s->allsym) {
if(!s->reachable || s->special || s->type != SRODATA)
continue;
if(strncmp(s->name, "type.", 5) == 0) {
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
index fbc6a3c698..0c58d628b4 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -257,15 +257,8 @@ func TestLargeDefs(t *testing.T) {
}
}
- n := 10000
- if testing.Short() {
- // Issue 9656: 10,000 is too aggressive for several
- // builders, with ~120 MB of disk consumed. 1,000 is
- // still enough to exercise the old bug.
- n = 1000
- }
printf("package large\n\ntype T struct {\n")
- for i := 0; i < n; i++ {
+ for i := 0; i < 1000; i++ {
printf("f%d int `tag:\"", i)
for j := 0; j < 100; j++ {
printf("t%d=%d,", j, j)
diff --git a/src/cmd/pprof/internal/report/report.go b/src/cmd/pprof/internal/report/report.go
index e5977fd034..586f41d4d6 100644
--- a/src/cmd/pprof/internal/report/report.go
+++ b/src/cmd/pprof/internal/report/report.go
@@ -1531,7 +1531,7 @@ func memoryLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok
output, toUnit = float64(value)/1024, "kB"
case "mb", "mbyte", "megabyte":
output, toUnit = float64(value)/(1024*1024), "MB"
- case "gb", "gbyte", "giggabyte":
+ case "gb", "gbyte", "gigabyte":
output, toUnit = float64(value)/(1024*1024*1024), "GB"
}
return output, toUnit, true
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
index 0a69c36afc..24692dc166 100644
--- a/src/cmd/yacc/yacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -603,6 +603,7 @@ outer:
}
levprd[nprod] |= ACTFLAG
fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
+ fmt.Fprintf(fcode, "\n\t\t%sDollar = %sS[%spt-%v:%spt+1]", prefix, prefix, prefix, mem-1, prefix)
cpyact(curprod, mem)
// action within rule...
@@ -1345,7 +1346,7 @@ loop:
ungetrune(finput, c)
continue loop
}
- fmt.Fprintf(fcode, "%sS[%spt-%v]", prefix, prefix, max-j-1)
+ fmt.Fprintf(fcode, "%sDollar[%v]", prefix, j)
// put out the proper tag
if ntypes != 0 {
@@ -3264,6 +3265,7 @@ func $$Parse($$lex $$Lexer) int {
var $$n int
var $$lval $$SymType
var $$VAL $$SymType
+ var $$Dollar []$$SymType
$$S := make([]$$SymType, $$MaxDepth)
Nerrs := 0 /* number of errors */
diff --git a/src/compress/bzip2/bzip2_test.go b/src/compress/bzip2/bzip2_test.go
index fb79d089eb..77c50dfe94 100644
--- a/src/compress/bzip2/bzip2_test.go
+++ b/src/compress/bzip2/bzip2_test.go
@@ -200,7 +200,7 @@ func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) }
func BenchmarkDecodeTwain(b *testing.B) { benchmarkDecode(b, twain) }
func TestBufferOverrun(t *testing.T) {
- // Tests https://code.google.com/p/go/issues/detail?id=5747.
+ // Tests https://golang.org/issue/5747.
buffer := bytes.NewReader([]byte(bufferOverrunBase64))
decoder := base64.NewDecoder(base64.StdEncoding, buffer)
decompressor := NewReader(decoder)
@@ -209,7 +209,7 @@ func TestBufferOverrun(t *testing.T) {
}
func TestOutOfRangeSelector(t *testing.T) {
- // Tests https://code.google.com/p/go/issues/detail?id=8363.
+ // Tests https://golang.org/issue/8363.
buffer := bytes.NewReader(outOfRangeSelector)
decompressor := NewReader(buffer)
// This shouldn't panic.
diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go
index 730234c385..53bfd26438 100644
--- a/src/compress/flate/deflate_test.go
+++ b/src/compress/flate/deflate_test.go
@@ -407,7 +407,7 @@ func TestWriterDict(t *testing.T) {
}
}
-// See http://code.google.com/p/go/issues/detail?id=2508
+// See http://golang.org/issue/2508
func TestRegression2508(t *testing.T) {
if testing.Short() {
t.Logf("test disabled with -short")
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index a46133439d..c87da50df9 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -172,7 +172,7 @@ Curves:
// Although sending an empty NPN extension is reasonable, Firefox has
// had a bug around this. Best to send nothing at all if
// config.NextProtos is empty. See
- // https://code.google.com/p/go/issues/detail?id=5445.
+ // https://golang.org/issue/5445.
if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
hs.hello.nextProtoNeg = true
hs.hello.nextProtos = config.NextProtos
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index ec1981423d..0181f140fa 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -323,6 +323,8 @@ nextIntermediate:
}
func matchHostnames(pattern, host string) bool {
+ host = strings.TrimSuffix(host, ".")
+
if len(pattern) == 0 || len(host) == 0 {
return false
}
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index bd7cbed8a2..45d49ce3e3 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -161,11 +161,16 @@ var matchHostnamesTests = []matchHostnamesTest{
{"", "b.b.c", false},
{"a.b.c", "", false},
{"example.com", "example.com", true},
+ {"example.com", "example.com.", true},
{"example.com", "www.example.com", false},
{"*.example.com", "www.example.com", true},
+ {"*.example.com", "www.example.com.", true},
{"*.example.com", "xyz.www.example.com", false},
{"*.*.example.com", "xyz.www.example.com", true},
{"*.www.*.com", "xyz.www.example.com", true},
+ {"", ".", false},
+ {".", "", false},
+ {".", ".", false},
}
func TestMatchHostnames(t *testing.T) {
diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go
index 8c6342013d..9d6045c916 100644
--- a/src/encoding/xml/marshal.go
+++ b/src/encoding/xml/marshal.go
@@ -179,17 +179,24 @@ var (
)
// EncodeToken writes the given XML token to the stream.
-// It returns an error if StartElement and EndElement tokens are not properly matched.
+// It returns an error if StartElement and EndElement tokens are not
+// properly matched.
//
-// EncodeToken does not call Flush, because usually it is part of a larger operation
-// such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
-// during those), and those will call Flush when finished.
-// Callers that create an Encoder and then invoke EncodeToken directly, without
-// using Encode or EncodeElement, need to call Flush when finished to ensure
-// that the XML is written to the underlying writer.
+// EncodeToken does not call Flush, because usually it is part of a
+// larger operation such as Encode or EncodeElement (or a custom
+// Marshaler's MarshalXML invoked during those), and those will call
+// Flush when finished. Callers that create an Encoder and then invoke
+// EncodeToken directly, without using Encode or EncodeElement, need to
+// call Flush when finished to ensure that the XML is written to the
+// underlying writer.
//
-// EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token
-// in the stream.
+// EncodeToken allows writing a ProcInst with Target set to "xml" only
+// as the first token in the stream.
+//
+// When encoding a StartElement holding an XML namespace prefix
+// declaration for a prefix that is not already declared, contained
+// elements (including the StartElement itself) will use the declared
+// prefix when encoding names with matching namespace URIs.
func (enc *Encoder) EncodeToken(t Token) error {
p := &enc.p
switch t := t.(type) {
@@ -256,19 +263,27 @@ type printer struct {
depth int
indentedIn bool
putNewline bool
+ defaultNS string
attrNS map[string]string // map prefix -> name space
attrPrefix map[string]string // map name space -> prefix
- prefixes []string
+ prefixes []printerPrefix
tags []Name
}
-// createAttrPrefix finds the name space prefix attribute to use for the given name space,
-// defining a new prefix if necessary. It returns the prefix.
-func (p *printer) createAttrPrefix(url string) string {
- if prefix := p.attrPrefix[url]; prefix != "" {
- return prefix
- }
+// printerPrefix holds a namespace undo record.
+// When an element is popped, the prefix record
+// is set back to the recorded URL. The empty
+// prefix records the URL for the default name space.
+//
+// The start of an element is recorded with an element
+// that has mark=true.
+type printerPrefix struct {
+ prefix string
+ url string
+ mark bool
+}
+func (p *printer) prefixForNS(url string, isAttr bool) string {
// The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml"
// and must be referred to that way.
// (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns",
@@ -276,12 +291,97 @@ func (p *printer) createAttrPrefix(url string) string {
if url == xmlURL {
return "xml"
}
+ if !isAttr && url == p.defaultNS {
+ // We can use the default name space.
+ return ""
+ }
+ return p.attrPrefix[url]
+}
- // Need to define a new name space.
- if p.attrPrefix == nil {
- p.attrPrefix = make(map[string]string)
- p.attrNS = make(map[string]string)
+// defineNS pushes any namespace definition found in the given attribute.
+// If ignoreNonEmptyDefault is true, an xmlns="nonempty"
+// attribute will be ignored.
+func (p *printer) defineNS(attr Attr, ignoreNonEmptyDefault bool) error {
+ var prefix string
+ if attr.Name.Local == "xmlns" {
+ if attr.Name.Space != "" && attr.Name.Space != "xml" && attr.Name.Space != xmlURL {
+ return fmt.Errorf("xml: cannot redefine xmlns attribute prefix")
+ }
+ } else if attr.Name.Space == "xmlns" && attr.Name.Local != "" {
+ prefix = attr.Name.Local
+ if attr.Value == "" {
+ // Technically, an empty XML namespace is allowed for an attribute.
+ // From http://www.w3.org/TR/xml-names11/#scoping-defaulting:
+ //
+ // The attribute value in a namespace declaration for a prefix may be
+ // empty. This has the effect, within the scope of the declaration, of removing
+ // any association of the prefix with a namespace name.
+ //
+ // However our namespace prefixes here are used only as hints. There's
+ // no need to respect the removal of a namespace prefix, so we ignore it.
+ return nil
+ }
+ } else {
+ // Ignore: it's not a namespace definition
+ return nil
+ }
+ if prefix == "" {
+ if attr.Value == p.defaultNS {
+ // No need for redefinition.
+ return nil
+ }
+ if attr.Value != "" && ignoreNonEmptyDefault {
+ // We have an xmlns="..." value but
+ // it can't define a name space in this context,
+ // probably because the element has an empty
+ // name space. In this case, we just ignore
+ // the name space declaration.
+ return nil
+ }
+ } else if _, ok := p.attrPrefix[attr.Value]; ok {
+ // There's already a prefix for the given name space,
+ // so use that. This prevents us from
+ // having two prefixes for the same name space
+ // so attrNS and attrPrefix can remain bijective.
+ return nil
}
+ p.pushPrefix(prefix, attr.Value)
+ return nil
+}
+
+// createNSPrefix creates a name space prefix attribute
+// to use for the given name space, defining a new prefix
+// if necessary.
+// If isAttr is true, the prefix is to be created for an attribute
+// prefix, which means that the default name space cannot
+// be used.
+func (p *printer) createNSPrefix(url string, isAttr bool) {
+ if _, ok := p.attrPrefix[url]; ok {
+ // We already have a prefix for the given URL.
+ return
+ }
+ switch {
+ case !isAttr && url == p.defaultNS:
+ // We can use the default name space.
+ return
+ case url == "":
+ // The only way we can encode names in the empty
+ // name space is by using the default name space,
+ // so we must use that.
+ if p.defaultNS != "" {
+ // The default namespace is non-empty, so we
+ // need to set it to empty.
+ p.pushPrefix("", "")
+ }
+ return
+ case url == xmlURL:
+ return
+ }
+ // TODO If the URL is an existing prefix, we could
+ // use it as is. That would enable the
+ // marshaling of elements that had been unmarshaled
+ // and with a name space prefix that was not found.
+ // although technically it would be incorrect.
// Pick a name. We try to use the final element of the path
// but fall back to _.
@@ -306,39 +406,98 @@ func (p *printer) createAttrPrefix(url string) string {
}
}
- p.attrPrefix[url] = prefix
- p.attrNS[prefix] = url
-
- p.WriteString(`xmlns:`)
- p.WriteString(prefix)
- p.WriteString(`="`)
- EscapeText(p, []byte(url))
- p.WriteString(`" `)
+ p.pushPrefix(prefix, url)
+}
- p.prefixes = append(p.prefixes, prefix)
+// writeNamespaces writes xmlns attributes for all the
+// namespace prefixes that have been defined in
+// the current element.
+func (p *printer) writeNamespaces() {
+ for i := len(p.prefixes) - 1; i >= 0; i-- {
+ prefix := p.prefixes[i]
+ if prefix.mark {
+ return
+ }
+ p.WriteString(" ")
+ if prefix.prefix == "" {
+ // Default name space.
+ p.WriteString(`xmlns="`)
+ } else {
+ p.WriteString("xmlns:")
+ p.WriteString(prefix.prefix)
+ p.WriteString(`="`)
+ }
+ EscapeText(p, []byte(p.nsForPrefix(prefix.prefix)))
+ p.WriteString(`"`)
+ }
+}
- return prefix
+// pushPrefix pushes a new prefix on the prefix stack
+// without checking to see if it is already defined.
+func (p *printer) pushPrefix(prefix, url string) {
+ p.prefixes = append(p.prefixes, printerPrefix{
+ prefix: prefix,
+ url: p.nsForPrefix(prefix),
+ })
+ p.setAttrPrefix(prefix, url)
}
-// deleteAttrPrefix removes an attribute name space prefix.
-func (p *printer) deleteAttrPrefix(prefix string) {
- delete(p.attrPrefix, p.attrNS[prefix])
- delete(p.attrNS, prefix)
+// nsForPrefix returns the name space for the given
+// prefix. Note that this is not valid for the
+// empty attribute prefix, which always has an empty
+// name space.
+func (p *printer) nsForPrefix(prefix string) string {
+ if prefix == "" {
+ return p.defaultNS
+ }
+ return p.attrNS[prefix]
}
+// markPrefix marks the start of an element on the prefix
+// stack.
func (p *printer) markPrefix() {
- p.prefixes = append(p.prefixes, "")
+ p.prefixes = append(p.prefixes, printerPrefix{
+ mark: true,
+ })
}
+// popPrefix pops all defined prefixes for the current
+// element.
func (p *printer) popPrefix() {
for len(p.prefixes) > 0 {
prefix := p.prefixes[len(p.prefixes)-1]
p.prefixes = p.prefixes[:len(p.prefixes)-1]
- if prefix == "" {
+ if prefix.mark {
break
}
- p.deleteAttrPrefix(prefix)
+ p.setAttrPrefix(prefix.prefix, prefix.url)
+ }
+}
+
+// setAttrPrefix sets an attribute name space prefix.
+// If url is empty, the attribute is removed.
+// If prefix is empty, the default name space is set.
+func (p *printer) setAttrPrefix(prefix, url string) {
+ if prefix == "" {
+ p.defaultNS = url
+ return
+ }
+ if url == "" {
+ delete(p.attrPrefix, p.attrNS[prefix])
+ delete(p.attrNS, prefix)
+ return
+ }
+ if p.attrPrefix == nil {
+ // Need to define a new name space.
+ p.attrPrefix = make(map[string]string)
+ p.attrNS = make(map[string]string)
}
+ // Remove any old prefix value. This is OK because we maintain a
+ // strict one-to-one mapping between prefix and URL (see
+ // defineNS)
+ delete(p.attrPrefix, p.attrNS[prefix])
+ p.attrPrefix[url] = prefix
+ p.attrNS[prefix] = url
}
var (
@@ -376,23 +535,23 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
// Check for marshaler.
if val.CanInterface() && typ.Implements(marshalerType) {
- return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate))
+ return p.marshalInterface(val.Interface().(Marshaler), p.defaultStart(typ, finfo, startTemplate))
}
if val.CanAddr() {
pv := val.Addr()
if pv.CanInterface() && pv.Type().Implements(marshalerType) {
- return p.marshalInterface(pv.Interface().(Marshaler), defaultStart(pv.Type(), finfo, startTemplate))
+ return p.marshalInterface(pv.Interface().(Marshaler), p.defaultStart(pv.Type(), finfo, startTemplate))
}
}
// Check for text marshaler.
if val.CanInterface() && typ.Implements(textMarshalerType) {
- return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), defaultStart(typ, finfo, startTemplate))
+ return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), p.defaultStart(typ, finfo, startTemplate))
}
if val.CanAddr() {
pv := val.Addr()
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
- return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), defaultStart(pv.Type(), finfo, startTemplate))
+ return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), p.defaultStart(pv.Type(), finfo, startTemplate))
}
}
@@ -419,6 +578,10 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
// 3. type name
var start StartElement
+ // Historic behaviour: elements use the default name space
+ // they are contained in by default.
+ start.Name.Space = p.defaultNS
+
if startTemplate != nil {
start.Name = startTemplate.Name
start.Attr = append(start.Attr, startTemplate.Attr...)
@@ -431,7 +594,10 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
}
}
if start.Name.Local == "" && finfo != nil {
- start.Name.Space, start.Name.Local = finfo.xmlns, finfo.name
+ start.Name.Local = finfo.name
+ if finfo.xmlns != "" {
+ start.Name.Space = finfo.xmlns
+ }
}
if start.Name.Local == "" {
name := typ.Name()
@@ -440,6 +606,9 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
}
start.Name.Local = name
}
+ // Historic behaviour: an element that's in a namespace sets
+ // the default namespace for all elements contained within it.
+ start.setDefaultNamespace()
// Attributes
for i := range tinfo.fields {
@@ -552,7 +721,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
// defaultStart returns the default start element to use,
// given the reflect type, field info, and start template.
-func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
+func (p *printer) defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
var start StartElement
// Precedence for the XML element name is as above,
// except that we do not look inside structs for the first field.
@@ -569,6 +738,12 @@ func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElemen
// since it has the Marshaler methods.
start.Name.Local = typ.Elem().Name()
}
+ // Historic behaviour: elements use the name space of
+ // the element they are contained in by default.
+ if start.Name.Space == "" {
+ start.Name.Space = p.defaultNS
+ }
+ start.setDefaultNamespace()
return start
}
@@ -613,29 +788,44 @@ func (p *printer) writeStart(start *StartElement) error {
p.tags = append(p.tags, start.Name)
p.markPrefix()
+ // Define any name spaces explicitly declared in the attributes.
+ // We do this as a separate pass so that explicitly declared prefixes
+ // will take precedence over implicitly declared prefixes
+ // regardless of the order of the attributes.
+ ignoreNonEmptyDefault := start.Name.Space == ""
+ for _, attr := range start.Attr {
+ if err := p.defineNS(attr, ignoreNonEmptyDefault); err != nil {
+ return err
+ }
+ }
+ // Define any new name spaces implied by the attributes.
+ for _, attr := range start.Attr {
+ name := attr.Name
+ // From http://www.w3.org/TR/xml-names11/#defaulting
+ // "Default namespace declarations do not apply directly
+ // to attribute names; the interpretation of unprefixed
+ // attributes is determined by the element on which they
+ // appear."
+ // This means we don't need to create a new namespace
+ // when an attribute name space is empty.
+ if name.Space != "" && !name.isNamespace() {
+ p.createNSPrefix(name.Space, true)
+ }
+ }
+ p.createNSPrefix(start.Name.Space, false)
p.writeIndent(1)
p.WriteByte('<')
- p.WriteString(start.Name.Local)
-
- if start.Name.Space != "" {
- p.WriteString(` xmlns="`)
- p.EscapeString(start.Name.Space)
- p.WriteByte('"')
- }
-
- // Attributes
+ p.writeName(start.Name, false)
+ p.writeNamespaces()
for _, attr := range start.Attr {
name := attr.Name
- if name.Local == "" {
+ if name.Local == "" || name.isNamespace() {
+ // Namespaces have already been written by writeNamespaces above.
continue
}
p.WriteByte(' ')
- if name.Space != "" {
- p.WriteString(p.createAttrPrefix(name.Space))
- p.WriteByte(':')
- }
- p.WriteString(name.Local)
+ p.writeName(name, true)
p.WriteString(`="`)
p.EscapeString(attr.Value)
p.WriteByte('"')
@@ -644,6 +834,16 @@ func (p *printer) writeStart(start *StartElement) error {
return nil
}
+// writeName writes the given name. It assumes
+// that p.createNSPrefix(name) has already been called.
+func (p *printer) writeName(name Name, isAttr bool) {
+ if prefix := p.prefixForNS(name.Space, isAttr); prefix != "" {
+ p.WriteString(prefix)
+ p.WriteByte(':')
+ }
+ p.WriteString(name.Local)
+}
+
func (p *printer) writeEnd(name Name) error {
if name.Local == "" {
return fmt.Errorf("xml: end tag with no name")
@@ -662,7 +862,7 @@ func (p *printer) writeEnd(name Name) error {
p.writeIndent(-1)
p.WriteByte('<')
p.WriteByte('/')
- p.WriteString(name.Local)
+ p.writeName(name, false)
p.WriteByte('>')
p.popPrefix()
return nil
diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go
index cdd52ff97f..cc6994338d 100644
--- a/src/encoding/xml/marshal_test.go
+++ b/src/encoding/xml/marshal_test.go
@@ -1194,41 +1194,363 @@ func TestStructPointerMarshal(t *testing.T) {
}
var encodeTokenTests = []struct {
- tok Token
+ desc string
+ toks []Token
want string
- ok bool
-}{
- {StartElement{Name{"space", "local"}, nil}, "<local xmlns=\"space\">", true},
- {StartElement{Name{"space", ""}, nil}, "", false},
- {EndElement{Name{"space", ""}}, "", false},
- {CharData("foo"), "foo", true},
- {Comment("foo"), "<!--foo-->", true},
- {Comment("foo-->"), "", false},
- {ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
- {ProcInst{"", []byte("Instruction")}, "", false},
- {ProcInst{"Target", []byte("Instruction?>")}, "", false},
- {Directive("foo"), "<!foo>", true},
- {Directive("foo>"), "", false},
-}
+ err string
+}{{
+ desc: "start element with name space",
+ toks: []Token{
+ StartElement{Name{"space", "local"}, nil},
+ },
+ want: `<space:local xmlns:space="space">`,
+}, {
+ desc: "start element with no name",
+ toks: []Token{
+ StartElement{Name{"space", ""}, nil},
+ },
+ err: "xml: start tag with no name",
+}, {
+ desc: "end element with no name",
+ toks: []Token{
+ EndElement{Name{"space", ""}},
+ },
+ err: "xml: end tag with no name",
+}, {
+ desc: "char data",
+ toks: []Token{
+ CharData("foo"),
+ },
+ want: `foo`,
+}, {
+ desc: "char data with escaped chars",
+ toks: []Token{
+ CharData(" \t\n"),
+ },
+ want: ` &#x9;&#xA;`,
+}, {
+ desc: "comment",
+ toks: []Token{
+ Comment("foo"),
+ },
+ want: `<!--foo-->`,
+}, {
+ desc: "comment with invalid content",
+ toks: []Token{
+ Comment("foo-->"),
+ },
+ err: "xml: EncodeToken of Comment containing --> marker",
+}, {
+ desc: "proc instruction",
+ toks: []Token{
+ ProcInst{"Target", []byte("Instruction")},
+ },
+ want: `<?Target Instruction?>`,
+}, {
+ desc: "proc instruction with empty target",
+ toks: []Token{
+ ProcInst{"", []byte("Instruction")},
+ },
+ err: "xml: EncodeToken of ProcInst with invalid Target",
+}, {
+ desc: "proc instruction with bad content",
+ toks: []Token{
+ ProcInst{"", []byte("Instruction?>")},
+ },
+ err: "xml: EncodeToken of ProcInst with invalid Target",
+}, {
+ desc: "directive",
+ toks: []Token{
+ Directive("foo"),
+ },
+ want: `<!foo>`,
+}, {
+ desc: "directive instruction with bad name",
+ toks: []Token{
+ Directive("foo>"),
+ },
+ err: "xml: EncodeToken of Directive containing > marker",
+}, {
+ desc: "end tag without start tag",
+ toks: []Token{
+ EndElement{Name{"foo", "bar"}},
+ },
+ err: "xml: end tag </bar> without start tag",
+}, {
+ desc: "mismatching end tag local name",
+ toks: []Token{
+ StartElement{Name{"", "foo"}, nil},
+ EndElement{Name{"", "bar"}},
+ },
+ err: "xml: end tag </bar> does not match start tag <foo>",
+ want: `<foo>`,
+}, {
+ desc: "mismatching end tag namespace",
+ toks: []Token{
+ StartElement{Name{"space", "foo"}, nil},
+ EndElement{Name{"another", "foo"}},
+ },
+ err: "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space",
+ want: `<space:foo xmlns:space="space">`,
+}, {
+ desc: "start element with explicit namespace",
+ toks: []Token{
+ StartElement{Name{"space", "local"}, []Attr{
+ {Name{"xmlns", "x"}, "space"},
+ {Name{"space", "foo"}, "value"},
+ }},
+ },
+ want: `<x:local xmlns:x="space" x:foo="value">`,
+}, {
+ desc: "start element with explicit namespace and colliding prefix",
+ toks: []Token{
+ StartElement{Name{"space", "local"}, []Attr{
+ {Name{"xmlns", "x"}, "space"},
+ {Name{"space", "foo"}, "value"},
+ {Name{"x", "bar"}, "other"},
+ }},
+ },
+ want: `<x:local xmlns:x_1="x" xmlns:x="space" x:foo="value" x_1:bar="other">`,
+}, {
+ desc: "start element using previously defined namespace",
+ toks: []Token{
+ StartElement{Name{"", "local"}, []Attr{
+ {Name{"xmlns", "x"}, "space"},
+ }},
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"space", "x"}, "y"},
+ }},
+ },
+ want: `<local xmlns:x="space"><x:foo x:x="y">`,
+}, {
+ desc: "nested name space with same prefix",
+ toks: []Token{
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"xmlns", "x"}, "space1"},
+ }},
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"xmlns", "x"}, "space2"},
+ }},
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"space1", "a"}, "space1 value"},
+ {Name{"space2", "b"}, "space2 value"},
+ }},
+ EndElement{Name{"", "foo"}},
+ EndElement{Name{"", "foo"}},
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"space1", "a"}, "space1 value"},
+ {Name{"space2", "b"}, "space2 value"},
+ }},
+ },
+ want: `<foo xmlns:x="space1"><foo xmlns:x="space2"><foo xmlns:space1="space1" space1:a="space1 value" x:b="space2 value"></foo></foo><foo xmlns:space2="space2" x:a="space1 value" space2:b="space2 value">`,
+}, {
+ desc: "start element defining several prefixes for the same name space",
+ toks: []Token{
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"xmlns", "a"}, "space"},
+ {Name{"xmlns", "b"}, "space"},
+ {Name{"space", "x"}, "value"},
+ }},
+ },
+ want: `<a:foo xmlns:a="space" a:x="value">`,
+}, {
+ desc: "nested element redefines name space",
+ toks: []Token{
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"xmlns", "x"}, "space"},
+ }},
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"xmlns", "y"}, "space"},
+ {Name{"space", "a"}, "value"},
+ }},
+ },
+ want: `<foo xmlns:x="space"><x:foo x:a="value">`,
+}, {
+ desc: "nested element creates alias for default name space",
+ toks: []Token{
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"", "xmlns"}, "space"},
+ }},
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"xmlns", "y"}, "space"},
+ {Name{"space", "a"}, "value"},
+ }},
+ },
+ want: `<foo xmlns="space"><foo xmlns:y="space" y:a="value">`,
+}, {
+ desc: "nested element defines default name space with existing prefix",
+ toks: []Token{
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"xmlns", "x"}, "space"},
+ }},
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"", "xmlns"}, "space"},
+ {Name{"space", "a"}, "value"},
+ }},
+ },
+ want: `<foo xmlns:x="space"><foo xmlns="space" x:a="value">`,
+}, {
+ desc: "nested element uses empty attribute name space when default ns defined",
+ toks: []Token{
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"", "xmlns"}, "space"},
+ }},
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"", "attr"}, "value"},
+ }},
+ },
+ want: `<foo xmlns="space"><foo attr="value">`,
+}, {
+ desc: "redefine xmlns",
+ toks: []Token{
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"foo", "xmlns"}, "space"},
+ }},
+ },
+ err: `xml: cannot redefine xmlns attribute prefix`,
+}, {
+ desc: "xmlns with explicit name space #1",
+ toks: []Token{
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"xml", "xmlns"}, "space"},
+ }},
+ },
+ want: `<foo xmlns="space">`,
+}, {
+ desc: "xmlns with explicit name space #2",
+ toks: []Token{
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{xmlURL, "xmlns"}, "space"},
+ }},
+ },
+ want: `<foo xmlns="space">`,
+}, {
+ desc: "empty name space declaration is ignored",
+ toks: []Token{
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"xmlns", "foo"}, ""},
+ }},
+ },
+ want: `<foo>`,
+}, {
+ desc: "attribute with no name is ignored",
+ toks: []Token{
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"", ""}, "value"},
+ }},
+ },
+ want: `<foo>`,
+}, {
+ desc: "namespace URL with non-valid name",
+ toks: []Token{
+ StartElement{Name{"/34", "foo"}, []Attr{
+ {Name{"/34", "x"}, "value"},
+ }},
+ },
+ want: `<_:foo xmlns:_="/34" _:x="value">`,
+}, {
+ desc: "nested element resets default namespace to empty",
+ toks: []Token{
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"", "xmlns"}, "space"},
+ }},
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"", "xmlns"}, ""},
+ {Name{"", "x"}, "value"},
+ {Name{"space", "x"}, "value"},
+ }},
+ },
+ want: `<foo xmlns="space"><foo xmlns:space="space" xmlns="" x="value" space:x="value">`,
+}, {
+ desc: "nested element requires empty default name space",
+ toks: []Token{
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"", "xmlns"}, "space"},
+ }},
+ StartElement{Name{"", "foo"}, nil},
+ },
+ want: `<foo xmlns="space"><foo xmlns="">`,
+}, {
+ desc: "attribute uses name space from xmlns",
+ toks: []Token{
+ StartElement{Name{"some/space", "foo"}, []Attr{
+ {Name{"", "attr"}, "value"},
+ {Name{"some/space", "other"}, "other value"},
+ }},
+ },
+ want: `<space:foo xmlns:space="some/space" attr="value" space:other="other value">`,
+}, {
+ desc: "default name space should not be used by attributes",
+ toks: []Token{
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"", "xmlns"}, "space"},
+ {Name{"xmlns", "bar"}, "space"},
+ {Name{"space", "baz"}, "foo"},
+ }},
+ StartElement{Name{"space", "baz"}, nil},
+ EndElement{Name{"space", "baz"}},
+ EndElement{Name{"space", "foo"}},
+ },
+ want: `<foo xmlns:bar="space" xmlns="space" bar:baz="foo"><baz></baz></foo>`,
+}, {
+ desc: "default name space not used by attributes, not explicitly defined",
+ toks: []Token{
+ StartElement{Name{"space", "foo"}, []Attr{
+ {Name{"", "xmlns"}, "space"},
+ {Name{"space", "baz"}, "foo"},
+ }},
+ StartElement{Name{"space", "baz"}, nil},
+ EndElement{Name{"space", "baz"}},
+ EndElement{Name{"space", "foo"}},
+ },
+ want: `<foo xmlns:space="space" xmlns="space" space:baz="foo"><baz></baz></foo>`,
+}, {
+ desc: "impossible xmlns declaration",
+ toks: []Token{
+ StartElement{Name{"", "foo"}, []Attr{
+ {Name{"", "xmlns"}, "space"},
+ }},
+ StartElement{Name{"space", "bar"}, []Attr{
+ {Name{"space", "attr"}, "value"},
+ }},
+ },
+ want: `<foo><space:bar xmlns:space="space" space:attr="value">`,
+}}
func TestEncodeToken(t *testing.T) {
- for _, tt := range encodeTokenTests {
+loop:
+ for i, tt := range encodeTokenTests {
var buf bytes.Buffer
enc := NewEncoder(&buf)
- err := enc.EncodeToken(tt.tok)
+ var err error
+ for j, tok := range tt.toks {
+ err = enc.EncodeToken(tok)
+ if err != nil && j < len(tt.toks)-1 {
+ t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err)
+ continue loop
+ }
+ }
+ errorf := func(f string, a ...interface{}) {
+ t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...))
+ }
switch {
- case !tt.ok && err == nil:
- t.Errorf("enc.EncodeToken(%#v): expected error; got none", tt.tok)
- case tt.ok && err != nil:
- t.Fatalf("enc.EncodeToken: %v", err)
- case !tt.ok && err != nil:
- // expected error, got one
+ case tt.err != "" && err == nil:
+ errorf(" expected error; got none")
+ continue
+ case tt.err == "" && err != nil:
+ errorf(" got error: %v", err)
+ continue
+ case tt.err != "" && err != nil && tt.err != err.Error():
+ errorf(" error mismatch; got %v, want %v", err, tt.err)
+ continue
}
if err := enc.Flush(); err != nil {
- t.Fatalf("enc.EncodeToken: %v", err)
+ errorf(" %v", err)
+ continue
}
if got := buf.String(); got != tt.want {
- t.Errorf("enc.EncodeToken = %s; want: %s", got, tt.want)
+ errorf("\ngot %v\nwant %v", got, tt.want)
+ continue
}
}
}
diff --git a/src/encoding/xml/read_test.go b/src/encoding/xml/read_test.go
index 01f55d0dd0..02f1e10c33 100644
--- a/src/encoding/xml/read_test.go
+++ b/src/encoding/xml/read_test.go
@@ -5,6 +5,8 @@
package xml
import (
+ "bytes"
+ "fmt"
"io"
"reflect"
"strings"
@@ -484,6 +486,34 @@ func TestUnmarshalNS(t *testing.T) {
}
}
+func TestRoundTrip(t *testing.T) {
+ // From issue 7535
+ const s = `<ex:element xmlns:ex="http://example.com/schema"></ex:element>`
+ in := bytes.NewBufferString(s)
+ for i := 0; i < 10; i++ {
+ out := &bytes.Buffer{}
+ d := NewDecoder(in)
+ e := NewEncoder(out)
+
+ for {
+ t, err := d.Token()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ fmt.Println("failed:", err)
+ return
+ }
+ e.EncodeToken(t)
+ }
+ e.Flush()
+ in = out
+ }
+ if got := in.String(); got != s {
+ t.Errorf("have: %q\nwant: %q\n", got, s)
+ }
+}
+
func TestMarshalNS(t *testing.T) {
dst := Tables{"hello", "world"}
data, err := Marshal(&dst)
@@ -607,7 +637,7 @@ func TestMarshalNSAttr(t *testing.T) {
if err != nil {
t.Fatalf("Marshal: %v", err)
}
- want := `<TableAttrs><TAttr xmlns:html4="http://www.w3.org/TR/html4/" html4:table="hello" xmlns:furniture="http://www.w3schools.com/furniture" furniture:table="world" xml:lang="en_US" xmlns:_xml="http://golang.org/xml/" _xml:other="other1" xmlns:_xmlfoo="http://golang.org/xmlfoo/" _xmlfoo:other="other2" xmlns:json="http://golang.org/json/" json:other="other3" xmlns:json_1="http://golang.org/2/json/" json_1:other="other4"></TAttr></TableAttrs>`
+ want := `<TableAttrs><TAttr xmlns:json_1="http://golang.org/2/json/" xmlns:json="http://golang.org/json/" xmlns:_xmlfoo="http://golang.org/xmlfoo/" xmlns:_xml="http://golang.org/xml/" xmlns:furniture="http://www.w3schools.com/furniture" xmlns:html4="http://www.w3.org/TR/html4/" html4:table="hello" furniture:table="world" xml:lang="en_US" _xml:other="other1" _xmlfoo:other="other2" json:other="other3" json_1:other="other4"></TAttr></TableAttrs>`
str := string(data)
if str != want {
t.Errorf("Marshal:\nhave: %#q\nwant: %#q\n", str, want)
@@ -694,7 +724,7 @@ type Pod struct {
Pea interface{} `xml:"Pea"`
}
-// https://code.google.com/p/go/issues/detail?id=6836
+// https://golang.org/issue/6836
func TestUnmarshalIntoInterface(t *testing.T) {
pod := new(Pod)
pod.Pea = new(Pea)
diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go
index 5690b20256..0c64cd730d 100644
--- a/src/encoding/xml/xml.go
+++ b/src/encoding/xml/xml.go
@@ -35,15 +35,24 @@ func (e *SyntaxError) Error() string {
return "XML syntax error on line " + strconv.Itoa(e.Line) + ": " + e.Msg
}
-// A Name represents an XML name (Local) annotated
-// with a name space identifier (Space).
-// In tokens returned by Decoder.Token, the Space identifier
-// is given as a canonical URL, not the short prefix used
-// in the document being parsed.
+// A Name represents an XML name (Local) annotated with a name space
+// identifier (Space). In tokens returned by Decoder.Token, the Space
+// identifier is given as a canonical URL, not the short prefix used in
+// the document being parsed.
+//
+// As a special case, XML namespace declarations will use the literal
+// string "xmlns" for the Space field instead of the fully resolved URL.
+// See Encoder.EncodeToken for more information on namespace encoding
+// behaviour.
type Name struct {
Space, Local string
}
+// isNamespace reports whether the name is a namespace-defining name.
+func (name Name) isNamespace() bool {
+ return name.Local == "xmlns" || name.Space == "xmlns"
+}
+
// An Attr represents an attribute in an XML element (Name=Value).
type Attr struct {
Name Name
@@ -72,6 +81,24 @@ func (e StartElement) End() EndElement {
return EndElement{e.Name}
}
+// setDefaultNamespace sets the namespace of the element
+// as the default for all elements contained within it.
+func (e *StartElement) setDefaultNamespace() {
+ if e.Name.Space == "" {
+ // If there's no namespace on the element, don't
+ // set the default. Strictly speaking this might be wrong, as
+ // we can't tell if the element had no namespace set
+ // or was just using the default namespace.
+ return
+ }
+ e.Attr = append(e.Attr, Attr{
+ Name: Name{
+ Local: "xmlns",
+ },
+ Value: e.Name.Space,
+ })
+}
+
// An EndElement represents an XML end element.
type EndElement struct {
Name Name
@@ -723,7 +750,7 @@ func (d *Decoder) rawToken() (Token, error) {
return nil, d.err
}
- attr = make([]Attr, 0, 4)
+ attr = []Attr{}
for {
d.space()
if b, ok = d.mustgetc(); !ok {
@@ -747,7 +774,11 @@ func (d *Decoder) rawToken() (Token, error) {
n := len(attr)
if n >= cap(attr) {
- nattr := make([]Attr, n, 2*cap(attr))
+ nCap := 2 * cap(attr)
+ if nCap == 0 {
+ nCap = 4
+ }
+ nattr := make([]Attr, n, nCap)
copy(nattr, attr)
attr = nattr
}
diff --git a/src/expvar/expvar_test.go b/src/expvar/expvar_test.go
index 765e3b757e..11e6497b96 100644
--- a/src/expvar/expvar_test.go
+++ b/src/expvar/expvar_test.go
@@ -7,8 +7,11 @@ package expvar
import (
"bytes"
"encoding/json"
+ "net"
"net/http/httptest"
+ "runtime"
"strconv"
+ "sync"
"testing"
)
@@ -47,6 +50,26 @@ func TestInt(t *testing.T) {
}
}
+func BenchmarkIntAdd(b *testing.B) {
+ var v Int
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ v.Add(1)
+ }
+ })
+}
+
+func BenchmarkIntSet(b *testing.B) {
+ var v Int
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ v.Set(1)
+ }
+ })
+}
+
func TestFloat(t *testing.T) {
RemoveAll()
reqs := NewFloat("requests-float")
@@ -73,6 +96,26 @@ func TestFloat(t *testing.T) {
}
}
+func BenchmarkFloatAdd(b *testing.B) {
+ var f Float
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ f.Add(1.0)
+ }
+ })
+}
+
+func BenchmarkFloatSet(b *testing.B) {
+ var f Float
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ f.Set(1.0)
+ }
+ })
+}
+
func TestString(t *testing.T) {
RemoveAll()
name := NewString("my-name")
@@ -90,6 +133,16 @@ func TestString(t *testing.T) {
}
}
+func BenchmarkStringSet(b *testing.B) {
+ var s String
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ s.Set("red")
+ }
+ })
+}
+
func TestMapCounter(t *testing.T) {
RemoveAll()
colors := NewMap("bike-shed-colors")
@@ -130,6 +183,38 @@ func TestMapCounter(t *testing.T) {
}
}
+func BenchmarkMapSet(b *testing.B) {
+ m := new(Map).Init()
+
+ v := new(Int)
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ m.Set("red", v)
+ }
+ })
+}
+
+func BenchmarkMapAddSame(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ m := new(Map).Init()
+ m.Add("red", 1)
+ m.Add("red", 1)
+ m.Add("red", 1)
+ m.Add("red", 1)
+ }
+}
+
+func BenchmarkMapAddDifferent(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ m := new(Map).Init()
+ m.Add("red", 1)
+ m.Add("blue", 1)
+ m.Add("green", 1)
+ m.Add("yellow", 1)
+ }
+}
+
func TestFunc(t *testing.T) {
RemoveAll()
var x interface{} = []string{"a", "b"}
@@ -165,3 +250,135 @@ func TestHandler(t *testing.T) {
t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
}
}
+
+func BenchmarkRealworldExpvarUsage(b *testing.B) {
+ var (
+ bytesSent Int
+ bytesRead Int
+ )
+
+ // The benchmark creates GOMAXPROCS client/server pairs.
+ // Each pair creates 4 goroutines: client reader/writer and server reader/writer.
+ // The benchmark stresses concurrent reading and writing to the same connection.
+ // Such pattern is used in net/http and net/rpc.
+
+ b.StopTimer()
+
+ P := runtime.GOMAXPROCS(0)
+ N := b.N / P
+ W := 1000
+
+ // Setup P client/server connections.
+ clients := make([]net.Conn, P)
+ servers := make([]net.Conn, P)
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ b.Fatalf("Listen failed: %v", err)
+ }
+ defer ln.Close()
+ done := make(chan bool)
+ go func() {
+ for p := 0; p < P; p++ {
+ s, err := ln.Accept()
+ if err != nil {
+ b.Errorf("Accept failed: %v", err)
+ return
+ }
+ servers[p] = s
+ }
+ done <- true
+ }()
+ for p := 0; p < P; p++ {
+ c, err := net.Dial("tcp", ln.Addr().String())
+ if err != nil {
+ b.Fatalf("Dial failed: %v", err)
+ }
+ clients[p] = c
+ }
+ <-done
+
+ b.StartTimer()
+
+ var wg sync.WaitGroup
+ wg.Add(4 * P)
+ for p := 0; p < P; p++ {
+ // Client writer.
+ go func(c net.Conn) {
+ defer wg.Done()
+ var buf [1]byte
+ for i := 0; i < N; i++ {
+ v := byte(i)
+ for w := 0; w < W; w++ {
+ v *= v
+ }
+ buf[0] = v
+ n, err := c.Write(buf[:])
+ if err != nil {
+ b.Errorf("Write failed: %v", err)
+ return
+ }
+
+ bytesSent.Add(int64(n))
+ }
+ }(clients[p])
+
+ // Pipe between server reader and server writer.
+ pipe := make(chan byte, 128)
+
+ // Server reader.
+ go func(s net.Conn) {
+ defer wg.Done()
+ var buf [1]byte
+ for i := 0; i < N; i++ {
+ n, err := s.Read(buf[:])
+
+ if err != nil {
+ b.Errorf("Read failed: %v", err)
+ return
+ }
+
+ bytesRead.Add(int64(n))
+ pipe <- buf[0]
+ }
+ }(servers[p])
+
+ // Server writer.
+ go func(s net.Conn) {
+ defer wg.Done()
+ var buf [1]byte
+ for i := 0; i < N; i++ {
+ v := <-pipe
+ for w := 0; w < W; w++ {
+ v *= v
+ }
+ buf[0] = v
+ n, err := s.Write(buf[:])
+ if err != nil {
+ b.Errorf("Write failed: %v", err)
+ return
+ }
+
+ bytesSent.Add(int64(n))
+ }
+ s.Close()
+ }(servers[p])
+
+ // Client reader.
+ go func(c net.Conn) {
+ defer wg.Done()
+ var buf [1]byte
+ for i := 0; i < N; i++ {
+ n, err := c.Read(buf[:])
+
+ if err != nil {
+ b.Errorf("Read failed: %v", err)
+ return
+ }
+
+ bytesRead.Add(int64(n))
+ }
+ c.Close()
+ }(clients[p])
+ }
+ wg.Wait()
+}
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index b3c1105156..98201a5d96 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -240,7 +240,7 @@ var pkgDeps = map[string][]string{
// Basic networking.
// Because net must be used by any package that wants to
// do networking portably, it must have a small dependency set: just L1+basic os.
- "net": {"L1", "CGO", "os", "syscall", "time"},
+ "net": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/windows"},
// NET enables use of basic network-related packages.
"NET": {
diff --git a/src/html/template/clone_test.go b/src/html/template/clone_test.go
index e11bff2c5d..5de3bc0eef 100644
--- a/src/html/template/clone_test.go
+++ b/src/html/template/clone_test.go
@@ -166,7 +166,7 @@ func TestCloneThenParse(t *testing.T) {
}
}
-// https://code.google.com/p/go/issues/detail?id=5980
+// https://golang.org/issue/5980
func TestFuncMapWorksAfterClone(t *testing.T) {
funcs := FuncMap{"customFunc": func() (string, error) {
return "", errors.New("issue5980")
diff --git a/src/html/template/content_test.go b/src/html/template/content_test.go
index 5f3ffe2d32..e698328693 100644
--- a/src/html/template/content_test.go
+++ b/src/html/template/content_test.go
@@ -260,7 +260,7 @@ func TestStringer(t *testing.T) {
}
}
-// https://code.google.com/p/go/issues/detail?id=5982
+// https://golang.org/issue/5982
func TestEscapingNilNonemptyInterfaces(t *testing.T) {
tmpl := Must(New("x").Parse("{{.E}}"))
diff --git a/src/image/image.go b/src/image/image.go
index e0ecd92baa..951cc8ae05 100644
--- a/src/image/image.go
+++ b/src/image/image.go
@@ -46,9 +46,9 @@ type Image interface {
}
// PalettedImage is an image whose colors may come from a limited palette.
-// If m is a PalettedImage and m.ColorModel() returns a PalettedColorModel p,
+// If m is a PalettedImage and m.ColorModel() returns a color.Palette p,
// then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
-// color model is not a PalettedColorModel, then ColorIndexAt's behavior is
+// color model is not a color.Palette, then ColorIndexAt's behavior is
// undefined.
type PalettedImage interface {
// ColorIndexAt returns the palette index of the pixel at (x, y).
diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go
new file mode 100644
index 0000000000..2541a83440
--- /dev/null
+++ b/src/internal/syscall/windows/syscall_windows.go
@@ -0,0 +1,99 @@
+// Copyright 2014 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 windows
+
+import (
+ "syscall"
+)
+
+//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
+
+const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
+
+const IF_TYPE_SOFTWARE_LOOPBACK = 24
+
+type SocketAddress struct {
+ Sockaddr *syscall.RawSockaddrAny
+ SockaddrLength int32
+}
+
+type IpAdapterUnicastAddress struct {
+ Length uint32
+ Flags uint32
+ Next *IpAdapterUnicastAddress
+ Address SocketAddress
+ PrefixOrigin int32
+ SuffixOrigin int32
+ DadState int32
+ ValidLifetime uint32
+ PreferredLifetime uint32
+ LeaseLifetime uint32
+ OnLinkPrefixLength uint8
+}
+
+type IpAdapterAnycastAddress struct {
+ Length uint32
+ Flags uint32
+ Next *IpAdapterAnycastAddress
+ Address SocketAddress
+}
+
+type IpAdapterMulticastAddress struct {
+ Length uint32
+ Flags uint32
+ Next *IpAdapterMulticastAddress
+ Address SocketAddress
+}
+
+type IpAdapterDnsServerAdapter struct {
+ Length uint32
+ Reserved uint32
+ Next *IpAdapterDnsServerAdapter
+ Address SocketAddress
+}
+
+type IpAdapterPrefix struct {
+ Length uint32
+ Flags uint32
+ Next *IpAdapterPrefix
+ Address SocketAddress
+ PrefixLength uint32
+}
+
+type IpAdapterAddresses struct {
+ Length uint32
+ IfIndex uint32
+ Next *IpAdapterAddresses
+ AdapterName *byte
+ FirstUnicastAddress *IpAdapterUnicastAddress
+ FirstAnycastAddress *IpAdapterAnycastAddress
+ FirstMulticastAddress *IpAdapterMulticastAddress
+ FirstDnsServerAddress *IpAdapterDnsServerAdapter
+ DnsSuffix *uint16
+ Description *uint16
+ FriendlyName *uint16
+ PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte
+ PhysicalAddressLength uint32
+ Flags uint32
+ Mtu uint32
+ IfType uint32
+ OperStatus uint32
+ Ipv6IfIndex uint32
+ ZoneIndices [16]uint32
+ FirstPrefix *IpAdapterPrefix
+ /* more fields might be present here. */
+}
+
+const (
+ IfOperStatusUp = 1
+ IfOperStatusDown = 2
+ IfOperStatusTesting = 3
+ IfOperStatusUnknown = 4
+ IfOperStatusDormant = 5
+ IfOperStatusNotPresent = 6
+ IfOperStatusLowerLayerDown = 7
+)
+
+//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go
new file mode 100644
index 0000000000..90e2034641
--- /dev/null
+++ b/src/internal/syscall/windows/zsyscall_windows.go
@@ -0,0 +1,20 @@
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package windows
+
+import "unsafe"
+import "syscall"
+
+var (
+ modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll")
+
+ procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
+)
+
+func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) {
+ r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizeOfPointer)), 0)
+ if r0 != 0 {
+ errcode = syscall.Errno(r0)
+ }
+ return
+}
diff --git a/src/lib9/math_darwin_arm.c b/src/lib9/math_darwin_arm.c
new file mode 100644
index 0000000000..ff5b0ce07a
--- /dev/null
+++ b/src/lib9/math_darwin_arm.c
@@ -0,0 +1,102 @@
+// Copyright 2014 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.
+
+// Some Darwin/ARM libc versions fail to provide a standard compliant version
+// of frexp and ldexp that could handle denormal floating point numbers.
+// The frexp and ldexp implementations are translated from their Go version.
+
+#include <stdint.h>
+
+// Assume double and uint64_t are using the same endian.
+union dint64 {
+ double d;
+ uint64_t u;
+};
+
+static const uint64_t mask = 0x7FF, bias = 1023;
+static const int shift = 64 - 11 - 1;
+static const uint64_t uvnan = 0x7FF8000000000001ULL, uvinf = 0x7FF0000000000000ULL,
+ uvneginf = 0xFFF0000000000000ULL;
+static const double smallestnormal = 2.2250738585072014e-308; // 2**-1022
+
+static inline uint64_t float64bits(double x) {
+ union dint64 u;
+ u.d = x;
+ return u.u;
+}
+static inline double float64frombits(uint64_t x) {
+ union dint64 u;
+ u.u = x;
+ return u.d;
+}
+static inline int isinf(double x) {
+ return float64bits(x) == uvinf || float64bits(x) == uvneginf;
+}
+static inline int isnan(double x) {
+ return x != x;
+}
+extern double fabs(double);
+static double normalize(double x, int *exp) {
+ if (fabs(x) < smallestnormal) {
+ *exp = -52;
+ return x * (double)(1LL<<52);
+ }
+ *exp = 0;
+ return x;
+}
+
+double ldexp(double frac, int exp) {
+ // special cases
+ if (frac == 0.0) return frac;
+ if (isinf(frac) || isnan(frac)) return frac;
+
+ int e;
+ frac = normalize(frac, &e);
+ exp += e;
+ uint64_t x = float64bits(frac);
+ exp += (int)((x>>shift)&mask) - bias;
+ if (exp < -1074) { // underflow
+ if (frac < 0.0) return float64frombits(1ULL<<63); // -0.0
+ return 0.0;
+ }
+ if (exp > 1023) { // overflow
+ if (frac < 0.0) return float64frombits(uvneginf);
+ return float64frombits(uvinf);
+ }
+ double m = 1;
+ if (exp < -1022) { // denormal
+ exp += 52;
+ m = 1.0 / (double)(1ULL<<52);
+ }
+ x &= ~(mask << shift);
+ x |= (uint64_t)(exp+bias) << shift;
+ return m * float64frombits(x);
+}
+
+double frexp(double f, int *exp) {
+ *exp = 0;
+ // special cases
+ if (f == 0.0) return f;
+ if (isinf(f) || isnan(f)) return f;
+
+ f = normalize(f, exp);
+ uint64_t x = float64bits(f);
+ *exp += (int)((x>>shift)&mask) - bias + 1;
+ x &= ~(mask << shift);
+ x |= (-1 + bias) << shift;
+ return float64frombits(x);
+}
+
+// On Darwin/ARM, the kernel insists on running VFP in runfast mode, and it
+// cannot deal with denormal floating point numbers in that mode, so we have
+// to disable the runfast mode if the client uses ldexp/frexp (i.e. 5g).
+void disable_vfp_runfast(void) __attribute__((constructor));
+void disable_vfp_runfast(void) {
+ __asm__ volatile (
+ "fmrx r0, fpscr\n"
+ "bic r0, r0, $0x03000000\n"
+ "fmxr fpscr, r0\n"
+ : : : "r0"
+ );
+}
diff --git a/src/liblink/asm5.c b/src/liblink/asm5.c
index 8d597750b7..398b7841c2 100644
--- a/src/liblink/asm5.c
+++ b/src/liblink/asm5.c
@@ -96,6 +96,7 @@ static Optab optab[] =
{ ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
{ ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 },
{ ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
+ { ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0 }, // prediction hinted form, hint ignored
{ AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
{ ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 },
@@ -353,14 +354,6 @@ static uchar xcmp[C_GOK+1][C_GOK+1];
static LSym *deferreturn;
-static void
-nocache(Prog *p)
-{
- p->optab = 0;
- p->from.class = 0;
- p->to.class = 0;
-}
-
/* size of a case statement including jump table */
static int32
casesz(Link *ctxt, Prog *p)
@@ -1638,8 +1631,11 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
// runtime.tlsg is special.
// Its "address" is the offset from the TLS thread pointer
// to the thread-local g and m pointers.
- // Emit a TLS relocation instead of a standard one.
- if(rel->sym == ctxt->tlsg) {
+ // Emit a TLS relocation instead of a standard one if its
+ // type is not explicitly set by runtime. This assumes that
+ // all references to runtime.tlsg should be accompanied with
+ // its type declaration if necessary.
+ if(rel->sym == ctxt->tlsg && ctxt->tlsg->type == 0) {
rel->type = R_TLS;
if(ctxt->flag_shared)
rel->add += ctxt->pc - p->pcrel->pc - 8 - rel->siz;
diff --git a/src/liblink/go.c b/src/liblink/go.c
index 754a7cc15e..08ce82b30c 100644
--- a/src/liblink/go.c
+++ b/src/liblink/go.c
@@ -133,3 +133,24 @@ double2ieee(uint64 *ieee, float64 f)
{
memmove(ieee, &f, 8);
}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->scond = zprog.scond;
+ p->from = zprog.from;
+ p->from3 = zprog.from3;
+ p->reg = zprog.reg;
+ p->to = zprog.to;
+}
+
+void
+nocache(Prog *p)
+{
+ p->optab = 0;
+ p->from.class = 0;
+ p->from3.class = 0;
+ p->to.class = 0;
+}
+
diff --git a/src/liblink/list5.c b/src/liblink/list5.c
index bca10f6899..3ea411d2b8 100644
--- a/src/liblink/list5.c
+++ b/src/liblink/list5.c
@@ -168,7 +168,7 @@ Dconv(Fmt *fp)
if(a->u.argsize == ArgsSizeUnknown)
sprint(str, "$%lld", a->offset);
else
- sprint(str, "$%lld-%lld", a->offset, a->u.argsize);
+ sprint(str, "$%lld-%d", a->offset, a->u.argsize);
break;
case TYPE_SHIFT:
diff --git a/src/liblink/list6.c b/src/liblink/list6.c
index d9e0b45c7a..b324ec89d6 100644
--- a/src/liblink/list6.c
+++ b/src/liblink/list6.c
@@ -206,7 +206,7 @@ Dconv(Fmt *fp)
if(a->u.argsize == ArgsSizeUnknown)
sprint(str, "$%lld", a->offset);
else
- sprint(str, "$%lld-%lld", a->offset, a->u.argsize);
+ sprint(str, "$%lld-%d", a->offset, a->u.argsize);
break;
case TYPE_FCONST:
diff --git a/src/liblink/list8.c b/src/liblink/list8.c
index dbba103280..07c1d7cd67 100644
--- a/src/liblink/list8.c
+++ b/src/liblink/list8.c
@@ -193,7 +193,7 @@ Dconv(Fmt *fp)
if(a->u.argsize == ArgsSizeUnknown)
sprint(str, "$%lld", a->offset);
else
- sprint(str, "$%lld-%lld", a->offset, a->u.argsize);
+ sprint(str, "$%lld-%d", a->offset, a->u.argsize);
break;
case TYPE_FCONST:
diff --git a/src/liblink/list9.c b/src/liblink/list9.c
index a45e73e61e..ac37bb566e 100644
--- a/src/liblink/list9.c
+++ b/src/liblink/list9.c
@@ -172,7 +172,7 @@ Dconv(Fmt *fp)
if(a->u.argsize == ArgsSizeUnknown)
sprint(str, "$%lld", a->offset);
else
- sprint(str, "$%lld-%lld", a->offset, a->u.argsize);
+ sprint(str, "$%lld-%d", a->offset, a->u.argsize);
break;
case TYPE_MEM:
diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c
index 805d7a59c2..abddbc3c4f 100644
--- a/src/liblink/obj5.c
+++ b/src/liblink/obj5.c
@@ -185,14 +185,6 @@ linkcase(Prog *casep)
}
static void
-nocache5(Prog *p)
-{
- p->optab = 0;
- p->from.class = 0;
- p->to.class = 0;
-}
-
-static void
preprocess(Link *ctxt, LSym *cursym)
{
Prog *p, *pl, *p1, *p2, *q, *q1, *q2;
@@ -478,7 +470,7 @@ preprocess(Link *ctxt, LSym *cursym)
break;
case ARET:
- nocache5(p);
+ nocache(p);
if(cursym->text->mark & LEAF) {
if(!autosize) {
p->as = AB;
diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c
index cddc723bf2..546c89d53c 100644
--- a/src/liblink/obj6.c
+++ b/src/liblink/obj6.c
@@ -35,18 +35,6 @@
#include "../cmd/6l/6.out.h"
#include "../runtime/stack.h"
-static void
-nopout(Prog *p)
-{
- p->as = ANOP;
- p->from.type = TYPE_NONE;
- p->from.reg = 0;
- p->from.name = 0;
- p->to.type = TYPE_NONE;
- p->to.reg = 0;
- p->to.name = 0;
-}
-
static void nacladdr(Link*, Prog*, Addr*);
static int
diff --git a/src/liblink/sym.c b/src/liblink/sym.c
index 079f600aa9..cae7e4aafe 100644
--- a/src/liblink/sym.c
+++ b/src/liblink/sym.c
@@ -148,15 +148,15 @@ linknew(LinkArch *arch)
switch(ctxt->arch->thechar) {
default:
sysfatal("unknown thread-local storage offset for nacl/%s", ctxt->arch->name);
+ case '5':
+ ctxt->tlsoffset = 0;
+ break;
case '6':
ctxt->tlsoffset = 0;
break;
case '8':
ctxt->tlsoffset = -8;
break;
- case '5':
- ctxt->tlsoffset = 0;
- break;
}
break;
@@ -174,6 +174,9 @@ linknew(LinkArch *arch)
case '8':
ctxt->tlsoffset = 0x468;
break;
+ case '5':
+ ctxt->tlsoffset = 0; // dummy value, not needed
+ break;
}
break;
}
diff --git a/src/math/all_test.go b/src/math/all_test.go
index 763efb2e64..0848c506e4 100644
--- a/src/math/all_test.go
+++ b/src/math/all_test.go
@@ -2606,7 +2606,7 @@ func TestLargeTan(t *testing.T) {
// Check that math constants are accepted by compiler
// and have right value (assumes strconv.ParseFloat works).
-// http://code.google.com/p/go/issues/detail?id=201
+// http://golang.org/issue/201
type floatTest struct {
val interface{}
diff --git a/src/math/big/float.go b/src/math/big/float.go
index ea42a9166e..06b3ae2f40 100644
--- a/src/math/big/float.go
+++ b/src/math/big/float.go
@@ -9,7 +9,7 @@
// rounding mode of the result operand determines the rounding
// mode of an operation. This is a from-scratch implementation.
-// CAUTION: WORK IN PROGRESS - ANY ASPECT OF THIS IMPLEMENTATION MAY CHANGE!
+// CAUTION: WORK IN PROGRESS - USE AT YOUR OWN RISK.
package big
@@ -18,47 +18,38 @@ import (
"math"
)
-// TODO(gri): Determine if there's a more natural way to set the precision.
-// Should there be a special meaning for prec 0? Such as "full precision"?
-// (would be possible for all ops except quotient).
-
const debugFloat = true // enable for debugging
-// Internal representation: A floating-point value x != 0 consists
-// of a sign (x.neg), mantissa (x.mant), and exponent (x.exp) such
-// that
-//
-// x = sign * 0.mantissa * 2**exponent
+// A Float represents a multi-precision floating point number of the form
//
-// and the mantissa is interpreted as a value between 0.5 and 1:
+// sign × mantissa × 2**exponent
//
-// 0.5 <= mantissa < 1.0
-//
-// The mantissa bits are stored in the shortest nat slice long enough
-// to hold x.prec mantissa bits. The mantissa is normalized such that
-// the msb of x.mant == 1. Thus, if the precision is not a multiple of
-// the Word size _W, x.mant[0] contains trailing zero bits. The number
-// 0 is represented by an empty mantissa and a zero exponent.
-
-// A Float represents a multi-precision floating point number
-// of the form
+// with 0.5 <= mantissa < 1.0, and MinExp <= exponent <= MaxExp (with the
+// exception of 0 and Inf which have a 0 mantissa and special exponents).
//
-// sign * mantissa * 2**exponent
+// Each Float value also has a precision, rounding mode, and accuracy.
//
-// Each value also has a precision, rounding mode, and accuracy value:
-// The precision is the number of mantissa bits used to represent a
-// value, and the result of operations is rounded to that many bits
-// according to the value's rounding mode (unless specified othewise).
-// The accuracy value indicates the rounding error with respect to the
-// exact (not rounded) value.
+// The precision is the number of mantissa bits used to represent the
+// value. The rounding mode specifies how a result should be rounded
+// to fit into the mantissa bits, and accuracy describes the rounding
+// error with respect to the exact result.
//
-// The zero value for a Float represents the number 0.
+// All operations, including setters, that specify a *Float for the result,
+// usually via the receiver, round their result to the result's precision
+// and according to its rounding mode, unless specified otherwise. If the
+// result precision is 0 (see below), it is set to the precision of the
+// argument with the largest precision value before any rounding takes
+// place.
+// TODO(gri) should the rounding mode also be copied in this case?
//
-// By setting the desired precision to 24 (or 53) and using ToNearestEven
-// rounding, Float arithmetic operations emulate the corresponding float32
-// or float64 IEEE-754 operations (except for denormalized numbers and NaNs).
+// By setting the desired precision to 24 or 53 and using ToNearestEven
+// rounding, Float operations produce the same results as the corresponding
+// float32 or float64 IEEE-754 arithmetic for normalized operands (no NaNs
+// or denormalized numbers). Additionally, positive and negative zeros and
+// infinities are fully supported.
//
-// CAUTION: THIS IS WORK IN PROGRESS - USE AT YOUR OWN RISK.
+// The zero (uninitialized) value for a Float is ready to use and
+// represents the number +0.0 of 0 bit precision.
//
type Float struct {
mode RoundingMode
@@ -69,31 +60,42 @@ type Float struct {
prec uint // TODO(gri) make this a 32bit field
}
+// Internal representation details: The mantissa bits x.mant of a Float x
+// are stored in the shortest nat slice long enough to hold x.prec bits.
+// Unless x is a zero or an infinity, x.mant is normalized such that the
+// msb of x.mant == 1. Thus, if the precision is not a multiple of the
+// the Word size _W, x.mant[0] contains trailing zero bits. Zero and Inf
+// values have an empty mantissa and a 0 or infExp exponent, respectively.
+
// NewFloat returns a new Float with value x rounded
// to prec bits according to the given rounding mode.
+// If prec == 0, the result has value 0.0 independent
+// of the value of x.
+// BUG(gri) For prec == 0 and x == Inf, the result
+// should be Inf as well.
+// TODO(gri) rethink this signature.
func NewFloat(x float64, prec uint, mode RoundingMode) *Float {
- // TODO(gri) should make this more efficient
- z := new(Float).SetFloat64(x)
- return z.Round(z, prec, mode)
+ var z Float
+ if prec > 0 {
+ // TODO(gri) should make this more efficient
+ z.SetFloat64(x)
+ return z.Round(&z, prec, mode)
+ }
+ z.mode = mode // TODO(gri) don't do this twice for prec > 0
+ return &z
}
-// infExp is the exponent value for infinity.
-const infExp = 1<<31 - 1
+const (
+ MaxExp = math.MaxInt32 // largest supported exponent magnitude
+ infExp = -MaxExp - 1 // exponent for Inf values
+)
-// NewInf returns a new Float with value positive infinity (sign >= 0),
-// or negative infinity (sign < 0).
+// NewInf returns a new infinite Float value with value +Inf (sign >= 0),
+// or -Inf (sign < 0).
func NewInf(sign int) *Float {
return &Float{neg: sign < 0, exp: infExp}
}
-func (z *Float) setExp(e int64) {
- e32 := int32(e)
- if int64(e32) != e {
- panic("exponent overflow") // TODO(gri) handle this gracefully
- }
- z.exp = e32
-}
-
// Accuracy describes the rounding error produced by the most recent
// operation that generated a Float value, relative to the exact value:
//
@@ -155,7 +157,7 @@ func (mode RoundingMode) String() string {
}
// Precision returns the mantissa precision of x in bits.
-// The precision may be 0 if x == 0. // TODO(gri) Determine a better approach.
+// The precision may be 0 for |x| == 0 or |x| == Inf.
func (x *Float) Precision() uint {
return uint(x.prec)
}
@@ -170,11 +172,111 @@ func (x *Float) Mode() RoundingMode {
return x.mode
}
+// Sign returns:
+//
+// -1 if x < 0
+// 0 if x == 0 or x == -0
+// +1 if x > 0
+//
+func (x *Float) Sign() int {
+ s := 0
+ if len(x.mant) != 0 || x.exp == infExp {
+ s = 1 // non-zero x
+ }
+ if x.neg {
+ s = -s
+ }
+ return s
+}
+
+// MantExp breaks x into its mantissa and exponent components.
+// It returns mant and exp satisfying x == mant × 2**exp, with
+// the absolute value of mant satisfying 0.5 <= |mant| < 1.0.
+// mant has the same precision and rounding mode as x.
+//
+// Special cases are:
+//
+// ( ±0).MantExp() = ±0, 0
+// (±Inf).MantExp() = ±Inf, 0
+//
+// MantExp does not modify x; the result mant is a new Float.
+func (x *Float) MantExp() (mant *Float, exp int) {
+ mant = new(Float).Copy(x)
+ if x.exp != infExp {
+ mant.exp = 0
+ exp = int(x.exp)
+ }
+ return
+}
+
+// SetMantExp is the inverse of MantExp. It sets z to mant × 2**exp and
+// and returns z. The result z has the same precision and rounding mode
+// as mant.
+//
+// Special cases are:
+//
+// z.SetMantExp( ±0, exp) = ±0
+// z.SetMantExp(±Inf, exp) = ±Inf
+//
+// The result is ±Inf if the magnitude of exp is > MaxExp.
+func (z *Float) SetMantExp(mant *Float, exp int) *Float {
+ z.Copy(mant)
+ if len(z.mant) == 0 || z.exp == infExp {
+ return z
+ }
+ z.setExp(int64(exp))
+ return z
+}
+
+// IsInt reports whether x is an integer.
+// ±Inf are not considered integers.
+func (x *Float) IsInt() bool {
+ if debugFloat {
+ x.validate()
+ }
+ // pick off easy cases
+ if x.exp <= 0 {
+ // |x| < 1 || |x| == Inf
+ return len(x.mant) == 0 && x.exp != infExp
+ }
+ // x.exp > 0
+ return x.prec <= uint(x.exp) || x.minPrec() <= uint(x.exp) // not enough bits for fractional mantissa
+}
+
+// IsInf reports whether x is an infinity, according to sign.
+// If sign > 0, IsInf reports whether x is positive infinity.
+// If sign < 0, IsInf reports whether x is negative infinity.
+// If sign == 0, IsInf reports whether x is either infinity.
+func (x *Float) IsInf(sign int) bool {
+ return x.exp == infExp && (sign == 0 || x.neg == (sign < 0))
+}
+
+// setExp sets the exponent for z.
+// If the exponent's magnitude is too large, z becomes ±Inf.
+func (z *Float) setExp(e int64) {
+ if -MaxExp <= e && e <= MaxExp {
+ if len(z.mant) == 0 {
+ e = 0
+ }
+ z.exp = int32(e)
+ return
+ }
+ // Inf
+ z.mant = z.mant[:0]
+ z.exp = infExp
+}
+
// debugging support
func (x *Float) validate() {
- // assumes x != 0
const msb = 1 << (_W - 1)
m := len(x.mant)
+ if m == 0 {
+ // 0.0 or Inf
+ if x.exp != 0 && x.exp != infExp {
+ panic(fmt.Sprintf("empty matissa with invalid exponent %d", x.exp))
+ }
+ return
+ }
if x.mant[m-1]&msb == 0 {
panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Format('p', 0)))
}
@@ -185,21 +287,24 @@ func (x *Float) validate() {
// round rounds z according to z.mode to z.prec bits and sets z.acc accordingly.
// sbit must be 0 or 1 and summarizes any "sticky bit" information one might
-// have before calling round. z's mantissa must be normalized, with the msb set.
+// have before calling round. z's mantissa must be normalized (with the msb set)
+// or empty.
func (z *Float) round(sbit uint) {
z.acc = Exact
- // handle zero
+ // handle zero and Inf
m := uint(len(z.mant)) // mantissa length in words for current precision
if m == 0 {
- z.exp = 0
+ if z.exp != infExp {
+ z.exp = 0
+ }
return
}
+ // z.prec > 0
if debugFloat {
z.validate()
}
- // z.prec > 0
bits := m * _W // available mantissa bits
if bits == z.prec {
@@ -342,8 +447,9 @@ func (z *Float) round(sbit uint) {
}
// Round sets z to the value of x rounded according to mode to prec bits and returns z.
+// TODO(gri) rethink this signature.
func (z *Float) Round(x *Float, prec uint, mode RoundingMode) *Float {
- z.Set(x)
+ z.Copy(x)
z.prec = prec
z.mode = mode
z.round(0)
@@ -369,24 +475,33 @@ func nlz64(x uint64) uint {
panic("unreachable")
}
-// SetUint64 sets z to x and returns z.
-// Precision is set to 64 bits.
+// SetUint64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 64 (and rounding will have
+// no effect).
func (z *Float) SetUint64(x uint64) *Float {
+ if z.prec == 0 {
+ z.prec = 64
+ }
+ z.acc = Exact
z.neg = false
- z.prec = 64
if x == 0 {
z.mant = z.mant[:0]
z.exp = 0
return z
}
+ // x != 0
s := nlz64(x)
z.mant = z.mant.setUint64(x << s)
- z.exp = int32(64 - s)
+ z.exp = int32(64 - s) // always fits
+ if z.prec < 64 {
+ z.round(0)
+ }
return z
}
-// SetInt64 sets z to x and returns z.
-// Precision is set to 64 bits.
+// SetInt64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 64 (and rounding will have
+// no effect).
func (z *Float) SetInt64(x int64) *Float {
u := x
if u < 0 {
@@ -397,27 +512,40 @@ func (z *Float) SetInt64(x int64) *Float {
return z
}
-// SetFloat64 sets z to x and returns z.
-// Precision is set to 53 bits.
-// TODO(gri) test denormals, +/-Inf, disallow NaN.
+// SetFloat64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 53 (and rounding will have
+// no effect).
+// If x is denormalized or NaN, the result is unspecified.
+// TODO(gri) should return nil in those cases
func (z *Float) SetFloat64(x float64) *Float {
- z.prec = 53
- z.neg = math.Signbit(x) // handle -0 correctly (-0 == 0)
+ if z.prec == 0 {
+ z.prec = 53
+ }
+ z.acc = Exact
+ z.neg = math.Signbit(x) // handle -0 correctly
+ if math.IsInf(x, 0) {
+ z.mant = z.mant[:0]
+ z.exp = infExp
+ return z
+ }
if x == 0 {
z.mant = z.mant[:0]
z.exp = 0
return z
}
+ // x != 0
fmant, exp := math.Frexp(x) // get normalized mantissa
z.mant = z.mant.setUint64(1<<63 | math.Float64bits(fmant)<<11)
- z.exp = int32(exp)
+ z.exp = int32(exp) // always fits
+ if z.prec < 53 {
+ z.round(0)
+ }
return z
}
// fnorm normalizes mantissa m by shifting it to the left
-// such that the msb of the most-significant word (msw)
-// is 1. It returns the shift amount.
-// It assumes that m is not the zero nat.
+// such that the msb of the most-significant word (msw) is 1.
+// It returns the shift amount. It assumes that len(m) != 0.
func fnorm(m nat) uint {
if debugFloat && (len(m) == 0 || m[len(m)-1] == 0) {
panic("msw of mantissa is 0")
@@ -432,38 +560,80 @@ func fnorm(m nat) uint {
return s
}
-// SetInt sets z to x and returns z.
-// Precision is set to the number of bits required to represent x accurately.
-// TODO(gri) what about precision for x == 0?
+// SetInt sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to the larger of x.BitLen()
+// or 64 (and rounding will have no effect).
func (z *Float) SetInt(x *Int) *Float {
+ // TODO(gri) can be more efficient if z.prec > 0
+ // but small compared to the size of x, or if there
+ // are many trailing 0's.
+ bits := uint(x.BitLen())
+ if z.prec == 0 {
+ z.prec = umax(bits, 64)
+ }
+ z.acc = Exact
+ z.neg = x.neg
if len(x.abs) == 0 {
- z.neg = false
z.mant = z.mant[:0]
z.exp = 0
- // z.prec = ?
return z
}
// x != 0
- z.neg = x.neg
z.mant = z.mant.set(x.abs)
- e := uint(len(z.mant))*_W - fnorm(z.mant)
- z.exp = int32(e)
- z.prec = e
+ fnorm(z.mant)
+ z.setExp(int64(bits))
+ if z.prec < bits {
+ z.round(0)
+ }
return z
}
-// SetRat sets z to x rounded to the precision of z and returns z.
-func (z *Float) SetRat(x *Rat, prec uint) *Float {
- panic("unimplemented")
+// SetRat sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to the largest of a.BitLen(),
+// b.BitLen(), or 64; with x = a/b.
+func (z *Float) SetRat(x *Rat) *Float {
+ // TODO(gri) can be more efficient if x is an integer
+ var a, b Float
+ a.SetInt(x.Num())
+ b.SetInt(x.Denom())
+ if z.prec == 0 {
+ z.prec = umax(a.prec, b.prec)
+ }
+ return z.Quo(&a, &b)
}
-// Set sets z to x, with the same precision as x, and returns z.
+// Set sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to the precision of x
+// before setting z (and rounding will have no effect).
+// Rounding is performed according to z's precision and rounding
+// mode; and z's accuracy reports the result error relative to the
+// exact (not rounded) result.
func (z *Float) Set(x *Float) *Float {
if z != x {
+ if z.prec == 0 {
+ z.prec = x.prec
+ }
+ z.acc = Exact
+ z.neg = x.neg
+ z.exp = x.exp
+ z.mant = z.mant.set(x.mant)
+ if z.prec < x.prec {
+ z.round(0)
+ }
+ }
+ return z
+}
+
+// Copy sets z to x, with the same precision and rounding mode as x,
+// and returns z.
+func (z *Float) Copy(x *Float) *Float {
+ if z != x {
+ z.acc = Exact
z.neg = x.neg
z.exp = x.exp
z.mant = z.mant.set(x.mant)
z.prec = x.prec
+ z.mode = x.mode
}
return z
}
@@ -484,29 +654,119 @@ func high64(x nat) uint64 {
return v
}
-// TODO(gri) FIX THIS (rounding mode, errors, accuracy, etc.)
-func (x *Float) Uint64() uint64 {
- m := high64(x.mant)
- s := x.exp
- if s >= 0 {
- return m >> (64 - uint(s))
+// minPrec returns the minimum precision required to represent
+// x without loss of accuracy.
+// TODO(gri) this might be useful to export, perhaps under a better name
+func (x *Float) minPrec() uint {
+ return uint(len(x.mant))*_W - x.mant.trailingZeroBits()
+}
+
+// Uint64 returns the unsigned integer resulting from truncating x
+// towards zero. If 0 <= x <= math.MaxUint64, the result is Exact
+// if x is an integer and Below otherwise.
+// The result is (0, Above) for x < 0, and (math.MaxUint64, Below)
+// for x > math.MaxUint64.
+func (x *Float) Uint64() (uint64, Accuracy) {
+ if debugFloat {
+ x.validate()
}
- return 0 // imprecise
+ switch x.ord() {
+ case -2, -1:
+ // x < 0
+ return 0, Above
+ case 0:
+ // x == 0 || x == -0
+ return 0, Exact
+ case 1:
+ // 0 < x < +Inf
+ if x.exp <= 0 {
+ // 0 < x < 1
+ return 0, Below
+ }
+ // 1 <= x < +Inf
+ if x.exp <= 64 {
+ // u = trunc(x) fits into a uint64
+ u := high64(x.mant) >> (64 - uint32(x.exp))
+ if x.minPrec() <= 64 {
+ return u, Exact
+ }
+ return u, Below // x truncated
+ }
+ fallthrough // x too large
+ case 2:
+ // x == +Inf
+ return math.MaxUint64, Below
+ }
+ panic("unreachable")
}
-// TODO(gri) FIX THIS (rounding mode, errors, etc.)
-func (x *Float) Int64() int64 {
- v := int64(x.Uint64())
- if x.neg {
- return -v
+// Int64 returns the integer resulting from truncating x towards zero.
+// If math.MinInt64 <= x <= math.MaxInt64, the result is Exact if x is
+// an integer, and Above (x < 0) or Below (x > 0) otherwise.
+// The result is (math.MinInt64, Above) for x < math.MinInt64, and
+// (math.MaxInt64, Below) for x > math.MaxInt64.
+func (x *Float) Int64() (int64, Accuracy) {
+ if debugFloat {
+ x.validate()
}
- return v
+
+ switch x.ord() {
+ case -2:
+ // x == -Inf
+ return math.MinInt64, Above
+ case 0:
+ // x == 0 || x == -0
+ return 0, Exact
+ case -1, 1:
+ // 0 < |x| < +Inf
+ acc := Below
+ if x.neg {
+ acc = Above
+ }
+ if x.exp <= 0 {
+ // 0 < |x| < 1
+ return 0, acc
+ }
+ // 1 <= |x| < +Inf
+ if x.exp <= 63 {
+ // i = trunc(x) fits into an int64 (excluding math.MinInt64)
+ i := int64(high64(x.mant) >> (64 - uint32(x.exp)))
+ if x.neg {
+ i = -i
+ }
+ if x.minPrec() <= 63 {
+ return i, Exact
+ }
+ return i, acc // x truncated
+ }
+ if x.neg {
+ // check for special case x == math.MinInt64 (i.e., x == -(0.5 << 64))
+ if x.exp == 64 && x.minPrec() == 1 {
+ acc = Exact
+ }
+ return math.MinInt64, acc
+ }
+ fallthrough
+ case 2:
+ // x == +Inf
+ return math.MaxInt64, Below
+ }
+ panic("unreachable")
}
// Float64 returns the closest float64 value of x
// by rounding to nearest with 53 bits precision.
// TODO(gri) implement/document error scenarios.
func (x *Float) Float64() (float64, Accuracy) {
+ // x == ±Inf
+ if x.exp == infExp {
+ var sign int
+ if x.neg {
+ sign = -1
+ }
+ return math.Inf(sign), Exact
+ }
+ // x == 0
if len(x.mant) == 0 {
return 0, Exact
}
@@ -521,39 +781,66 @@ func (x *Float) Float64() (float64, Accuracy) {
return math.Float64frombits(s | e<<52 | m), r.acc
}
-func (x *Float) Int() *Int {
- if len(x.mant) == 0 {
- return new(Int)
+// Int returns the result of truncating x towards zero; or nil
+// if x is an infinity. The result is Exact if x.IsInt();
+// otherwise it is Below for x > 0, and Above for x < 0.
+func (x *Float) Int() (res *Int, acc Accuracy) {
+ if debugFloat {
+ x.validate()
}
- panic("unimplemented")
-}
-
-func (x *Float) Rat() *Rat {
- panic("unimplemented")
-}
-
-func (x *Float) IsInt() bool {
- if len(x.mant) == 0 {
- return true
+ // accuracy for inexact results
+ acc = Below // truncation
+ if x.neg {
+ acc = Above
}
+ // pick off easy cases
if x.exp <= 0 {
- return false
+ // |x| < 1 || |x| == Inf
+ if x.exp == infExp {
+ return nil, acc // ±Inf
+ }
+ if len(x.mant) == 0 {
+ acc = Exact // ±0
+ }
+ return new(Int), acc // ±0.xxx
}
- if uint(x.exp) >= x.prec {
- return true
+ // x.exp > 0
+ // x.mant[len(x.mant)-1] != 0
+ // determine minimum required precision for x
+ allBits := uint(len(x.mant)) * _W
+ exp := uint(x.exp)
+ if x.minPrec() <= exp {
+ acc = Exact
}
+ // shift mantissa as needed
+ res = &Int{neg: x.neg}
+ // TODO(gri) should have a shift that takes positive and negative shift counts
+ switch {
+ case exp > allBits:
+ res.abs = res.abs.shl(x.mant, exp-allBits)
+ default:
+ res.abs = res.abs.set(x.mant)
+ case exp < allBits:
+ res.abs = res.abs.shr(x.mant, allBits-exp)
+ }
+ return
+}
+
+// BUG(gri) Rat is not yet implemented
+func (x *Float) Rat() *Rat {
panic("unimplemented")
}
-// Abs sets z to |x| (the absolute value of x) and returns z.
-// TODO(gri) should Abs (and Neg) below ignore z's precision and rounding mode?
+// Abs sets z to the (possibly rounded) value |x| (the absolute value of x)
+// and returns z.
func (z *Float) Abs(x *Float) *Float {
z.Set(x)
z.neg = false
return z
}
-// Neg sets z to x with its sign negated, and returns z.
+// Neg sets z to the (possibly rounded) value of x with its sign negated,
+// and returns z.
func (z *Float) Neg(x *Float) *Float {
z.Set(x)
z.neg = !z.neg
@@ -561,7 +848,7 @@ func (z *Float) Neg(x *Float) *Float {
}
// z = x + y, ignoring signs of x and y.
-// x and y must not be 0.
+// x and y must not be 0 or an Inf.
func (z *Float) uadd(x, y *Float) {
// Note: This implementation requires 2 shifts most of the
// time. It is also inefficient if exponents or precisions
@@ -603,7 +890,7 @@ func (z *Float) uadd(x, y *Float) {
}
// z = x - y for x >= y, ignoring signs of x and y.
-// x and y must not be zero.
+// x and y must not be 0 or an Inf.
func (z *Float) usub(x, y *Float) {
// This code is symmetric to uadd.
// We have not factored the common code out because
@@ -643,7 +930,7 @@ func (z *Float) usub(x, y *Float) {
}
// z = x * y, ignoring signs of x and y.
-// x and y must not be zero.
+// x and y must not be 0 or an Inf.
func (z *Float) umul(x, y *Float) {
if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
panic("umul called with 0 argument")
@@ -664,7 +951,7 @@ func (z *Float) umul(x, y *Float) {
}
// z = x / y, ignoring signs of x and y.
-// x and y must not be zero.
+// x and y must not be 0 or an Inf.
func (z *Float) uquo(x, y *Float) {
if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
panic("uquo called with 0 argument")
@@ -708,7 +995,7 @@ func (z *Float) uquo(x, y *Float) {
}
// ucmp returns -1, 0, or 1, depending on whether x < y, x == y, or x > y,
-// while ignoring the signs of x and y. x and y must not be zero.
+// while ignoring the signs of x and y. x and y must not be 0 or an Inf.
func (x *Float) ucmp(y *Float) int {
if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
panic("ucmp called with 0 argument")
@@ -765,16 +1052,24 @@ func (x *Float) ucmp(y *Float) int {
// sign as x even when x is zero.
// Add sets z to the rounded sum x+y and returns z.
+// If z's precision is 0, it is changed to the larger
+// of x's or y's precision before the operation.
// Rounding is performed according to z's precision
// and rounding mode; and z's accuracy reports the
// result error relative to the exact (not rounded)
// result.
func (z *Float) Add(x, y *Float) *Float {
+ if z.prec == 0 {
+ z.prec = umax(x.prec, y.prec)
+ }
+
// TODO(gri) what about -0?
if len(y.mant) == 0 {
+ // TODO(gri) handle Inf
return z.Round(x, z.prec, z.mode)
}
if len(x.mant) == 0 {
+ // TODO(gri) handle Inf
return z.Round(y, z.prec, z.mode)
}
@@ -799,13 +1094,15 @@ func (z *Float) Add(x, y *Float) *Float {
}
// Sub sets z to the rounded difference x-y and returns z.
-// Rounding is performed according to z's precision
-// and rounding mode; and z's accuracy reports the
-// result error relative to the exact (not rounded)
-// result.
+// Precision, rounding, and accuracy reporting are as for Add.
func (z *Float) Sub(x, y *Float) *Float {
+ if z.prec == 0 {
+ z.prec = umax(x.prec, y.prec)
+ }
+
// TODO(gri) what about -0?
if len(y.mant) == 0 {
+ // TODO(gri) handle Inf
return z.Round(x, z.prec, z.mode)
}
if len(x.mant) == 0 {
@@ -836,11 +1133,14 @@ func (z *Float) Sub(x, y *Float) *Float {
}
// Mul sets z to the rounded product x*y and returns z.
-// Rounding is performed according to z's precision
-// and rounding mode; and z's accuracy reports the
-// result error relative to the exact (not rounded)
-// result.
+// Precision, rounding, and accuracy reporting are as for Add.
func (z *Float) Mul(x, y *Float) *Float {
+ if z.prec == 0 {
+ z.prec = umax(x.prec, y.prec)
+ }
+
+ // TODO(gri) handle Inf
+
// TODO(gri) what about -0?
if len(x.mant) == 0 || len(y.mant) == 0 {
z.neg = false
@@ -857,47 +1157,61 @@ func (z *Float) Mul(x, y *Float) *Float {
}
// Quo sets z to the rounded quotient x/y and returns z.
-// If y == 0, a division-by-zero run-time panic occurs. TODO(gri) this should become Inf
-// Rounding is performed according to z's precision
-// and rounding mode; and z's accuracy reports the
-// result error relative to the exact (not rounded)
-// result.
+// Precision, rounding, and accuracy reporting are as for Add.
func (z *Float) Quo(x, y *Float) *Float {
- // TODO(gri) what about -0?
+ if z.prec == 0 {
+ z.prec = umax(x.prec, y.prec)
+ }
+
+ // TODO(gri) handle Inf
+
+ // TODO(gri) check that this is correct
+ z.neg = x.neg != y.neg
+
+ if len(y.mant) == 0 {
+ z.setExp(infExp)
+ return z
+ }
+
if len(x.mant) == 0 {
- z.neg = false
z.mant = z.mant[:0]
z.exp = 0
z.acc = Exact
return z
}
- if len(y.mant) == 0 {
- panic("division-by-zero") // TODO(gri) handle this better
- }
// x, y != 0
z.uquo(x, y)
- z.neg = x.neg != y.neg
return z
}
// Lsh sets z to the rounded x * (1<<s) and returns z.
+// If z's precision is 0, it is changed to x's precision.
// Rounding is performed according to z's precision
// and rounding mode; and z's accuracy reports the
// result error relative to the exact (not rounded)
// result.
func (z *Float) Lsh(x *Float, s uint, mode RoundingMode) *Float {
+ if z.prec == 0 {
+ z.prec = x.prec
+ }
+
+ // TODO(gri) handle Inf
+
z.Round(x, z.prec, mode)
z.setExp(int64(z.exp) + int64(s))
return z
}
// Rsh sets z to the rounded x / (1<<s) and returns z.
-// Rounding is performed according to z's precision
-// and rounding mode; and z's accuracy reports the
-// result error relative to the exact (not rounded)
-// result.
+// Precision, rounding, and accuracy reporting are as for Lsh.
func (z *Float) Rsh(x *Float, s uint, mode RoundingMode) *Float {
+ if z.prec == 0 {
+ z.prec = x.prec
+ }
+
+ // TODO(gri) handle Inf
+
z.Round(x, z.prec, mode)
z.setExp(int64(z.exp) - int64(s))
return z
@@ -909,49 +1223,60 @@ func (z *Float) Rsh(x *Float, s uint, mode RoundingMode) *Float {
// 0 if x == y (incl. -0 == 0)
// +1 if x > y
//
+// Infinities with matching sign are equal.
func (x *Float) Cmp(y *Float) int {
- // special cases
- switch {
- case len(x.mant) == 0:
- // 0 cmp y == -sign(y)
- return -y.Sign()
- case len(y.mant) == 0:
- // x cmp 0 == sign(x)
- return x.Sign()
+ if debugFloat {
+ x.validate()
+ y.validate()
}
- // x != 0 && y != 0
- // x cmp y == x cmp y
- // x cmp (-y) == 1
- // (-x) cmp y == -1
- // (-x) cmp (-y) == -(x cmp y)
+ mx := x.ord()
+ my := y.ord()
switch {
- case x.neg == y.neg:
- r := x.ucmp(y)
- if x.neg {
- r = -r
- }
- return r
- case x.neg:
+ case mx < my:
return -1
- default:
- return 1
+ case mx > my:
+ return +1
}
+ // mx == my
+
+ // only if |mx| == 1 we have to compare the mantissae
+ switch mx {
+ case -1:
+ return -x.ucmp(y)
+ case +1:
+ return +x.ucmp(y)
+ }
+
return 0
}
-// Sign returns:
+func umax(x, y uint) uint {
+ if x > y {
+ return x
+ }
+ return y
+}
+
+// ord classifies x and returns:
//
-// -1 if x < 0
-// 0 if x == 0 (incl. x == -0)
-// +1 if x > 0
+// -2 if -Inf == x
+// -1 if -Inf < x < 0
+// 0 if x == 0 (signed or unsigned)
+// +1 if 0 < x < +Inf
+// +2 if x == +Inf
//
-func (x *Float) Sign() int {
+// TODO(gri) export (and remove IsInf)?
+func (x *Float) ord() int {
+ m := 1 // common case
if len(x.mant) == 0 {
- return 0
+ m = 0
+ if x.exp == infExp {
+ m = 2
+ }
}
if x.neg {
- return -1
+ m = -m
}
- return 1
+ return m
}
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go
index ec67a6d606..dd059ba4a5 100644
--- a/src/math/big/float_test.go
+++ b/src/math/big/float_test.go
@@ -6,11 +6,210 @@ package big
import (
"fmt"
+ "math"
"sort"
"strconv"
+ "strings"
"testing"
)
+func (x *Float) uint64() uint64 {
+ u, acc := x.Uint64()
+ if acc != Exact {
+ panic(fmt.Sprintf("%s is not a uint64", x.Format('g', 10)))
+ }
+ return u
+}
+
+func (x *Float) int64() int64 {
+ i, acc := x.Int64()
+ if acc != Exact {
+ panic(fmt.Sprintf("%s is not an int64", x.Format('g', 10)))
+ }
+ return i
+}
+
+func TestFloatZeroValue(t *testing.T) {
+ // zero (uninitialized) value is a ready-to-use 0.0
+ var x Float
+ if s := x.Format('f', 1); s != "0.0" {
+ t.Errorf("zero value = %s; want 0.0", s)
+ }
+
+ // zero value has precision 0
+ if prec := x.Precision(); prec != 0 {
+ t.Errorf("prec = %d; want 0", prec)
+ }
+
+ // zero value can be used in any and all positions of binary operations
+ make := func(x int) *Float {
+ if x == 0 {
+ return new(Float) // 0 translates into the zero value
+ }
+ return NewFloat(float64(x), 10, 0)
+ }
+ for _, test := range []struct {
+ z, x, y, want int
+ opname rune
+ op func(z, x, y *Float) *Float
+ }{
+ {0, 0, 0, 0, '+', (*Float).Add},
+ {0, 1, 2, 3, '+', (*Float).Add},
+ {1, 2, 0, 2, '+', (*Float).Add},
+ {2, 0, 1, 1, '+', (*Float).Add},
+
+ {0, 0, 0, 0, '-', (*Float).Sub},
+ {0, 1, 2, -1, '-', (*Float).Sub},
+ {1, 2, 0, 2, '-', (*Float).Sub},
+ {2, 0, 1, -1, '-', (*Float).Sub},
+
+ {0, 0, 0, 0, '*', (*Float).Mul},
+ {0, 1, 2, 2, '*', (*Float).Mul},
+ {1, 2, 0, 0, '*', (*Float).Mul},
+ {2, 0, 1, 0, '*', (*Float).Mul},
+
+ {0, 0, 0, 0, '/', (*Float).Quo}, // = +Inf
+ {0, 2, 1, 2, '/', (*Float).Quo},
+ {1, 2, 0, 0, '/', (*Float).Quo}, // = +Inf
+ {2, 0, 1, 0, '/', (*Float).Quo},
+ } {
+ z := make(test.z)
+ test.op(z, make(test.x), make(test.y))
+ got := 0
+ if !z.IsInf(0) {
+ got = int(z.int64())
+ }
+ if got != test.want {
+ t.Errorf("%d %c %d = %d; want %d", test.x, test.opname, test.y, got, test.want)
+ }
+ }
+
+ // TODO(gri) test how precision is set for zero value results
+}
+
+func makeFloat(s string) *Float {
+ if s == "Inf" || s == "+Inf" {
+ return NewInf(+1)
+ }
+ if s == "-Inf" {
+ return NewInf(-1)
+ }
+ var x Float
+ x.prec = 1000 // TODO(gri) find a better way to do this
+ if _, ok := x.SetString(s); !ok {
+ panic(fmt.Sprintf("%q is not a valid float", s))
+ }
+ return &x
+}
+
+func TestFloatSign(t *testing.T) {
+ for _, test := range []struct {
+ x string
+ s int
+ }{
+ {"-Inf", -1},
+ {"-1", -1},
+ {"-0", 0},
+ {"+0", 0},
+ {"+1", +1},
+ {"+Inf", +1},
+ } {
+ x := makeFloat(test.x)
+ s := x.Sign()
+ if s != test.s {
+ t.Errorf("%s.Sign() = %d; want %d", test.x, s, test.s)
+ }
+ }
+}
+
+// feq(x, y) is like x.Cmp(y) == 0 but it also considers the sign of 0 (0 != -0).
+func feq(x, y *Float) bool {
+ return x.Cmp(y) == 0 && x.neg == y.neg
+}
+
+func TestFloatMantExp(t *testing.T) {
+ for _, test := range []struct {
+ x string
+ frac string
+ exp int
+ }{
+ {"0", "0", 0},
+ {"+0", "0", 0},
+ {"-0", "-0", 0},
+ {"Inf", "+Inf", 0},
+ {"+Inf", "+Inf", 0},
+ {"-Inf", "-Inf", 0},
+ {"1.5", "0.75", 1},
+ {"1.024e3", "0.5", 11},
+ {"-0.125", "-0.5", -2},
+ } {
+ x := makeFloat(test.x)
+ frac := makeFloat(test.frac)
+ f, e := x.MantExp()
+ if !feq(f, frac) || e != test.exp {
+ t.Errorf("%s.MantExp() = %s, %d; want %s, %d", test.x, f.Format('g', 10), e, test.frac, test.exp)
+ }
+ }
+}
+
+func TestFloatSetMantExp(t *testing.T) {
+ for _, test := range []struct {
+ frac string
+ exp int
+ z string
+ }{
+ {"0", 0, "0"},
+ {"+0", 0, "0"},
+ {"-0", 0, "-0"},
+ {"Inf", 1234, "+Inf"},
+ {"+Inf", -1234, "+Inf"},
+ {"-Inf", -1234, "-Inf"},
+ {"0", -MaxExp - 1, "0"},
+ {"1", -MaxExp - 1, "+Inf"}, // exponent magnitude too large
+ {"-1", -MaxExp - 1, "-Inf"}, // exponent magnitude too large
+ {"0.75", 1, "1.5"},
+ {"0.5", 11, "1024"},
+ {"-0.5", -2, "-0.125"},
+ } {
+ frac := makeFloat(test.frac)
+ want := makeFloat(test.z)
+ var z Float
+ z.SetMantExp(frac, test.exp)
+ if !feq(&z, want) {
+ t.Errorf("SetMantExp(%s, %d) = %s; want %s", test.frac, test.exp, z.Format('g', 10), test.z)
+ }
+ }
+}
+
+func TestFloatIsInt(t *testing.T) {
+ for _, test := range []string{
+ "0 int",
+ "-0 int",
+ "1 int",
+ "-1 int",
+ "0.5",
+ "1.23",
+ "1.23e1",
+ "1.23e2 int",
+ "0.000000001e+8",
+ "0.000000001e+9 int",
+ "1.2345e200 int",
+ "Inf",
+ "+Inf",
+ "-Inf",
+ } {
+ s := strings.TrimSuffix(test, " int")
+ want := s != test
+ if got := makeFloat(s).IsInt(); got != want {
+ t.Errorf("%s.IsInt() == %t", s, got)
+ }
+ }
+}
+
+func TestFloatIsInf(t *testing.T) {
+ // TODO(gri) implement this
+}
+
func fromBinary(s string) int64 {
x, err := strconv.ParseInt(s, 2, 64)
if err != nil {
@@ -66,7 +265,7 @@ func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) {
f.Round(f, prec, mode)
// check result
- r1 := f.Int64()
+ r1 := f.int64()
p1 := f.Precision()
a1 := f.Accuracy()
if r1 != r || p1 != prec || a1 != a {
@@ -203,9 +402,21 @@ func TestFloatSetUint64(t *testing.T) {
1 << 32,
1<<64 - 1,
} {
- f := new(Float).SetUint64(want)
- if got := f.Uint64(); got != want {
- t.Errorf("got %d (%s); want %d", got, f.Format('p', 0), want)
+ var f Float
+ f.SetUint64(want)
+ if got := f.uint64(); got != want {
+ t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
+ }
+ }
+
+ // test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+ const x uint64 = 0x8765432187654321 // 64 bits needed
+ for prec := uint(1); prec <= 64; prec++ {
+ f := NewFloat(0, prec, ToZero).SetUint64(x)
+ got := f.uint64()
+ want := x &^ (1<<(64-prec) - 1) // cut off (round to zero) low 64-prec bits
+ if got != want {
+ t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
}
}
}
@@ -225,12 +436,24 @@ func TestFloatSetInt64(t *testing.T) {
if i&1 != 0 {
want = -want
}
- f := new(Float).SetInt64(want)
- if got := f.Int64(); got != want {
- t.Errorf("got %d (%s); want %d", got, f.Format('p', 0), want)
+ var f Float
+ f.SetInt64(want)
+ if got := f.int64(); got != want {
+ t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
}
}
}
+
+ // test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+ const x int64 = 0x7654321076543210 // 63 bits needed
+ for prec := uint(1); prec <= 63; prec++ {
+ f := NewFloat(0, prec, ToZero).SetInt64(x)
+ got := f.int64()
+ want := x &^ (1<<(63-prec) - 1) // cut off (round to zero) low 63-prec bits
+ if got != want {
+ t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
+ }
+ }
}
func TestFloatSetFloat64(t *testing.T) {
@@ -244,21 +467,265 @@ func TestFloatSetFloat64(t *testing.T) {
3.14159265e10,
2.718281828e-123,
1.0 / 3,
+ math.Inf(-1),
+ math.Inf(0),
+ -math.Inf(1),
} {
for i := range [2]int{} {
if i&1 != 0 {
want = -want
}
- f := new(Float).SetFloat64(want)
+ var f Float
+ f.SetFloat64(want)
if got, _ := f.Float64(); got != want {
t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want)
}
}
}
+
+ // test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+ const x uint64 = 0x8765432143218 // 53 bits needed
+ for prec := uint(1); prec <= 52; prec++ {
+ f := NewFloat(0, prec, ToZero).SetFloat64(float64(x))
+ got, _ := f.Float64()
+ want := float64(x &^ (1<<(52-prec) - 1)) // cut off (round to zero) low 53-prec bits
+ if got != want {
+ t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want)
+ }
+ }
}
func TestFloatSetInt(t *testing.T) {
- // TODO(gri) implement
+ for _, want := range []string{
+ "0",
+ "1",
+ "-1",
+ "1234567890",
+ "123456789012345678901234567890",
+ "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ } {
+ var x Int
+ _, ok := x.SetString(want, 0)
+ if !ok {
+ t.Errorf("invalid integer %s", want)
+ continue
+ }
+ n := x.BitLen()
+
+ var f Float
+ f.SetInt(&x)
+
+ // check precision
+ if n < 64 {
+ n = 64
+ }
+ if prec := f.Precision(); prec != uint(n) {
+ t.Errorf("got prec = %d; want %d", prec, n)
+ }
+
+ // check value
+ got := f.Format('g', 100)
+ if got != want {
+ t.Errorf("got %s (%s); want %s", got, f.Format('p', 0), want)
+ }
+ }
+
+ // TODO(gri) test basic rounding behavior
+}
+
+func TestFloatSetRat(t *testing.T) {
+ for _, want := range []string{
+ "0",
+ "1",
+ "-1",
+ "1234567890",
+ "123456789012345678901234567890",
+ "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "1.2",
+ "3.14159265",
+ // TODO(gri) expand
+ } {
+ var x Rat
+ _, ok := x.SetString(want)
+ if !ok {
+ t.Errorf("invalid fraction %s", want)
+ continue
+ }
+ n := max(x.Num().BitLen(), x.Denom().BitLen())
+
+ var f1 Float
+ var f2 = NewFloat(0, 1000, 0) // set a high precision - TODO(gri) find a cleaner way
+ f1.SetRat(&x)
+ f2.SetRat(&x)
+
+ // check precision when set automatically
+ if n < 64 {
+ n = 64
+ }
+ if prec := f1.Precision(); prec != uint(n) {
+ t.Errorf("got prec = %d; want %d", prec, n)
+ }
+
+ got := f2.Format('g', 100)
+ if got != want {
+ t.Errorf("got %s (%s); want %s", got, f2.Format('p', 0), want)
+ }
+ }
+}
+
+func TestFloatUint64(t *testing.T) {
+ for _, test := range []struct {
+ x string
+ out uint64
+ acc Accuracy
+ }{
+ {"-Inf", 0, Above},
+ {"-1", 0, Above},
+ {"-1e-1000", 0, Above},
+ {"-0", 0, Exact},
+ {"0", 0, Exact},
+ {"1e-1000", 0, Below},
+ {"1", 1, Exact},
+ {"1.000000000000000000001", 1, Below},
+ {"12345.0", 12345, Exact},
+ {"12345.000000000000000000001", 12345, Below},
+ {"18446744073709551615", 18446744073709551615, Exact},
+ {"18446744073709551615.000000000000000000001", math.MaxUint64, Below},
+ {"18446744073709551616", math.MaxUint64, Below},
+ {"1e10000", math.MaxUint64, Below},
+ {"+Inf", math.MaxUint64, Below},
+ } {
+ x := makeFloat(test.x)
+ out, acc := x.Uint64()
+ if out != test.out || acc != test.acc {
+ t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
+ }
+ }
+}
+
+func TestFloatInt64(t *testing.T) {
+ for _, test := range []struct {
+ x string
+ out int64
+ acc Accuracy
+ }{
+ {"-Inf", math.MinInt64, Above},
+ {"-1e10000", math.MinInt64, Above},
+ {"-9223372036854775809", math.MinInt64, Above},
+ {"-9223372036854775808.000000000000000000001", math.MinInt64, Above},
+ {"-9223372036854775808", -9223372036854775808, Exact},
+ {"-9223372036854775807.000000000000000000001", -9223372036854775807, Above},
+ {"-9223372036854775807", -9223372036854775807, Exact},
+ {"-12345.000000000000000000001", -12345, Above},
+ {"-12345.0", -12345, Exact},
+ {"-1.000000000000000000001", -1, Above},
+ {"-1", -1, Exact},
+ {"-1e-1000", 0, Above},
+ {"0", 0, Exact},
+ {"1e-1000", 0, Below},
+ {"1", 1, Exact},
+ {"1.000000000000000000001", 1, Below},
+ {"12345.0", 12345, Exact},
+ {"12345.000000000000000000001", 12345, Below},
+ {"9223372036854775807", 9223372036854775807, Exact},
+ {"9223372036854775807.000000000000000000001", math.MaxInt64, Below},
+ {"9223372036854775808", math.MaxInt64, Below},
+ {"1e10000", math.MaxInt64, Below},
+ {"+Inf", math.MaxInt64, Below},
+ } {
+ x := makeFloat(test.x)
+ out, acc := x.Int64()
+ if out != test.out || acc != test.acc {
+ t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
+ }
+ }
+}
+
+func TestFloatInt(t *testing.T) {
+ for _, test := range []struct {
+ x string
+ out string
+ acc Accuracy
+ }{
+ {"0", "0", Exact},
+ {"+0", "0", Exact},
+ {"-0", "0", Exact},
+ {"Inf", "nil", Below},
+ {"+Inf", "nil", Below},
+ {"-Inf", "nil", Above},
+ {"1", "1", Exact},
+ {"-1", "-1", Exact},
+ {"1.23", "1", Below},
+ {"-1.23", "-1", Above},
+ {"123e-2", "1", Below},
+ {"123e-3", "0", Below},
+ {"123e-4", "0", Below},
+ {"1e-1000", "0", Below},
+ {"-1e-1000", "0", Above},
+ {"1e+10", "10000000000", Exact},
+ {"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact},
+ } {
+ x := makeFloat(test.x)
+ out, acc := x.Int()
+ got := "nil"
+ if out != nil {
+ got = out.String()
+ }
+ if got != test.out || acc != test.acc {
+ t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.out, test.acc)
+ }
+ }
+}
+
+func TestFloatRat(t *testing.T) {
+ // TODO(gri) implement this
+}
+
+func TestFloatAbs(t *testing.T) {
+ for _, test := range []string{
+ "0",
+ "1",
+ "1234",
+ "1.23e-2",
+ "1e-1000",
+ "1e1000",
+ "Inf",
+ } {
+ p := makeFloat(test)
+ a := new(Float).Abs(p)
+ if !feq(a, p) {
+ t.Errorf("%s: got %s; want %s", test, a.Format('g', 10), test)
+ }
+
+ n := makeFloat("-" + test)
+ a.Abs(n)
+ if !feq(a, p) {
+ t.Errorf("-%s: got %s; want %s", test, a.Format('g', 10), test)
+ }
+ }
+}
+
+func TestFloatNeg(t *testing.T) {
+ for _, test := range []string{
+ "0",
+ "1",
+ "1234",
+ "1.23e-2",
+ "1e-1000",
+ "1e1000",
+ "Inf",
+ } {
+ p1 := makeFloat(test)
+ n1 := makeFloat("-" + test)
+ n2 := new(Float).Neg(p1)
+ p2 := new(Float).Neg(n2)
+ if !feq(n2, n1) {
+ t.Errorf("%s: got %s; want %s", test, n2.Format('g', 10), n1.Format('g', 10))
+ }
+ if !feq(p2, p1) {
+ t.Errorf("%s: got %s; want %s", test, p2.Format('g', 10), p1.Format('g', 10))
+ }
+ }
}
// Selected precisions with which to run various tests.
@@ -386,6 +853,7 @@ func TestFloatAdd64(t *testing.T) {
}
func TestFloatMul(t *testing.T) {
+ // TODO(gri) implement this
}
// TestFloatMul64 tests that Float.Mul/Quo of numbers with
@@ -521,6 +989,51 @@ func TestFloatQuo(t *testing.T) {
}
}
+// TestFloatQuoSmoke tests all divisions x/y for values x, y in the range [-n, +n];
+// it serves as a smoke test for basic correctness of division.
+func TestFloatQuoSmoke(t *testing.T) {
+ n := 1000
+ if testing.Short() {
+ n = 10
+ }
+
+ const dprec = 3 // max. precision variation
+ const prec = 10 + dprec // enough bits to hold n precisely
+ for x := -n; x <= n; x++ {
+ for y := -n; y < n; y++ {
+ if y == 0 {
+ continue
+ }
+
+ a := float64(x)
+ b := float64(y)
+ c := a / b
+
+ // vary operand precision (only ok as long as a, b can be represented correctly)
+ for ad := -dprec; ad <= dprec; ad++ {
+ for bd := -dprec; bd <= dprec; bd++ {
+ A := NewFloat(a, uint(prec+ad), 0)
+ B := NewFloat(b, uint(prec+bd), 0)
+ C := NewFloat(0, 53, 0).Quo(A, B) // C has float64 mantissa width
+
+ cc, acc := C.Float64()
+ if cc != c {
+ t.Errorf("%g/%g = %s; want %.5g\n", a, b, C.Format('g', 5), c)
+ continue
+ }
+ if acc != Exact {
+ t.Errorf("%g/%g got %s result; want exact result", a, b, acc)
+ }
+ }
+ }
+ }
+ }
+}
+
+func TestFloatCmp(t *testing.T) {
+ // TODO(gri) implement this
+}
+
// normBits returns the normalized bits for x: It
// removes multiple equal entries by treating them
// as an addition (e.g., []int{5, 5} => []int{6}),
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
index 06c1f14471..71920cd51c 100644
--- a/src/math/big/floatconv.go
+++ b/src/math/big/floatconv.go
@@ -57,6 +57,7 @@ func (z *Float) SetString(s string) (*Float, bool) {
// with base 0 or 10 corresponds to the value 1.2 * 2**3.
//
// BUG(gri) This signature conflicts with Scan(s fmt.ScanState, ch rune) error.
+// TODO(gri) What should the default precision be?
func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
// sign
z.neg, err = scanSign(r)
@@ -162,8 +163,8 @@ func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b i
// Format converts the floating-point number x to a string according
// to the given format and precision prec. The format is one of:
//
-// 'e' -d.dddde±dd, decimal exponent
-// 'E' -d.ddddE±dd, decimal exponent
+// 'e' -d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
+// 'E' -d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
// 'f' -ddddd.dddd, no exponent
// 'g' like 'e' for large exponents, like 'f' otherwise
// 'G' like 'E' for large exponents, like 'f' otherwise
@@ -182,7 +183,7 @@ func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b i
// number of digits necessary such that ParseFloat will return f exactly.
// The prec value is ignored for the 'b' or 'p' format.
//
-// BUG(gri) Currently, Format only accepts the 'b' and 'p' format.
+// BUG(gri) Currently, Format does not accept negative precisions.
func (x *Float) Format(format byte, prec int) string {
const extra = 10 // TODO(gri) determine a good/better value here
return string(x.Append(make([]byte, 0, prec+extra), format, prec))
@@ -191,13 +192,27 @@ func (x *Float) Format(format byte, prec int) string {
// Append appends the string form of the floating-point number x,
// as generated by x.Format, to buf and returns the extended buffer.
func (x *Float) Append(buf []byte, format byte, prec int) []byte {
+ // TODO(gri) factor out handling of sign?
+
+ // Inf
+ if x.IsInf(0) {
+ var ch byte = '+'
+ if x.neg {
+ ch = '-'
+ }
+ buf = append(buf, ch)
+ return append(buf, "Inf"...)
+ }
+
+ // easy formats
switch format {
case 'b':
return x.bstring(buf)
case 'p':
return x.pstring(buf)
}
- return append(buf, fmt.Sprintf(`%%!c`, format)...)
+
+ return x.bigFtoa(buf, format, prec)
}
// BUG(gri): Currently, String uses the 'p' (rather than 'g') format.
@@ -211,7 +226,6 @@ func (x *Float) String() string {
// The mantissa is normalized such that is uses x.Precision() bits in binary
// representation.
func (x *Float) bstring(buf []byte) []byte {
- // TODO(gri) handle Inf
if x.neg {
buf = append(buf, '-')
}
@@ -239,7 +253,6 @@ func (x *Float) bstring(buf []byte) []byte {
// ad returns the extended buffer.
// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
func (x *Float) pstring(buf []byte) []byte {
- // TODO(gri) handle Inf
if x.neg {
buf = append(buf, '-')
}
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
index 0e8bfb39ab..11e5df448a 100644
--- a/src/math/big/floatconv_test.go
+++ b/src/math/big/floatconv_test.go
@@ -5,6 +5,8 @@
package big
import (
+ "io"
+ "math"
"strconv"
"testing"
)
@@ -71,37 +73,157 @@ func TestFloatSetFloat64String(t *testing.T) {
}
}
-func TestFloatFormat(t *testing.T) {
+const (
+ below1e23 = 99999999999999974834176
+ above1e23 = 100000000000000008388608
+)
+
+func TestFloat64Format(t *testing.T) {
for _, test := range []struct {
- x string
+ x float64
format byte
prec int
want string
}{
- {"0", 'b', 0, "0"},
- {"-0", 'b', 0, "-0"},
- {"1.0", 'b', 0, "4503599627370496p-52"},
- {"-1.0", 'b', 0, "-4503599627370496p-52"},
- {"4503599627370496", 'b', 0, "4503599627370496p+0"},
+ {0, 'f', 0, "0"},
+ {math.Copysign(0, -1), 'f', 0, "-0"},
+ {1, 'f', 0, "1"},
+ {-1, 'f', 0, "-1"},
- {"0", 'p', 0, "0"},
- {"-0", 'p', 0, "-0"},
- {"1024.0", 'p', 0, "0x.8p11"},
- {"-1024.0", 'p', 0, "-0x.8p11"},
- } {
- f64, err := strconv.ParseFloat(test.x, 64)
- if err != nil {
- t.Error(err)
- continue
- }
+ {1.459, 'e', 0, "1e+00"},
+ {2.459, 'e', 1, "2.5e+00"},
+ {3.459, 'e', 2, "3.46e+00"},
+ {4.459, 'e', 3, "4.459e+00"},
+ {5.459, 'e', 4, "5.4590e+00"},
+
+ {1.459, 'f', 0, "1"},
+ {2.459, 'f', 1, "2.5"},
+ {3.459, 'f', 2, "3.46"},
+ {4.459, 'f', 3, "4.459"},
+ {5.459, 'f', 4, "5.4590"},
+
+ {0, 'b', 0, "0"},
+ {math.Copysign(0, -1), 'b', 0, "-0"},
+ {1.0, 'b', 0, "4503599627370496p-52"},
+ {-1.0, 'b', 0, "-4503599627370496p-52"},
+ {4503599627370496, 'b', 0, "4503599627370496p+0"},
+
+ {0, 'p', 0, "0"},
+ {math.Copysign(0, -1), 'p', 0, "-0"},
+ {1024.0, 'p', 0, "0x.8p11"},
+ {-1024.0, 'p', 0, "-0x.8p11"},
+
+ // all test cases below from strconv/ftoa_test.go
+ {1, 'e', 5, "1.00000e+00"},
+ {1, 'f', 5, "1.00000"},
+ {1, 'g', 5, "1"},
+ // {1, 'g', -1, "1"},
+ // {20, 'g', -1, "20"},
+ // {1234567.8, 'g', -1, "1.2345678e+06"},
+ // {200000, 'g', -1, "200000"},
+ // {2000000, 'g', -1, "2e+06"},
+
+ // g conversion and zero suppression
+ {400, 'g', 2, "4e+02"},
+ {40, 'g', 2, "40"},
+ {4, 'g', 2, "4"},
+ {.4, 'g', 2, "0.4"},
+ {.04, 'g', 2, "0.04"},
+ {.004, 'g', 2, "0.004"},
+ {.0004, 'g', 2, "0.0004"},
+ {.00004, 'g', 2, "4e-05"},
+ {.000004, 'g', 2, "4e-06"},
+
+ {0, 'e', 5, "0.00000e+00"},
+ {0, 'f', 5, "0.00000"},
+ {0, 'g', 5, "0"},
+ // {0, 'g', -1, "0"},
+
+ {-1, 'e', 5, "-1.00000e+00"},
+ {-1, 'f', 5, "-1.00000"},
+ {-1, 'g', 5, "-1"},
+ // {-1, 'g', -1, "-1"},
- f := new(Float).SetFloat64(f64)
+ {12, 'e', 5, "1.20000e+01"},
+ {12, 'f', 5, "12.00000"},
+ {12, 'g', 5, "12"},
+ // {12, 'g', -1, "12"},
+
+ {123456700, 'e', 5, "1.23457e+08"},
+ {123456700, 'f', 5, "123456700.00000"},
+ {123456700, 'g', 5, "1.2346e+08"},
+ // {123456700, 'g', -1, "1.234567e+08"},
+
+ {1.2345e6, 'e', 5, "1.23450e+06"},
+ {1.2345e6, 'f', 5, "1234500.00000"},
+ {1.2345e6, 'g', 5, "1.2345e+06"},
+
+ {1e23, 'e', 17, "9.99999999999999916e+22"},
+ {1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
+ {1e23, 'g', 17, "9.9999999999999992e+22"},
+
+ // {1e23, 'e', -1, "1e+23"},
+ // {1e23, 'f', -1, "100000000000000000000000"},
+ // {1e23, 'g', -1, "1e+23"},
+
+ {below1e23, 'e', 17, "9.99999999999999748e+22"},
+ {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
+ {below1e23, 'g', 17, "9.9999999999999975e+22"},
+
+ // {below1e23, 'e', -1, "9.999999999999997e+22"},
+ // {below1e23, 'f', -1, "99999999999999970000000"},
+ // {below1e23, 'g', -1, "9.999999999999997e+22"},
+
+ {above1e23, 'e', 17, "1.00000000000000008e+23"},
+ {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
+ // {above1e23, 'g', 17, "1.0000000000000001e+23"},
+
+ // {above1e23, 'e', -1, "1.0000000000000001e+23"},
+ // {above1e23, 'f', -1, "100000000000000010000000"},
+ // {above1e23, 'g', -1, "1.0000000000000001e+23"},
+
+ // {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
+ // {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
+
+ // {32, 'g', -1, "32"},
+ // {32, 'g', 0, "3e+01"},
+
+ // {100, 'x', -1, "%x"},
+
+ // {math.NaN(), 'g', -1, "NaN"},
+ // {-math.NaN(), 'g', -1, "NaN"},
+ {math.Inf(0), 'g', -1, "+Inf"},
+ {math.Inf(-1), 'g', -1, "-Inf"},
+ {-math.Inf(0), 'g', -1, "-Inf"},
+
+ {-1, 'b', -1, "-4503599627370496p-52"},
+
+ // fixed bugs
+ {0.9, 'f', 1, "0.9"},
+ {0.09, 'f', 1, "0.1"},
+ {0.0999, 'f', 1, "0.1"},
+ {0.05, 'f', 1, "0.1"},
+ {0.05, 'f', 0, "0"},
+ {0.5, 'f', 1, "0.5"},
+ {0.5, 'f', 0, "0"},
+ {1.5, 'f', 0, "2"},
+
+ // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+ // {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
+ // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+ // {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
+
+ // Issue 2625.
+ {383260575764816448, 'f', 0, "383260575764816448"},
+ // {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
+ } {
+ f := new(Float).SetFloat64(test.x)
got := f.Format(test.format, test.prec)
if got != test.want {
t.Errorf("%v: got %s; want %s", test, got, test.want)
}
- if test.format == 'b' && f64 == 0 {
+ if test.format == 'b' && test.x == 0 {
continue // 'b' format in strconv.Float requires knowledge of bias for 0.0
}
if test.format == 'p' {
@@ -109,9 +231,97 @@ func TestFloatFormat(t *testing.T) {
}
// verify that Float format matches strconv format
- want := strconv.FormatFloat(f64, test.format, test.prec, 64)
+ want := strconv.FormatFloat(test.x, test.format, test.prec, 64)
if got != want {
- t.Errorf("%v: got %s; want %s", test, got, want)
+ t.Errorf("%v: got %s; want %s (strconv)", test, got, want)
+ }
+ }
+}
+
+func TestFloatFormat(t *testing.T) {
+ for _, test := range []struct {
+ x string
+ format byte
+ prec int
+ want string
+ }{
+ {"0", 'f', 0, "0"},
+ {"-0", 'f', 0, "-0"},
+ {"1", 'f', 0, "1"},
+ {"-1", 'f', 0, "-1"},
+
+ {"1.459", 'e', 0, "1e+00"},
+ {"2.459", 'e', 1, "2.5e+00"},
+ {"3.459", 'e', 2, "3.46e+00"},
+ {"4.459", 'e', 3, "4.459e+00"},
+ {"5.459", 'e', 4, "5.4590e+00"},
+
+ {"1.459", 'E', 0, "1E+00"},
+ {"2.459", 'E', 1, "2.5E+00"},
+ {"3.459", 'E', 2, "3.46E+00"},
+ {"4.459", 'E', 3, "4.459E+00"},
+ {"5.459", 'E', 4, "5.4590E+00"},
+
+ {"1.459", 'f', 0, "1"},
+ {"2.459", 'f', 1, "2.5"},
+ {"3.459", 'f', 2, "3.46"},
+ {"4.459", 'f', 3, "4.459"},
+ {"5.459", 'f', 4, "5.4590"},
+
+ {"1.459", 'g', 0, "1"},
+ {"2.459", 'g', 1, "2"},
+ {"3.459", 'g', 2, "3.5"},
+ {"4.459", 'g', 3, "4.46"},
+ {"5.459", 'g', 4, "5.459"},
+
+ {"1459", 'g', 0, "1e+03"},
+ {"2459", 'g', 1, "2e+03"},
+ {"3459", 'g', 2, "3.5e+03"},
+ {"4459", 'g', 3, "4.46e+03"},
+ {"5459", 'g', 4, "5459"},
+
+ {"1459", 'G', 0, "1E+03"},
+ {"2459", 'G', 1, "2E+03"},
+ {"3459", 'G', 2, "3.5E+03"},
+ {"4459", 'G', 3, "4.46E+03"},
+ {"5459", 'G', 4, "5459"},
+
+ {"3", 'e', 40, "3.0000000000000000000000000000000000000000e+00"},
+ {"3", 'f', 40, "3.0000000000000000000000000000000000000000"},
+ {"3", 'g', 40, "3"},
+
+ {"3e40", 'e', 40, "3.0000000000000000000000000000000000000000e+40"},
+ {"3e40", 'f', 4, "30000000000000000000000000000000000000000.0000"},
+ {"3e40", 'g', 40, "3e+40"},
+
+ // TODO(gri) need tests for actual large Floats
+
+ // These depend on the selected mantissa length to match strconv.FormatFloat.
+ // Disabled for now.
+ // {"0", 'b', 0, "0"},
+ // {"-0", 'b', 0, "-0"},
+ // {"1.0", 'b', 0, "4503599627370496p-52"},
+ // {"-1.0", 'b', 0, "-4503599627370496p-52"},
+ // {"4503599627370496", 'b', 0, "4503599627370496p+0"},
+
+ {"0", 'p', 0, "0"},
+ {"-0", 'p', 0, "-0"},
+ {"1024.0", 'p', 0, "0x.8p11"},
+ {"-1024.0", 'p', 0, "-0x.8p11"},
+
+ // unsupported format
+ {"3.14", 'x', 0, "%x"},
+ } {
+ f, _, err := ParseFloat(test.x, 0, 1000, ToNearestEven)
+ // TODO(gri) should we return io.EOF at the end?
+ if err != nil && err != io.EOF {
+ t.Errorf("%v: %s", test, err)
+ continue
+ }
+
+ got := f.Format(test.format, test.prec)
+ if got != test.want {
+ t.Errorf("%v: got %s; want %s", test, got, test.want)
}
}
}
diff --git a/src/math/big/ftoa.go b/src/math/big/ftoa.go
new file mode 100644
index 0000000000..148081589d
--- /dev/null
+++ b/src/math/big/ftoa.go
@@ -0,0 +1,184 @@
+// Copyright 2015 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.
+
+// This file implements the 'e', 'f', 'g' floating-point formats.
+// It is closely following the corresponding implementation in
+// strconv/ftoa.go, but modified and simplified for big.Float.
+
+// Algorithm:
+// 1) convert Float to multiprecision decimal
+// 2) round to desired precision
+// 3) read digits out and format
+
+package big
+
+import "strconv"
+
+// TODO(gri) Consider moving sign into decimal - could make the signatures below cleaner.
+
+// bigFtoa formats a float for the %e, %E, %f, %g, and %G formats.
+func (f *Float) bigFtoa(buf []byte, fmt byte, prec int) []byte {
+ // TODO(gri) handle Inf.
+
+ // 1) convert Float to multiprecision decimal
+ var d decimal
+ d.init(f.mant, int(f.exp)-f.mant.bitLen())
+
+ // 2) round to desired precision
+ shortest := false
+ if prec < 0 {
+ shortest = true
+ panic("unimplemented")
+ // TODO(gri) complete this
+ // roundShortest(&d, f.mant, int(f.exp))
+ // Precision for shortest representation mode.
+ switch fmt {
+ case 'e', 'E':
+ prec = len(d.mant) - 1
+ case 'f':
+ prec = max(len(d.mant)-d.exp, 0)
+ case 'g', 'G':
+ prec = len(d.mant)
+ }
+ } else {
+ // round appropriately
+ switch fmt {
+ case 'e', 'E':
+ // one digit before and number of digits after decimal point
+ d.round(1 + prec)
+ case 'f':
+ // number of digits before and after decimal point
+ d.round(d.exp + prec)
+ case 'g', 'G':
+ if prec == 0 {
+ prec = 1
+ }
+ d.round(prec)
+ }
+ }
+
+ // 3) read digits out and format
+ switch fmt {
+ case 'e', 'E':
+ return fmtE(buf, fmt, prec, f.neg, d)
+ case 'f':
+ return fmtF(buf, prec, f.neg, d)
+ case 'g', 'G':
+ // trim trailing fractional zeros in %e format
+ eprec := prec
+ if eprec > len(d.mant) && len(d.mant) >= d.exp {
+ eprec = len(d.mant)
+ }
+ // %e is used if the exponent from the conversion
+ // is less than -4 or greater than or equal to the precision.
+ // If precision was the shortest possible, use eprec = 6 for
+ // this decision.
+ if shortest {
+ eprec = 6
+ }
+ exp := d.exp - 1
+ if exp < -4 || exp >= eprec {
+ if prec > len(d.mant) {
+ prec = len(d.mant)
+ }
+ return fmtE(buf, fmt+'e'-'g', prec-1, f.neg, d)
+ }
+ if prec > d.exp {
+ prec = len(d.mant)
+ }
+ return fmtF(buf, max(prec-d.exp, 0), f.neg, d)
+ }
+
+ // unknown format
+ return append(buf, '%', fmt)
+}
+
+// %e: -d.ddddde±dd
+func fmtE(buf []byte, fmt byte, prec int, neg bool, d decimal) []byte {
+ // sign
+ if neg {
+ buf = append(buf, '-')
+ }
+
+ // first digit
+ ch := byte('0')
+ if len(d.mant) > 0 {
+ ch = d.mant[0]
+ }
+ buf = append(buf, ch)
+
+ // .moredigits
+ if prec > 0 {
+ buf = append(buf, '.')
+ i := 1
+ m := min(len(d.mant), prec+1)
+ if i < m {
+ buf = append(buf, d.mant[i:m]...)
+ i = m
+ }
+ for ; i <= prec; i++ {
+ buf = append(buf, '0')
+ }
+ }
+
+ // e±
+ buf = append(buf, fmt)
+ var exp int64
+ if len(d.mant) > 0 {
+ exp = int64(d.exp) - 1 // -1 because first digit was printed before '.'
+ }
+ if exp < 0 {
+ ch = '-'
+ exp = -exp
+ } else {
+ ch = '+'
+ }
+ buf = append(buf, ch)
+
+ // dd...d
+ if exp < 10 {
+ buf = append(buf, '0') // at least 2 exponent digits
+ }
+ return strconv.AppendInt(buf, exp, 10)
+}
+
+// %f: -ddddddd.ddddd
+func fmtF(buf []byte, prec int, neg bool, d decimal) []byte {
+ // sign
+ if neg {
+ buf = append(buf, '-')
+ }
+
+ // integer, padded with zeros as needed
+ if d.exp > 0 {
+ m := min(len(d.mant), d.exp)
+ buf = append(buf, d.mant[:m]...)
+ for ; m < d.exp; m++ {
+ buf = append(buf, '0')
+ }
+ } else {
+ buf = append(buf, '0')
+ }
+
+ // fraction
+ if prec > 0 {
+ buf = append(buf, '.')
+ for i := 0; i < prec; i++ {
+ ch := byte('0')
+ if j := d.exp + i; 0 <= j && j < len(d.mant) {
+ ch = d.mant[j]
+ }
+ buf = append(buf, ch)
+ }
+ }
+
+ return buf
+}
+
+func min(x, y int) int {
+ if x < y {
+ return x
+ }
+ return y
+}
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index 1418dca335..cb8c76bed1 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -655,7 +655,7 @@ var primes = []string{
"10953742525620032441",
"17908251027575790097",
- // http://code.google.com/p/go/issues/detail?id=638
+ // http://golang.org/issue/638
"18699199384836356663",
"98920366548084643601728869055592650835572950932266967461790948584315647051443",
diff --git a/src/nacltest.bash b/src/nacltest.bash
index 6220d39f13..534f1ef5af 100755
--- a/src/nacltest.bash
+++ b/src/nacltest.bash
@@ -62,7 +62,7 @@ fi
# Run host build to get toolchain for running zip generator.
unset GOOS GOARCH
if [ ! -f make.bash ]; then
- echo 'nacl.bash must be run from $GOROOT/src' 1>&2
+ echo 'nacltest.bash must be run from $GOROOT/src' 1>&2
exit 1
fi
GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH ./make.bash
diff --git a/src/net/dial.go b/src/net/dial.go
index e6f0436cdd..0424ed250f 100644
--- a/src/net/dial.go
+++ b/src/net/dial.go
@@ -159,13 +159,15 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
if err != nil {
return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err}
}
- dialer := func(deadline time.Time) (Conn, error) {
- return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline)
- }
+ var dialer func(deadline time.Time) (Conn, error)
if ras, ok := ra.(addrList); ok && d.DualStack && network == "tcp" {
dialer = func(deadline time.Time) (Conn, error) {
return dialMulti(network, address, d.LocalAddr, ras, deadline)
}
+ } else {
+ dialer = func(deadline time.Time) (Conn, error) {
+ return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline)
+ }
}
c, err := dial(network, ra.toAddr(), dialer, d.deadline())
if d.KeepAlive > 0 && err == nil {
diff --git a/src/net/hosts_test.go b/src/net/hosts_test.go
index 2fe358e079..5bb663b4c7 100644
--- a/src/net/hosts_test.go
+++ b/src/net/hosts_test.go
@@ -53,7 +53,7 @@ func TestLookupStaticHost(t *testing.T) {
hostsPath = p
}
-// https://code.google.com/p/go/issues/detail?id=6646
+// https://golang.org/issue/6646
func TestSingleLineHostsFile(t *testing.T) {
p := hostsPath
hostsPath = "testdata/hosts_singleline"
diff --git a/src/net/http/proxy_test.go b/src/net/http/proxy_test.go
index b6aed3792b..823d1447ee 100644
--- a/src/net/http/proxy_test.go
+++ b/src/net/http/proxy_test.go
@@ -18,7 +18,7 @@ var UseProxyTests = []struct {
match bool
}{
// Never proxy localhost:
- {"localhost:80", false},
+ {"localhost", false},
{"127.0.0.1", false},
{"127.0.0.2", false},
{"[::1]", false},
diff --git a/src/net/http/request.go b/src/net/http/request.go
index 63d7d44aa0..f7a7f19b9b 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -673,7 +673,7 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
// MaxBytesReader is similar to io.LimitReader but is intended for
// limiting the size of incoming request bodies. In contrast to
// io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a
-// non-EOF error for a Read beyond the limit, and Closes the
+// non-EOF error for a Read beyond the limit, and closes the
// underlying reader when its Close method is called.
//
// MaxBytesReader prevents clients from accidentally or maliciously
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index 85d5705137..c21b57b57e 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -416,7 +416,7 @@ func TestServeMuxHandlerRedirects(t *testing.T) {
}
}
-// Tests for http://code.google.com/p/go/issues/detail?id=900
+// Tests for http://golang.org/issue/900
func TestMuxRedirectLeadingSlashes(t *testing.T) {
paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
for _, path := range paths {
@@ -2124,7 +2124,7 @@ func TestDoubleHijack(t *testing.T) {
<-conn.closec
}
-// http://code.google.com/p/go/issues/detail?id=5955
+// http://golang.org/issue/5955
// Note that this does not test the "request too large"
// exit path from the http server. This is intentional;
// not sending Connection: close is just a minor wire
diff --git a/src/net/interface_test.go b/src/net/interface_test.go
index fbf15de4d3..15c0cd7be4 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -38,8 +38,7 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
return ""
}
for _, ifa := range ifat {
- switch ifa := ifa.(type) {
- case *IPNet:
+ if ifa, ok := ifa.(*IPNet); ok {
if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
return ifa.IP.String()
}
@@ -49,10 +48,6 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
}
func TestInterfaces(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("temporarily disabled until golang.org/issue/5395 is fixed")
- }
-
ift, err := Interfaces()
if err != nil {
t.Fatal(err)
@@ -110,10 +105,6 @@ func TestInterfaces(t *testing.T) {
}
func TestInterfaceAddrs(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("temporarily disabled until golang.org/issue/5395 is fixed")
- }
-
ift, err := Interfaces()
if err != nil {
t.Fatal(err)
diff --git a/src/net/interface_windows.go b/src/net/interface_windows.go
index 0759dc255d..438dc874d6 100644
--- a/src/net/interface_windows.go
+++ b/src/net/interface_windows.go
@@ -5,123 +5,139 @@
package net
import (
+ "internal/syscall/windows"
"os"
"syscall"
"unsafe"
)
-func bytePtrToString(p *uint8) string {
- a := (*[10000]uint8)(unsafe.Pointer(p))
- i := 0
- for a[i] != 0 {
- i++
- }
- return string(a[:i])
-}
+func getAdapters() (*windows.IpAdapterAddresses, error) {
+ block := uint32(unsafe.Sizeof(windows.IpAdapterAddresses{}))
-func getAdapterList() (*syscall.IpAdapterInfo, error) {
- b := make([]byte, 1000)
- l := uint32(len(b))
- a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
- // TODO(mikio): GetAdaptersInfo returns IP_ADAPTER_INFO that
- // contains IPv4 address list only. We should use another API
- // for fetching IPv6 stuff from the kernel.
- err := syscall.GetAdaptersInfo(a, &l)
- if err == syscall.ERROR_BUFFER_OVERFLOW {
- b = make([]byte, l)
- a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
- err = syscall.GetAdaptersInfo(a, &l)
- }
- if err != nil {
- return nil, os.NewSyscallError("GetAdaptersInfo", err)
+ // pre-allocate a 15KB working buffer pointed to by the AdapterAddresses
+ // parameter.
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
+ size := uint32(15000)
+
+ var addrs []windows.IpAdapterAddresses
+ for {
+ addrs = make([]windows.IpAdapterAddresses, size/block+1)
+ err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, &addrs[0], &size)
+ if err == nil {
+ break
+ }
+ if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
+ return nil, os.NewSyscallError("GetAdaptersAddresses", err)
+ }
}
- return a, nil
+ return &addrs[0], nil
}
-func getInterfaceList() ([]syscall.InterfaceInfo, error) {
+func getInterfaceInfos() ([]syscall.InterfaceInfo, error) {
s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
if err != nil {
return nil, os.NewSyscallError("Socket", err)
}
defer syscall.Closesocket(s)
- ii := [20]syscall.InterfaceInfo{}
+ iia := [20]syscall.InterfaceInfo{}
ret := uint32(0)
- size := uint32(unsafe.Sizeof(ii))
- err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
+ size := uint32(unsafe.Sizeof(iia))
+ err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&iia[0])), size, &ret, nil, 0)
if err != nil {
return nil, os.NewSyscallError("WSAIoctl", err)
}
- c := ret / uint32(unsafe.Sizeof(ii[0]))
- return ii[:c-1], nil
+ iilen := ret / uint32(unsafe.Sizeof(iia[0]))
+ return iia[:iilen-1], nil
+}
+
+func bytesEqualIP(a []byte, b []int8) bool {
+ for i := 0; i < len(a); i++ {
+ if a[i] != byte(b[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+func findInterfaceInfo(iis []syscall.InterfaceInfo, paddr *windows.IpAdapterAddresses) *syscall.InterfaceInfo {
+ for _, ii := range iis {
+ iaddr := (*syscall.RawSockaddr)(unsafe.Pointer(&ii.Address))
+ puni := paddr.FirstUnicastAddress
+ for ; puni != nil; puni = puni.Next {
+ if iaddr.Family == puni.Address.Sockaddr.Addr.Family {
+ switch iaddr.Family {
+ case syscall.AF_INET:
+ a := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
+ if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) {
+ return &ii
+ }
+ case syscall.AF_INET6:
+ a := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&ii.Address)).Addr
+ if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) {
+ return &ii
+ }
+ default:
+ continue
+ }
+ }
+ }
+ }
+ return nil
}
// If the ifindex is zero, interfaceTable returns mappings of all
// network interfaces. Otherwise it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
- ai, err := getAdapterList()
+ paddr, err := getAdapters()
if err != nil {
return nil, err
}
- ii, err := getInterfaceList()
+ iis, err := getInterfaceInfos()
if err != nil {
return nil, err
}
var ift []Interface
- for ; ai != nil; ai = ai.Next {
- index := ai.Index
+ for ; paddr != nil; paddr = paddr.Next {
+ index := paddr.IfIndex
+ if paddr.Ipv6IfIndex != 0 {
+ index = paddr.Ipv6IfIndex
+ }
if ifindex == 0 || ifindex == int(index) {
+ ii := findInterfaceInfo(iis, paddr)
+ if ii == nil {
+ continue
+ }
var flags Flags
-
- row := syscall.MibIfRow{Index: index}
- e := syscall.GetIfEntry(&row)
- if e != nil {
- return nil, os.NewSyscallError("GetIfEntry", e)
+ if paddr.Flags&windows.IfOperStatusUp != 0 {
+ flags |= FlagUp
}
-
- for _, ii := range ii {
- ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
- ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3])
- ipl := &ai.IpAddressList
- for ipl != nil {
- ips := bytePtrToString(&ipl.IpAddress.String[0])
- if ipv4.Equal(parseIPv4(ips)) {
- break
- }
- ipl = ipl.Next
- }
- if ipl == nil {
- continue
- }
- if ii.Flags&syscall.IFF_UP != 0 {
- flags |= FlagUp
- }
- if ii.Flags&syscall.IFF_LOOPBACK != 0 {
- flags |= FlagLoopback
- }
- if ii.Flags&syscall.IFF_BROADCAST != 0 {
- flags |= FlagBroadcast
- }
- if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
- flags |= FlagPointToPoint
- }
- if ii.Flags&syscall.IFF_MULTICAST != 0 {
- flags |= FlagMulticast
- }
+ if paddr.IfType&windows.IF_TYPE_SOFTWARE_LOOPBACK != 0 {
+ flags |= FlagLoopback
+ }
+ if ii.Flags&syscall.IFF_BROADCAST != 0 {
+ flags |= FlagBroadcast
+ }
+ if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
+ flags |= FlagPointToPoint
+ }
+ if ii.Flags&syscall.IFF_MULTICAST != 0 {
+ flags |= FlagMulticast
}
-
- name := bytePtrToString(&ai.AdapterName[0])
-
ifi := Interface{
Index: int(index),
- MTU: int(row.Mtu),
- Name: name,
- HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]),
- Flags: flags}
+ MTU: int(paddr.Mtu),
+ Name: syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(paddr.FriendlyName)))[:]),
+ HardwareAddr: HardwareAddr(paddr.PhysicalAddress[:]),
+ Flags: flags,
+ }
ift = append(ift, ifi)
+ if ifindex == int(ifi.Index) {
+ break
+ }
}
}
return ift, nil
@@ -131,28 +147,86 @@ func interfaceTable(ifindex int) ([]Interface, error) {
// network interfaces. Otherwise it returns addresses for a specific
// interface.
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
- ai, err := getAdapterList()
+ paddr, err := getAdapters()
if err != nil {
return nil, err
}
var ifat []Addr
- for ; ai != nil; ai = ai.Next {
- index := ai.Index
+ for ; paddr != nil; paddr = paddr.Next {
+ index := paddr.IfIndex
+ if paddr.Ipv6IfIndex != 0 {
+ index = paddr.Ipv6IfIndex
+ }
if ifi == nil || ifi.Index == int(index) {
- ipl := &ai.IpAddressList
- for ; ipl != nil; ipl = ipl.Next {
- ifa := IPAddr{IP: parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))}
- ifat = append(ifat, ifa.toAddr())
+ puni := paddr.FirstUnicastAddress
+ for ; puni != nil; puni = puni.Next {
+ if sa, err := puni.Address.Sockaddr.Sockaddr(); err == nil {
+ switch sav := sa.(type) {
+ case *syscall.SockaddrInet4:
+ ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv4len)}
+ copy(ifa.IP, sav.Addr[:])
+ ifat = append(ifat, ifa)
+ case *syscall.SockaddrInet6:
+ ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv6len)}
+ copy(ifa.IP, sav.Addr[:])
+ ifat = append(ifat, ifa)
+ }
+ }
+ }
+ pany := paddr.FirstAnycastAddress
+ for ; pany != nil; pany = pany.Next {
+ if sa, err := pany.Address.Sockaddr.Sockaddr(); err == nil {
+ switch sav := sa.(type) {
+ case *syscall.SockaddrInet4:
+ ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv4len)}
+ copy(ifa.IP, sav.Addr[:])
+ ifat = append(ifat, ifa)
+ case *syscall.SockaddrInet6:
+ ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv6len)}
+ copy(ifa.IP, sav.Addr[:])
+ ifat = append(ifat, ifa)
+ }
+ }
}
}
}
+
return ifat, nil
}
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
- // TODO(mikio): Implement this like other platforms.
- return nil, nil
+ paddr, err := getAdapters()
+ if err != nil {
+ return nil, err
+ }
+
+ var ifat []Addr
+ for ; paddr != nil; paddr = paddr.Next {
+ index := paddr.IfIndex
+ if paddr.Ipv6IfIndex != 0 {
+ index = paddr.Ipv6IfIndex
+ }
+ if ifi == nil || ifi.Index == int(index) {
+ pmul := paddr.FirstMulticastAddress
+ for ; pmul != nil; pmul = pmul.Next {
+ if sa, err := pmul.Address.Sockaddr.Sockaddr(); err == nil {
+ switch sav := sa.(type) {
+ case *syscall.SockaddrInet4:
+ ifa := &IPAddr{IP: make(IP, IPv4len)}
+ copy(ifa.IP, sav.Addr[:])
+ ifat = append(ifat, ifa.toAddr())
+ case *syscall.SockaddrInet6:
+ ifa := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifa.IP, sav.Addr[:])
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+ }
+ }
+ }
+
+ return ifat, nil
}
diff --git a/src/net/net.go b/src/net/net.go
index c850d2b1fd..339c972906 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -135,6 +135,8 @@ func (c *conn) Close() error {
}
// LocalAddr returns the local network address.
+// The Addr returned is shared by all invocations of LocalAddr, so
+// do not modify it.
func (c *conn) LocalAddr() Addr {
if !c.ok() {
return nil
@@ -143,6 +145,8 @@ func (c *conn) LocalAddr() Addr {
}
// RemoteAddr returns the remote network address.
+// The Addr returned is shared by all invocations of RemoteAddr, so
+// do not modify it.
func (c *conn) RemoteAddr() Addr {
if !c.ok() {
return nil
diff --git a/src/net/smtp/example_test.go b/src/net/smtp/example_test.go
index d551e365a9..16419f4276 100644
--- a/src/net/smtp/example_test.go
+++ b/src/net/smtp/example_test.go
@@ -46,14 +46,36 @@ func Example() {
}
}
+// variables to make ExamplePlainAuth compile, without adding
+// unnecessary noise there.
+var (
+ from = "gopher@example.net"
+ msg = []byte("dummy message")
+ recipients = []string{"foo@example.com"}
+)
+
func ExamplePlainAuth() {
+ // hostname is used by PlainAuth to validate the TLS certificate.
+ hostname := "mail.example.com"
+ auth := smtp.PlainAuth("", "user@example.com", "password", hostname)
+
+ err := smtp.SendMail(hostname+":25", auth, from, recipients, msg)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func ExampleSendMail() {
// Set up authentication information.
auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com")
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
to := []string{"recipient@example.net"}
- msg := []byte("This is the email body.")
+ msg := []byte("To: recipient@example.net\r\n" +
+ "Subject: discount Gophers!\r\n" +
+ "\r\n" +
+ "This is the email body.\r\n")
err := smtp.SendMail("mail.example.com:25", auth, "sender@example.org", to, msg)
if err != nil {
log.Fatal(err)
diff --git a/src/net/smtp/smtp.go b/src/net/smtp/smtp.go
index c9b3c07aa8..81f3c0bd62 100644
--- a/src/net/smtp/smtp.go
+++ b/src/net/smtp/smtp.go
@@ -264,9 +264,9 @@ func (d *dataCloser) Close() error {
}
// Data issues a DATA command to the server and returns a writer that
-// can be used to write the data. The caller should close the writer
-// before calling any more methods on c.
-// A call to Data must be preceded by one or more calls to Rcpt.
+// can be used to write the mail headers and body. The caller should
+// close the writer before calling any more methods on c. A call to
+// Data must be preceded by one or more calls to Rcpt.
func (c *Client) Data() (io.WriteCloser, error) {
_, _, err := c.cmd(354, "DATA")
if err != nil {
@@ -281,6 +281,21 @@ var testHookStartTLS func(*tls.Config) // nil, except for tests
// possible, authenticates with the optional mechanism a if possible,
// and then sends an email from address from, to addresses to, with
// message msg.
+//
+// The addresses in the to parameter are the SMTP RCPT addresses.
+//
+// The msg parameter should be an RFC 822-style email with headers
+// first, a blank line, and then the message body. The lines of msg
+// should be CRLF terminated. The msg headers should usually include
+// fields such as "From", "To", "Subject", and "Cc". Sending "Bcc"
+// messages is accomplished by including an email address in the to
+// parameter but not including it in the msg headers.
+//
+// The SendMail function and the the net/smtp package are low-level
+// mechanisms and provide no support for DKIM signing, MIME
+// attachments (see the mime/multipart package), or other mail
+// functionality. Higher-level packages exist outside of the standard
+// library.
func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {
c, err := Dial(addr)
if err != nil {
diff --git a/src/net/tcpsock_plan9.go b/src/net/tcpsock_plan9.go
index 52019d7b4e..ae2194277d 100644
--- a/src/net/tcpsock_plan9.go
+++ b/src/net/tcpsock_plan9.go
@@ -157,6 +157,8 @@ func (l *TCPListener) Close() error {
}
// Addr returns the listener's network address, a *TCPAddr.
+// The Addr returned is shared by all invocations of Addr, so
+// do not modify it.
func (l *TCPListener) Addr() Addr { return l.fd.laddr }
// SetDeadline sets the deadline associated with the listener.
diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go
index dd78aefa77..aaff0acaa6 100644
--- a/src/net/tcpsock_posix.go
+++ b/src/net/tcpsock_posix.go
@@ -258,6 +258,8 @@ func (l *TCPListener) Close() error {
}
// Addr returns the listener's network address, a *TCPAddr.
+// The Addr returned is shared by all invocations of Addr, so
+// do not modify it.
func (l *TCPListener) Addr() Addr { return l.fd.laddr }
// SetDeadline sets the deadline associated with the listener.
diff --git a/src/net/udp_test.go b/src/net/udp_test.go
index 125bbca6c4..2be2c319a7 100644
--- a/src/net/udp_test.go
+++ b/src/net/udp_test.go
@@ -81,26 +81,26 @@ func TestWriteToUDP(t *testing.T) {
t.Skipf("skipping test on %q", runtime.GOOS)
}
- l, err := ListenPacket("udp", "127.0.0.1:0")
+ c, err := ListenPacket("udp", "127.0.0.1:0")
if err != nil {
- t.Fatalf("Listen failed: %v", err)
+ t.Fatal(err)
}
- defer l.Close()
+ defer c.Close()
- testWriteToConn(t, l.LocalAddr().String())
- testWriteToPacketConn(t, l.LocalAddr().String())
+ testWriteToConn(t, c.LocalAddr().String())
+ testWriteToPacketConn(t, c.LocalAddr().String())
}
func testWriteToConn(t *testing.T, raddr string) {
c, err := Dial("udp", raddr)
if err != nil {
- t.Fatalf("Dial failed: %v", err)
+ t.Fatal(err)
}
defer c.Close()
ra, err := ResolveUDPAddr("udp", raddr)
if err != nil {
- t.Fatalf("ResolveUDPAddr failed: %v", err)
+ t.Fatal(err)
}
_, err = c.(*UDPConn).WriteToUDP([]byte("Connection-oriented mode socket"), ra)
@@ -121,36 +121,70 @@ func testWriteToConn(t *testing.T, raddr string) {
_, err = c.Write([]byte("Connection-oriented mode socket"))
if err != nil {
- t.Fatalf("Write failed: %v", err)
+ t.Fatal(err)
+ }
+
+ _, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-oriented mode socket"), nil, ra)
+ if err == nil {
+ t.Fatal("WriteMsgUDP should fail")
+ }
+ if err != nil && err.(*OpError).Err != ErrWriteToConnected {
+ t.Fatalf("WriteMsgUDP should fail as ErrWriteToConnected: %v", err)
+ }
+ _, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-oriented mode socket"), nil, nil)
+ switch runtime.GOOS {
+ case "nacl", "windows": // see golang.org/issue/9252
+ t.Skipf("not implemented yet on %s", runtime.GOOS)
+ default:
+ if err != nil {
+ t.Fatal(err)
+ }
}
}
func testWriteToPacketConn(t *testing.T, raddr string) {
c, err := ListenPacket("udp", "127.0.0.1:0")
if err != nil {
- t.Fatalf("ListenPacket failed: %v", err)
+ t.Fatal(err)
}
defer c.Close()
ra, err := ResolveUDPAddr("udp", raddr)
if err != nil {
- t.Fatalf("ResolveUDPAddr failed: %v", err)
+ t.Fatal(err)
}
_, err = c.(*UDPConn).WriteToUDP([]byte("Connection-less mode socket"), ra)
if err != nil {
- t.Fatalf("WriteToUDP failed: %v", err)
+ t.Fatal(err)
}
_, err = c.WriteTo([]byte("Connection-less mode socket"), ra)
if err != nil {
- t.Fatalf("WriteTo failed: %v", err)
+ t.Fatal(err)
}
_, err = c.(*UDPConn).Write([]byte("Connection-less mode socket"))
if err == nil {
t.Fatal("Write should fail")
}
+
+ _, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-less mode socket"), nil, nil)
+ if err == nil {
+ t.Fatal("WriteMsgUDP should fail")
+ }
+ if err != nil && err.(*OpError).Err != errMissingAddress {
+ t.Fatalf("WriteMsgUDP should fail as errMissingAddress: %v", err)
+ }
+ _, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-less mode socket"), nil, ra)
+ switch runtime.GOOS {
+ case "nacl", "windows": // see golang.org/issue/9252
+ t.Skipf("not implemented yet on %s", runtime.GOOS)
+ default:
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
}
var udpConnLocalNameTests = []struct {
diff --git a/src/net/udpsock_plan9.go b/src/net/udpsock_plan9.go
index 510ac5e4aa..269272632a 100644
--- a/src/net/udpsock_plan9.go
+++ b/src/net/udpsock_plan9.go
@@ -101,9 +101,11 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
return c.WriteToUDP(b, a)
}
-// WriteMsgUDP writes a packet to addr via c, copying the payload from
-// b and the associated out-of-band data from oob. It returns the
-// number of payload and out-of-band bytes written.
+// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
+// to c's remote destination address if c is connected (in which case
+// addr must be nil). The payload is copied from b and the associated
+// out-of-band data is copied from oob. It returns the number of
+// payload and out-of-band bytes written.
func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
return 0, 0, syscall.EPLAN9
}
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index a0533366a4..0770b7c5ce 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -139,17 +139,19 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
return c.WriteToUDP(b, a)
}
-// WriteMsgUDP writes a packet to addr via c, copying the payload from
-// b and the associated out-of-band data from oob. It returns the
-// number of payload and out-of-band bytes written.
+// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
+// to c's remote destination address if c is connected (in which case
+// addr must be nil). The payload is copied from b and the associated
+// out-of-band data is copied from oob. It returns the number of
+// payload and out-of-band bytes written.
func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
if !c.ok() {
return 0, 0, syscall.EINVAL
}
- if c.fd.isConnected {
+ if c.fd.isConnected && addr != nil {
return 0, 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
}
- if addr == nil {
+ if !c.fd.isConnected && addr == nil {
return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
}
sa, err := addr.sockaddr(c.fd.family)
diff --git a/src/net/unixsock_plan9.go b/src/net/unixsock_plan9.go
index c60c1d83bb..64a511d648 100644
--- a/src/net/unixsock_plan9.go
+++ b/src/net/unixsock_plan9.go
@@ -115,6 +115,8 @@ func (l *UnixListener) Close() error {
}
// Addr returns the listener's network address.
+// The Addr returned is shared by all invocations of Addr, so
+// do not modify it.
func (l *UnixListener) Addr() Addr { return nil }
// SetDeadline sets the deadline associated with the listener.
diff --git a/src/net/unixsock_posix.go b/src/net/unixsock_posix.go
index 3c2e78bdca..d7127d9c69 100644
--- a/src/net/unixsock_posix.go
+++ b/src/net/unixsock_posix.go
@@ -321,6 +321,8 @@ func (l *UnixListener) Close() error {
}
// Addr returns the listener's network address.
+// The Addr returned is shared by all invocations of Addr, so
+// do not modify it.
func (l *UnixListener) Addr() Addr { return l.fd.laddr }
// SetDeadline sets the deadline associated with the listener.
diff --git a/src/os/os_test.go b/src/os/os_test.go
index a30a2b0313..5285b76024 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -21,7 +21,6 @@ import (
"sync"
"syscall"
"testing"
- "text/template"
"time"
)
@@ -491,6 +490,30 @@ func TestReaddirStatFailures(t *testing.T) {
}
}
+// Readdir on a regular file should fail.
+func TestReaddirOfFile(t *testing.T) {
+ f, err := ioutil.TempFile("", "_Go_ReaddirOfFile")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer Remove(f.Name())
+ f.Write([]byte("foo"))
+ f.Close()
+ reg, err := Open(f.Name())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer reg.Close()
+
+ names, err := reg.Readdirnames(-1)
+ if err == nil {
+ t.Error("Readdirnames succeeded; want non-nil error")
+ }
+ if len(names) > 0 {
+ t.Errorf("unexpected dir names in regular file: %q", names)
+ }
+}
+
func TestHardLink(t *testing.T) {
// Hardlinks are not supported under windows or Plan 9.
if runtime.GOOS == "plan9" {
@@ -922,7 +945,7 @@ func TestSeek(t *testing.T) {
if off != tt.out || err != nil {
if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 {
// Reiserfs rejects the big seeks.
- // http://code.google.com/p/go/issues/detail?id=91
+ // http://golang.org/issue/91
break
}
t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
@@ -1304,39 +1327,9 @@ func testKillProcess(t *testing.T, processKiller func(p *Process)) {
t.Skipf("skipping on %s", runtime.GOOS)
}
- dir, err := ioutil.TempDir("", "go-build")
- if err != nil {
- t.Fatalf("Failed to create temp directory: %v", err)
- }
- defer RemoveAll(dir)
-
- src := filepath.Join(dir, "main.go")
- f, err := Create(src)
- if err != nil {
- t.Fatalf("Failed to create %v: %v", src, err)
- }
- st := template.Must(template.New("source").Parse(`
-package main
-import "time"
-func main() {
- time.Sleep(time.Second)
-}
-`))
- err = st.Execute(f, nil)
- if err != nil {
- f.Close()
- t.Fatalf("Failed to execute template: %v", err)
- }
- f.Close()
-
- exe := filepath.Join(dir, "main.exe")
- output, err := osexec.Command("go", "build", "-o", exe, src).CombinedOutput()
- if err != nil {
- t.Fatalf("Failed to build exe %v: %v %v", exe, err, string(output))
- }
-
- cmd := osexec.Command(exe)
- err = cmd.Start()
+ // Re-exec the test binary itself to emulate "sleep 1".
+ cmd := osexec.Command(Args[0], "-test.run", "TestSleep")
+ err := cmd.Start()
if err != nil {
t.Fatalf("Failed to start test process: %v", err)
}
@@ -1350,6 +1343,15 @@ func main() {
}
}
+// TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we
+// don't have to rely on an external "sleep" command being available.
+func TestSleep(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skipping in short mode")
+ }
+ time.Sleep(time.Second)
+}
+
func TestKillStartProcess(t *testing.T) {
testKillProcess(t, func(p *Process) {
err := p.Kill()
diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go
index fd96713eac..3ea0fc7f4f 100644
--- a/src/os/os_windows_test.go
+++ b/src/os/os_windows_test.go
@@ -3,11 +3,15 @@ package os_test
import (
"io/ioutil"
"os"
+ osexec "os/exec"
"path/filepath"
+ "strings"
"syscall"
"testing"
)
+var supportJunctionLinks = true
+
func init() {
tmpdir, err := ioutil.TempDir("", "symtest")
if err != nil {
@@ -16,14 +20,18 @@ func init() {
defer os.RemoveAll(tmpdir)
err = os.Symlink("target", filepath.Join(tmpdir, "symlink"))
- if err == nil {
- return
+ if err != nil {
+ err = err.(*os.LinkError).Err
+ switch err {
+ case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
+ supportsSymlinks = false
+ }
}
+ defer os.Remove("target")
- err = err.(*os.LinkError).Err
- switch err {
- case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
- supportsSymlinks = false
+ b, _ := osexec.Command("cmd", "/c", "mklink", "/?").Output()
+ if !strings.Contains(string(b), " /J ") {
+ supportJunctionLinks = false
}
}
@@ -79,3 +87,33 @@ func TestSameWindowsFile(t *testing.T) {
t.Errorf("files should be same")
}
}
+
+func TestStatJunctionLink(t *testing.T) {
+ if !supportJunctionLinks {
+ t.Skip("skipping because junction links are not supported")
+ }
+
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatalf("failed to create temp directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ link := filepath.Join(filepath.Dir(dir), filepath.Base(dir)+"-link")
+
+ output, err := osexec.Command("cmd", "/c", "mklink", "/J", link, dir).CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to run mklink %v %v: %v %q", link, dir, err, output)
+ }
+ defer os.Remove(link)
+
+ fi, err := os.Stat(link)
+ if err != nil {
+ t.Fatalf("failed to stat link %v: %v", link, err)
+ }
+ expected := filepath.Base(dir)
+ got := fi.Name()
+ if !fi.IsDir() || expected != got {
+ t.Fatalf("link should point to %v but points to %v instead", expected, got)
+ }
+}
diff --git a/src/os/signal/signal.go b/src/os/signal/signal.go
index 3004275495..81906d6f40 100644
--- a/src/os/signal/signal.go
+++ b/src/os/signal/signal.go
@@ -5,8 +5,6 @@
// Package signal implements access to incoming signals.
package signal
-// BUG(rsc): This package is not yet implemented on Plan 9.
-
import (
"os"
"sync"
diff --git a/src/os/signal/signal_plan9.go b/src/os/signal/signal_plan9.go
new file mode 100644
index 0000000000..45355da48a
--- /dev/null
+++ b/src/os/signal/signal_plan9.go
@@ -0,0 +1,55 @@
+// Copyright 2012 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 signal
+
+import (
+ "os"
+ "syscall"
+)
+
+var sigtab = make(map[os.Signal]int)
+
+// In sig.s; jumps to runtime.
+func signal_disable(uint32)
+func signal_enable(uint32)
+func signal_recv() string
+
+func init() {
+ signal_enable(0) // first call - initialize
+ go loop()
+}
+
+func loop() {
+ for {
+ process(syscall.Note(signal_recv()))
+ }
+}
+
+const numSig = 256
+
+func signum(sig os.Signal) int {
+ switch sig := sig.(type) {
+ case syscall.Note:
+ n, ok := sigtab[sig]
+ if !ok {
+ n = len(sigtab) + 1
+ if n > numSig {
+ return -1
+ }
+ sigtab[sig] = n
+ }
+ return n
+ default:
+ return -1
+ }
+}
+
+func enableSignal(sig int) {
+ signal_enable(uint32(sig))
+}
+
+func disableSignal(sig int) {
+ signal_disable(uint32(sig))
+}
diff --git a/src/os/signal/signal_plan9_test.go b/src/os/signal/signal_plan9_test.go
new file mode 100644
index 0000000000..10bfdc3ff1
--- /dev/null
+++ b/src/os/signal/signal_plan9_test.go
@@ -0,0 +1,181 @@
+// 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.
+
+package signal
+
+import (
+ "os"
+ "runtime"
+ "syscall"
+ "testing"
+ "time"
+)
+
+func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
+ select {
+ case s := <-c:
+ if s != sig {
+ t.Fatalf("signal was %v, want %v", s, sig)
+ }
+ case <-time.After(1 * time.Second):
+ t.Fatalf("timeout waiting for %v", sig)
+ }
+}
+
+// Test that basic signal handling works.
+func TestSignal(t *testing.T) {
+ // Ask for hangup
+ c := make(chan os.Signal, 1)
+ Notify(c, syscall.Note("hangup"))
+ defer Stop(c)
+
+ // Send this process a hangup
+ t.Logf("hangup...")
+ postNote(syscall.Getpid(), "hangup")
+ waitSig(t, c, syscall.Note("hangup"))
+
+ // Ask for everything we can get.
+ c1 := make(chan os.Signal, 1)
+ Notify(c1)
+
+ // Send this process an alarm
+ t.Logf("alarm...")
+ postNote(syscall.Getpid(), "alarm")
+ waitSig(t, c1, syscall.Note("alarm"))
+
+ // Send two more hangups, to make sure that
+ // they get delivered on c1 and that not reading
+ // from c does not block everything.
+ t.Logf("hangup...")
+ postNote(syscall.Getpid(), "hangup")
+ waitSig(t, c1, syscall.Note("hangup"))
+ t.Logf("hangup...")
+ postNote(syscall.Getpid(), "hangup")
+ waitSig(t, c1, syscall.Note("hangup"))
+
+ // The first SIGHUP should be waiting for us on c.
+ waitSig(t, c, syscall.Note("hangup"))
+}
+
+func TestStress(t *testing.T) {
+ dur := 3 * time.Second
+ if testing.Short() {
+ dur = 100 * time.Millisecond
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+ done := make(chan bool)
+ finished := make(chan bool)
+ go func() {
+ sig := make(chan os.Signal, 1)
+ Notify(sig, syscall.Note("alarm"))
+ defer Stop(sig)
+ Loop:
+ for {
+ select {
+ case <-sig:
+ case <-done:
+ break Loop
+ }
+ }
+ finished <- true
+ }()
+ go func() {
+ Loop:
+ for {
+ select {
+ case <-done:
+ break Loop
+ default:
+ postNote(syscall.Getpid(), "alarm")
+ runtime.Gosched()
+ }
+ }
+ finished <- true
+ }()
+ time.Sleep(dur)
+ close(done)
+ <-finished
+ <-finished
+ // When run with 'go test -cpu=1,2,4' alarm from this test can slip
+ // into subsequent TestSignal() causing failure.
+ // Sleep for a while to reduce the possibility of the failure.
+ time.Sleep(10 * time.Millisecond)
+}
+
+// Test that Stop cancels the channel's registrations.
+func TestStop(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ sigs := []string{
+ "alarm",
+ "hangup",
+ }
+
+ for _, sig := range sigs {
+ // Send the signal.
+ // If it's alarm, we should not see it.
+ // If it's hangup, maybe we'll die. Let the flag tell us what to do.
+ if sig != "hangup" {
+ postNote(syscall.Getpid(), sig)
+ }
+ time.Sleep(100 * time.Millisecond)
+
+ // Ask for signal
+ c := make(chan os.Signal, 1)
+ Notify(c, syscall.Note(sig))
+ defer Stop(c)
+
+ // Send this process that signal
+ postNote(syscall.Getpid(), sig)
+ waitSig(t, c, syscall.Note(sig))
+
+ Stop(c)
+ select {
+ case s := <-c:
+ t.Fatalf("unexpected signal %v", s)
+ case <-time.After(100 * time.Millisecond):
+ // nothing to read - good
+ }
+
+ // Send the signal.
+ // If it's alarm, we should not see it.
+ // If it's hangup, maybe we'll die. Let the flag tell us what to do.
+ if sig != "hangup" {
+ postNote(syscall.Getpid(), sig)
+ }
+
+ select {
+ case s := <-c:
+ t.Fatalf("unexpected signal %v", s)
+ case <-time.After(100 * time.Millisecond):
+ // nothing to read - good
+ }
+ }
+}
+
+func itoa(val int) string {
+ if val < 0 {
+ return "-" + itoa(-val)
+ }
+ var buf [32]byte // big enough for int64
+ i := len(buf) - 1
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ return string(buf[i:])
+}
+
+func postNote(pid int, note string) error {
+ f, err := os.OpenFile("/proc/"+itoa(pid)+"/note", os.O_WRONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ _, err = f.Write([]byte(note))
+ return err
+}
diff --git a/src/os/signal/signal_stub.go b/src/os/signal/signal_stub.go
deleted file mode 100644
index d0a6935ff2..0000000000
--- a/src/os/signal/signal_stub.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2012 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.
-
-// +build plan9
-
-package signal
-
-import "os"
-
-const numSig = 0
-
-func signum(sig os.Signal) int { return -1 }
-
-func disableSignal(int) {}
-
-func enableSignal(int) {}
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index c4f74b97ff..293d316124 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -1008,7 +1008,7 @@ func TestDriveLetterInEvalSymlinks(t *testing.T) {
}
}
-func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486
+func TestBug3486(t *testing.T) { // http://golang.org/issue/3486
root, err := filepath.EvalSymlinks(runtime.GOROOT() + "/test")
if err != nil {
t.Fatal(err)
diff --git a/src/race.bat b/src/race.bat
index 8858c57b06..027c475640 100644
--- a/src/race.bat
+++ b/src/race.bat
@@ -18,7 +18,7 @@ goto end
set GOROOT=%CD%\..
call make.bat --dist-tool >NUL
if errorlevel 1 goto fail
-.\cmd\dist\dist env -wp >env.bat
+.\cmd\dist\dist env -w -p >env.bat
if errorlevel 1 goto fail
call env.bat
del env.bat
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 7d40f9a8b6..2be32f31b4 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -2735,6 +2735,8 @@ var tagGetTests = []struct {
{`protobuf:"PB(1,2)"`, `rotobuf`, ``},
{`protobuf:"PB(1,2)" json:"name"`, `json`, `name`},
{`protobuf:"PB(1,2)" json:"name"`, `protobuf`, `PB(1,2)`},
+ {`k0:"values contain spaces" k1:"and\ttabs"`, "k0", "values contain spaces"},
+ {`k0:"values contain spaces" k1:"and\ttabs"`, "k1", "and\ttabs"},
}
func TestTagGet(t *testing.T) {
diff --git a/src/reflect/type.go b/src/reflect/type.go
index ae7d165a68..0a8c40808a 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -762,8 +762,11 @@ type StructTag string
// If the tag does not have the conventional format, the value
// returned by Get is unspecified.
func (tag StructTag) Get(key string) string {
+ // When modifying this code, also update the validateStructTag code
+ // in golang.org/x/tools/cmd/vet/structtag.go.
+
for tag != "" {
- // skip leading space
+ // Skip leading space.
i := 0
for i < len(tag) && tag[i] == ' ' {
i++
@@ -773,19 +776,21 @@ func (tag StructTag) Get(key string) string {
break
}
- // scan to colon.
- // a space or a quote is a syntax error
+ // Scan to colon. A space, a quote or a control character is a syntax error.
+ // Strictly speaking, control chars include the range [0x7f, 0x9f], not just
+ // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
+ // as it is simpler to inspect the tag's bytes than the tag's runes.
i = 0
- for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' {
+ for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
i++
}
- if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
+ if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
break
}
name := string(tag[:i])
tag = tag[i+1:]
- // scan quoted string to find value
+ // Scan quoted string to find value.
i = 1
for i < len(tag) && tag[i] != '"' {
if tag[i] == '\\' {
@@ -800,7 +805,10 @@ func (tag StructTag) Get(key string) string {
tag = tag[i+1:]
if key == name {
- value, _ := strconv.Unquote(qvalue)
+ value, err := strconv.Unquote(qvalue)
+ if err != nil {
+ break
+ }
return value
}
}
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 4060206eac..081c4d9d7b 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -2439,12 +2439,27 @@ func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
func makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
func makemap(t *rtype) (m unsafe.Pointer)
+
+//go:noescape
func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
+
func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
+
+//go:noescape
func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer)
+
+// m escapes into the return value, but the caller of mapiterinit
+// doesn't let the return value escape.
+//go:noescape
func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer
+
+//go:noescape
func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
+
+//go:noescape
func mapiternext(it unsafe.Pointer)
+
+//go:noescape
func maplen(m unsafe.Pointer) int
// call calls fn with a copy of the n argument bytes pointed at by arg.
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index 49bba32ebe..58a0d502bd 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -1298,26 +1298,22 @@ eq:
RET
// eqstring tests whether two strings are equal.
+// The compiler guarantees that strings passed
+// to eqstring have equal length.
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$0-17
- MOVL s1len+4(FP), AX
- MOVL s2len+12(FP), BX
- CMPL AX, BX
- JNE different
MOVL s1str+0(FP), SI
MOVL s2str+8(FP), DI
CMPL SI, DI
JEQ same
+ MOVL s1len+4(FP), BX
CALL runtime·memeqbody(SB)
MOVB AX, v+16(FP)
RET
same:
MOVB $1, v+16(FP)
RET
-different:
- MOVB $0, v+16(FP)
- RET
TEXT bytes·Equal(SB),NOSPLIT,$0-25
MOVL a_len+4(FP), BX
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index f09e5ae250..f6c1c5f6e6 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -1262,26 +1262,22 @@ eq:
RET
// eqstring tests whether two strings are equal.
+// The compiler guarantees that strings passed
+// to eqstring have equal length.
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
- MOVQ s1len+8(FP), AX
- MOVQ s2len+24(FP), BX
- CMPQ AX, BX
- JNE noteq
MOVQ s1str+0(FP), SI
MOVQ s2str+16(FP), DI
CMPQ SI, DI
JEQ eq
+ MOVQ s1len+8(FP), BX
CALL runtime·memeqbody(SB)
MOVB AX, v+32(FP)
RET
eq:
MOVB $1, v+32(FP)
RET
-noteq:
- MOVB $0, v+32(FP)
- RET
// a in SI
// b in DI
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index 77355bb998..f2324285a5 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -704,26 +704,22 @@ eq:
RET
// eqstring tests whether two strings are equal.
+// The compiler guarantees that strings passed
+// to eqstring have equal length.
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$0-17
- MOVL s1len+4(FP), AX
- MOVL s2len+12(FP), BX
- CMPL AX, BX
- JNE different
MOVL s1str+0(FP), SI
MOVL s2str+8(FP), DI
CMPL SI, DI
JEQ same
+ MOVL s1len+4(FP), BX
CALL runtime·memeqbody(SB)
MOVB AX, v+16(FP)
RET
same:
MOVB $1, v+16(FP)
RET
-different:
- MOVB $0, v+16(FP)
- RET
// a in SI
// b in DI
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index f3ce1a8f17..2efeaaa531 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -39,20 +39,8 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$-4
BL runtime·emptyfunc(SB) // fault if stack check is wrong
-#ifndef GOOS_nacl
- // if there is an _cgo_init, call it.
- MOVW _cgo_init(SB), R4
- CMP $0, R4
- B.EQ nocgo
- MRC 15, 0, R0, C13, C0, 3 // load TLS base pointer
- MOVW R0, R3 // arg 3: TLS base pointer
- MOVW $runtime·tlsg(SB), R2 // arg 2: tlsg
- MOVW $setg_gcc<>(SB), R1 // arg 1: setg
- MOVW g, R0 // arg 0: G
- BL (R4) // will clobber R0-R3
-#endif
+ BL runtime·_initcgo(SB) // will clobber R0-R3
-nocgo:
// update stackguard after _cgo_init
MOVW (g_stack+stack_lo)(g), R0
ADD $const__StackGuard, R0
@@ -806,21 +794,18 @@ eq:
RET
// eqstring tests whether two strings are equal.
+// The compiler guarantees that strings passed
+// to eqstring have equal length.
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$-4-17
- MOVW s1len+4(FP), R0
- MOVW s2len+12(FP), R1
- MOVW $0, R7
- CMP R0, R1
- MOVB.NE R7, v+16(FP)
- RET.NE
MOVW s1str+0(FP), R2
MOVW s2str+8(FP), R3
MOVW $1, R8
MOVB R8, v+16(FP)
CMP R2, R3
RET.EQ
+ MOVW s1len+4(FP), R0
ADD R2, R0, R6
loop:
CMP R2, R6
@@ -829,14 +814,10 @@ loop:
MOVBU.P 1(R3), R5
CMP R4, R5
BEQ loop
- MOVB R7, v+16(FP)
+ MOVW $0, R8
+ MOVB R8, v+16(FP)
RET
-// void setg_gcc(G*); set g called from gcc.
-TEXT setg_gcc<>(SB),NOSPLIT,$0
- MOVW R0, g
- B runtime·save_g(SB)
-
// TODO: share code with memeq?
TEXT bytes·Equal(SB),NOSPLIT,$0
MOVW a_len+4(FP), R1
diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s
index 660c7cdfe5..694dfcc24e 100644
--- a/src/runtime/asm_ppc64x.s
+++ b/src/runtime/asm_ppc64x.s
@@ -969,30 +969,30 @@ eq:
RETURN
// eqstring tests whether two strings are equal.
+// The compiler guarantees that strings passed
+// to eqstring have equal length.
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
- MOVD s1len+8(FP), R4
- MOVD s2len+24(FP), R5
- CMP R4, R5
- BNE noteq
-
MOVD s1str+0(FP), R3
MOVD s2str+16(FP), R4
+ MOVD $1, R5
+ MOVB R5, ret+32(FP)
+ CMP R3, R4
+ BNE 2(PC)
+ RETURN
+ MOVD s1len+8(FP), R5
SUB $1, R3
SUB $1, R4
ADD R3, R5, R8
loop:
CMP R3, R8
- BNE 4(PC)
- MOVD $1, R3
- MOVB R3, ret+32(FP)
+ BNE 2(PC)
RETURN
MOVBZU 1(R3), R6
MOVBZU 1(R4), R7
CMP R6, R7
BEQ loop
-noteq:
MOVB R0, ret+32(FP)
RETURN
diff --git a/src/runtime/cgo/cgo.go b/src/runtime/cgo/cgo.go
index 8528692f7b..9a41399cd6 100644
--- a/src/runtime/cgo/cgo.go
+++ b/src/runtime/cgo/cgo.go
@@ -11,7 +11,7 @@ package cgo
/*
-#cgo darwin LDFLAGS: -lpthread
+#cgo darwin,!arm LDFLAGS: -lpthread
#cgo dragonfly LDFLAGS: -lpthread
#cgo freebsd LDFLAGS: -lpthread
#cgo android LDFLAGS: -llog
diff --git a/src/runtime/cgo/gcc_arm.S b/src/runtime/cgo/gcc_arm.S
index d5833bfad0..980ab579e4 100644
--- a/src/runtime/cgo/gcc_arm.S
+++ b/src/runtime/cgo/gcc_arm.S
@@ -11,6 +11,10 @@
#define EXT(s) s
#endif
+// Apple's ld64 wants 4-byte alignment for ARM code sections.
+// .align in both Apple as and GNU as treat n as aligning to 2**n bytes.
+.align 2
+
/*
* void crosscall_arm1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
*
diff --git a/src/runtime/cgo/gcc_darwin_arm.c b/src/runtime/cgo/gcc_darwin_arm.c
new file mode 100644
index 0000000000..d56c55777d
--- /dev/null
+++ b/src/runtime/cgo/gcc_darwin_arm.c
@@ -0,0 +1,99 @@
+// Copyright 2014 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 <string.h> /* for strerror */
+#include <pthread.h>
+#include <signal.h>
+#include <limits.h>
+#include "libcgo.h"
+
+#define magic (0xe696c4f4U)
+
+// inittls allocates a thread-local storage slot for g.
+//
+// It finds the first available slot using pthread_key_create and uses
+// it as the offset value for runtime.tlsg.
+static void
+inittls(void **tlsg, void **tlsbase)
+{
+ pthread_key_t k;
+ int i, err;
+
+ err = pthread_key_create(&k, nil);
+ if(err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_key_create failed: %d\n", err);
+ abort();
+ }
+ //fprintf(stderr, "runtime/cgo: k = %d, tlsbase = %p\n", (int)k, tlsbase); // debug
+ pthread_setspecific(k, (void*)magic);
+ // The first key should be at 258.
+ for (i=0; i<PTHREAD_KEYS_MAX; i++) {
+ if (*(tlsbase+i) == (void*)magic) {
+ *tlsg = (void*)(i*sizeof(void *));
+ pthread_setspecific(k, 0);
+ return;
+ }
+ }
+ fprintf(stderr, "runtime/cgo: could not find pthread key.\n");
+ abort();
+}
+
+static void *threadentry(void*);
+void (*setg_gcc)(void*);
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ sigset_t ign, oset;
+ pthread_t p;
+ size_t size;
+ int err;
+
+ sigfillset(&ign);
+ pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+ pthread_attr_init(&attr);
+ size = 0;
+ pthread_attr_getstacksize(&attr, &size);
+ // Leave stacklo=0 and set stackhi=size; mstack will do the rest.
+ ts->g->stackhi = size;
+ err = pthread_create(&p, &attr, threadentry, ts);
+
+ pthread_sigmask(SIG_SETMASK, &oset, nil);
+
+ if (err != 0) {
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+ abort();
+ }
+}
+
+extern void crosscall_arm1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)v;
+ free(v);
+
+ crosscall_arm1(ts.fn, setg_gcc, (void*)ts.g);
+ return nil;
+}
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+ pthread_attr_t attr;
+ size_t size;
+
+ setg_gcc = setg;
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stacklo = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+
+ // yes, tlsbase from mrc might not be correctly aligned.
+ inittls(tlsg, (void**)((uintptr)tlsbase & ~3));
+}
diff --git a/src/runtime/compiler.go b/src/runtime/compiler.go
index 562a460226..f6edc95959 100644
--- a/src/runtime/compiler.go
+++ b/src/runtime/compiler.go
@@ -7,7 +7,7 @@ package runtime
// Compiler is the name of the compiler toolchain that built the
// running binary. Known toolchains are:
//
-// gc The 5g/6g/8g compiler suite at code.google.com/p/go.
+// gc The 5g/6g/8g compiler suite at go.googlesource.com/go.
// gccgo The gccgo front end, part of the GCC compiler suite.
//
const Compiler = "gc"
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index 43cea9008a..715b2da232 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -10,6 +10,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "regexp"
"runtime"
"strings"
"sync"
@@ -17,17 +18,20 @@ import (
"text/template"
)
-// testEnv excludes GODEBUG from the environment
-// to prevent its output from breaking tests that
-// are trying to parse other command output.
func testEnv(cmd *exec.Cmd) *exec.Cmd {
if cmd.Env != nil {
panic("environment already set")
}
for _, env := range os.Environ() {
+ // Exclude GODEBUG from the environment to prevent its output
+ // from breaking tests that are trying to parse other command output.
if strings.HasPrefix(env, "GODEBUG=") {
continue
}
+ // Exclude GOTRACEBACK for the same reason.
+ if strings.HasPrefix(env, "GOTRACEBACK=") {
+ continue
+ }
cmd.Env = append(cmd.Env, env)
}
return cmd
@@ -217,6 +221,14 @@ func TestMainGoroutineId(t *testing.T) {
}
}
+func TestNoHelperGoroutines(t *testing.T) {
+ output := executeTest(t, noHelperGoroutinesSource, nil)
+ matches := regexp.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output, -1)
+ if len(matches) != 1 || matches[0][0] != "goroutine 1 [" {
+ t.Fatalf("want to see only goroutine 1, see:\n%s", output)
+ }
+}
+
func TestBreakpoint(t *testing.T) {
output := executeTest(t, breakpointSource, nil)
want := "runtime.Breakpoint()"
@@ -431,6 +443,22 @@ func main() {
}
`
+const noHelperGoroutinesSource = `
+package main
+import (
+ "runtime"
+ "time"
+)
+func init() {
+ i := 0
+ runtime.SetFinalizer(&i, func(p *int) {})
+ time.AfterFunc(time.Hour, func() {})
+ panic("oops")
+}
+func main() {
+}
+`
+
const breakpointSource = `
package main
import "runtime"
diff --git a/src/runtime/defs_darwin_arm.go b/src/runtime/defs_darwin_arm.go
new file mode 100644
index 0000000000..92bab509fb
--- /dev/null
+++ b/src/runtime/defs_darwin_arm.go
@@ -0,0 +1,245 @@
+// Note: cgo can't handle some Darwin/ARM structures, so this file can't
+// be auto generated by cgo yet.
+// Created based on output of `cgo -cdefs defs_darwin.go` and Darwin/ARM
+// specific header (mainly mcontext and ucontext related stuff)
+
+package runtime
+
+import "unsafe"
+
+const (
+ _EINTR = 0x4
+ _EFAULT = 0xe
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x1000
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_DONTNEED = 0x4
+ _MADV_FREE = 0x5
+
+ _MACH_MSG_TYPE_MOVE_RECEIVE = 0x10
+ _MACH_MSG_TYPE_MOVE_SEND = 0x11
+ _MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
+ _MACH_MSG_TYPE_COPY_SEND = 0x13
+ _MACH_MSG_TYPE_MAKE_SEND = 0x14
+ _MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
+ _MACH_MSG_TYPE_COPY_RECEIVE = 0x16
+
+ _MACH_MSG_PORT_DESCRIPTOR = 0x0
+ _MACH_MSG_OOL_DESCRIPTOR = 0x1
+ _MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2
+ _MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
+
+ _MACH_MSGH_BITS_COMPLEX = 0x80000000
+
+ _MACH_SEND_MSG = 0x1
+ _MACH_RCV_MSG = 0x2
+ _MACH_RCV_LARGE = 0x4
+
+ _MACH_SEND_TIMEOUT = 0x10
+ _MACH_SEND_INTERRUPT = 0x40
+ _MACH_SEND_ALWAYS = 0x10000
+ _MACH_SEND_TRAILER = 0x20000
+ _MACH_RCV_TIMEOUT = 0x100
+ _MACH_RCV_NOTIFY = 0x200
+ _MACH_RCV_INTERRUPT = 0x400
+ _MACH_RCV_OVERWRITE = 0x1000
+
+ _NDR_PROTOCOL_2_0 = 0x0
+ _NDR_INT_BIG_ENDIAN = 0x0
+ _NDR_INT_LITTLE_ENDIAN = 0x1
+ _NDR_FLOAT_IEEE = 0x0
+ _NDR_CHAR_ASCII = 0x0
+
+ _SA_SIGINFO = 0x40
+ _SA_RESTART = 0x2
+ _SA_ONSTACK = 0x1
+ _SA_USERTRAMP = 0x100
+ _SA_64REGSET = 0x200
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGTERM = 0xf
+ _SIGURG = 0x10
+ _SIGSTOP = 0x11
+ _SIGTSTP = 0x12
+ _SIGCONT = 0x13
+ _SIGCHLD = 0x14
+ _SIGTTIN = 0x15
+ _SIGTTOU = 0x16
+ _SIGIO = 0x17
+ _SIGXCPU = 0x18
+ _SIGXFSZ = 0x19
+ _SIGVTALRM = 0x1a
+ _SIGPROF = 0x1b
+ _SIGWINCH = 0x1c
+ _SIGINFO = 0x1d
+ _SIGUSR1 = 0x1e
+ _SIGUSR2 = 0x1f
+
+ _FPE_INTDIV = 0x7
+ _FPE_INTOVF = 0x8
+ _FPE_FLTDIV = 0x1
+ _FPE_FLTOVF = 0x2
+ _FPE_FLTUND = 0x3
+ _FPE_FLTRES = 0x4
+ _FPE_FLTINV = 0x5
+ _FPE_FLTSUB = 0x6
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EV_ADD = 0x1
+ _EV_DELETE = 0x2
+ _EV_CLEAR = 0x20
+ _EV_RECEIPT = 0x40
+ _EV_ERROR = 0x4000
+ _EVFILT_READ = -0x1
+ _EVFILT_WRITE = -0x2
+)
+
+type machbody struct {
+ msgh_descriptor_count uint32
+}
+
+type machheader struct {
+ msgh_bits uint32
+ msgh_size uint32
+ msgh_remote_port uint32
+ msgh_local_port uint32
+ msgh_reserved uint32
+ msgh_id int32
+}
+
+type machndr struct {
+ mig_vers uint8
+ if_vers uint8
+ reserved1 uint8
+ mig_encoding uint8
+ int_rep uint8
+ char_rep uint8
+ float_rep uint8
+ reserved2 uint8
+}
+
+type machport struct {
+ name uint32
+ pad1 uint32
+ pad2 uint16
+ disposition uint8
+ _type uint8
+}
+
+type stackt struct {
+ ss_sp *byte
+ ss_size uintptr
+ ss_flags int32
+}
+
+type sigactiont struct {
+ __sigaction_u [4]byte
+ sa_tramp unsafe.Pointer
+ sa_mask uint32
+ sa_flags int32
+}
+
+type siginfo struct {
+ si_signo int32
+ si_errno int32
+ si_code int32
+ si_pid int32
+ si_uid uint32
+ si_status int32
+ si_addr *byte
+ si_value [4]byte
+ si_band int32
+ __pad [7]uint32
+}
+
+type timeval struct {
+ tv_sec int32
+ tv_usec int32
+}
+
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type timespec struct {
+ tv_sec int32
+ tv_nsec int32
+}
+
+type floatstate32 struct {
+ r [32]uint32
+ fpscr uint32
+}
+
+type regs32 struct {
+ r [13]uint32 // r0 to r12
+ sp uint32 // r13
+ lr uint32 // r14
+ pc uint32 // r15
+ cpsr uint32
+}
+
+type exceptionstate32 struct {
+ trapno uint32 // NOTE: on 386, the trapno field is split into trapno and cpu
+ err uint32
+ faultvaddr uint32
+}
+
+type mcontext32 struct {
+ es exceptionstate32
+ ss regs32
+ fs floatstate32
+}
+
+type ucontext struct {
+ uc_onstack int32
+ uc_sigmask uint32
+ uc_stack stackt
+ uc_link *ucontext
+ uc_mcsize uint32
+ uc_mcontext *mcontext32
+}
+
+type keventt struct {
+ ident uint32
+ filter int16
+ flags uint16
+ fflags uint32
+ data int32
+ udata *byte
+}
diff --git a/src/runtime/defs_windows_386.go b/src/runtime/defs_windows_386.go
index abec2d839f..c860f74a3f 100644
--- a/src/runtime/defs_windows_386.go
+++ b/src/runtime/defs_windows_386.go
@@ -101,6 +101,12 @@ type context struct {
extendedregisters [512]uint8
}
+func (c *context) ip() uintptr { return uintptr(c.eip) }
+func (c *context) sp() uintptr { return uintptr(c.esp) }
+
+func (c *context) setip(x uintptr) { c.eip = uint32(x) }
+func (c *context) setsp(x uintptr) { c.esp = uint32(x) }
+
type overlapped struct {
internal uint32
internalhigh uint32
diff --git a/src/runtime/defs_windows_amd64.go b/src/runtime/defs_windows_amd64.go
index 81b13597b7..d1e55ec426 100644
--- a/src/runtime/defs_windows_amd64.go
+++ b/src/runtime/defs_windows_amd64.go
@@ -116,6 +116,12 @@ type context struct {
lastexceptionfromrip uint64
}
+func (c *context) ip() uintptr { return uintptr(c.rip) }
+func (c *context) sp() uintptr { return uintptr(c.rsp) }
+
+func (c *context) setip(x uintptr) { c.rip = uint64(x) }
+func (c *context) setsp(x uintptr) { c.rsp = uint64(x) }
+
type overlapped struct {
internal uint64
internalhigh uint64
diff --git a/src/runtime/gcwork.go b/src/runtime/gcwork.go
new file mode 100644
index 0000000000..cf5a97957f
--- /dev/null
+++ b/src/runtime/gcwork.go
@@ -0,0 +1,338 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+const (
+ _Debugwbufs = true // if true check wbufs consistency
+ _WorkbufSize = 1 * 256 // in bytes - if small wbufs are passed to GC in a timely fashion.
+)
+
+type workbufhdr struct {
+ node lfnode // must be first
+ nobj uintptr
+ id uintptr
+ inuse bool // This workbuf is in use by some gorotuine and is not on the work.empty/partial/full queues.
+ log [4]uintptr // line numbers forming a history of ownership changes to workbuf
+}
+
+type workbuf struct {
+ workbufhdr
+ // account for the above fields
+ obj [(_WorkbufSize - unsafe.Sizeof(workbufhdr{})) / ptrSize]uintptr
+}
+
+// workbuf factory routines. These funcs are used to manage the
+// workbufs. They cache workbuf in the m struct field currentwbuf.
+// If the GC asks for some work these are the only routines that
+// make partially full wbufs available to the GC.
+// Each of the gets and puts also take an distinct integer that is used
+// to record a brief history of changes to ownership of the workbuf.
+// The convention is to use a unique line number but any encoding
+// is permissible. For example if you want to pass in 2 bits of information
+// you could simple add lineno1*100000+lineno2.
+
+// logget records the past few values of entry to aid in debugging.
+// logget checks the buffer b is not currently in use.
+func (b *workbuf) logget(entry uintptr) {
+ if !_Debugwbufs {
+ return
+ }
+ if b.inuse {
+ println("runtime: logget fails log entry=", entry,
+ "b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
+ "b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
+ throw("logget: get not legal")
+ }
+ b.inuse = true
+ copy(b.log[1:], b.log[:])
+ b.log[0] = entry
+}
+
+// logput records the past few values of entry to aid in debugging.
+// logput checks the buffer b is currently in use.
+func (b *workbuf) logput(entry uintptr) {
+ if !_Debugwbufs {
+ return
+ }
+ if !b.inuse {
+ println("runtime:logput fails log entry=", entry,
+ "b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
+ "b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
+ throw("logput: put not legal")
+ }
+ b.inuse = false
+ copy(b.log[1:], b.log[:])
+ b.log[0] = entry
+}
+
+func (b *workbuf) checknonempty() {
+ if b.nobj == 0 {
+ println("runtime: nonempty check fails",
+ "b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
+ "b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
+ throw("workbuf is empty")
+ }
+}
+
+func (b *workbuf) checkempty() {
+ if b.nobj != 0 {
+ println("runtime: empty check fails",
+ "b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
+ "b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
+ throw("workbuf is not empty")
+ }
+}
+
+// checknocurrentwbuf checks that the m's currentwbuf field is empty
+func checknocurrentwbuf() {
+ if getg().m.currentwbuf != 0 {
+ throw("unexpected currentwbuf")
+ }
+}
+
+// getempty pops an empty work buffer off the work.empty list,
+// allocating new buffers if none are available.
+// entry is used to record a brief history of ownership.
+//go:nowritebarrier
+func getempty(entry uintptr) *workbuf {
+ var b *workbuf
+ if work.empty != 0 {
+ b = (*workbuf)(lfstackpop(&work.empty))
+ if b != nil {
+ b.checkempty()
+ }
+ }
+ if b == nil {
+ b = (*workbuf)(persistentalloc(unsafe.Sizeof(*b), _CacheLineSize, &memstats.gc_sys))
+ }
+ b.logget(entry)
+ return b
+}
+
+// putempty puts a workbuf onto the work.empty list.
+// Upon entry this go routine owns b. The lfstackpush relinquishes ownership.
+//go:nowritebarrier
+func putempty(b *workbuf, entry uintptr) {
+ b.checkempty()
+ b.logput(entry)
+ lfstackpush(&work.empty, &b.node)
+}
+
+// putfull puts the workbuf on the work.full list for the GC.
+// putfull accepts partially full buffers so the GC can avoid competing
+// with the mutators for ownership of partially full buffers.
+//go:nowritebarrier
+func putfull(b *workbuf, entry uintptr) {
+ b.checknonempty()
+ b.logput(entry)
+ lfstackpush(&work.full, &b.node)
+}
+
+// getpartialorempty tries to return a partially empty
+// and if none are available returns an empty one.
+// entry is used to provide a brief histoy of ownership
+// using entry + xxx00000 to
+// indicating that two line numbers in the call chain.
+//go:nowritebarrier
+func getpartialorempty(entry uintptr) *workbuf {
+ var b *workbuf
+ // If this m has a buf in currentwbuf then as an optimization
+ // simply return that buffer. If it turns out currentwbuf
+ // is full, put it on the work.full queue and get another
+ // workbuf off the partial or empty queue.
+ if getg().m.currentwbuf != 0 {
+ b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0)))
+ if b != nil {
+ if b.nobj <= uintptr(len(b.obj)) {
+ return b
+ }
+ putfull(b, entry+80100000)
+ }
+ }
+ b = (*workbuf)(lfstackpop(&work.partial))
+ if b != nil {
+ b.logget(entry)
+ return b
+ }
+ // Let getempty do the logget check but
+ // use the entry to encode that it passed
+ // through this routine.
+ b = getempty(entry + 80700000)
+ return b
+}
+
+// putpartial puts empty buffers on the work.empty queue,
+// full buffers on the work.full queue and
+// others on the work.partial queue.
+// entry is used to provide a brief histoy of ownership
+// using entry + xxx00000 to
+// indicating that two call chain line numbers.
+//go:nowritebarrier
+func putpartial(b *workbuf, entry uintptr) {
+ if b.nobj == 0 {
+ putempty(b, entry+81500000)
+ } else if b.nobj < uintptr(len(b.obj)) {
+ b.logput(entry)
+ lfstackpush(&work.partial, &b.node)
+ } else if b.nobj == uintptr(len(b.obj)) {
+ b.logput(entry)
+ lfstackpush(&work.full, &b.node)
+ } else {
+ throw("putpartial: bad Workbuf b.nobj")
+ }
+}
+
+// trygetfull tries to get a full or partially empty workbuffer.
+// If one is not immediately available return nil
+//go:nowritebarrier
+func trygetfull(entry uintptr) *workbuf {
+ b := (*workbuf)(lfstackpop(&work.full))
+ if b == nil {
+ b = (*workbuf)(lfstackpop(&work.partial))
+ }
+ if b != nil {
+ b.logget(entry)
+ b.checknonempty()
+ return b
+ }
+ // full and partial are both empty so see if there
+ // is an work available on currentwbuf.
+ // This is an optimization to shift
+ // processing from the STW marktermination phase into
+ // the concurrent mark phase.
+ if getg().m.currentwbuf != 0 {
+ b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0)))
+ if b != nil {
+ if b.nobj != 0 {
+ return b
+ }
+ putempty(b, 839)
+ b = nil
+ }
+ }
+ return b
+}
+
+// Get a full work buffer off the work.full or a partially
+// filled one off the work.partial list. If nothing is available
+// wait until all the other gc helpers have finished and then
+// return nil.
+// getfull acts as a barrier for work.nproc helpers. As long as one
+// gchelper is actively marking objects it
+// may create a workbuffer that the other helpers can work on.
+// The for loop either exits when a work buffer is found
+// or when _all_ of the work.nproc GC helpers are in the loop
+// looking for work and thus not capable of creating new work.
+// This is in fact the termination condition for the STW mark
+// phase.
+//go:nowritebarrier
+func getfull(entry uintptr) *workbuf {
+ b := (*workbuf)(lfstackpop(&work.full))
+ if b != nil {
+ b.logget(entry)
+ b.checknonempty()
+ return b
+ }
+ b = (*workbuf)(lfstackpop(&work.partial))
+ if b != nil {
+ b.logget(entry)
+ return b
+ }
+ // Make sure that currentwbuf is also not a source for pointers to be
+ // processed. This is an optimization that shifts processing
+ // from the mark termination STW phase to the concurrent mark phase.
+ if getg().m.currentwbuf != 0 {
+ b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0)))
+ if b != nil {
+ if b.nobj != 0 {
+ return b
+ }
+ putempty(b, 877)
+ b = nil
+ }
+ }
+
+ xadd(&work.nwait, +1)
+ for i := 0; ; i++ {
+ if work.full != 0 {
+ xadd(&work.nwait, -1)
+ b = (*workbuf)(lfstackpop(&work.full))
+ if b == nil {
+ b = (*workbuf)(lfstackpop(&work.partial))
+ }
+ if b != nil {
+ b.logget(entry)
+ b.checknonempty()
+ return b
+ }
+ xadd(&work.nwait, +1)
+ }
+ if work.nwait == work.nproc {
+ return nil
+ }
+ _g_ := getg()
+ if i < 10 {
+ _g_.m.gcstats.nprocyield++
+ procyield(20)
+ } else if i < 20 {
+ _g_.m.gcstats.nosyield++
+ osyield()
+ } else {
+ _g_.m.gcstats.nsleep++
+ usleep(100)
+ }
+ }
+}
+
+//go:nowritebarrier
+func handoff(b *workbuf) *workbuf {
+ // Make new buffer with half of b's pointers.
+ b1 := getempty(915)
+ n := b.nobj / 2
+ b.nobj -= n
+ b1.nobj = n
+ memmove(unsafe.Pointer(&b1.obj[0]), unsafe.Pointer(&b.obj[b.nobj]), n*unsafe.Sizeof(b1.obj[0]))
+ _g_ := getg()
+ _g_.m.gcstats.nhandoff++
+ _g_.m.gcstats.nhandoffcnt += uint64(n)
+
+ // Put b on full list - let first half of b get stolen.
+ putfull(b, 942)
+ return b1
+}
+
+// 1 when you are harvesting so that the write buffer code shade can
+// detect calls during a presumable STW write barrier.
+var harvestingwbufs uint32
+
+// harvestwbufs moves non-empty workbufs to work.full from m.currentwuf
+// Must be in a STW phase.
+// xchguintptr is used since there are write barrier calls from the GC helper
+// routines even during a STW phase.
+// TODO: chase down write barrier calls in STW phase and understand and eliminate
+// them.
+//go:nowritebarrier
+func harvestwbufs() {
+ // announce to write buffer that you are harvesting the currentwbufs
+ atomicstore(&harvestingwbufs, 1)
+
+ for mp := allm; mp != nil; mp = mp.alllink {
+ wbuf := (*workbuf)(unsafe.Pointer(xchguintptr(&mp.currentwbuf, 0)))
+ // TODO: beat write barriers out of the mark termination and eliminate xchg
+ // tempwbuf := (*workbuf)(unsafe.Pointer(tempm.currentwbuf))
+ // tempm.currentwbuf = 0
+ if wbuf != nil {
+ if wbuf.nobj == 0 {
+ putempty(wbuf, 945)
+ } else {
+ putfull(wbuf, 947) //use full instead of partial so GC doesn't compete to get wbuf
+ }
+ }
+ }
+
+ atomicstore(&harvestingwbufs, 0)
+}
diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go
index 058d1c76c4..c7c1198259 100644
--- a/src/runtime/hashmap.go
+++ b/src/runtime/hashmap.go
@@ -182,8 +182,14 @@ func (h *hmap) createOverflow() {
}
}
-func makemap(t *maptype, hint int64) *hmap {
+// makemap implements a Go map creation make(map[k]v, hint)
+// If the compiler has determined that the map or the first bucket
+// can be created on the stack, h and/or bucket may be non-nil.
+// If h != nil, the map can be created directly in h.
+// If bucket != nil, bucket can be used as the first bucket.
+func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != uintptr(t.hmap.size) {
+ println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size)
throw("bad hmap size")
}
@@ -238,7 +244,7 @@ func makemap(t *maptype, hint int64) *hmap {
// allocate initial hash table
// if B == 0, the buckets field is allocated lazily later (in mapassign)
// If hint is large zeroing this memory could take a while.
- var buckets unsafe.Pointer
+ buckets := bucket
if B != 0 {
if checkgc {
memstats.next_gc = memstats.heap_alloc
@@ -250,7 +256,9 @@ func makemap(t *maptype, hint int64) *hmap {
if checkgc {
memstats.next_gc = memstats.heap_alloc
}
- h := (*hmap)(newobject(t.hmap))
+ if h == nil {
+ h = (*hmap)(newobject(t.hmap))
+ }
h.count = 0
h.B = B
h.flags = 0
@@ -956,7 +964,7 @@ func ismapkey(t *_type) bool {
//go:linkname reflect_makemap reflect.makemap
func reflect_makemap(t *maptype) *hmap {
- return makemap(t, 0)
+ return makemap(t, 0, nil, nil)
}
//go:linkname reflect_mapaccess reflect.mapaccess
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
index 6cbb5f3775..7b4a846195 100644
--- a/src/runtime/heapdump.go
+++ b/src/runtime/heapdump.go
@@ -344,7 +344,7 @@ func dumpgoroutine(gp *g) {
dumpint(uint64(gp.goid))
dumpint(uint64(gp.gopc))
dumpint(uint64(readgstatus(gp)))
- dumpbool(gp.issystem)
+ dumpbool(isSystemGoroutine(gp))
dumpbool(false) // isbackground
dumpint(uint64(gp.waitsince))
dumpstr(gp.waitreason)
diff --git a/src/runtime/iface_test.go b/src/runtime/iface_test.go
index bca0ea0ee7..bfeb94b8aa 100644
--- a/src/runtime/iface_test.go
+++ b/src/runtime/iface_test.go
@@ -5,6 +5,7 @@
package runtime_test
import (
+ "runtime"
"testing"
)
@@ -38,6 +39,47 @@ var (
tl TL
)
+// Issue 9370
+func TestCmpIfaceConcreteAlloc(t *testing.T) {
+ if runtime.Compiler != "gc" {
+ t.Skip("skipping on non-gc compiler")
+ }
+
+ n := testing.AllocsPerRun(1, func() {
+ _ = e == ts
+ _ = i1 == ts
+ _ = e == 1
+ })
+
+ if n > 0 {
+ t.Fatalf("iface cmp allocs=%v; want 0", n)
+ }
+}
+
+func BenchmarkEqEfaceConcrete(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = e == ts
+ }
+}
+
+func BenchmarkEqIfaceConcrete(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = i1 == ts
+ }
+}
+
+func BenchmarkNeEfaceConcrete(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = e != ts
+ }
+}
+
+func BenchmarkNeIfaceConcrete(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = i1 != ts
+ }
+}
+
func BenchmarkConvT2ESmall(b *testing.B) {
for i := 0; i < b.N; i++ {
e = ts
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index b8b1f4ed36..06ba124473 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -312,6 +312,7 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
// For now this must be bracketed with a stoptheworld and a starttheworld to ensure
// all go routines see the new barrier.
+//go:nowritebarrier
func gcinstallmarkwb() {
gcphase = _GCmark
}
@@ -389,6 +390,7 @@ func gcwork(force int32) {
gctimer.cycle.installmarkwb = nanotime()
systemstack(stoptheworld)
systemstack(gcinstallmarkwb)
+ systemstack(harvestwbufs)
systemstack(starttheworld)
gctimer.cycle.mark = nanotime()
systemstack(gcmark_m)
diff --git a/src/runtime/malloc1.go b/src/runtime/malloc1.go
index 4d0754ba9d..18d998b554 100644
--- a/src/runtime/malloc1.go
+++ b/src/runtime/malloc1.go
@@ -99,7 +99,7 @@ func mallocinit() {
var reserved bool
// limit = runtime.memlimit();
- // See https://code.google.com/p/go/issues/detail?id=5049
+ // See https://golang.org/issue/5049
// TODO(rsc): Fix after 1.1.
limit = 0
diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go
index 92da2d8209..55f1f82625 100644
--- a/src/runtime/map_test.go
+++ b/src/runtime/map_test.go
@@ -535,3 +535,13 @@ func benchmarkMapPop(b *testing.B, n int) {
func BenchmarkMapPop100(b *testing.B) { benchmarkMapPop(b, 100) }
func BenchmarkMapPop1000(b *testing.B) { benchmarkMapPop(b, 1000) }
func BenchmarkMapPop10000(b *testing.B) { benchmarkMapPop(b, 10000) }
+
+func TestNonEscapingMap(t *testing.T) {
+ n := testing.AllocsPerRun(1000, func() {
+ m := make(map[int]int)
+ m[0] = 0
+ })
+ if n != 0 {
+ t.Fatalf("want 0 allocs, got %v", n)
+ }
+}
diff --git a/src/runtime/mapspeed_test.go b/src/runtime/mapspeed_test.go
index 119eb3f39c..b036d2a3ab 100644
--- a/src/runtime/mapspeed_test.go
+++ b/src/runtime/mapspeed_test.go
@@ -234,6 +234,15 @@ func BenchmarkNewEmptyMap(b *testing.B) {
}
}
+func BenchmarkNewSmallMap(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ m := make(map[int]int)
+ m[0] = 0
+ m[1] = 1
+ }
+}
+
func BenchmarkMapIter(b *testing.B) {
m := make(map[int]bool)
for i := 0; i < 8; i++ {
diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go
index 33d67c4976..f6e9269858 100644
--- a/src/runtime/mbarrier.go
+++ b/src/runtime/mbarrier.go
@@ -328,6 +328,13 @@ func typedslicecopy(typ *_type, dst, src slice) int {
dstp := unsafe.Pointer(dst.array)
srcp := unsafe.Pointer(src.array)
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer(&typ))
+ pc := funcPC(slicecopy)
+ racewriterangepc(dstp, uintptr(n)*typ.size, callerpc, pc)
+ racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc)
+ }
+
if !needwb() {
memmove(dstp, srcp, uintptr(n)*typ.size)
return int(n)
diff --git a/src/runtime/mem_linux.go b/src/runtime/mem_linux.go
index aa99b762bf..920fbcf6d6 100644
--- a/src/runtime/mem_linux.go
+++ b/src/runtime/mem_linux.go
@@ -54,7 +54,6 @@ func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
if uintptr(p) < 4096 {
if uintptr(p) == _EACCES {
print("runtime: mmap: access denied\n")
- print("if you're running SELinux, enable execmem for this process.\n")
exit(2)
}
if uintptr(p) == _EAGAIN {
diff --git a/src/runtime/mem_plan9.go b/src/runtime/mem_plan9.go
index 477a52700e..6ceed25d87 100644
--- a/src/runtime/mem_plan9.go
+++ b/src/runtime/mem_plan9.go
@@ -48,6 +48,7 @@ func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
n = memRound(n)
if bloc == uintptr(v)+n {
bloc -= n
+ memclr(unsafe.Pointer(bloc), n)
}
unlock(&memlock)
}
diff --git a/src/runtime/mem_windows.go b/src/runtime/mem_windows.go
index d72d49b975..a800ccae1d 100644
--- a/src/runtime/mem_windows.go
+++ b/src/runtime/mem_windows.go
@@ -18,16 +18,6 @@ const (
_PAGE_NOACCESS = 0x0001
)
-//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc "kernel32.dll"
-//go:cgo_import_dynamic runtime._VirtualFree VirtualFree "kernel32.dll"
-//go:cgo_import_dynamic runtime._VirtualProtect VirtualProtect "kernel32.dll"
-
-var (
- _VirtualAlloc,
- _VirtualFree,
- _VirtualProtect stdFunction
-)
-
//go:nosplit
func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
xadd64(stat, int64(n))
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
index 28afa0dfab..525aa0955a 100644
--- a/src/runtime/mfinal.go
+++ b/src/runtime/mfinal.go
@@ -102,7 +102,10 @@ func wakefing() *g {
return res
}
-var fingCreate uint32
+var (
+ fingCreate uint32
+ fingRunning bool
+)
func createfing() {
// start the finalizer goroutine exactly once
@@ -126,9 +129,7 @@ func runfinq() {
gp := getg()
fing = gp
fingwait = true
- gp.issystem = true
goparkunlock(&finlock, "finalizer wait", traceEvGoBlock)
- gp.issystem = false
continue
}
unlock(&finlock)
@@ -169,7 +170,9 @@ func runfinq() {
default:
throw("bad kind in runfinq")
}
+ fingRunning = true
reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
+ fingRunning = false
// drop finalizer queue references to finalized object
f.fn = nil
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 75b1e52916..1a3e70fcdd 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -122,8 +122,6 @@ const (
_DebugGC = 0
_DebugGCPtrs = false // if true, print trace of every pointer load during GC
_ConcurrentSweep = true
-
- _WorkbufSize = 4 * 256
_FinBlockSize = 4 * 1024
_RootData = 0
_RootBss = 1
@@ -154,12 +152,6 @@ var gcpercent int32
//
var worldsema uint32 = 1
-type workbuf struct {
- node lfnode // must be first
- nobj uintptr
- obj [(_WorkbufSize - unsafe.Sizeof(lfnode{}) - ptrSize) / ptrSize]uintptr
-}
-
var data, edata, bss, ebss, gcdata, gcbss struct{}
var gcdatamask bitvector
@@ -347,7 +339,8 @@ func greyobject(obj, base, off uintptr, hbits heapBits, wbuf *workbuf) *workbuf
// If workbuf is full, obtain an empty one.
if wbuf.nobj >= uintptr(len(wbuf.obj)) {
- wbuf = getempty(wbuf)
+ putfull(wbuf, 358)
+ wbuf = getempty(359)
}
wbuf.obj[wbuf.nobj] = obj
@@ -426,13 +419,10 @@ func scanobject(b, n uintptr, ptrmask *uint8, wbuf *workbuf) *workbuf {
return wbuf
}
-// scanblock starts by scanning b as scanobject would.
-// If the gcphase is GCscan, that's all scanblock does.
-// Otherwise it traverses some fraction of the pointers it found in b, recursively.
-// As a special case, scanblock(nil, 0, nil) means to scan previously queued work,
-// stopping only when no work is left in the system.
+// scanblock scans b as scanobject would.
+// If the gcphase is GCscan, scanblock performs additional checks.
//go:nowritebarrier
-func scanblock(b0, n0 uintptr, ptrmask *uint8) {
+func scanblock(b0, n0 uintptr, ptrmask *uint8, wbuf *workbuf) *workbuf {
// Use local copies of original parameters, so that a stack trace
// due to one of the throws below shows the original block
// base and extent.
@@ -443,48 +433,40 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8) {
// 1. nil - obtain pointer mask from GC bitmap.
// 2. pointer to a compact mask (for stacks and data).
- wbuf := getpartialorempty()
- if b != 0 {
- wbuf = scanobject(b, n, ptrmask, wbuf)
- if gcphase == _GCscan {
- if inheap(b) && ptrmask == nil {
- // b is in heap, we are in GCscan so there should be a ptrmask.
- throw("scanblock: In GCscan phase and inheap is true.")
- }
- // GCscan only goes one level deep since mark wb not turned on.
- putpartial(wbuf)
- return
+ if wbuf == nil {
+ wbuf = getpartialorempty(460) // no wbuf passed in.
+ }
+ wbuf = scanobject(b, n, ptrmask, wbuf)
+ if gcphase == _GCscan {
+ if inheap(b) && ptrmask == nil {
+ // b is in heap, we are in GCscan so there should be a ptrmask.
+ throw("scanblock: In GCscan phase and inheap is true.")
}
}
-
- drainallwbufs := b == 0
- drainworkbuf(wbuf, drainallwbufs)
+ return wbuf
}
-// Scan objects in wbuf until wbuf is empty.
-// If drainallwbufs is true find all other available workbufs and repeat the process.
+// gcDrain scans objects in work buffers (starting with wbuf), blackening grey
+// objects until all work buffers have been drained.
//go:nowritebarrier
-func drainworkbuf(wbuf *workbuf, drainallwbufs bool) {
+func gcDrain(wbuf *workbuf) {
+ if wbuf == nil {
+ wbuf = getpartialorempty(472)
+ }
+ checknocurrentwbuf()
if gcphase != _GCmark && gcphase != _GCmarktermination {
- println("gcphase", gcphase)
- throw("scanblock phase")
+ throw("scanblock phase incorrect")
}
for {
if wbuf.nobj == 0 {
- if !drainallwbufs {
- putempty(wbuf)
- return
- }
+ putempty(wbuf, 496)
// Refill workbuf from global queue.
- wbuf = getfull(wbuf)
+ wbuf = getfull(504)
if wbuf == nil { // nil means out of work barrier reached
- return
- }
-
- if wbuf.nobj <= 0 {
- throw("runtime:scanblock getfull returns empty buffer")
+ break
}
+ wbuf.checknonempty()
}
// If another proc wants a pointer, give it some.
@@ -493,52 +475,61 @@ func drainworkbuf(wbuf *workbuf, drainallwbufs bool) {
}
// This might be a good place to add prefetch code...
- // if(wbuf->nobj > 4) {
- // PREFETCH(wbuf->obj[wbuf->nobj - 3];
+ // if(wbuf.nobj > 4) {
+ // PREFETCH(wbuf->obj[wbuf.nobj - 3];
// }
wbuf.nobj--
b := wbuf.obj[wbuf.nobj]
+ // If the current wbuf is filled by the scan a new wbuf might be
+ // returned that could possibly hold only a single object. This
+ // could result in each iteration draining only a single object
+ // out of the wbuf passed in + a single object placed
+ // into an empty wbuf in scanobject so there could be
+ // a performance hit as we keep fetching fresh wbufs.
wbuf = scanobject(b, 0, nil, wbuf)
}
+ checknocurrentwbuf()
}
-// Scan count objects starting with those in wbuf.
+// gcDrainN scans n objects starting with those in wbuf, blackening
+// grey objects.
//go:nowritebarrier
-func drainobjects(wbuf *workbuf, count uintptr) {
- for i := uintptr(0); i < count; i++ {
+func gcDrainN(wbuf *workbuf, n uintptr) *workbuf {
+ checknocurrentwbuf()
+ for i := uintptr(0); i < n; i++ {
if wbuf.nobj == 0 {
- putempty(wbuf)
- wbuf = trygetfull()
+ putempty(wbuf, 544)
+ wbuf = trygetfull(545)
if wbuf == nil {
- return
+ return nil
}
}
// This might be a good place to add prefetch code...
- // if(wbuf->nobj > 4) {
- // PREFETCH(wbuf->obj[wbuf->nobj - 3];
+ // if(wbuf.nobj > 4) {
+ // PREFETCH(wbuf->obj[wbuf.nobj - 3];
// }
wbuf.nobj--
b := wbuf.obj[wbuf.nobj]
wbuf = scanobject(b, 0, nil, wbuf)
}
- putpartial(wbuf)
- return
+ return wbuf
}
//go:nowritebarrier
func markroot(desc *parfor, i uint32) {
// Note: if you add a case here, please also update heapdump.c:dumproots.
+ wbuf := (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0)))
switch i {
case _RootData:
- scanblock(uintptr(unsafe.Pointer(&data)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)), gcdatamask.bytedata)
+ wbuf = scanblock(uintptr(unsafe.Pointer(&data)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)), gcdatamask.bytedata, wbuf)
case _RootBss:
- scanblock(uintptr(unsafe.Pointer(&bss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)), gcbssmask.bytedata)
+ wbuf = scanblock(uintptr(unsafe.Pointer(&bss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)), gcbssmask.bytedata, wbuf)
case _RootFinalizers:
for fb := allfin; fb != nil; fb = fb.alllink {
- scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0])
+ wbuf = scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], wbuf)
}
case _RootSpans:
@@ -564,9 +555,9 @@ func markroot(desc *parfor, i uint32) {
// A finalizer can be set for an inner byte of an object, find object beginning.
p := uintptr(s.start<<_PageShift) + uintptr(spf.special.offset)/s.elemsize*s.elemsize
if gcphase != _GCscan {
- scanblock(p, s.elemsize, nil) // scanned during mark phase
+ wbuf = scanblock(p, s.elemsize, nil, wbuf) // scanned during mark phase
}
- scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptr[0])
+ wbuf = scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptr[0], wbuf)
}
}
@@ -626,157 +617,14 @@ func markroot(desc *parfor, i uint32) {
restartg(gp)
}
}
-}
-
-// Get an empty work buffer off the work.empty list,
-// allocating new buffers as needed.
-//go:nowritebarrier
-func getempty(b *workbuf) *workbuf {
- if b != nil {
- putfull(b)
- b = nil
- }
- if work.empty != 0 {
- b = (*workbuf)(lfstackpop(&work.empty))
- }
- if b != nil && b.nobj != 0 {
- _g_ := getg()
- print("m", _g_.m.id, ": getempty: popped b=", b, " with non-zero b.nobj=", b.nobj, "\n")
- throw("getempty: workbuffer not empty, b->nobj not 0")
- }
- if b == nil {
- b = (*workbuf)(persistentalloc(unsafe.Sizeof(*b), _CacheLineSize, &memstats.gc_sys))
- b.nobj = 0
- }
- return b
-}
-
-//go:nowritebarrier
-func putempty(b *workbuf) {
- if b.nobj != 0 {
- throw("putempty: b->nobj not 0")
- }
- lfstackpush(&work.empty, &b.node)
-}
-
-//go:nowritebarrier
-func putfull(b *workbuf) {
- if b.nobj <= 0 {
- throw("putfull: b->nobj <= 0")
- }
- lfstackpush(&work.full, &b.node)
-}
-
-// Get an partially empty work buffer
-// if none are available get an empty one.
-//go:nowritebarrier
-func getpartialorempty() *workbuf {
- b := (*workbuf)(lfstackpop(&work.partial))
- if b == nil {
- b = getempty(nil)
- }
- return b
-}
-
-//go:nowritebarrier
-func putpartial(b *workbuf) {
- if b.nobj == 0 {
- lfstackpush(&work.empty, &b.node)
- } else if b.nobj < uintptr(len(b.obj)) {
- lfstackpush(&work.partial, &b.node)
- } else if b.nobj == uintptr(len(b.obj)) {
- lfstackpush(&work.full, &b.node)
- } else {
- print("b=", b, " b.nobj=", b.nobj, " len(b.obj)=", len(b.obj), "\n")
- throw("putpartial: bad Workbuf b.nobj")
- }
-}
-
-// trygetfull tries to get a full or partially empty workbuffer.
-// if one is not immediately available return nil
-//go:nowritebarrier
-func trygetfull() *workbuf {
- wbuf := (*workbuf)(lfstackpop(&work.full))
if wbuf == nil {
- wbuf = (*workbuf)(lfstackpop(&work.partial))
- }
- return wbuf
-}
-
-// Get a full work buffer off the work.full or a partially
-// filled one off the work.partial list. If nothing is available
-// wait until all the other gc helpers have finished and then
-// return nil.
-// getfull acts as a barrier for work.nproc helpers. As long as one
-// gchelper is actively marking objects it
-// may create a workbuffer that the other helpers can work on.
-// The for loop either exits when a work buffer is found
-// or when _all_ of the work.nproc GC helpers are in the loop
-// looking for work and thus not capable of creating new work.
-// This is in fact the termination condition for the STW mark
-// phase.
-//go:nowritebarrier
-func getfull(b *workbuf) *workbuf {
- if b != nil {
- putempty(b)
- }
-
- b = (*workbuf)(lfstackpop(&work.full))
- if b == nil {
- b = (*workbuf)(lfstackpop(&work.partial))
- }
- if b != nil {
- return b
- }
-
- xadd(&work.nwait, +1)
- for i := 0; ; i++ {
- if work.full != 0 {
- xadd(&work.nwait, -1)
- b = (*workbuf)(lfstackpop(&work.full))
- if b == nil {
- b = (*workbuf)(lfstackpop(&work.partial))
- }
- if b != nil {
- return b
- }
- xadd(&work.nwait, +1)
- }
- if work.nwait == work.nproc {
- return nil
- }
- _g_ := getg()
- if i < 10 {
- _g_.m.gcstats.nprocyield++
- procyield(20)
- } else if i < 20 {
- _g_.m.gcstats.nosyield++
- osyield()
- } else {
- _g_.m.gcstats.nsleep++
- usleep(100)
- }
+ return
+ } else {
+ putpartial(wbuf, 670)
}
}
//go:nowritebarrier
-func handoff(b *workbuf) *workbuf {
- // Make new buffer with half of b's pointers.
- b1 := getempty(nil)
- n := b.nobj / 2
- b.nobj -= n
- b1.nobj = n
- memmove(unsafe.Pointer(&b1.obj[0]), unsafe.Pointer(&b.obj[b.nobj]), n*unsafe.Sizeof(b1.obj[0]))
- _g_ := getg()
- _g_.m.gcstats.nhandoff++
- _g_.m.gcstats.nhandoffcnt += uint64(n)
-
- // Put b on full list - let first half of b get stolen.
- lfstackpush(&work.full, &b.node)
- return b1
-}
-
-//go:nowritebarrier
func stackmapdata(stkmap *stackmap, n int32) bitvector {
if n < 0 || n >= stkmap.n {
throw("stackmapdata: index out of range")
@@ -786,13 +634,13 @@ func stackmapdata(stkmap *stackmap, n int32) bitvector {
// Scan a stack frame: local variables and function arguments/results.
//go:nowritebarrier
-func scanframe(frame *stkframe, unused unsafe.Pointer) bool {
+func scanframeworker(frame *stkframe, unused unsafe.Pointer, wbuf *workbuf) *workbuf {
f := frame.fn
targetpc := frame.continpc
if targetpc == 0 {
// Frame is dead.
- return true
+ return wbuf
}
if _DebugGC > 1 {
print("scanframe ", funcname(f), "\n")
@@ -831,7 +679,7 @@ func scanframe(frame *stkframe, unused unsafe.Pointer) bool {
}
bv := stackmapdata(stkmap, pcdata)
size = (uintptr(bv.n) / typeBitsWidth) * ptrSize
- scanblock(frame.varp-size, size, bv.bytedata)
+ wbuf = scanblock(frame.varp-size, size, bv.bytedata, wbuf)
}
// Scan arguments.
@@ -852,9 +700,9 @@ func scanframe(frame *stkframe, unused unsafe.Pointer) bool {
}
bv = stackmapdata(stkmap, pcdata)
}
- scanblock(frame.argp, uintptr(bv.n)/typeBitsWidth*ptrSize, bv.bytedata)
+ wbuf = scanblock(frame.argp, uintptr(bv.n)/typeBitsWidth*ptrSize, bv.bytedata, wbuf)
}
- return true
+ return wbuf
}
//go:nowritebarrier
@@ -889,8 +737,19 @@ func scanstack(gp *g) {
throw("can't scan gchelper stack")
}
+ wbuf := (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0)))
+ scanframe := func(frame *stkframe, unused unsafe.Pointer) bool {
+ // Pick up wbuf as free variable so gentraceback and friends can
+ // keep the same signature.
+ wbuf = scanframeworker(frame, unused, wbuf)
+ return true
+ }
gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0)
tracebackdefers(gp, scanframe, nil)
+ wbuf = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, uintptr(unsafe.Pointer(wbuf)))))
+ if wbuf != nil {
+ throw("wbuf not nil after stack scans")
+ }
gp.gcscanvalid = true
}
@@ -898,17 +757,34 @@ func scanstack(gp *g) {
// The object is not nil and known to be in the heap.
//go:nowritebarrier
func shade(b uintptr) {
+ var wbuf *workbuf
+
if !inheap(b) {
throw("shade: passed an address not in the heap")
}
-
- wbuf := getpartialorempty()
-
if obj, hbits := heapBitsForObject(b); obj != 0 {
- wbuf = greyobject(obj, 0, 0, hbits, wbuf)
- }
+ // TODO: this would be a great place to put a check to see
+ // if we are harvesting and if we are then we should
+ // figure out why there is a call to shade when the
+ // harvester thinks we are in a STW.
+ // if atomicload(&harvestingwbufs) == uint32(1) {
+ // // Throw here to discover write barriers
+ // // being executed during a STW.
+ // }
- putpartial(wbuf)
+ wbuf = getpartialorempty(1181)
+ wbuf := greyobject(obj, 0, 0, hbits, wbuf)
+ checknocurrentwbuf()
+ // This is part of the write barrier so put the wbuf back.
+ if gcphase == _GCmarktermination {
+ putpartial(wbuf, 1191) // Put on full???
+ } else {
+ wbuf = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, uintptr(unsafe.Pointer(wbuf)))))
+ if wbuf != nil {
+ throw("m.currentwbuf lost in shade")
+ }
+ }
+ }
}
// gchelpwork does a small bounded amount of gc work. The purpose is to
@@ -931,10 +807,24 @@ func gchelpwork() {
// scanstack(gp)
case _GCmark:
// Get a full work buffer and empty it.
- var wbuf *workbuf
- wbuf = trygetfull()
+ m := getg().m
+ // drain your own currentwbuf first in the hopes that it will
+ // be more cache friendly.
+ wbuf := (*workbuf)(unsafe.Pointer(xchguintptr(&m.currentwbuf, 0)))
+ // wbuf := (*workbuf)(unsafe.Pointer(m.currentwbuf))
+ // m.currentwbuf = 0
+ if wbuf == nil {
+ wbuf = trygetfull(1228)
+ }
if wbuf != nil {
- drainobjects(wbuf, uintptr(len(wbuf.obj))) // drain upto one buffer's worth of objects
+ wbuf = gcDrainN(wbuf, uintptr(len(wbuf.obj))) // drain upto one buffer's worth of objects
+ if wbuf != nil {
+ if wbuf.nobj != 0 {
+ putfull(wbuf, 1175)
+ } else {
+ putempty(wbuf, 1177)
+ }
+ }
}
case _GCmarktermination:
// We should never be here since the world is stopped.
@@ -1249,7 +1139,7 @@ func gchelper() {
// parallel mark for over GC roots
parfordo(work.markfor)
if gcphase != _GCscan {
- scanblock(0, 0, nil) // blocks in getfull
+ gcDrain(nil) // blocks in getfull
}
if trace.enabled {
@@ -1380,7 +1270,7 @@ var heapminimum = uint64(4 << 20)
func gcinit() {
if unsafe.Sizeof(workbuf{}) != _WorkbufSize {
- throw("runtime: size of Workbuf is suboptimal")
+ throw("size of Workbuf is suboptimal")
}
work.markfor = parforalloc(_MaxGcproc)
@@ -1508,16 +1398,12 @@ func gcscan_m() {
}
// Mark all objects that are known about.
+// This is the concurrent mark phase.
//go:nowritebarrier
func gcmark_m() {
- scanblock(0, 0, nil)
-}
-
-// For now this must be bracketed with a stoptheworld and a starttheworld to ensure
-// all go routines see the new barrier.
-//go:nowritebarrier
-func gcinstallmarkwb_m() {
- gcphase = _GCmark
+ gcDrain(nil)
+ // TODO add another harvestwbuf and reset work.nwait=0, work.ndone=0, and work.nproc=1
+ // and repeat the above gcDrain.
}
// For now this must be bracketed with a stoptheworld and a starttheworld to ensure
@@ -1527,12 +1413,14 @@ func gcinstalloffwb_m() {
gcphase = _GCoff
}
+// STW is in effect at this point.
//TODO go:nowritebarrier
func gc(start_time int64, eagersweep bool) {
if _DebugGCPtrs {
print("GC start\n")
}
+ gcphase = _GCmarktermination
if debug.allocfreetrace > 0 {
tracegc()
}
@@ -1571,12 +1459,10 @@ func gc(start_time int64, eagersweep bool) {
mheap_.gcspans = mheap_.allspans
work.spans = h_allspans
unlock(&mheap_.lock)
- oldphase := gcphase
work.nwait = 0
work.ndone = 0
work.nproc = uint32(gcprocs())
- gcphase = _GCmarktermination
// World is stopped so allglen will not change.
for i := uintptr(0); i < allglen; i++ {
@@ -1599,9 +1485,10 @@ func gc(start_time int64, eagersweep bool) {
t2 = nanotime()
}
+ harvestwbufs() // move local workbufs onto global queues where the GC can find them
gchelperstart()
parfordo(work.markfor)
- scanblock(0, 0, nil)
+ gcDrain(nil)
if work.full != 0 {
throw("work.full != 0")
@@ -1610,7 +1497,7 @@ func gc(start_time int64, eagersweep bool) {
throw("work.partial != 0")
}
- gcphase = oldphase
+ gcphase = _GCoff
var t3 int64
if debug.gctrace > 0 {
t3 = nanotime()
@@ -1755,7 +1642,7 @@ func readGCStats_m(pauses *[]uint64) {
p := *pauses
// Calling code in runtime/debug should make the slice large enough.
if cap(p) < len(memstats.pause_ns)+3 {
- throw("runtime: short slice passed to readGCStats")
+ throw("short slice passed to readGCStats")
}
// Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns.
diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go
index bbd786d519..f54d93377d 100644
--- a/src/runtime/mgc0.go
+++ b/src/runtime/mgc0.go
@@ -62,7 +62,6 @@ func clearpools() {
// bggc holds the state of the backgroundgc.
func backgroundgc() {
bggc.g = getg()
- bggc.g.issystem = true
for {
gcwork(0)
lock(&bggc.lock)
@@ -73,7 +72,6 @@ func backgroundgc() {
func bgsweep() {
sweep.g = getg()
- getg().issystem = true
for {
for gosweepone() != ^uintptr(0) {
sweep.nbgsweep++
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index 11bc809ec1..13f1b363d0 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -318,8 +318,7 @@ HaveSpan:
t.needzero = s.needzero
s.state = _MSpanStack // prevent coalescing with s
t.state = _MSpanStack
- mHeap_FreeSpanLocked(h, t, false, false)
- t.unusedsince = s.unusedsince // preserve age (TODO: wrong: t is possibly merged and/or deallocated at this point)
+ mHeap_FreeSpanLocked(h, t, false, false, s.unusedsince)
s.state = _MSpanFree
}
s.unusedsince = 0
@@ -395,7 +394,7 @@ func mHeap_Grow(h *mheap, npage uintptr) bool {
h_spans[p+s.npages-1] = s
atomicstore(&s.sweepgen, h.sweepgen)
s.state = _MSpanInUse
- mHeap_FreeSpanLocked(h, s, false, true)
+ mHeap_FreeSpanLocked(h, s, false, true, 0)
return true
}
@@ -442,7 +441,7 @@ func mHeap_Free(h *mheap, s *mspan, acct int32) {
memstats.heap_alloc -= uint64(s.npages << _PageShift)
memstats.heap_objects--
}
- mHeap_FreeSpanLocked(h, s, true, true)
+ mHeap_FreeSpanLocked(h, s, true, true, 0)
if trace.enabled {
traceHeapAlloc()
}
@@ -458,11 +457,11 @@ func mHeap_FreeStack(h *mheap, s *mspan) {
s.needzero = 1
lock(&h.lock)
memstats.stacks_inuse -= uint64(s.npages << _PageShift)
- mHeap_FreeSpanLocked(h, s, true, true)
+ mHeap_FreeSpanLocked(h, s, true, true, 0)
unlock(&h.lock)
}
-func mHeap_FreeSpanLocked(h *mheap, s *mspan, acctinuse, acctidle bool) {
+func mHeap_FreeSpanLocked(h *mheap, s *mspan, acctinuse, acctidle bool, unusedsince int64) {
switch s.state {
case _MSpanStack:
if s.ref != 0 {
@@ -488,7 +487,10 @@ func mHeap_FreeSpanLocked(h *mheap, s *mspan, acctinuse, acctidle bool) {
// Stamp newly unused spans. The scavenger will use that
// info to potentially give back some pages to the OS.
- s.unusedsince = nanotime()
+ s.unusedsince = unusedsince
+ if unusedsince == 0 {
+ s.unusedsince = nanotime()
+ }
s.npreleased = 0
// Coalesce with earlier, later spans.
diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go
index 8e0750d607..0861e20f0c 100644
--- a/src/runtime/netpoll_windows.go
+++ b/src/runtime/netpoll_windows.go
@@ -10,16 +10,6 @@ import (
const _DWORD_MAX = 0xffffffff
-//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll"
-//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll"
-//go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll"
-
-var (
- _CreateIoCompletionPort,
- _GetQueuedCompletionStatus,
- _WSAGetOverlappedResult stdFunction
-)
-
const _INVALID_HANDLE_VALUE = ^uintptr(0)
// net_op must be the same as beginning of net.operation. Keep these in sync.
diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go
index 8655c083b2..2de6b09343 100644
--- a/src/runtime/os1_windows.go
+++ b/src/runtime/os1_windows.go
@@ -11,6 +11,7 @@ import (
//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
//go:cgo_import_dynamic runtime._CloseHandle CloseHandle "kernel32.dll"
//go:cgo_import_dynamic runtime._CreateEventA CreateEventA "kernel32.dll"
+//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll"
//go:cgo_import_dynamic runtime._CreateThread CreateThread "kernel32.dll"
//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA "kernel32.dll"
//go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
@@ -21,6 +22,7 @@ import (
//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll"
//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle "kernel32.dll"
//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo "kernel32.dll"
//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext "kernel32.dll"
@@ -37,14 +39,22 @@ import (
//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer "kernel32.dll"
//go:cgo_import_dynamic runtime._Sleep Sleep "kernel32.dll"
//go:cgo_import_dynamic runtime._SuspendThread SuspendThread "kernel32.dll"
+//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc "kernel32.dll"
+//go:cgo_import_dynamic runtime._VirtualFree VirtualFree "kernel32.dll"
+//go:cgo_import_dynamic runtime._VirtualProtect VirtualProtect "kernel32.dll"
+//go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll"
//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject "kernel32.dll"
//go:cgo_import_dynamic runtime._WriteFile WriteFile "kernel32.dll"
//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod "winmm.dll"
var (
+ // Following syscalls are available on every Windows PC.
+ // All these variables are set by the Windows executable
+ // loader before the Go program starts.
_AddVectoredExceptionHandler,
_CloseHandle,
_CreateEventA,
+ _CreateIoCompletionPort,
_CreateThread,
_CreateWaitableTimerA,
_CryptAcquireContextW,
@@ -55,6 +65,7 @@ var (
_FreeEnvironmentStringsW,
_GetEnvironmentStringsW,
_GetProcAddress,
+ _GetQueuedCompletionStatus,
_GetStdHandle,
_GetSystemInfo,
_GetThreadContext,
@@ -71,12 +82,36 @@ var (
_SetWaitableTimer,
_Sleep,
_SuspendThread,
+ _VirtualAlloc,
+ _VirtualFree,
+ _VirtualProtect,
+ _WSAGetOverlappedResult,
_WaitForSingleObject,
_WriteFile,
_timeBeginPeriod stdFunction
+
+ // Following syscalls are only available on some Windows PCs.
+ // We will load syscalls, if available, before using them.
+ _AddVectoredContinueHandler,
+ _GetQueuedCompletionStatusEx stdFunction
)
-var _GetQueuedCompletionStatusEx stdFunction
+func loadOptionalSyscalls() {
+ var buf [50]byte // large enough for longest string
+ strtoptr := func(s string) uintptr {
+ buf[copy(buf[:], s)] = 0 // nil-terminated for OS
+ return uintptr(noescape(unsafe.Pointer(&buf[0])))
+ }
+ l := stdcall1(_LoadLibraryA, strtoptr("kernel32.dll"))
+ findfunc := func(name string) stdFunction {
+ f := stdcall2(_GetProcAddress, l, strtoptr(name))
+ return stdFunction(unsafe.Pointer(f))
+ }
+ if l != 0 {
+ _AddVectoredContinueHandler = findfunc("AddVectoredContinueHandler")
+ _GetQueuedCompletionStatusEx = findfunc("GetQueuedCompletionStatusEx")
+ }
+}
// in sys_windows_386.s and sys_windows_amd64.s
func externalthreadhandler()
@@ -117,34 +152,24 @@ func disableWER() {
stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
}
-var (
- kernel32Name = []byte("kernel32.dll\x00")
- addVectoredContinueHandlerName = []byte("AddVectoredContinueHandler\x00")
- getQueuedCompletionStatusExName = []byte("GetQueuedCompletionStatusEx\x00")
-)
-
func osinit() {
setBadSignalMsg()
- kernel32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32Name[0])))
+ loadOptionalSyscalls()
disableWER()
externalthreadhandlerp = funcPC(externalthreadhandler)
stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
- addVectoredContinueHandler := uintptr(0)
- if kernel32 != 0 {
- addVectoredContinueHandler = stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&addVectoredContinueHandlerName[0])))
- }
- if addVectoredContinueHandler == 0 || unsafe.Sizeof(&kernel32) == 4 {
+ if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 {
// use SetUnhandledExceptionFilter for windows-386 or
// if VectoredContinueHandler is unavailable.
// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
} else {
- stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 1, funcPC(firstcontinuetramp))
- stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 0, funcPC(lastcontinuetramp))
+ stdcall2(_AddVectoredContinueHandler, 1, funcPC(firstcontinuetramp))
+ stdcall2(_AddVectoredContinueHandler, 0, funcPC(lastcontinuetramp))
}
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
@@ -158,10 +183,6 @@ func osinit() {
// equivalent threads that all do a mix of GUI, IO, computations, etc.
// In such context dynamic priority boosting does nothing but harm, so we turn it off.
stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
-
- if kernel32 != 0 {
- _GetQueuedCompletionStatusEx = stdFunction(unsafe.Pointer(stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&getQueuedCompletionStatusExName[0])))))
- }
}
//go:nosplit
@@ -506,7 +527,7 @@ func profilem(mp *m) {
r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15))
r.contextflags = _CONTEXT_CONTROL
stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r)))
- dosigprof(r, gp, mp)
+ sigprof((*byte)(unsafe.Pointer(r.ip())), (*byte)(unsafe.Pointer(r.sp())), nil, gp, mp)
}
func profileloop1() {
diff --git a/src/runtime/os1_windows_386.go b/src/runtime/os1_windows_386.go
index 7b4fdfe94a..b7eae204d1 100644
--- a/src/runtime/os1_windows_386.go
+++ b/src/runtime/os1_windows_386.go
@@ -118,7 +118,3 @@ func sigenable(sig uint32) {
func sigdisable(sig uint32) {
}
-
-func dosigprof(r *context, gp *g, mp *m) {
- sigprof((*byte)(unsafe.Pointer(uintptr(r.eip))), (*byte)(unsafe.Pointer(uintptr(r.esp))), nil, gp, mp)
-}
diff --git a/src/runtime/os1_windows_amd64.go b/src/runtime/os1_windows_amd64.go
index c211f6fd91..4163fcf23d 100644
--- a/src/runtime/os1_windows_amd64.go
+++ b/src/runtime/os1_windows_amd64.go
@@ -137,7 +137,3 @@ func sigenable(sig uint32) {
func sigdisable(sig uint32) {
}
-
-func dosigprof(r *context, gp *g, mp *m) {
- sigprof((*byte)(unsafe.Pointer(uintptr(r.rip))), (*byte)(unsafe.Pointer(uintptr(r.rsp))), nil, gp, mp)
-}
diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go
index 58ca0e7b2f..facaab2546 100644
--- a/src/runtime/os3_plan9.go
+++ b/src/runtime/os3_plan9.go
@@ -72,9 +72,9 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int {
return _NCONT
}
if flags&_SigNotify != 0 {
- // TODO(ality): See if os/signal wants it.
- //if(sigsend(...))
- // return _NCONT;
+ if sendNote(note) {
+ return _NCONT
+ }
}
if flags&_SigKill != 0 {
goto Exit
diff --git a/src/runtime/os_darwin_arm.go b/src/runtime/os_darwin_arm.go
new file mode 100644
index 0000000000..d3336c012a
--- /dev/null
+++ b/src/runtime/os_darwin_arm.go
@@ -0,0 +1,17 @@
+// Copyright 2014 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
+
+func checkgoarm() {
+ return // TODO(minux)
+}
+
+//go:nosplit
+func cputicks() int64 {
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+ // TODO: need more entropy to better seed fastrand1.
+ return nanotime()
+}
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index 679bf34519..870404b948 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -6,6 +6,11 @@ package runtime
import "unsafe"
+func close(fd int32) int32
+
+//go:noescape
+func open(name *byte, mode, perm int32) int32
+
//go:noescape
func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
diff --git a/src/runtime/os_windows_386.go b/src/runtime/os_windows_386.go
deleted file mode 100644
index 86a1906c0c..0000000000
--- a/src/runtime/os_windows_386.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2014 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
-
-// contextPC returns the EIP (program counter) register from the context.
-func contextPC(r *context) uintptr { return uintptr(r.eip) }
-
-// contextSP returns the ESP (stack pointer) register from the context.
-func contextSP(r *context) uintptr { return uintptr(r.esp) }
diff --git a/src/runtime/os_windows_amd64.go b/src/runtime/os_windows_amd64.go
deleted file mode 100644
index 3f4d4d07cb..0000000000
--- a/src/runtime/os_windows_amd64.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2014 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
-
-// contextPC returns the RIP (program counter) register from the context.
-func contextPC(r *context) uintptr { return uintptr(r.rip) }
-
-// contextSP returns the RSP (stack pointer) register from the context.
-func contextSP(r *context) uintptr { return uintptr(r.rsp) }
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index c8f6de1ac8..027416a9ec 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -32,7 +32,9 @@ func main() {
maxstacksize = 250000000
}
- systemstack(newsysmon)
+ systemstack(func() {
+ newm(sysmon, nil)
+ })
// Lock the main goroutine onto this, the main OS thread,
// during initialization. Most programs won't care, but a few
@@ -110,7 +112,6 @@ func init() {
func forcegchelper() {
forcegc.g = getg()
- forcegc.g.issystem = true
for {
lock(&forcegc.lock)
if forcegc.idle != 0 {
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
index 70addbffad..471ffc83a3 100644
--- a/src/runtime/proc1.go
+++ b/src/runtime/proc1.go
@@ -81,10 +81,6 @@ func schedinit() {
}
}
-func newsysmon() {
- _newm(sysmon, nil)
-}
-
func dumpgstatus(gp *g) {
_g_ := getg()
print("runtime: gp: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
@@ -638,7 +634,7 @@ func starttheworld() {
notewakeup(&mp.park)
} else {
// Start M to run P. Do not start another M below.
- _newm(nil, p)
+ newm(nil, p)
add = false
}
}
@@ -658,7 +654,7 @@ func starttheworld() {
// coordinate. This lazy approach works out in practice:
// we don't mind if the first couple gc rounds don't have quite
// the maximum number of procs.
- _newm(mhelpgc, nil)
+ newm(mhelpgc, nil)
}
_g_.m.locks--
if _g_.m.locks == 0 && _g_.preempt { // restore the preemption request in case we've cleared it in newstack
@@ -960,7 +956,7 @@ func unlockextra(mp *m) {
}
// Create a new m. It will start off with a call to fn, or else the scheduler.
-func _newm(fn func(), _p_ *p) {
+func newm(fn func(), _p_ *p) {
mp := allocm(_p_)
mp.nextp = _p_
mp.mstartfn = *(*unsafe.Pointer)(unsafe.Pointer(&fn))
@@ -1037,7 +1033,7 @@ func startm(_p_ *p, spinning bool) {
if spinning {
fn = mspinning
}
- _newm(fn, _p_)
+ newm(fn, _p_)
return
}
if mp.spinning {
@@ -2636,7 +2632,7 @@ func checkdead() {
lock(&allglock)
for i := 0; i < len(allgs); i++ {
gp := allgs[i]
- if gp.issystem {
+ if isSystemGoroutine(gp) {
continue
}
s := readgstatus(gp)
@@ -2667,7 +2663,7 @@ func checkdead() {
}
mp := mget()
if mp == nil {
- _newm(nil, _p_)
+ newm(nil, _p_)
} else {
mp.nextp = _p_
notewakeup(&mp.park)
diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go
index 3b78b01ca3..88cd48486a 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -435,6 +435,18 @@ func BenchmarkCreateGoroutinesCapture(b *testing.B) {
}
}
+func BenchmarkClosureCall(b *testing.B) {
+ sum := 0
+ off1 := 1
+ for i := 0; i < b.N; i++ {
+ off2 := 2
+ func() {
+ sum += i + off1 + off2
+ }()
+ }
+ _ = sum
+}
+
type Matrix [][]float64
func BenchmarkMatmult(b *testing.B) {
diff --git a/src/runtime/race/race_test.go b/src/runtime/race/race_test.go
index 7e0ee866a6..f4caff0ed4 100644
--- a/src/runtime/race/race_test.go
+++ b/src/runtime/race/race_test.go
@@ -152,7 +152,7 @@ func runTests() ([]byte, error) {
}
cmd.Env = append(cmd.Env, env)
}
- cmd.Env = append(cmd.Env, `GORACE="suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0"`)
+ cmd.Env = append(cmd.Env, `GORACE=suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0`)
return cmd.CombinedOutput()
}
diff --git a/src/runtime/race/testdata/slice_test.go b/src/runtime/race/testdata/slice_test.go
index 5702d1ac85..32ae878970 100644
--- a/src/runtime/race/testdata/slice_test.go
+++ b/src/runtime/race/testdata/slice_test.go
@@ -144,6 +144,54 @@ func TestNoRaceSliceCopyRead(t *testing.T) {
<-ch
}
+func TestRacePointerSliceCopyRead(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]*int, 10)
+ b := make([]*int, 10)
+ go func() {
+ _ = a[5]
+ ch <- true
+ }()
+ copy(a, b)
+ <-ch
+}
+
+func TestNoRacePointerSliceWriteCopy(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]*int, 10)
+ b := make([]*int, 10)
+ go func() {
+ a[5] = new(int)
+ ch <- true
+ }()
+ copy(a[:5], b[:5])
+ <-ch
+}
+
+func TestRacePointerSliceCopyWrite2(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]*int, 10)
+ b := make([]*int, 10)
+ go func() {
+ b[5] = new(int)
+ ch <- true
+ }()
+ copy(a, b)
+ <-ch
+}
+
+func TestNoRacePointerSliceCopyRead(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]*int, 10)
+ b := make([]*int, 10)
+ go func() {
+ _ = b[5]
+ ch <- true
+ }()
+ copy(a, b)
+ <-ch
+}
+
func TestNoRaceSliceWriteSlice2(t *testing.T) {
ch := make(chan bool, 1)
a := make([]float64, 10)
@@ -395,6 +443,53 @@ func TestRaceSliceAppendString(t *testing.T) {
<-c
}
+func TestRacePointerSliceAppend(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]*int, 10, 20)
+ go func() {
+ _ = append(s, new(int))
+ c <- true
+ }()
+ _ = append(s, new(int))
+ <-c
+}
+
+func TestRacePointerSliceAppendWrite(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]*int, 10)
+ go func() {
+ _ = append(s, new(int))
+ c <- true
+ }()
+ s[0] = new(int)
+ <-c
+}
+
+func TestRacePointerSliceAppendSlice(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]*int, 10)
+ go func() {
+ s2 := make([]*int, 10)
+ _ = append(s, s2...)
+ c <- true
+ }()
+ s[0] = new(int)
+ <-c
+}
+
+func TestRacePointerSliceAppendSlice2(t *testing.T) {
+ c := make(chan bool, 1)
+ s := make([]*int, 10)
+ s2foobar := make([]*int, 10)
+ go func() {
+ _ = append(s, s2foobar...)
+ c <- true
+ }()
+ println("WRITE:", &s2foobar[5])
+ s2foobar[5] = nil
+ <-c
+}
+
func TestNoRaceSliceIndexAccess(t *testing.T) {
c := make(chan bool, 1)
s := make([]int, 10)
diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s
index 972cbe3f8a..267cd6cec4 100644
--- a/src/runtime/race_amd64.s
+++ b/src/runtime/race_amd64.s
@@ -383,8 +383,9 @@ TEXT runtime·racesymbolizethunk(SB), NOSPLIT, $56-8
MOVQ g_m(R13), R13
MOVQ m_g0(R13), R14
MOVQ R14, g(R12) // g = m->g0
- MOVQ RARG0, 0(SP) // func arg
+ PUSHQ RARG0 // func arg
CALL runtime·racesymbolize(SB)
+ POPQ R12
// All registers are smashed after Go code, reload.
get_tls(R12)
MOVQ g(R12), R13
diff --git a/src/runtime/rt0_darwin_arm.s b/src/runtime/rt0_darwin_arm.s
new file mode 100644
index 0000000000..4d31e3a78a
--- /dev/null
+++ b/src/runtime/rt0_darwin_arm.s
@@ -0,0 +1,18 @@
+// Copyright 2014 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 "textflag.h"
+
+TEXT _rt0_arm_darwin(SB),7,$-4
+ // prepare arguments for main (_rt0_go)
+ MOVW (R13), R0 // argc
+ MOVW $4(R13), R1 // argv
+ MOVW $main(SB), R4
+ B (R4)
+
+TEXT main(SB),NOSPLIT,$-8
+ // save argc and argv onto stack
+ MOVM.DB.W [R0-R1], (R13)
+ MOVW $runtime·rt0_go(SB), R4
+ B (R4)
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index 4a74dd372a..4911dc000d 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -1,21 +1,23 @@
package runtime_test
import (
+ "fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
+ "runtime"
"testing"
)
func checkGdbPython(t *testing.T) {
- cmd := exec.Command("gdb", "-nx", "-q", "--batch", "-ex", "python import sys; print('golang gdb python support')")
+ cmd := exec.Command("gdb", "-nx", "-q", "--batch", "-iex", "python import sys; print('go gdb python support')")
out, err := cmd.CombinedOutput()
if err != nil {
- t.Skipf("skipping due to issue running gdb%v", err)
+ t.Skipf("skipping due to issue running gdb: %v", err)
}
- if string(out) != "golang gdb python support\n" {
+ if string(out) != "go gdb python support\n" {
t.Skipf("skipping due to lack of python gdb support: %s", out)
}
}
@@ -29,7 +31,6 @@ func main() {
`
func TestGdbLoadRuntimeSupport(t *testing.T) {
-
checkGdbPython(t)
dir, err := ioutil.TempDir("", "go-build")
@@ -51,7 +52,8 @@ func TestGdbLoadRuntimeSupport(t *testing.T) {
t.Fatalf("building source %v\n%s", err, out)
}
- got, _ := exec.Command("gdb", "-nx", "-q", "--batch", "-ex", "source runtime-gdb.py",
+ got, _ := exec.Command("gdb", "-nx", "-q", "--batch", "-iex",
+ fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()),
filepath.Join(dir, "a.exe")).CombinedOutput()
if string(got) != "Loading Go Runtime support.\n" {
t.Fatalf("%s", got)
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index e38d11a59d..ca3e7d564e 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -199,7 +199,6 @@ type g struct {
waitsince int64 // approx time when the g become blocked
waitreason string // if status==gwaiting
schedlink *g
- issystem bool // do not output in stack dump, ignore in deadlock detector
preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
paniconfault bool // panic (instead of crash) on unexpected fault address
preemptscan bool // preempted g does scan for gc
@@ -275,6 +274,7 @@ type m struct {
waitsemacount uint32
waitsemalock uint32
gcstats gcstats
+ currentwbuf uintptr // use locks or atomic operations such as xchguinptr to access.
needextram bool
traceback uint8
waitunlockf unsafe.Pointer // todo go func(*g, unsafe.pointer) bool
diff --git a/src/runtime/signal_darwin_arm.go b/src/runtime/signal_darwin_arm.go
new file mode 100644
index 0000000000..1441a655ef
--- /dev/null
+++ b/src/runtime/signal_darwin_arm.go
@@ -0,0 +1,44 @@
+// Copyright 2014 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
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *regs32 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+func (c *sigctxt) r0() uint32 { return c.regs().r[0] }
+func (c *sigctxt) r1() uint32 { return c.regs().r[1] }
+func (c *sigctxt) r2() uint32 { return c.regs().r[2] }
+func (c *sigctxt) r3() uint32 { return c.regs().r[3] }
+func (c *sigctxt) r4() uint32 { return c.regs().r[4] }
+func (c *sigctxt) r5() uint32 { return c.regs().r[5] }
+func (c *sigctxt) r6() uint32 { return c.regs().r[6] }
+func (c *sigctxt) r7() uint32 { return c.regs().r[7] }
+func (c *sigctxt) r8() uint32 { return c.regs().r[8] }
+func (c *sigctxt) r9() uint32 { return c.regs().r[9] }
+func (c *sigctxt) r10() uint32 { return c.regs().r[10] }
+func (c *sigctxt) fp() uint32 { return c.regs().r[11] }
+func (c *sigctxt) ip() uint32 { return c.regs().r[12] }
+func (c *sigctxt) sp() uint32 { return c.regs().sp }
+func (c *sigctxt) lr() uint32 { return c.regs().lr }
+func (c *sigctxt) pc() uint32 { return c.regs().pc }
+func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr }
+func (c *sigctxt) fault() uint32 { return uint32(uintptr(unsafe.Pointer(c.info.si_addr))) }
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) trap() uint32 { return 0 }
+func (c *sigctxt) error() uint32 { return 0 }
+func (c *sigctxt) oldmask() uint32 { return 0 }
+
+func (c *sigctxt) set_pc(x uint32) { c.regs().pc = x }
+func (c *sigctxt) set_sp(x uint32) { c.regs().sp = x }
+func (c *sigctxt) set_lr(x uint32) { c.regs().lr = x }
+func (c *sigctxt) set_r10(x uint32) { c.regs().r[10] = x }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = (*byte)(unsafe.Pointer(uintptr(x))) }
diff --git a/src/runtime/signals_windows.h b/src/runtime/signals_windows.h
deleted file mode 100644
index 6943714b0f..0000000000
--- a/src/runtime/signals_windows.h
+++ /dev/null
@@ -1,3 +0,0 @@
-// Copyright 2011 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.
diff --git a/src/runtime/sigqueue.go b/src/runtime/sigqueue.go
index fbe3425fa6..5cfc926f67 100644
--- a/src/runtime/sigqueue.go
+++ b/src/runtime/sigqueue.go
@@ -24,6 +24,8 @@
// unnecessary rechecks of sig.mask, but it cannot lead to missed signals
// nor deadlocks.
+// +build !plan9
+
package runtime
import "unsafe"
diff --git a/src/runtime/sigqueue_plan9.go b/src/runtime/sigqueue_plan9.go
new file mode 100644
index 0000000000..b029a300a8
--- /dev/null
+++ b/src/runtime/sigqueue_plan9.go
@@ -0,0 +1,115 @@
+// 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.
+
+// This file implements runtime support for signal handling.
+
+package runtime
+
+const qsize = 64
+
+var sig struct {
+ q noteQueue
+ inuse bool
+
+ lock mutex
+ note note
+ sleeping bool
+}
+
+type noteQueue struct {
+ lock mutex
+ data [qsize]*byte
+ ri int
+ wi int
+ full bool
+}
+
+func (q *noteQueue) push(item *byte) bool {
+ lock(&q.lock)
+ if q.full {
+ unlock(&q.lock)
+ return false
+ }
+ q.data[q.wi] = item
+ q.wi++
+ if q.wi == qsize {
+ q.wi = 0
+ }
+ if q.wi == q.ri {
+ q.full = true
+ }
+ unlock(&q.lock)
+ return true
+}
+
+func (q *noteQueue) pop() *byte {
+ lock(&q.lock)
+ q.full = false
+ if q.ri == q.wi {
+ unlock(&q.lock)
+ return nil
+ }
+ item := q.data[q.ri]
+ q.ri++
+ if q.ri == qsize {
+ q.ri = 0
+ }
+ unlock(&q.lock)
+ return item
+}
+
+// Called from sighandler to send a signal back out of the signal handling thread.
+// Reports whether the signal was sent. If not, the caller typically crashes the program.
+func sendNote(s *byte) bool {
+ if !sig.inuse {
+ return false
+ }
+
+ // Add signal to outgoing queue.
+ if !sig.q.push(s) {
+ return false
+ }
+
+ lock(&sig.lock)
+ if sig.sleeping {
+ sig.sleeping = false
+ notewakeup(&sig.note)
+ }
+ unlock(&sig.lock)
+
+ return true
+}
+
+// Called to receive the next queued signal.
+// Must only be called from a single goroutine at a time.
+func signal_recv() string {
+ for {
+ note := sig.q.pop()
+ if note != nil {
+ return gostring(note)
+ }
+
+ lock(&sig.lock)
+ sig.sleeping = true
+ noteclear(&sig.note)
+ unlock(&sig.lock)
+ notetsleepg(&sig.note, -1)
+ }
+}
+
+// Must only be called from a single goroutine at a time.
+func signal_enable(s uint32) {
+ if !sig.inuse {
+ // The first call to signal_enable is for us
+ // to use for initialization. It does not pass
+ // signal information in m.
+ sig.inuse = true // enable reception of signals; cannot disable
+ noteclear(&sig.note)
+ return
+ }
+}
+
+// Must only be called from a single goroutine at a time.
+func signal_disable(s uint32) {
+}
diff --git a/src/runtime/stack.h b/src/runtime/stack.h
index b790e70103..88c7e02f40 100644
--- a/src/runtime/stack.h
+++ b/src/runtime/stack.h
@@ -7,14 +7,22 @@
enum {
#ifdef GOOS_windows
-#define StackSystem (512*sizeof(uintptr))
-#else
+#define STACKSYSTEM (512 * sizeof(uintptr))
+#endif // GOOS_windows
#ifdef GOOS_plan9
-#define StackSystem (512)
-#else
- StackSystem = 0,
-#endif // Plan 9
-#endif // Windows
+#define STACKSYSTEM 512
+#endif // GOOS_plan9
+#ifdef GOOS_darwin
+#ifdef GOARCH_arm
+#define STACKSYSTEM 1024
+#endif // GOARCH_arm
+#endif // GOOS_darwin
+
+#ifndef STACKSYSTEM
+#define STACKSYSTEM 0
+#endif
+
+ StackSystem = STACKSYSTEM,
StackBig = 4096,
StackGuard = 640 + StackSystem,
diff --git a/src/runtime/stack2.go b/src/runtime/stack2.go
index 8a78b1ad96..07a7d38f0c 100644
--- a/src/runtime/stack2.go
+++ b/src/runtime/stack2.go
@@ -57,9 +57,9 @@ functions to make sure that this limit cannot be violated.
const (
// StackSystem is a number of additional bytes to add
// to each stack below the usual guard area for OS-specific
- // purposes like signal handling. Used on Windows and on
- // Plan 9 because they do not use a separate stack.
- _StackSystem = goos_windows*512*ptrSize + goos_plan9*512
+ // purposes like signal handling. Used on Windows, Plan 9,
+ // and Darwin/ARM because they do not use a separate stack.
+ _StackSystem = goos_windows*512*ptrSize + goos_plan9*512 + goos_darwin*goarch_arm*1024
// The minimum size of stack used by Go code
_StackMin = 2048
diff --git a/src/runtime/string.go b/src/runtime/string.go
index 46c3502f77..0ba309cf02 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -129,8 +129,13 @@ func slicebytetostringtmp(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
-func stringtoslicebyte(s string) []byte {
- b := rawbyteslice(len(s))
+func stringtoslicebyte(buf *tmpBuf, s string) []byte {
+ var b []byte
+ if buf != nil && len(s) <= len(buf) {
+ b = buf[:len(s)]
+ } else {
+ b = rawbyteslice(len(s))
+ }
copy(b, s)
return b
}
@@ -147,7 +152,7 @@ func stringtoslicebytetmp(s string) []byte {
return *(*[]byte)(unsafe.Pointer(&ret))
}
-func stringtoslicerune(s string) []rune {
+func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
// two passes.
// unlike slicerunetostring, no race because strings are immutable.
n := 0
@@ -157,7 +162,12 @@ func stringtoslicerune(s string) []rune {
s = s[k:]
n++
}
- a := rawruneslice(n)
+ var a []rune
+ if buf != nil && n <= len(buf) {
+ a = buf[:n]
+ } else {
+ a = rawruneslice(n)
+ }
n = 0
for len(t) > 0 {
r, k := charntorune(t)
@@ -168,7 +178,7 @@ func stringtoslicerune(s string) []rune {
return a
}
-func slicerunetostring(a []rune) string {
+func slicerunetostring(buf *tmpBuf, a []rune) string {
if raceenabled && len(a) > 0 {
racereadrangepc(unsafe.Pointer(&a[0]),
uintptr(len(a))*unsafe.Sizeof(a[0]),
@@ -180,7 +190,7 @@ func slicerunetostring(a []rune) string {
for _, r := range a {
size1 += runetochar(dum[:], r)
}
- s, b := rawstring(size1 + 3)
+ s, b := rawstringtmp(buf, size1+3)
size2 := 0
for _, r := range a {
// check for race
@@ -309,11 +319,6 @@ func gobytes(p *byte, n int) []byte {
return x
}
-func gostringsize(n int) string {
- s, _ := rawstring(n)
- return s
-}
-
func gostring(p *byte) string {
l := findnull(p)
if l == 0 {
diff --git a/src/runtime/stubs3.go b/src/runtime/stubs3.go
deleted file mode 100644
index ffaa28775d..0000000000
--- a/src/runtime/stubs3.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2014 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.
-
-// +build plan9
-
-package runtime
-
-func close(fd int32) int32
-
-//go:noescape
-func open(name *byte, mode, perm int32) int32
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index db20ab11e1..3e46d428f7 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -44,8 +44,8 @@ type functab struct {
funcoff uintptr
}
-const minfunc = 16 // minimum function size
-const pcbucketsize = 256*minfunc // size of bucket in the pc->func lookup table
+const minfunc = 16 // minimum function size
+const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table
// findfunctab is an array of these structures.
// Each bucket represents 4096 bytes of the text segment.
@@ -56,7 +56,7 @@ const pcbucketsize = 256*minfunc // size of bucket in the pc->func lookup table
// index to find the target function.
// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
type findfuncbucket struct {
- idx uint32
+ idx uint32
subbuckets [16]byte
}
@@ -154,9 +154,9 @@ func findfunc(pc uintptr) *_func {
x := pc - minpc
b := x / pcbucketsize
- i := x % pcbucketsize / (pcbucketsize/nsub)
+ i := x % pcbucketsize / (pcbucketsize / nsub)
- ffb := (*findfuncbucket)(add(unsafe.Pointer(&findfunctab), b * unsafe.Sizeof(findfuncbucket{})))
+ ffb := (*findfuncbucket)(add(unsafe.Pointer(&findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
idx := ffb.idx + uint32(ffb.subbuckets[i])
if pc < ftab[idx].entry {
throw("findfunc: bad findfunctab entry")
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
new file mode 100644
index 0000000000..e1b2b664b6
--- /dev/null
+++ b/src/runtime/sys_darwin_arm.s
@@ -0,0 +1,481 @@
+// Copyright 2014 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.
+
+// System calls and other sys.stuff for ARM, Darwin
+// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
+// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+// Copied from /usr/include/sys/syscall.h
+#define SYS_exit 1
+#define SYS_read 3
+#define SYS_write 4
+#define SYS_open 5
+#define SYS_close 6
+#define SYS_mmap 197
+#define SYS_munmap 73
+#define SYS_madvise 75
+#define SYS_mincore 78
+#define SYS_gettimeofday 116
+#define SYS_kill 37
+#define SYS_getpid 20
+#define SYS___pthread_kill 328
+#define SYS_setitimer 83
+#define SYS___sysctl 202
+#define SYS_sigprocmask 48
+#define SYS_sigaction 46
+#define SYS_sigreturn 184
+#define SYS_select 93
+#define SYS_bsdthread_register 366
+#define SYS_bsdthread_create 360
+#define SYS_bsdthread_terminate 361
+#define SYS_kqueue 362
+#define SYS_kevent 363
+#define SYS_fcntl 92
+
+TEXT notok<>(SB),NOSPLIT,$0
+ MOVW $0, R8
+ MOVW R8, (R8)
+ B 0(PC)
+
+TEXT runtime·open(SB),NOSPLIT,$0
+ MOVW name+0(FP), R0
+ MOVW mode+4(FP), R1
+ MOVW perm+8(FP), R2
+ MOVW $SYS_open, R12
+ SWI $0x80
+ MOVW R0, ret+12(FP)
+ RET
+
+TEXT runtime·close(SB),NOSPLIT,$0
+ MOVW fd+0(FP), R0
+ MOVW $SYS_close, R12
+ SWI $0x80
+ MOVW R0, ret+4(FP)
+ RET
+
+TEXT runtime·write(SB),NOSPLIT,$0
+ MOVW fd+0(FP), R0
+ MOVW p+4(FP), R1
+ MOVW n+8(FP), R2
+ MOVW $SYS_write, R12
+ SWI $0x80
+ MOVW R0, ret+12(FP)
+ RET
+
+TEXT runtime·read(SB),NOSPLIT,$0
+ MOVW fd+0(FP), R0
+ MOVW p+4(FP), R1
+ MOVW n+8(FP), R2
+ MOVW $SYS_read, R12
+ SWI $0x80
+ MOVW R0, ret+12(FP)
+ RET
+
+TEXT runtime·exit(SB),NOSPLIT,$-4
+ MOVW 0(FP), R0
+ MOVW $SYS_exit, R12
+ SWI $0x80
+ MOVW $1234, R0
+ MOVW $1002, R1
+ MOVW R0, (R1) // fail hard
+
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
+TEXT runtime·exit1(SB),NOSPLIT,$0
+ MOVW $SYS_bsdthread_terminate, R12
+ SWI $0x80
+ MOVW $1234, R0
+ MOVW $1003, R1
+ MOVW R0, (R1) // fail hard
+
+TEXT runtime·raise(SB),NOSPLIT,$24
+ MOVW $SYS_getpid, R12
+ SWI $0x80
+ // arg 1 pid already in R0 from getpid
+ MOVW sig+0(FP), R1 // arg 2 - signal
+ MOVW $1, R2 // arg 3 - posix
+ MOVW $SYS_kill, R12
+ SWI $0x80
+ RET
+
+TEXT runtime·mmap(SB),NOSPLIT,$0
+ MOVW addr+0(FP), R0
+ MOVW n+4(FP), R1
+ MOVW prot+8(FP), R2
+ MOVW flags+12(FP), R3
+ MOVW fd+16(FP), R4
+ MOVW off+20(FP), R5
+ MOVW $0, R6 // off_t is uint64_t
+ MOVW $SYS_mmap, R12
+ SWI $0x80
+ MOVW R0, ret+24(FP)
+ RET
+
+TEXT runtime·munmap(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW $SYS_munmap, R12
+ SWI $0x80
+ BL.CS notok<>(SB)
+ RET
+
+TEXT runtime·madvise(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_madvise, R12
+ SWI $0x80
+ BL.CS notok<>(SB)
+ RET
+
+TEXT runtime·setitimer(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_setitimer, R12
+ SWI $0x80
+ RET
+
+TEXT runtime·mincore(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_mincore, R12
+ SWI $0x80
+ RET
+
+TEXT time·now(SB), 7, $32
+ MOVW $8(R13), R0 // timeval
+ MOVW $0, R1 // zone
+ MOVW $SYS_gettimeofday, R12
+ SWI $0x80 // Note: R0 is tv_sec, R1 is tv_usec
+
+ MOVW R1, R2 // usec
+
+ MOVW R0, 0(FP)
+ MOVW $0, R1
+ MOVW R1, 4(FP)
+ MOVW $1000, R3
+ MUL R3, R2
+ MOVW R2, 8(FP)
+ RET
+
+TEXT runtime·nanotime(SB),NOSPLIT,$32
+ MOVW $8(R13), R0 // timeval
+ MOVW $0, R1 // zone
+ MOVW $SYS_gettimeofday, R12
+ SWI $0x80 // Note: R0 is tv_sec, R1 is tv_usec
+
+ MOVW R1, R2
+ MOVW $1000000000, R3
+ MULLU R0, R3, (R1, R0)
+ MOVW $1000, R3
+ MOVW $0, R4
+ MUL R3, R2
+ ADD.S R2, R0
+ ADC R4, R1
+
+ MOVW R0, 0(FP)
+ MOVW R1, 4(FP)
+ RET
+
+// Sigtramp's job is to call the actual signal handler.
+// It is called with the following arguments on the stack:
+// LR "return address" - ignored
+// R0 actual handler
+// R1 siginfo style - ignored
+// R2 signal number
+// R3 siginfo
+// -4(FP) context, beware that 0(FP) is the saved LR
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // this might be called in external code context,
+ // where g is not set.
+ // first save R0, because runtime·load_g will clobber it
+ MOVM.DB.W [R0], (R13)
+ MOVB runtime·iscgo(SB), R0
+ CMP $0, R0
+ BL.NE runtime·load_g(SB)
+
+ CMP $0, g
+ BNE cont
+ // fake function call stack frame for badsignal
+ // we only need to pass R2 (signal number), but
+ // badsignal will expect R2 at 4(R13), so we also
+ // push R1 onto stack. turns out we do need R1
+ // to do sigreturn.
+ MOVM.DB.W [R1,R2], (R13)
+ MOVW $runtime·badsignal(SB), R11
+ BL (R11)
+ MOVM.IA.W [R1], (R13) // saved infostype
+ ADD $(4+4), R13 // +4: also need to remove the pushed R0.
+ MOVW -4(FP), R0 // load ucontext
+ B ret
+
+cont:
+ // Restore R0
+ MOVM.IA.W (R13), [R0]
+
+ // NOTE: some Darwin/ARM kernels always use the main stack to run the
+ // signal handler. We need to switch to gsignal ourselves.
+ MOVW g_m(g), R11
+ MOVW m_gsignal(R11), R5
+ MOVW (g_stack+stack_hi)(R5), R6
+ SUB $28, R6
+
+ // copy arguments for call to sighandler
+ MOVW R2, 4(R6) // signal num
+ MOVW R3, 8(R6) // signal info
+ MOVW g, 16(R6) // old_g
+ MOVW -4(FP), R4
+ MOVW R4, 12(R6) // context
+
+ // Backup ucontext and infostyle
+ MOVW R4, 20(R6)
+ MOVW R1, 24(R6)
+
+ // switch stack and g
+ MOVW R6, R13 // sigtramp can not re-entrant, so no need to back up R13.
+ MOVW R5, g
+
+ BL (R0)
+
+ // call sigreturn
+ MOVW 20(R13), R0 // saved ucontext
+ MOVW 24(R13), R1 // saved infostyle
+ret:
+ MOVW $SYS_sigreturn, R12 // sigreturn(ucontext, infostyle)
+ SWI $0x80
+
+ // if sigreturn fails, we can do nothing but exit
+ B runtime·exit(SB)
+
+TEXT runtime·sigprocmask(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_sigprocmask, R12
+ SWI $0x80
+ BL.CS notok<>(SB)
+ RET
+
+TEXT runtime·sigaction(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_sigaction, R12
+ SWI $0x80
+ RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$12
+ MOVW usec+0(FP), R0
+ MOVW R0, R1
+ MOVW $1000000, R2
+ DIV R2, R0
+ MOD R2, R1
+ MOVW R0, -12(SP)
+ MOVW R1, -8(SP)
+
+ // select(0, 0, 0, 0, &tv)
+ MOVW $0, R0
+ MOVW $0, R1
+ MOVW $0, R2
+ MOVW $0, R3
+ MOVW $-12(SP), R4
+ MOVW $SYS_select, R12
+ SWI $0x80
+ RET
+
+TEXT runtime·cas(SB),NOSPLIT,$0
+ B runtime·armcas(SB)
+
+TEXT runtime·casp1(SB),NOSPLIT,$0
+ B runtime·cas(SB)
+
+TEXT runtime·sysctl(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW 12(FP), R3
+ MOVW 16(FP), R4
+ MOVW 20(FP), R5
+ MOVW $SYS___sysctl, R12 // syscall entry
+ SWI $0x80
+ BCC sysctl_ret
+ RSB $0, R0, R0
+ MOVW R0, ret+24(FP)
+ RET
+sysctl_ret:
+ MOVW $0, R0
+ MOVW R0, ret+24(FP)
+ RET
+
+// Thread related functions
+// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
+TEXT runtime·bsdthread_create(SB),NOSPLIT,$0
+ // Set up arguments to bsdthread_create system call.
+ // The ones in quotes pass through to the thread callback
+ // uninterpreted, so we can put whatever we want there.
+ MOVW fn+12(FP), R0 // "func"
+ MOVW mm+4(FP), R1 // "arg"
+ MOVW stk+0(FP), R2 // stack
+ MOVW gg+8(FP), R3 // "pthread"
+ MOVW $0x01000000, R4 // flags = PTHREAD_START_CUSTOM
+ MOVW $0, R5 // paranoia
+ MOVW $SYS_bsdthread_create, R12
+ SWI $0x80
+ BCC create_ret
+ RSB $0, R0, R0
+ MOVW R0, ret+16(FP)
+ RET
+create_ret:
+ MOVW $0, R0
+ MOVW R0, ret+16(FP)
+ RET
+
+// The thread that bsdthread_create creates starts executing here,
+// because we registered this function using bsdthread_register
+// at startup.
+// R0 = "pthread"
+// R1 = mach thread port
+// R2 = "func" (= fn)
+// R3 = "arg" (= m)
+// R4 = stack
+// R5 = flags (= 0)
+// XXX: how to deal with R4/SP? ref: Libc-594.9.1/arm/pthreads/thread_start.s
+TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
+ MOVW R1, m_procid(R3) // thread port is m->procid
+ MOVW m_g0(R3), g
+ MOVW R3, g_m(g)
+ // ARM don't have runtime·stackcheck(SB)
+ // disable runfast mode of vfp
+ EOR R12, R12
+ WORD $0xeee1ca10 // fmxr fpscr, ip
+ BL (R2) // fn
+ BL runtime·exit1(SB)
+ RET
+
+// int32 bsdthread_register(void)
+// registers callbacks for threadstart (see bsdthread_create above
+// and wqthread and pthsize (not used). returns 0 on success.
+TEXT runtime·bsdthread_register(SB),NOSPLIT,$0
+ MOVW $runtime·bsdthread_start(SB), R0 // threadstart
+ MOVW $0, R1 // wqthread, not used by us
+ MOVW $0, R2 // pthsize, not used by us
+ MOVW $0, R3 // dummy_value [sic]
+ MOVW $0, R4 // targetconc_ptr
+ MOVW $0, R5 // dispatchqueue_offset
+ MOVW $SYS_bsdthread_register, R12 // bsdthread_register
+ SWI $0x80
+ MOVW R0, ret+0(FP)
+ RET
+
+// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
+TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW 12(FP), R3
+ MOVW 16(FP), R4
+ MOVW 20(FP), R5
+ MOVW 24(FP), R6
+ MVN $30, R12
+ SWI $0x80
+ MOVW R0, 28(FP)
+ RET
+
+TEXT runtime·mach_task_self(SB),NOSPLIT,$0
+ MVN $27, R12 // task_self_trap
+ SWI $0x80
+ MOVW R0, 0(FP)
+ RET
+
+TEXT runtime·mach_thread_self(SB),NOSPLIT,$0
+ MVN $26, R12 // thread_self_trap
+ SWI $0x80
+ MOVW R0, 0(FP)
+ RET
+
+TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
+ MVN $25, R12 // mach_reply_port
+ SWI $0x80
+ MOVW R0, 0(FP)
+ RET
+
+// Mach provides trap versions of the semaphore ops,
+// instead of requiring the use of RPC.
+
+// uint32 mach_semaphore_wait(uint32)
+TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MVN $35, R12 // semaphore_wait_trap
+ SWI $0x80
+ MOVW R0, ret+4(FP)
+ RET
+
+// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MVN $37, R12 // semaphore_timedwait_trap
+ SWI $0x80
+ MOVW R0, ret+12(FP)
+ RET
+
+// uint32 mach_semaphore_signal(uint32)
+TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MVN $32, R12 // semaphore_signal_trap
+ SWI $0x80
+ MOVW R0, ret+4(FP)
+ RET
+
+// uint32 mach_semaphore_signal_all(uint32)
+TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
+ MOVW 0(FP), R0
+ MVN $33, R12 // semaphore_signal_all_trap
+ SWI $0x80
+ MOVW R0, ret+4(FP)
+ RET
+
+// int32 runtime·kqueue(void)
+TEXT runtime·kqueue(SB),NOSPLIT,$0
+ MOVW $SYS_kqueue, R12
+ SWI $0x80
+ RSB.CS $0, R0, R0
+ MOVW R0, ret+0(FP)
+ RET
+
+// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout)
+TEXT runtime·kevent(SB),NOSPLIT,$0
+ MOVW $SYS_kevent, R12
+ MOVW kq+0(FP), R0
+ MOVW changelist+4(FP), R1
+ MOVW nchanges+8(FP), R2
+ MOVW eventlist+12(FP), R3
+ MOVW nevents+16(FP), R4
+ MOVW timeout+20(FP), R5
+ SWI $0x80
+ RSB.CS $0, R0, R0
+ MOVW R0, ret+24(FP)
+ RET
+
+// int32 runtime·closeonexec(int32 fd)
+TEXT runtime·closeonexec(SB),NOSPLIT,$0
+ MOVW $SYS_fcntl, R12
+ MOVW 0(FP), R0
+ MOVW $2, R1 // F_SETFD
+ MOVW $1, R2 // FD_CLOEXEC
+ SWI $0x80
+ RET
+
+// sigaltstack on some darwin/arm version is buggy and will always
+// run the signal handler on the main stack, so our sigtramp has
+// to do the stack switch ourselves.
+TEXT runtime·sigaltstack(SB),NOSPLIT,$0
+ RET
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 50895ca8ec..6a2cc2136c 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -153,7 +153,6 @@ func deltimer(t *timer) bool {
// If addtimer inserts a new earlier event, addtimer1 wakes timerproc early.
func timerproc() {
timers.gp = getg()
- timers.gp.issystem = true
for {
lock(&timers.lock)
timers.sleeping = false
diff --git a/src/runtime/tls_arm.s b/src/runtime/tls_arm.s
index 7c5c0e215e..d130d42cf2 100644
--- a/src/runtime/tls_arm.s
+++ b/src/runtime/tls_arm.s
@@ -15,8 +15,14 @@
// Note: both functions will clobber R0 and R11 and
// can be called from 5c ABI code.
-// On android, runtime.tlsg is a normal variable.
+// On android and darwin, runtime.tlsg is a normal variable.
// TLS offset is computed in x_cgo_inittls.
+#ifdef GOOS_android
+#define TLSG_IS_VARIABLE
+#endif
+#ifdef GOOS_darwin
+#define TLSG_IS_VARIABLE
+#endif
// save_g saves the g register into pthread-provided
// thread-local memory, so that we can call externally compiled
@@ -34,10 +40,11 @@ TEXT runtime·save_g(SB),NOSPLIT,$-4
// a call to runtime.read_tls_fallback which jumps to __kuser_get_tls.
// The replacement function saves LR in R11 over the call to read_tls_fallback.
MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+ BIC $3, R0 // Darwin/ARM might return unaligned pointer
// $runtime.tlsg(SB) is a special linker symbol.
// It is the offset from the TLS base pointer to our
// thread-local storage for g.
-#ifdef GOOS_android
+#ifdef TLSG_IS_VARIABLE
MOVW runtime·tlsg(SB), R11
#else
MOVW $runtime·tlsg(SB), R11
@@ -57,10 +64,11 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
#endif
// See save_g
MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+ BIC $3, R0 // Darwin/ARM might return unaligned pointer
// $runtime.tlsg(SB) is a special linker symbol.
// It is the offset from the TLS base pointer to our
// thread-local storage for g.
-#ifdef GOOS_android
+#ifdef TLSG_IS_VARIABLE
MOVW runtime·tlsg(SB), R11
#else
MOVW $runtime·tlsg(SB), R11
@@ -68,3 +76,28 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
ADD R11, R0
MOVW 0(R0), g
RET
+
+TEXT runtime·_initcgo(SB),NOSPLIT,$0
+#ifndef GOOS_nacl
+ // if there is an _cgo_init, call it.
+ MOVW _cgo_init(SB), R4
+ CMP $0, R4
+ B.EQ nocgo
+ MRC 15, 0, R0, C13, C0, 3 // load TLS base pointer
+ MOVW R0, R3 // arg 3: TLS base pointer
+ MOVW $runtime·tlsg(SB), R2 // arg 2: tlsg
+ MOVW $setg_gcc<>(SB), R1 // arg 1: setg
+ MOVW g, R0 // arg 0: G
+ BL (R4) // will clobber R0-R3
+#endif
+nocgo:
+ RET
+
+// void setg_gcc(G*); set g called from gcc.
+TEXT setg_gcc<>(SB),NOSPLIT,$0
+ MOVW R0, g
+ B runtime·save_g(SB)
+
+#ifdef TLSG_IS_VARIABLE
+GLOBL runtime·tlsg+0(SB), NOPTR, $4
+#endif
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 6c87d7e2e4..8c31c5abad 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -39,6 +39,11 @@ var (
mstartPC uintptr
rt0_goPC uintptr
sigpanicPC uintptr
+ runfinqPC uintptr
+ backgroundgcPC uintptr
+ bgsweepPC uintptr
+ forcegchelperPC uintptr
+ timerprocPC uintptr
systemstack_switchPC uintptr
externalthreadhandlerp uintptr // initialized elsewhere
@@ -56,6 +61,11 @@ func tracebackinit() {
mstartPC = funcPC(mstart)
rt0_goPC = funcPC(rt0_go)
sigpanicPC = funcPC(sigpanic)
+ runfinqPC = funcPC(runfinq)
+ backgroundgcPC = funcPC(backgroundgc)
+ bgsweepPC = funcPC(bgsweep)
+ forcegchelperPC = funcPC(forcegchelper)
+ timerprocPC = funcPC(timerproc)
systemstack_switchPC = funcPC(systemstack_switch)
}
@@ -606,7 +616,7 @@ func tracebackothers(me *g) {
lock(&allglock)
for _, gp := range allgs {
- if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || gp.issystem && level < 2 {
+ if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp) && level < 2 {
continue
}
print("\n")
@@ -631,3 +641,14 @@ func topofstack(f *_func) bool {
pc == rt0_goPC ||
externalthreadhandlerp != 0 && pc == externalthreadhandlerp
}
+
+// isSystemGoroutine returns true if the goroutine g must be omitted in
+// stack dumps and deadlock detector.
+func isSystemGoroutine(gp *g) bool {
+ pc := gp.startpc
+ return pc == runfinqPC && !fingRunning ||
+ pc == backgroundgcPC ||
+ pc == bgsweepPC ||
+ pc == forcegchelperPC ||
+ pc == timerprocPC
+}
diff --git a/src/sort/sort.go b/src/sort/sort.go
index b52b54ed8f..0a446c8255 100644
--- a/src/sort/sort.go
+++ b/src/sort/sort.go
@@ -296,7 +296,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
// and Jukka Teuhola; Nordic Journal of Computing 3,1 (1996), 27-40:
// The given algorithms are in-place, number of Swap and Assignments
// grow as n log n but the algorithm is not stable.
-// - "Fast Stable In-Plcae Sorting with O(n) Data Moves" J.I. Munro and
+// - "Fast Stable In-Place Sorting with O(n) Data Moves" J.I. Munro and
// V. Raman in Algorithmica (1996) 16, 115-160:
// This algorithm either needs additional 2n bits or works only if there
// are enough different elements available to encode some permutations
diff --git a/src/strconv/decimal.go b/src/strconv/decimal.go
index 42601283d2..3d7c8d1da9 100644
--- a/src/strconv/decimal.go
+++ b/src/strconv/decimal.go
@@ -12,7 +12,7 @@
package strconv
type decimal struct {
- d [800]byte // digits
+ d [800]byte // digits, big-endian representation
nd int // number of digits used
dp int // decimal point
neg bool
@@ -105,7 +105,7 @@ func (a *decimal) Assign(v uint64) {
// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
const maxShift = 27
-// Binary shift right (* 2) by k bits. k <= maxShift to avoid overflow.
+// Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow.
func rightShift(a *decimal, k uint) {
r := 0 // read pointer
w := 0 // write pointer
@@ -228,7 +228,7 @@ func prefixIsLessThan(b []byte, s string) bool {
return false
}
-// Binary shift left (/ 2) by k bits. k <= maxShift to avoid overflow.
+// Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow.
func leftShift(a *decimal, k uint) {
delta := leftcheats[k].delta
if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
diff --git a/src/strconv/ftoa.go b/src/strconv/ftoa.go
index 1a9c41b85a..f885d96e9c 100644
--- a/src/strconv/ftoa.go
+++ b/src/strconv/ftoa.go
@@ -119,7 +119,7 @@ func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
// Precision for shortest representation mode.
switch fmt {
case 'e', 'E':
- prec = digs.nd - 1
+ prec = max(digs.nd-1, 0)
case 'f':
prec = max(digs.nd-digs.dp, 0)
case 'g', 'G':
@@ -348,14 +348,13 @@ func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte {
if prec > 0 {
dst = append(dst, '.')
i := 1
- m := d.nd + prec + 1 - max(d.nd, prec+1)
- for i < m {
- dst = append(dst, d.d[i])
- i++
+ m := min(d.nd, prec+1)
+ if i < m {
+ dst = append(dst, d.d[i:m]...)
+ i = m
}
- for i <= prec {
+ for ; i <= prec; i++ {
dst = append(dst, '0')
- i++
}
}
@@ -373,27 +372,16 @@ func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte {
}
dst = append(dst, ch)
- // dddd
- var buf [3]byte
- i := len(buf)
- for exp >= 10 {
- i--
- buf[i] = byte(exp%10 + '0')
- exp /= 10
+ // dd or ddd
+ switch {
+ case exp < 10:
+ dst = append(dst, '0', byte(exp)+'0')
+ case exp < 100:
+ dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
+ default:
+ dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0')
}
- // exp < 10
- i--
- buf[i] = byte(exp + '0')
- switch i {
- case 0:
- dst = append(dst, buf[0], buf[1], buf[2])
- case 1:
- dst = append(dst, buf[1], buf[2])
- case 2:
- // leading zeroes
- dst = append(dst, '0', buf[2])
- }
return dst
}
@@ -406,11 +394,9 @@ func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte {
// integer, padded with zeros as needed.
if d.dp > 0 {
- var i int
- for i = 0; i < d.dp && i < d.nd; i++ {
- dst = append(dst, d.d[i])
- }
- for ; i < d.dp; i++ {
+ m := min(d.nd, d.dp)
+ dst = append(dst, d.d[:m]...)
+ for ; m < d.dp; m++ {
dst = append(dst, '0')
}
} else {
@@ -467,6 +453,13 @@ func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
return append(dst, buf[w:]...)
}
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
func max(a, b int) int {
if a > b {
return a
diff --git a/src/sync/atomic/asm_darwin_arm.s b/src/sync/atomic/asm_darwin_arm.s
new file mode 100644
index 0000000000..36dd4835f7
--- /dev/null
+++ b/src/sync/atomic/asm_darwin_arm.s
@@ -0,0 +1,99 @@
+// Copyright 2012 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 "textflag.h"
+
+// Darwin/ARM atomic operations.
+
+TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0
+ B ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0
+ B ·armCompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0
+ B ·CompareAndSwapUint32(SB)
+
+TEXT ·AddInt32(SB),NOSPLIT,$0
+ B ·AddUint32(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0
+ B ·armAddUint32(SB)
+
+TEXT ·AddUintptr(SB),NOSPLIT,$0
+ B ·AddUint32(SB)
+
+TEXT ·SwapInt32(SB),NOSPLIT,$0
+ B ·SwapUint32(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0
+ B ·armSwapUint32(SB)
+
+TEXT ·SwapUintptr(SB),NOSPLIT,$0
+ B ·SwapUint32(SB)
+
+TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
+ B ·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$-4
+ B ·armCompareAndSwapUint64(SB)
+
+TEXT ·AddInt64(SB),NOSPLIT,$0
+ B ·addUint64(SB)
+
+TEXT ·AddUint64(SB),NOSPLIT,$0
+ B ·addUint64(SB)
+
+TEXT ·SwapInt64(SB),NOSPLIT,$0
+ B ·swapUint64(SB)
+
+TEXT ·SwapUint64(SB),NOSPLIT,$0
+ B ·swapUint64(SB)
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0
+ B ·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-8
+ MOVW addr+0(FP), R1
+load32loop:
+ LDREX (R1), R2 // loads R2
+ STREX R2, (R1), R0 // stores R2
+ CMP $0, R0
+ BNE load32loop
+ MOVW R2, val+4(FP)
+ RET
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0
+ B ·loadUint64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0
+ B ·loadUint64(SB)
+
+TEXT ·LoadUintptr(SB),NOSPLIT,$0
+ B ·LoadUint32(SB)
+
+TEXT ·LoadPointer(SB),NOSPLIT,$0
+ B ·LoadUint32(SB)
+
+TEXT ·StoreInt32(SB),NOSPLIT,$0
+ B ·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),NOSPLIT,$0-8
+ MOVW addr+0(FP), R1
+ MOVW val+4(FP), R2
+storeloop:
+ LDREX (R1), R4 // loads R4
+ STREX R2, (R1), R0 // stores R2
+ CMP $0, R0
+ BNE storeloop
+ RET
+
+TEXT ·StoreInt64(SB),NOSPLIT,$0
+ B ·storeUint64(SB)
+
+TEXT ·StoreUint64(SB),NOSPLIT,$0
+ B ·storeUint64(SB)
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0
+ B ·StoreUint32(SB)
diff --git a/src/syscall/asm_darwin_arm.s b/src/syscall/asm_darwin_arm.s
new file mode 100644
index 0000000000..f75aa19086
--- /dev/null
+++ b/src/syscall/asm_darwin_arm.s
@@ -0,0 +1,134 @@
+// Copyright 2014 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 "textflag.h"
+
+//
+// System call support for ARM, Darwin
+//
+
+// func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT ·Syscall(SB),NOSPLIT,$0-32
+ BL runtime·entersyscall(SB)
+ MOVW 4(SP), R12
+ MOVW 8(SP), R0
+ MOVW 12(SP), R1
+ MOVW 16(SP), R2
+ SWI $0x80
+ BCC ok
+ MOVW $-1, R1
+ MOVW R1, 20(SP) // r1
+ MOVW $0, R2
+ MOVW R2, 24(SP) // r2
+ MOVW R0, 28(SP) // errno
+ BL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVW R0, 20(SP) // r1
+ MOVW R1, 24(SP) // r2
+ MOVW $0, R0
+ MOVW R0, 28(SP) // errno
+ BL runtime·exitsyscall(SB)
+ RET
+
+// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+ MOVW 4(SP), R12 // syscall entry
+ MOVW 8(SP), R0
+ MOVW 12(SP), R1
+ MOVW 16(SP), R2
+ SWI $0x80
+ BCC ok1
+ MOVW $-1, R1
+ MOVW R1, 20(SP) // r1
+ MOVW $0, R2
+ MOVW R2, 24(SP) // r2
+ MOVW R0, 28(SP) // errno
+ RET
+ok1:
+ MOVW R0, 20(SP) // r1
+ MOVW R1, 24(SP) // r2
+ MOVW $0, R0
+ MOVW R0, 28(SP) // errno
+ RET
+
+// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+TEXT ·Syscall6(SB),NOSPLIT,$0-44
+ BL runtime·entersyscall(SB)
+ MOVW 4(SP), R12 // syscall entry
+ MOVW 8(SP), R0
+ MOVW 12(SP), R1
+ MOVW 16(SP), R2
+ MOVW 20(SP), R3
+ MOVW 24(SP), R4
+ MOVW 28(SP), R5
+ SWI $0x80
+ BCC ok6
+ MOVW $-1, R1
+ MOVW R1, 32(SP) // r1
+ MOVW $0, R2
+ MOVW R2, 36(SP) // r2
+ MOVW R0, 40(SP) // errno
+ BL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVW R0, 32(SP) // r1
+ MOVW R1, 36(SP) // r2
+ MOVW $0, R0
+ MOVW R0, 40(SP) // errno
+ BL runtime·exitsyscall(SB)
+ RET
+
+// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+ MOVW 4(SP), R12 // syscall entry
+ MOVW 8(SP), R0
+ MOVW 12(SP), R1
+ MOVW 16(SP), R2
+ MOVW 20(SP), R3
+ MOVW 24(SP), R4
+ MOVW 28(SP), R5
+ SWI $0x80
+ BCC ok2
+ MOVW $-1, R1
+ MOVW R1, 32(SP) // r1
+ MOVW $0, R2
+ MOVW R2, 36(SP) // r2
+ MOVW R0, 40(SP) // errno
+ RET
+ok2:
+ MOVW R0, 32(SP) // r1
+ MOVW R1, 36(SP) // r2
+ MOVW $0, R0
+ MOVW R0, 40(SP) // errno
+ RET
+
+// Actually Syscall7.
+TEXT ·Syscall9(SB),NOSPLIT,$0-56
+ BL runtime·entersyscall(SB)
+ MOVW 4(SP), R12 // syscall entry
+ MOVW 8(SP), R0
+ MOVW 12(SP), R1
+ MOVW 16(SP), R2
+ MOVW 20(SP), R3
+ MOVW 24(SP), R4
+ MOVW 28(SP), R5
+ MOVW 32(SP), R6
+ SWI $0x80
+ BCC ok9
+ MOVW $-1, R1
+ MOVW R1, 44(SP) // r1
+ MOVW $0, R2
+ MOVW R2, 48(SP) // r2
+ MOVW R0, 52(SP) // errno
+ BL runtime·exitsyscall(SB)
+ RET
+ok9:
+ MOVW R0, 44(SP) // r1
+ MOVW R1, 48(SP) // r2
+ MOVW $0, R0
+ MOVW R0, 52(SP) // errno
+ BL runtime·exitsyscall(SB)
+ RET
+
diff --git a/src/syscall/syscall_bsd.go b/src/syscall/syscall_bsd.go
index 2556fa8746..af563910b1 100644
--- a/src/syscall/syscall_bsd.go
+++ b/src/syscall/syscall_bsd.go
@@ -68,40 +68,7 @@ func ReadDirent(fd int, buf []byte) (n int, err error) {
// actual system call is getdirentries64, 64 is a good guess.
// TODO(rsc): Can we use a single global basep for all calls?
var base = (*uintptr)(unsafe.Pointer(new(uint64)))
- n, err = Getdirentries(fd, buf, base)
-
- // On OS X 10.10 Yosemite, if you have a directory that can be returned
- // in a single getdirentries64 call (for example, a directory with one file),
- // and you read from the directory at EOF twice, you get EOF both times:
- // fd = open("dir")
- // getdirentries64(fd) // returns data
- // getdirentries64(fd) // returns 0 (EOF)
- // getdirentries64(fd) // returns 0 (EOF)
- //
- // But if you remove the file in the middle between the two calls, the
- // second call returns an error instead.
- // fd = open("dir")
- // getdirentries64(fd) // returns data
- // getdirentries64(fd) // returns 0 (EOF)
- // remove("dir/file")
- // getdirentries64(fd) // returns ENOENT/EINVAL
- //
- // Whether you get ENOENT or EINVAL depends on exactly what was
- // in the directory. It is deterministic, just data-dependent.
- //
- // This only happens in small directories. A directory containing more data
- // than fits in a 4k getdirentries64 call will return EOF correctly.
- // (It's not clear if the criteria is that the directory be split across multiple
- // getdirentries64 calls or that it be split across multiple file system blocks.)
- //
- // We could change package os to avoid the second read at EOF,
- // and maybe we should, but that's a bit involved.
- // For now, treat the EINVAL/ENOENT as EOF.
- if runtime.GOOS == "darwin" && (err == EINVAL || err == ENOENT) {
- err = nil
- }
-
- return
+ return Getdirentries(fd, buf, base)
}
// Wait status is 7 bits at bottom, either 0 (exited),
diff --git a/src/syscall/syscall_darwin_arm.go b/src/syscall/syscall_darwin_arm.go
new file mode 100644
index 0000000000..2a7d4f2db6
--- /dev/null
+++ b/src/syscall/syscall_darwin_arm.go
@@ -0,0 +1,70 @@
+// Copyright 2014 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 syscall
+
+import "unsafe"
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int32(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int32(nsec / 1e9)
+ return
+}
+
+//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
+func Gettimeofday(tv *Timeval) (err error) {
+ // The tv passed to gettimeofday must be non-nil
+ // but is otherwise unused. The answers come back
+ // in the two registers.
+ sec, usec, err := gettimeofday(tv)
+ tv.Sec = int32(sec)
+ tv.Usec = int32(usec)
+ return err
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint32(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ var length = uint64(count)
+
+ _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0)
+
+ written = int(length)
+
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index 8ac498df78..feb329f530 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -1003,13 +1003,22 @@ func Readlink(path string, buf []byte) (n int, err error) {
}
rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
- if uintptr(bytesReturned) < unsafe.Sizeof(*rdb) ||
- rdb.ReparseTag != IO_REPARSE_TAG_SYMLINK {
- // the path is not a symlink but another type of reparse point
+ var s string
+ switch rdb.ReparseTag {
+ case IO_REPARSE_TAG_SYMLINK:
+ data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
+ p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
+ s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
+ case _IO_REPARSE_TAG_MOUNT_POINT:
+ data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
+ p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
+ s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
+ default:
+ // the path is not a symlink or junction but another type of reparse
+ // point
return -1, ENOENT
}
-
- s := UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(&rdb.PathBuffer[0]))[:rdb.PrintNameLength/2])
n = copy(buf, []byte(s))
+
return n, nil
}
diff --git a/src/syscall/zerrors_darwin_arm.go b/src/syscall/zerrors_darwin_arm.go
new file mode 100644
index 0000000000..7e800d4259
--- /dev/null
+++ b/src/syscall/zerrors_darwin_arm.go
@@ -0,0 +1,1349 @@
+// mkerrors.sh
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- _const.go
+
+package syscall
+
+const (
+ AF_APPLETALK = 0x10
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_CNT = 0x15
+ AF_COIP = 0x14
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_E164 = 0x1c
+ AF_ECMA = 0x8
+ AF_HYLINK = 0xf
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x1e
+ AF_IPX = 0x17
+ AF_ISDN = 0x1c
+ AF_ISO = 0x7
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_LOCAL = 0x1
+ AF_MAX = 0x25
+ AF_NATM = 0x1f
+ AF_NDRV = 0x1b
+ AF_NETBIOS = 0x21
+ AF_NS = 0x6
+ AF_OSI = 0x7
+ AF_PPP = 0x22
+ AF_PUP = 0x4
+ AF_RESERVED_36 = 0x24
+ AF_ROUTE = 0x11
+ AF_SIP = 0x18
+ AF_SNA = 0xb
+ AF_SYSTEM = 0x20
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ B0 = 0x0
+ B110 = 0x6e
+ B115200 = 0x1c200
+ B1200 = 0x4b0
+ B134 = 0x86
+ B14400 = 0x3840
+ B150 = 0x96
+ B1800 = 0x708
+ B19200 = 0x4b00
+ B200 = 0xc8
+ B230400 = 0x38400
+ B2400 = 0x960
+ B28800 = 0x7080
+ B300 = 0x12c
+ B38400 = 0x9600
+ B4800 = 0x12c0
+ B50 = 0x32
+ B57600 = 0xe100
+ B600 = 0x258
+ B7200 = 0x1c20
+ B75 = 0x4b
+ B76800 = 0x12c00
+ B9600 = 0x2580
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc00c4279
+ BIOCGETIF = 0x4020426b
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044272
+ BIOCGRTIMEOUT = 0x4008426e
+ BIOCGSEESENT = 0x40044276
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = 0xc0044266
+ BIOCSDLT = 0x80044278
+ BIOCSETF = 0x80084267
+ BIOCSETIF = 0x8020426c
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044273
+ BIOCSRTIMEOUT = 0x8008426d
+ BIOCSSEESENT = 0x80044277
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x80000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ BRKINT = 0x2
+ CFLUSH = 0xf
+ CLOCAL = 0x8000
+ CREAD = 0x800
+ CS5 = 0x0
+ CS6 = 0x100
+ CS7 = 0x200
+ CS8 = 0x300
+ CSIZE = 0x300
+ CSTART = 0x11
+ CSTATUS = 0x14
+ CSTOP = 0x13
+ CSTOPB = 0x400
+ CSUSP = 0x1a
+ CTL_MAXNAME = 0xc
+ CTL_NET = 0x4
+ DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
+ DLT_ARCNET = 0x7
+ DLT_ATM_CLIP = 0x13
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AX25 = 0x3
+ DLT_CHAOS = 0x5
+ DLT_CHDLC = 0x68
+ DLT_C_HDLC = 0x68
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_FDDI = 0xa
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_IEEE802_11_RADIO_AVS = 0xa3
+ DLT_LINUX_SLL = 0x71
+ DLT_LOOP = 0x6c
+ DLT_NULL = 0x0
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_SERIAL = 0x32
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xc
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ DT_WHT = 0xe
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ EVFILT_AIO = -0x3
+ EVFILT_FS = -0x9
+ EVFILT_MACHPORT = -0x8
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0x9
+ EVFILT_THREADMARKER = 0x9
+ EVFILT_TIMER = -0x7
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG0 = 0x1000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_OOBAND = 0x2000
+ EV_POLL = 0x1000
+ EV_RECEIPT = 0x40
+ EV_SYSFLAGS = 0xf000
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ FLUSHO = 0x800000
+ F_ADDSIGS = 0x3b
+ F_ALLOCATEALL = 0x4
+ F_ALLOCATECONTIG = 0x2
+ F_CHKCLEAN = 0x29
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x43
+ F_FREEZE_FS = 0x35
+ F_FULLFSYNC = 0x33
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0x7
+ F_GETOWN = 0x5
+ F_GETPATH = 0x32
+ F_GLOBAL_NOCACHE = 0x37
+ F_LOG2PHYS = 0x31
+ F_MARKDEPENDENCY = 0x3c
+ F_NOCACHE = 0x30
+ F_OK = 0x0
+ F_PATHPKG_CHECK = 0x34
+ F_PEOFPOSMODE = 0x3
+ F_PREALLOCATE = 0x2a
+ F_RDADVISE = 0x2c
+ F_RDAHEAD = 0x2d
+ F_RDLCK = 0x1
+ F_READBOOTSTRAP = 0x2e
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x8
+ F_SETLKW = 0x9
+ F_SETOWN = 0x6
+ F_SETSIZE = 0x2b
+ F_THAW_FS = 0x36
+ F_UNLCK = 0x2
+ F_VOLPOSMODE = 0x4
+ F_WRITEBOOTSTRAP = 0x2f
+ F_WRLCK = 0x3
+ HUPCL = 0x4000
+ ICANON = 0x100
+ ICRNL = 0x100
+ IEXTEN = 0x400
+ IFF_ALLMULTI = 0x200
+ IFF_ALTPHYS = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_AAL5 = 0x31
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ATM = 0x25
+ IFT_BRIDGE = 0xd1
+ IFT_CARP = 0xf8
+ IFT_CEPT = 0x13
+ IFT_DS3 = 0x1e
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0x38
+ IFT_FDDI = 0xf
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_GIF = 0x37
+ IFT_HDH1822 = 0x3
+ IFT_HIPPI = 0x2f
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE8023ADLAG = 0x88
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88026 = 0xa
+ IFT_L2VLAN = 0x87
+ IFT_LAPB = 0x10
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_NSIP = 0x1b
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PDP = 0xff
+ IFT_PFLOG = 0xf5
+ IFT_PFSYNC = 0xf6
+ IFT_PPP = 0x17
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PTPSERIAL = 0x16
+ IFT_RS232 = 0x21
+ IFT_SDLC = 0x11
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_STARLAN = 0xb
+ IFT_STF = 0x39
+ IFT_T1 = 0x12
+ IFT_ULTRA = 0x1d
+ IFT_V35 = 0x2d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IGNBRK = 0x1
+ IGNCR = 0x80
+ IGNPAR = 0x4
+ IMAXBEL = 0x2000
+ INLCR = 0x40
+ INPCK = 0x10
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LINKLOCALNETNUM = 0xa9fe0000
+ IN_LOOPBACKNET = 0x7f
+ IPPROTO_3PC = 0x22
+ IPPROTO_ADFS = 0x44
+ IPPROTO_AH = 0x33
+ IPPROTO_AHIP = 0x3d
+ IPPROTO_APES = 0x63
+ IPPROTO_ARGUS = 0xd
+ IPPROTO_AX25 = 0x5d
+ IPPROTO_BHA = 0x31
+ IPPROTO_BLT = 0x1e
+ IPPROTO_BRSATMON = 0x4c
+ IPPROTO_CFTP = 0x3e
+ IPPROTO_CHAOS = 0x10
+ IPPROTO_CMTP = 0x26
+ IPPROTO_CPHB = 0x49
+ IPPROTO_CPNX = 0x48
+ IPPROTO_DDP = 0x25
+ IPPROTO_DGP = 0x56
+ IPPROTO_DIVERT = 0xfe
+ IPPROTO_DONE = 0x101
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_EMCON = 0xe
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_ETHERIP = 0x61
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_GMTP = 0x64
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HELLO = 0x3f
+ IPPROTO_HMP = 0x14
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IDPR = 0x23
+ IPPROTO_IDRP = 0x2d
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IGP = 0x55
+ IPPROTO_IGRP = 0x58
+ IPPROTO_IL = 0x28
+ IPPROTO_INLSP = 0x34
+ IPPROTO_INP = 0x20
+ IPPROTO_IP = 0x0
+ IPPROTO_IPCOMP = 0x6c
+ IPPROTO_IPCV = 0x47
+ IPPROTO_IPEIP = 0x5e
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPPC = 0x43
+ IPPROTO_IPV4 = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_IRTP = 0x1c
+ IPPROTO_KRYPTOLAN = 0x41
+ IPPROTO_LARP = 0x5b
+ IPPROTO_LEAF1 = 0x19
+ IPPROTO_LEAF2 = 0x1a
+ IPPROTO_MAX = 0x100
+ IPPROTO_MAXID = 0x34
+ IPPROTO_MEAS = 0x13
+ IPPROTO_MHRP = 0x30
+ IPPROTO_MICP = 0x5f
+ IPPROTO_MTP = 0x5c
+ IPPROTO_MUX = 0x12
+ IPPROTO_ND = 0x4d
+ IPPROTO_NHRP = 0x36
+ IPPROTO_NONE = 0x3b
+ IPPROTO_NSP = 0x1f
+ IPPROTO_NVPII = 0xb
+ IPPROTO_OSPFIGP = 0x59
+ IPPROTO_PGM = 0x71
+ IPPROTO_PIGP = 0x9
+ IPPROTO_PIM = 0x67
+ IPPROTO_PRM = 0x15
+ IPPROTO_PUP = 0xc
+ IPPROTO_PVP = 0x4b
+ IPPROTO_RAW = 0xff
+ IPPROTO_RCCMON = 0xa
+ IPPROTO_RDP = 0x1b
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_RVD = 0x42
+ IPPROTO_SATEXPAK = 0x40
+ IPPROTO_SATMON = 0x45
+ IPPROTO_SCCSP = 0x60
+ IPPROTO_SDRP = 0x2a
+ IPPROTO_SEP = 0x21
+ IPPROTO_SRPC = 0x5a
+ IPPROTO_ST = 0x7
+ IPPROTO_SVMTP = 0x52
+ IPPROTO_SWIPE = 0x35
+ IPPROTO_TCF = 0x57
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_TPXX = 0x27
+ IPPROTO_TRUNK1 = 0x17
+ IPPROTO_TRUNK2 = 0x18
+ IPPROTO_TTP = 0x54
+ IPPROTO_UDP = 0x11
+ IPPROTO_VINES = 0x53
+ IPPROTO_VISA = 0x46
+ IPPROTO_VMTP = 0x51
+ IPPROTO_WBEXPAK = 0x4f
+ IPPROTO_WBMON = 0x4e
+ IPPROTO_WSN = 0x4a
+ IPPROTO_XNET = 0xf
+ IPPROTO_XTP = 0x24
+ IPV6_BINDV6ONLY = 0x1b
+ IPV6_CHECKSUM = 0x1a
+ IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+ IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+ IPV6_DEFHLIM = 0x40
+ IPV6_DSTOPTS = 0x17
+ IPV6_FAITH = 0x1d
+ IPV6_FLOWINFO_MASK = 0xffffff0f
+ IPV6_FLOWLABEL_MASK = 0xffff0f00
+ IPV6_FRAGTTL = 0x78
+ IPV6_FW_ADD = 0x1e
+ IPV6_FW_DEL = 0x1f
+ IPV6_FW_FLUSH = 0x20
+ IPV6_FW_GET = 0x22
+ IPV6_FW_ZERO = 0x21
+ IPV6_HLIMDEC = 0x1
+ IPV6_HOPLIMIT = 0x14
+ IPV6_HOPOPTS = 0x16
+ IPV6_IPSEC_POLICY = 0x1c
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MAXHLIM = 0xff
+ IPV6_MAXPACKET = 0xffff
+ IPV6_MMTU = 0x500
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_NEXTHOP = 0x15
+ IPV6_PKTINFO = 0x13
+ IPV6_PKTOPTIONS = 0x19
+ IPV6_PORTRANGE = 0xe
+ IPV6_PORTRANGE_DEFAULT = 0x0
+ IPV6_PORTRANGE_HIGH = 0x1
+ IPV6_PORTRANGE_LOW = 0x2
+ IPV6_RTHDR = 0x18
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_SOCKOPT_RESERVED1 = 0x3
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_V6ONLY = 0x1b
+ IPV6_VERSION = 0x60
+ IPV6_VERSION_MASK = 0xf0
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_DUMMYNET_CONFIGURE = 0x3c
+ IP_DUMMYNET_DEL = 0x3d
+ IP_DUMMYNET_FLUSH = 0x3e
+ IP_DUMMYNET_GET = 0x40
+ IP_FAITH = 0x16
+ IP_FW_ADD = 0x28
+ IP_FW_DEL = 0x29
+ IP_FW_FLUSH = 0x2a
+ IP_FW_GET = 0x2c
+ IP_FW_RESETLOG = 0x2d
+ IP_FW_ZERO = 0x2b
+ IP_HDRINCL = 0x2
+ IP_IPSEC_POLICY = 0x15
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0x14
+ IP_MF = 0x2000
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_MULTICAST_VIF = 0xe
+ IP_NAT__XXX = 0x37
+ IP_OFFMASK = 0x1fff
+ IP_OLD_FW_ADD = 0x32
+ IP_OLD_FW_DEL = 0x33
+ IP_OLD_FW_FLUSH = 0x34
+ IP_OLD_FW_GET = 0x36
+ IP_OLD_FW_RESETLOG = 0x38
+ IP_OLD_FW_ZERO = 0x35
+ IP_OPTIONS = 0x1
+ IP_PKTINFO = 0x1a
+ IP_PORTRANGE = 0x13
+ IP_PORTRANGE_DEFAULT = 0x0
+ IP_PORTRANGE_HIGH = 0x1
+ IP_PORTRANGE_LOW = 0x2
+ IP_RECVDSTADDR = 0x7
+ IP_RECVIF = 0x14
+ IP_RECVOPTS = 0x5
+ IP_RECVPKTINFO = 0x1a
+ IP_RECVRETOPTS = 0x6
+ IP_RECVTTL = 0x18
+ IP_RETOPTS = 0x8
+ IP_RF = 0x8000
+ IP_RSVP_OFF = 0x10
+ IP_RSVP_ON = 0xf
+ IP_RSVP_VIF_OFF = 0x12
+ IP_RSVP_VIF_ON = 0x11
+ IP_STRIPHDR = 0x17
+ IP_TOS = 0x3
+ IP_TRAFFIC_MGT_BACKGROUND = 0x41
+ IP_TTL = 0x4
+ ISIG = 0x80
+ ISTRIP = 0x20
+ IUTF8 = 0x4000
+ IXANY = 0x800
+ IXOFF = 0x400
+ IXON = 0x200
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x5
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x1000
+ MAP_COPY = 0x2
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_NOCACHE = 0x400
+ MAP_NOEXTEND = 0x100
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_RESERVED0080 = 0x80
+ MAP_SHARED = 0x1
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOF = 0x100
+ MSG_EOR = 0x8
+ MSG_FLUSH = 0x400
+ MSG_HAVEMORE = 0x2000
+ MSG_HOLD = 0x800
+ MSG_NEEDSA = 0x10000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_RCVMORE = 0x4000
+ MSG_SEND = 0x1000
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ MSG_WAITSTREAM = 0x200
+ MS_ASYNC = 0x1
+ MS_DEACTIVATE = 0x8
+ MS_INVALIDATE = 0x2
+ MS_KILLPAGES = 0x4
+ MS_SYNC = 0x10
+ NAME_MAX = 0xff
+ NET_RT_DUMP = 0x1
+ NET_RT_DUMP2 = 0x7
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_IFLIST2 = 0x6
+ NET_RT_MAXID = 0x8
+ NET_RT_STAT = 0x4
+ NET_RT_TRASH = 0x5
+ NOFLSH = 0x80000000
+ NOTE_ABSOLUTE = 0x8
+ NOTE_ATTRIB = 0x8
+ NOTE_CHILD = 0x4
+ NOTE_DELETE = 0x1
+ NOTE_EXEC = 0x20000000
+ NOTE_EXIT = 0x80000000
+ NOTE_EXTEND = 0x4
+ NOTE_FORK = 0x40000000
+ NOTE_LINK = 0x10
+ NOTE_LOWAT = 0x1
+ NOTE_NSECONDS = 0x4
+ NOTE_PCTRLMASK = -0x100000
+ NOTE_PDATAMASK = 0xfffff
+ NOTE_REAP = 0x10000000
+ NOTE_RENAME = 0x20
+ NOTE_REVOKE = 0x40
+ NOTE_SECONDS = 0x1
+ NOTE_SIGNAL = 0x8000000
+ NOTE_TRACK = 0x1
+ NOTE_TRACKERR = 0x2
+ NOTE_USECONDS = 0x2
+ NOTE_WRITE = 0x2
+ OCRNL = 0x10
+ OFDEL = 0x20000
+ OFILL = 0x80
+ ONLCR = 0x2
+ ONLRET = 0x40
+ ONOCR = 0x20
+ ONOEOT = 0x8
+ OPOST = 0x1
+ O_ACCMODE = 0x3
+ O_ALERT = 0x20000000
+ O_APPEND = 0x8
+ O_ASYNC = 0x40
+ O_CLOEXEC = 0x1000000
+ O_CREAT = 0x200
+ O_DIRECTORY = 0x100000
+ O_EVTONLY = 0x8000
+ O_EXCL = 0x800
+ O_EXLOCK = 0x20
+ O_FSYNC = 0x80
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x20000
+ O_NOFOLLOW = 0x100
+ O_NONBLOCK = 0x4
+ O_POPUP = 0x80000000
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_SHLOCK = 0x10
+ O_SYMLINK = 0x200000
+ O_SYNC = 0x80
+ O_TRUNC = 0x400
+ O_WRONLY = 0x1
+ PARENB = 0x1000
+ PARMRK = 0x8
+ PARODD = 0x2000
+ PENDIN = 0x20000000
+ PRIO_PGRP = 0x1
+ PRIO_PROCESS = 0x0
+ PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ PT_ATTACH = 0xa
+ PT_ATTACHEXC = 0xe
+ PT_CONTINUE = 0x7
+ PT_DENY_ATTACH = 0x1f
+ PT_DETACH = 0xb
+ PT_FIRSTMACH = 0x20
+ PT_FORCEQUOTA = 0x1e
+ PT_KILL = 0x8
+ PT_READ_D = 0x2
+ PT_READ_I = 0x1
+ PT_READ_U = 0x3
+ PT_SIGEXC = 0xc
+ PT_STEP = 0x9
+ PT_THUPDATE = 0xd
+ PT_TRACE_ME = 0x0
+ PT_WRITE_D = 0x5
+ PT_WRITE_I = 0x4
+ PT_WRITE_U = 0x6
+ RLIMIT_AS = 0x5
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x8
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = 0x7fffffffffffffff
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0x0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_MAX = 0x8
+ RTAX_NETMASK = 0x2
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_NETMASK = 0x4
+ RTF_BLACKHOLE = 0x1000
+ RTF_BROADCAST = 0x400000
+ RTF_CLONING = 0x100
+ RTF_CONDEMNED = 0x2000000
+ RTF_DELCLONE = 0x80
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_IFREF = 0x4000000
+ RTF_IFSCOPE = 0x1000000
+ RTF_LLINFO = 0x400
+ RTF_LOCAL = 0x200000
+ RTF_MODIFIED = 0x20
+ RTF_MULTICAST = 0x800000
+ RTF_PINNED = 0x100000
+ RTF_PRCLONING = 0x10000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x40000
+ RTF_REJECT = 0x8
+ RTF_STATIC = 0x800
+ RTF_UP = 0x1
+ RTF_WASCLONED = 0x20000
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DELMADDR = 0x10
+ RTM_GET = 0x4
+ RTM_GET2 = 0x14
+ RTM_IFINFO = 0xe
+ RTM_IFINFO2 = 0x12
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_NEWMADDR = 0xf
+ RTM_NEWMADDR2 = 0x13
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x5
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ SCM_CREDS = 0x3
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x2
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIOCADDMULTI = 0x80206931
+ SIOCAIFADDR = 0x8040691a
+ SIOCALIFADDR = 0x8118691d
+ SIOCARPIPLL = 0xc0206928
+ SIOCATMARK = 0x40047307
+ SIOCAUTOADDR = 0xc0206926
+ SIOCAUTONETMASK = 0x80206927
+ SIOCDELMULTI = 0x80206932
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFPHYADDR = 0x80206941
+ SIOCDLIFADDR = 0x8118691f
+ SIOCGETSGCNT = 0xc014721c
+ SIOCGETVIFCNT = 0xc014721b
+ SIOCGETVLAN = 0xc020697f
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFALTMTU = 0xc0206948
+ SIOCGIFASYNCMAP = 0xc020697c
+ SIOCGIFBOND = 0xc0206947
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCONF = 0xc0086924
+ SIOCGIFDEVMTU = 0xc0206944
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFKPI = 0xc0206987
+ SIOCGIFMAC = 0xc0206982
+ SIOCGIFMEDIA = 0xc0286938
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc0206933
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206940
+ SIOCGIFPHYS = 0xc0206935
+ SIOCGIFPSRCADDR = 0xc020693f
+ SIOCGIFSTATUS = 0xc331693d
+ SIOCGIFVLAN = 0xc020697f
+ SIOCGLIFADDR = 0xc118691e
+ SIOCGLIFPHYADDR = 0xc1186943
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCIFCREATE = 0xc0206978
+ SIOCIFDESTROY = 0x80206979
+ SIOCRSLVMULTI = 0xc008693b
+ SIOCSETVLAN = 0x8020697e
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFALTMTU = 0x80206945
+ SIOCSIFASYNCMAP = 0x8020697d
+ SIOCSIFBOND = 0x80206946
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFKPI = 0x80206986
+ SIOCSIFLLADDR = 0x8020693c
+ SIOCSIFMAC = 0x80206983
+ SIOCSIFMEDIA = 0xc0206937
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x80206934
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x8040693e
+ SIOCSIFPHYS = 0x80206936
+ SIOCSIFVLAN = 0x8020697e
+ SIOCSLIFPHYADDR = 0x81186942
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SOCK_DGRAM = 0x2
+ SOCK_MAXADDRLEN = 0xff
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_BROADCAST = 0x20
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_DONTTRUNC = 0x2000
+ SO_ERROR = 0x1007
+ SO_KEEPALIVE = 0x8
+ SO_LABEL = 0x1010
+ SO_LINGER = 0x80
+ SO_LINGER_SEC = 0x1080
+ SO_NKE = 0x1021
+ SO_NOADDRERR = 0x1023
+ SO_NOSIGPIPE = 0x1022
+ SO_NOTIFYCONFLICT = 0x1026
+ SO_NREAD = 0x1020
+ SO_NWRITE = 0x1024
+ SO_OOBINLINE = 0x100
+ SO_PEERLABEL = 0x1011
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_RESTRICTIONS = 0x1081
+ SO_RESTRICT_DENYIN = 0x1
+ SO_RESTRICT_DENYOUT = 0x2
+ SO_RESTRICT_DENYSET = 0x80000000
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_REUSESHAREUID = 0x1025
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_TIMESTAMP = 0x400
+ SO_TYPE = 0x1008
+ SO_UPCALLCLOSEWAIT = 0x1027
+ SO_USELOOPBACK = 0x40
+ SO_WANTMORE = 0x4000
+ SO_WANTOOBFLAG = 0x8000
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IFWHT = 0xe000
+ S_IFXATTR = 0x10000
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISTXT = 0x200
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ TCIFLUSH = 0x1
+ TCIOFLUSH = 0x3
+ TCOFLUSH = 0x2
+ TCP_KEEPALIVE = 0x10
+ TCP_MAXBURST = 0x4
+ TCP_MAXHLEN = 0x3c
+ TCP_MAXOLEN = 0x28
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_SACK = 0x3
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MINMSS = 0xd8
+ TCP_MINMSSOVERLOAD = 0x3e8
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_NOOPT = 0x8
+ TCP_NOPUSH = 0x4
+ TCSAFLUSH = 0x2
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDCDTIMESTAMP = 0x40087458
+ TIOCDRAIN = 0x2000745e
+ TIOCDSIMICROCODE = 0x20007455
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLUSH = 0x80047410
+ TIOCGDRAINWAIT = 0x40047456
+ TIOCGETA = 0x402c7413
+ TIOCGETD = 0x4004741a
+ TIOCGPGRP = 0x40047477
+ TIOCGWINSZ = 0x40087468
+ TIOCIXOFF = 0x20007480
+ TIOCIXON = 0x20007481
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGDTRWAIT = 0x4004745a
+ TIOCMGET = 0x4004746a
+ TIOCMODG = 0x40047403
+ TIOCMODS = 0x80047404
+ TIOCMSDTRWAIT = 0x8004745b
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCPTYGNAME = 0x40807453
+ TIOCPTYGRANT = 0x20007454
+ TIOCPTYUNLK = 0x20007452
+ TIOCREMOTE = 0x80047469
+ TIOCSBRK = 0x2000747b
+ TIOCSCONS = 0x20007463
+ TIOCSCTTY = 0x20007461
+ TIOCSDRAINWAIT = 0x80047457
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x802c7414
+ TIOCSETAF = 0x802c7416
+ TIOCSETAW = 0x802c7415
+ TIOCSETD = 0x8004741b
+ TIOCSIG = 0x2000745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x20007465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSWINSZ = 0x80087467
+ TIOCTIMESTAMP = 0x40087459
+ TIOCUCNTL = 0x80047466
+ TOSTOP = 0x400000
+ VDISCARD = 0xf
+ VDSUSP = 0xb
+ VEOF = 0x0
+ VEOL = 0x1
+ VEOL2 = 0x2
+ VERASE = 0x3
+ VINTR = 0x8
+ VKILL = 0x5
+ VLNEXT = 0xe
+ VMIN = 0x10
+ VQUIT = 0x9
+ VREPRINT = 0x6
+ VSTART = 0xc
+ VSTATUS = 0x12
+ VSTOP = 0xd
+ VSUSP = 0xa
+ VT0 = 0x0
+ VT1 = 0x10000
+ VTDLY = 0x10000
+ VTIME = 0x11
+ VWERASE = 0x4
+ WCONTINUED = 0x10
+ WCOREFLAG = 0x80
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOWAIT = 0x20
+ WORDSIZE = 0x20
+ WSTOPPED = 0x8
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x30)
+ EADDRNOTAVAIL = Errno(0x31)
+ EAFNOSUPPORT = Errno(0x2f)
+ EAGAIN = Errno(0x23)
+ EALREADY = Errno(0x25)
+ EAUTH = Errno(0x50)
+ EBADARCH = Errno(0x56)
+ EBADEXEC = Errno(0x55)
+ EBADF = Errno(0x9)
+ EBADMACHO = Errno(0x58)
+ EBADMSG = Errno(0x5e)
+ EBADRPC = Errno(0x48)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x59)
+ ECHILD = Errno(0xa)
+ ECONNABORTED = Errno(0x35)
+ ECONNREFUSED = Errno(0x3d)
+ ECONNRESET = Errno(0x36)
+ EDEADLK = Errno(0xb)
+ EDESTADDRREQ = Errno(0x27)
+ EDEVERR = Errno(0x53)
+ EDOM = Errno(0x21)
+ EDQUOT = Errno(0x45)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EFTYPE = Errno(0x4f)
+ EHOSTDOWN = Errno(0x40)
+ EHOSTUNREACH = Errno(0x41)
+ EIDRM = Errno(0x5a)
+ EILSEQ = Errno(0x5c)
+ EINPROGRESS = Errno(0x24)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x38)
+ EISDIR = Errno(0x15)
+ ELAST = Errno(0x67)
+ ELOOP = Errno(0x3e)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x28)
+ EMULTIHOP = Errno(0x5f)
+ ENAMETOOLONG = Errno(0x3f)
+ ENEEDAUTH = Errno(0x51)
+ ENETDOWN = Errno(0x32)
+ ENETRESET = Errno(0x34)
+ ENETUNREACH = Errno(0x33)
+ ENFILE = Errno(0x17)
+ ENOATTR = Errno(0x5d)
+ ENOBUFS = Errno(0x37)
+ ENODATA = Errno(0x60)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x4d)
+ ENOLINK = Errno(0x61)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x5b)
+ ENOPOLICY = Errno(0x67)
+ ENOPROTOOPT = Errno(0x2a)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x62)
+ ENOSTR = Errno(0x63)
+ ENOSYS = Errno(0x4e)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x39)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x42)
+ ENOTSOCK = Errno(0x26)
+ ENOTSUP = Errno(0x2d)
+ ENOTTY = Errno(0x19)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x66)
+ EOVERFLOW = Errno(0x54)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x2e)
+ EPIPE = Errno(0x20)
+ EPROCLIM = Errno(0x43)
+ EPROCUNAVAIL = Errno(0x4c)
+ EPROGMISMATCH = Errno(0x4b)
+ EPROGUNAVAIL = Errno(0x4a)
+ EPROTO = Errno(0x64)
+ EPROTONOSUPPORT = Errno(0x2b)
+ EPROTOTYPE = Errno(0x29)
+ EPWROFF = Errno(0x52)
+ ERANGE = Errno(0x22)
+ EREMOTE = Errno(0x47)
+ EROFS = Errno(0x1e)
+ ERPCMISMATCH = Errno(0x49)
+ ESHLIBVERS = Errno(0x57)
+ ESHUTDOWN = Errno(0x3a)
+ ESOCKTNOSUPPORT = Errno(0x2c)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESTALE = Errno(0x46)
+ ETIME = Errno(0x65)
+ ETIMEDOUT = Errno(0x3c)
+ ETOOMANYREFS = Errno(0x3b)
+ ETXTBSY = Errno(0x1a)
+ EUSERS = Errno(0x44)
+ EWOULDBLOCK = Errno(0x23)
+ EXDEV = Errno(0x12)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCHLD = Signal(0x14)
+ SIGCONT = Signal(0x13)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINFO = Signal(0x1d)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x17)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPROF = Signal(0x1b)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x11)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x12)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGURG = Signal(0x10)
+ SIGUSR1 = Signal(0x1e)
+ SIGUSR2 = Signal(0x1f)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "device not configured",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource deadlock avoided",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "resource busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "result too large",
+ 35: "resource temporarily unavailable",
+ 36: "operation now in progress",
+ 37: "operation already in progress",
+ 38: "socket operation on non-socket",
+ 39: "destination address required",
+ 40: "message too long",
+ 41: "protocol wrong type for socket",
+ 42: "protocol not available",
+ 43: "protocol not supported",
+ 44: "socket type not supported",
+ 45: "operation not supported",
+ 46: "protocol family not supported",
+ 47: "address family not supported by protocol family",
+ 48: "address already in use",
+ 49: "can't assign requested address",
+ 50: "network is down",
+ 51: "network is unreachable",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
+ 55: "no buffer space available",
+ 56: "socket is already connected",
+ 57: "socket is not connected",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "operation timed out",
+ 61: "connection refused",
+ 62: "too many levels of symbolic links",
+ 63: "file name too long",
+ 64: "host is down",
+ 65: "no route to host",
+ 66: "directory not empty",
+ 67: "too many processes",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
+ 71: "too many levels of remote in path",
+ 72: "RPC struct is bad",
+ 73: "RPC version wrong",
+ 74: "RPC prog. not avail",
+ 75: "program version wrong",
+ 76: "bad procedure for program",
+ 77: "no locks available",
+ 78: "function not implemented",
+ 79: "inappropriate file type or format",
+ 80: "authentication error",
+ 81: "need authenticator",
+ 82: "device power is off",
+ 83: "device error",
+ 84: "value too large to be stored in data type",
+ 85: "bad executable (or shared library)",
+ 86: "bad CPU type in executable",
+ 87: "shared library version mismatch",
+ 88: "malformed Mach-o file",
+ 89: "operation canceled",
+ 90: "identifier removed",
+ 91: "no message of desired type",
+ 92: "illegal byte sequence",
+ 93: "attribute not found",
+ 94: "bad message",
+ 95: "EMULTIHOP (Reserved)",
+ 96: "no message available on STREAM",
+ 97: "ENOLINK (Reserved)",
+ 98: "no STREAM resources",
+ 99: "not a STREAM",
+ 100: "protocol error",
+ 101: "STREAM ioctl timeout",
+ 102: "operation not supported on socket",
+ 103: "policy not found",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/BPT trap",
+ 6: "abort trap",
+ 7: "EMT trap",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "bus error",
+ 11: "segmentation fault",
+ 12: "bad system call",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "urgent I/O condition",
+ 17: "suspended (signal)",
+ 18: "suspended",
+ 19: "continued",
+ 20: "child exited",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "I/O possible",
+ 24: "cputime limit exceeded",
+ 25: "filesize limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window size changes",
+ 29: "information request",
+ 30: "user defined signal 1",
+ 31: "user defined signal 2",
+}
diff --git a/src/syscall/zsyscall_darwin_arm.go b/src/syscall/zsyscall_darwin_arm.go
new file mode 100644
index 0000000000..d851d69b43
--- /dev/null
+++ b/src/syscall/zsyscall_darwin_arm.go
@@ -0,0 +1,1324 @@
+// mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+ r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+ wpid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(s int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+ _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
+ r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
+ var _p0 unsafe.Pointer
+ if len(mib) > 0 {
+ _p0 = unsafe.Pointer(&mib[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, timeval *[2]Timeval) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimes(fd int, timeval *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe() (r int, w int, err error) {
+ r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
+ r = int(r0)
+ w = int(r1)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kill(pid int, signum int, posix int) (err error) {
+ _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chflags(path string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(fd int) (nfd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exchangedata(path1 string, path2 string, options int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path1)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(path2)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+ Syscall(SYS_EXIT, uintptr(code), 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchflags(path string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fpathconf(fd int, name int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstatfs(fd int, stat *Statfs_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdtablesize() (size int) {
+ r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
+ size = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+ r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getsid(pid int) (sid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+ sid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+ r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0)
+ tainted = bool(r0 != 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kqueue() (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(path string, link string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(link)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, backlog int) (err error) {
+ _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pathconf(path string, name int) (val int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(buf) > 0 {
+ _p1 = unsafe.Pointer(&buf[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(from string, to string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(from)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(to)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Revoke(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
+ newoffset = int64(int64(r1)<<32 | int64(r0))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
+ _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setegid(egid int) (err error) {
+ _, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seteuid(euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setgid(gid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setlogin(name string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(name)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setprivexec(flag int) (err error) {
+ _, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setuid(uid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Statfs(path string, stat *Statfs_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(path string, link string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(link)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() (err error) {
+ _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(newmask int) (oldmask int) {
+ r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Undelete(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(path string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+ r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
+ ret = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) {
+ r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+ sec = int32(r0)
+ usec = int32(r1)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/syscall/zsysnum_darwin_arm.go b/src/syscall/zsysnum_darwin_arm.go
new file mode 100644
index 0000000000..1a53f13eff
--- /dev/null
+++ b/src/syscall/zsysnum_darwin_arm.go
@@ -0,0 +1,345 @@
+// mksysnum_darwin.pl /usr/include/sys/syscall.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_WAIT4 = 7
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_CHDIR = 12
+ SYS_FCHDIR = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_CHOWN = 16
+ SYS_OBREAK = 17
+ SYS_OGETFSSTAT = 18
+ SYS_GETFSSTAT = 18
+ SYS_GETPID = 20
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_GETEUID = 25
+ SYS_PTRACE = 26
+ SYS_RECVMSG = 27
+ SYS_SENDMSG = 28
+ SYS_RECVFROM = 29
+ SYS_ACCEPT = 30
+ SYS_GETPEERNAME = 31
+ SYS_GETSOCKNAME = 32
+ SYS_ACCESS = 33
+ SYS_CHFLAGS = 34
+ SYS_FCHFLAGS = 35
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_GETPPID = 39
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_GETEGID = 43
+ SYS_PROFIL = 44
+ SYS_SIGACTION = 46
+ SYS_GETGID = 47
+ SYS_SIGPROCMASK = 48
+ SYS_GETLOGIN = 49
+ SYS_SETLOGIN = 50
+ SYS_ACCT = 51
+ SYS_SIGPENDING = 52
+ SYS_SIGALTSTACK = 53
+ SYS_IOCTL = 54
+ SYS_REBOOT = 55
+ SYS_REVOKE = 56
+ SYS_SYMLINK = 57
+ SYS_READLINK = 58
+ SYS_EXECVE = 59
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_MSYNC = 65
+ SYS_VFORK = 66
+ SYS_SBRK = 69
+ SYS_SSTK = 70
+ SYS_OVADVISE = 72
+ SYS_MUNMAP = 73
+ SYS_MPROTECT = 74
+ SYS_MADVISE = 75
+ SYS_MINCORE = 78
+ SYS_GETGROUPS = 79
+ SYS_SETGROUPS = 80
+ SYS_GETPGRP = 81
+ SYS_SETPGID = 82
+ SYS_SETITIMER = 83
+ SYS_SWAPON = 85
+ SYS_GETITIMER = 86
+ SYS_GETDTABLESIZE = 89
+ SYS_DUP2 = 90
+ SYS_FCNTL = 92
+ SYS_SELECT = 93
+ SYS_FSYNC = 95
+ SYS_SETPRIORITY = 96
+ SYS_SOCKET = 97
+ SYS_CONNECT = 98
+ SYS_GETPRIORITY = 100
+ SYS_BIND = 104
+ SYS_SETSOCKOPT = 105
+ SYS_LISTEN = 106
+ SYS_SIGSUSPEND = 111
+ SYS_GETTIMEOFDAY = 116
+ SYS_GETRUSAGE = 117
+ SYS_GETSOCKOPT = 118
+ SYS_READV = 120
+ SYS_WRITEV = 121
+ SYS_SETTIMEOFDAY = 122
+ SYS_FCHOWN = 123
+ SYS_FCHMOD = 124
+ SYS_SETREUID = 126
+ SYS_SETREGID = 127
+ SYS_RENAME = 128
+ SYS_FLOCK = 131
+ SYS_MKFIFO = 132
+ SYS_SENDTO = 133
+ SYS_SHUTDOWN = 134
+ SYS_SOCKETPAIR = 135
+ SYS_MKDIR = 136
+ SYS_RMDIR = 137
+ SYS_UTIMES = 138
+ SYS_FUTIMES = 139
+ SYS_ADJTIME = 140
+ SYS_GETHOSTUUID = 142
+ SYS_SETSID = 147
+ SYS_GETPGID = 151
+ SYS_SETPRIVEXEC = 152
+ SYS_PREAD = 153
+ SYS_PWRITE = 154
+ SYS_NFSSVC = 155
+ SYS_STATFS = 157
+ SYS_FSTATFS = 158
+ SYS_UNMOUNT = 159
+ SYS_GETFH = 161
+ SYS_QUOTACTL = 165
+ SYS_MOUNT = 167
+ SYS_CSOPS = 169
+ SYS_TABLE = 170
+ SYS_WAITID = 173
+ SYS_ADD_PROFIL = 176
+ SYS_KDEBUG_TRACE = 180
+ SYS_SETGID = 181
+ SYS_SETEGID = 182
+ SYS_SETEUID = 183
+ SYS_SIGRETURN = 184
+ SYS_CHUD = 185
+ SYS_STAT = 188
+ SYS_FSTAT = 189
+ SYS_LSTAT = 190
+ SYS_PATHCONF = 191
+ SYS_FPATHCONF = 192
+ SYS_GETRLIMIT = 194
+ SYS_SETRLIMIT = 195
+ SYS_GETDIRENTRIES = 196
+ SYS_MMAP = 197
+ SYS_LSEEK = 199
+ SYS_TRUNCATE = 200
+ SYS_FTRUNCATE = 201
+ SYS___SYSCTL = 202
+ SYS_MLOCK = 203
+ SYS_MUNLOCK = 204
+ SYS_UNDELETE = 205
+ SYS_ATSOCKET = 206
+ SYS_ATGETMSG = 207
+ SYS_ATPUTMSG = 208
+ SYS_ATPSNDREQ = 209
+ SYS_ATPSNDRSP = 210
+ SYS_ATPGETREQ = 211
+ SYS_ATPGETRSP = 212
+ SYS_KQUEUE_FROM_PORTSET_NP = 214
+ SYS_KQUEUE_PORTSET_NP = 215
+ SYS_MKCOMPLEX = 216
+ SYS_STATV = 217
+ SYS_LSTATV = 218
+ SYS_FSTATV = 219
+ SYS_GETATTRLIST = 220
+ SYS_SETATTRLIST = 221
+ SYS_GETDIRENTRIESATTR = 222
+ SYS_EXCHANGEDATA = 223
+ SYS_SEARCHFS = 225
+ SYS_DELETE = 226
+ SYS_COPYFILE = 227
+ SYS_POLL = 230
+ SYS_WATCHEVENT = 231
+ SYS_WAITEVENT = 232
+ SYS_MODWATCH = 233
+ SYS_GETXATTR = 234
+ SYS_FGETXATTR = 235
+ SYS_SETXATTR = 236
+ SYS_FSETXATTR = 237
+ SYS_REMOVEXATTR = 238
+ SYS_FREMOVEXATTR = 239
+ SYS_LISTXATTR = 240
+ SYS_FLISTXATTR = 241
+ SYS_FSCTL = 242
+ SYS_INITGROUPS = 243
+ SYS_POSIX_SPAWN = 244
+ SYS_NFSCLNT = 247
+ SYS_FHOPEN = 248
+ SYS_MINHERIT = 250
+ SYS_SEMSYS = 251
+ SYS_MSGSYS = 252
+ SYS_SHMSYS = 253
+ SYS_SEMCTL = 254
+ SYS_SEMGET = 255
+ SYS_SEMOP = 256
+ SYS_MSGCTL = 258
+ SYS_MSGGET = 259
+ SYS_MSGSND = 260
+ SYS_MSGRCV = 261
+ SYS_SHMAT = 262
+ SYS_SHMCTL = 263
+ SYS_SHMDT = 264
+ SYS_SHMGET = 265
+ SYS_SHM_OPEN = 266
+ SYS_SHM_UNLINK = 267
+ SYS_SEM_OPEN = 268
+ SYS_SEM_CLOSE = 269
+ SYS_SEM_UNLINK = 270
+ SYS_SEM_WAIT = 271
+ SYS_SEM_TRYWAIT = 272
+ SYS_SEM_POST = 273
+ SYS_SEM_GETVALUE = 274
+ SYS_SEM_INIT = 275
+ SYS_SEM_DESTROY = 276
+ SYS_OPEN_EXTENDED = 277
+ SYS_UMASK_EXTENDED = 278
+ SYS_STAT_EXTENDED = 279
+ SYS_LSTAT_EXTENDED = 280
+ SYS_FSTAT_EXTENDED = 281
+ SYS_CHMOD_EXTENDED = 282
+ SYS_FCHMOD_EXTENDED = 283
+ SYS_ACCESS_EXTENDED = 284
+ SYS_SETTID = 285
+ SYS_GETTID = 286
+ SYS_SETSGROUPS = 287
+ SYS_GETSGROUPS = 288
+ SYS_SETWGROUPS = 289
+ SYS_GETWGROUPS = 290
+ SYS_MKFIFO_EXTENDED = 291
+ SYS_MKDIR_EXTENDED = 292
+ SYS_IDENTITYSVC = 293
+ SYS_SHARED_REGION_CHECK_NP = 294
+ SYS_SHARED_REGION_MAP_NP = 295
+ SYS___PTHREAD_MUTEX_DESTROY = 301
+ SYS___PTHREAD_MUTEX_INIT = 302
+ SYS___PTHREAD_MUTEX_LOCK = 303
+ SYS___PTHREAD_MUTEX_TRYLOCK = 304
+ SYS___PTHREAD_MUTEX_UNLOCK = 305
+ SYS___PTHREAD_COND_INIT = 306
+ SYS___PTHREAD_COND_DESTROY = 307
+ SYS___PTHREAD_COND_BROADCAST = 308
+ SYS___PTHREAD_COND_SIGNAL = 309
+ SYS_GETSID = 310
+ SYS_SETTID_WITH_PID = 311
+ SYS___PTHREAD_COND_TIMEDWAIT = 312
+ SYS_AIO_FSYNC = 313
+ SYS_AIO_RETURN = 314
+ SYS_AIO_SUSPEND = 315
+ SYS_AIO_CANCEL = 316
+ SYS_AIO_ERROR = 317
+ SYS_AIO_READ = 318
+ SYS_AIO_WRITE = 319
+ SYS_LIO_LISTIO = 320
+ SYS___PTHREAD_COND_WAIT = 321
+ SYS_IOPOLICYSYS = 322
+ SYS_MLOCKALL = 324
+ SYS_MUNLOCKALL = 325
+ SYS_ISSETUGID = 327
+ SYS___PTHREAD_KILL = 328
+ SYS___PTHREAD_SIGMASK = 329
+ SYS___SIGWAIT = 330
+ SYS___DISABLE_THREADSIGNAL = 331
+ SYS___PTHREAD_MARKCANCEL = 332
+ SYS___PTHREAD_CANCELED = 333
+ SYS___SEMWAIT_SIGNAL = 334
+ SYS_PROC_INFO = 336
+ SYS_SENDFILE = 337
+ SYS_STAT64 = 338
+ SYS_FSTAT64 = 339
+ SYS_LSTAT64 = 340
+ SYS_STAT64_EXTENDED = 341
+ SYS_LSTAT64_EXTENDED = 342
+ SYS_FSTAT64_EXTENDED = 343
+ SYS_GETDIRENTRIES64 = 344
+ SYS_STATFS64 = 345
+ SYS_FSTATFS64 = 346
+ SYS_GETFSSTAT64 = 347
+ SYS___PTHREAD_CHDIR = 348
+ SYS___PTHREAD_FCHDIR = 349
+ SYS_AUDIT = 350
+ SYS_AUDITON = 351
+ SYS_GETAUID = 353
+ SYS_SETAUID = 354
+ SYS_GETAUDIT = 355
+ SYS_SETAUDIT = 356
+ SYS_GETAUDIT_ADDR = 357
+ SYS_SETAUDIT_ADDR = 358
+ SYS_AUDITCTL = 359
+ SYS_BSDTHREAD_CREATE = 360
+ SYS_BSDTHREAD_TERMINATE = 361
+ SYS_KQUEUE = 362
+ SYS_KEVENT = 363
+ SYS_LCHOWN = 364
+ SYS_STACK_SNAPSHOT = 365
+ SYS_BSDTHREAD_REGISTER = 366
+ SYS_WORKQ_OPEN = 367
+ SYS_WORKQ_OPS = 368
+ SYS___MAC_EXECVE = 380
+ SYS___MAC_SYSCALL = 381
+ SYS___MAC_GET_FILE = 382
+ SYS___MAC_SET_FILE = 383
+ SYS___MAC_GET_LINK = 384
+ SYS___MAC_SET_LINK = 385
+ SYS___MAC_GET_PROC = 386
+ SYS___MAC_SET_PROC = 387
+ SYS___MAC_GET_FD = 388
+ SYS___MAC_SET_FD = 389
+ SYS___MAC_GET_PID = 390
+ SYS___MAC_GET_LCID = 391
+ SYS___MAC_GET_LCTX = 392
+ SYS___MAC_SET_LCTX = 393
+ SYS_SETLCID = 394
+ SYS_GETLCID = 395
+ SYS_READ_NOCANCEL = 396
+ SYS_WRITE_NOCANCEL = 397
+ SYS_OPEN_NOCANCEL = 398
+ SYS_CLOSE_NOCANCEL = 399
+ SYS_WAIT4_NOCANCEL = 400
+ SYS_RECVMSG_NOCANCEL = 401
+ SYS_SENDMSG_NOCANCEL = 402
+ SYS_RECVFROM_NOCANCEL = 403
+ SYS_ACCEPT_NOCANCEL = 404
+ SYS_MSYNC_NOCANCEL = 405
+ SYS_FCNTL_NOCANCEL = 406
+ SYS_SELECT_NOCANCEL = 407
+ SYS_FSYNC_NOCANCEL = 408
+ SYS_CONNECT_NOCANCEL = 409
+ SYS_SIGSUSPEND_NOCANCEL = 410
+ SYS_READV_NOCANCEL = 411
+ SYS_WRITEV_NOCANCEL = 412
+ SYS_SENDTO_NOCANCEL = 413
+ SYS_PREAD_NOCANCEL = 414
+ SYS_PWRITE_NOCANCEL = 415
+ SYS_WAITID_NOCANCEL = 416
+ SYS_POLL_NOCANCEL = 417
+ SYS_MSGSND_NOCANCEL = 418
+ SYS_MSGRCV_NOCANCEL = 419
+ SYS_SEM_WAIT_NOCANCEL = 420
+ SYS_AIO_SUSPEND_NOCANCEL = 421
+ SYS___SIGWAIT_NOCANCEL = 422
+ SYS___SEMWAIT_SIGNAL_NOCANCEL = 423
+ SYS___MAC_MOUNT = 424
+ SYS___MAC_GET_MOUNT = 425
+ SYS___MAC_GETFSSTAT = 426
+ SYS_MAXSYSCALL = 427
+)
diff --git a/src/syscall/ztypes_darwin_arm.go b/src/syscall/ztypes_darwin_arm.go
new file mode 100644
index 0000000000..ec87f54fb2
--- /dev/null
+++ b/src/syscall/ztypes_darwin_arm.go
@@ -0,0 +1,447 @@
+// NOTE: cgo can't generate struct Stat_t and struct Statfs_t yet
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Timeval32 [0]byte
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev int32
+ Mode uint16
+ Nlink uint16
+ Ino uint64
+ Uid uint32
+ Gid uint32
+ Rdev int32
+ Atimespec Timespec
+ Mtimespec Timespec
+ Ctimespec Timespec
+ Birthtimespec Timespec
+ Size int64
+ Blocks int64
+ Blksize int32
+ Flags uint32
+ Gen uint32
+ Lspare int32
+ Qspare [2]int64
+}
+
+type Statfs_t struct {
+ Bsize uint32
+ Iosize int32
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Fsid Fsid
+ Owner uint32
+ Type uint32
+ Flags uint32
+ Fssubtype uint32
+ Fstypename [16]int8
+ Mntonname [1024]int8
+ Mntfromname [1024]int8
+ Reserved [8]uint32
+}
+
+type Flock_t struct {
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+}
+
+type Fstore_t struct {
+ Flags uint32
+ Posmode int32
+ Offset int64
+ Length int64
+ Bytesalloc int64
+}
+
+type Radvisory_t struct {
+ Offset int64
+ Count int32
+}
+
+type Fbootstraptransfer_t struct {
+ Offset int64
+ Length uint32
+ Buffer *byte
+}
+
+type Log2phys_t struct {
+ Flags uint32
+ Contigbytes int64
+ Devoffset int64
+}
+
+type Fsid struct {
+ Val [2]int32
+}
+
+type Dirent struct {
+ Ino uint64
+ Seekoff uint64
+ Reclen uint16
+ Namlen uint16
+ Type uint8
+ Name [1024]int8
+ Pad_cgo_0 [3]byte
+}
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [104]int8
+}
+
+type RawSockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [12]int8
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint32
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Iov *Iovec
+ Iovlen int32
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet4Pktinfo struct {
+ Ifindex uint32
+ Spec_dst [4]byte /* in_addr */
+ Addr [4]byte /* in_addr */
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+ Addr RawSockaddrInet6
+ Mtu uint32
+}
+
+type ICMPv6Filter struct {
+ Filt [8]uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x14
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet4Pktinfo = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofIPv6MTUInfo = 0x20
+ SizeofICMPv6Filter = 0x20
+)
+
+const (
+ PTRACE_TRACEME = 0x0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+)
+
+type Kevent_t struct {
+ Ident uint32
+ Filter int16
+ Flags uint16
+ Fflags uint32
+ Data int32
+ Udata *byte
+}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+const (
+ SizeofIfMsghdr = 0x70
+ SizeofIfData = 0x60
+ SizeofIfaMsghdr = 0x14
+ SizeofIfmaMsghdr = 0x10
+ SizeofIfmaMsghdr2 = 0x14
+ SizeofRtMsghdr = 0x5c
+ SizeofRtMetrics = 0x38
+)
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Typelen uint8
+ Physical uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Recvquota uint8
+ Xmitquota uint8
+ Unused1 uint8
+ Mtu uint32
+ Metric uint32
+ Baudrate uint32
+ Ipackets uint32
+ Ierrors uint32
+ Opackets uint32
+ Oerrors uint32
+ Collisions uint32
+ Ibytes uint32
+ Obytes uint32
+ Imcasts uint32
+ Omcasts uint32
+ Iqdrops uint32
+ Noproto uint32
+ Recvtiming uint32
+ Xmittiming uint32
+ Lastchange Timeval
+ Unused2 uint32
+ Hwassist uint32
+ Reserved1 uint32
+ Reserved2 uint32
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Metric int32
+}
+
+type IfmaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+}
+
+type IfmaMsghdr2 struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Refcount int32
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Use int32
+ Inits uint32
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Locks uint32
+ Mtu uint32
+ Hopcount uint32
+ Expire int32
+ Recvpipe uint32
+ Sendpipe uint32
+ Ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Pksent uint32
+ Filler [4]uint32
+}
+
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfProgram = 0x8
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint32
+ Drop uint32
+}
+
+type BpfProgram struct {
+ Len uint32
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfHdr struct {
+ Tstamp Timeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [2]byte
+}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
diff --git a/src/syscall/ztypes_windows.go b/src/syscall/ztypes_windows.go
index 4c8a99ab94..e5c732576b 100644
--- a/src/syscall/ztypes_windows.go
+++ b/src/syscall/ztypes_windows.go
@@ -1083,12 +1083,7 @@ type TCPKeepalive struct {
Interval uint32
}
-type reparseDataBuffer struct {
- ReparseTag uint32
- ReparseDataLength uint16
- Reserved uint16
-
- // SymbolicLinkReparseBuffer
+type symbolicLinkReparseBuffer struct {
SubstituteNameOffset uint16
SubstituteNameLength uint16
PrintNameOffset uint16
@@ -1097,9 +1092,27 @@ type reparseDataBuffer struct {
PathBuffer [1]uint16
}
+type mountPointReparseBuffer struct {
+ SubstituteNameOffset uint16
+ SubstituteNameLength uint16
+ PrintNameOffset uint16
+ PrintNameLength uint16
+ PathBuffer [1]uint16
+}
+
+type reparseDataBuffer struct {
+ ReparseTag uint32
+ ReparseDataLength uint16
+ Reserved uint16
+
+ // GenericReparseBuffer
+ reparseBuffer byte
+}
+
const (
FSCTL_GET_REPARSE_POINT = 0x900A8
MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024
+ _IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
IO_REPARSE_TAG_SYMLINK = 0xA000000C
SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1
)
diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go
index ffd5376844..62e696d221 100644
--- a/src/testing/benchmark.go
+++ b/src/testing/benchmark.go
@@ -280,6 +280,14 @@ func (r BenchmarkResult) MemString() string {
r.AllocedBytesPerOp(), r.AllocsPerOp())
}
+// benchmarkName returns full name of benchmark including procs suffix.
+func benchmarkName(name string, n int) string {
+ if n != 1 {
+ return fmt.Sprintf("%s-%d", name, n)
+ }
+ return name
+}
+
// An internal function but exported because it is cross-package; part of the implementation
// of the "go test" command.
func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) {
@@ -287,15 +295,30 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
if len(*matchBenchmarks) == 0 {
return
}
+ // Collect matching benchmarks and determine longest name.
+ maxprocs := 1
+ for _, procs := range cpuList {
+ if procs > maxprocs {
+ maxprocs = procs
+ }
+ }
+ maxlen := 0
+ var bs []InternalBenchmark
for _, Benchmark := range benchmarks {
matched, err := matchString(*matchBenchmarks, Benchmark.Name)
if err != nil {
fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.bench: %s\n", err)
os.Exit(1)
}
- if !matched {
- continue
+ if matched {
+ bs = append(bs, Benchmark)
+ benchName := benchmarkName(Benchmark.Name, maxprocs)
+ if l := len(benchName); l > maxlen {
+ maxlen = l
+ }
}
+ }
+ for _, Benchmark := range bs {
for _, procs := range cpuList {
runtime.GOMAXPROCS(procs)
b := &B{
@@ -304,11 +327,8 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
},
benchmark: Benchmark,
}
- benchName := Benchmark.Name
- if procs != 1 {
- benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
- }
- fmt.Printf("%s\t", benchName)
+ benchName := benchmarkName(Benchmark.Name, procs)
+ fmt.Printf("%-*s\t", maxlen, benchName)
r := b.run()
if b.failed {
// The output could be very long here, but probably isn't.
diff --git a/src/time/sys_unix.go b/src/time/sys_unix.go
index 379e13d6a5..e592415daa 100644
--- a/src/time/sys_unix.go
+++ b/src/time/sys_unix.go
@@ -74,3 +74,5 @@ func preadn(fd uintptr, buf []byte, off int) error {
}
return nil
}
+
+func isNotExist(err error) bool { return err == syscall.ENOENT }
diff --git a/src/time/zoneinfo_plan9.go b/src/time/zoneinfo_plan9.go
index 4bb0cb3909..0694f0a990 100644
--- a/src/time/zoneinfo_plan9.go
+++ b/src/time/zoneinfo_plan9.go
@@ -7,7 +7,6 @@
package time
import (
- "errors"
"runtime"
"syscall"
)
@@ -148,11 +147,12 @@ func initLocal() {
}
func loadLocation(name string) (*Location, error) {
- if z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name); err == nil {
- z.name = name
- return z, nil
+ z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name)
+ if err != nil {
+ return nil, err
}
- return nil, errors.New("unknown time zone " + name)
+ z.name = name
+ return z, nil
}
func forceZipFileForTesting(zipOnly bool) {
diff --git a/src/time/zoneinfo_unix.go b/src/time/zoneinfo_unix.go
index ab7e4612e4..66540969d5 100644
--- a/src/time/zoneinfo_unix.go
+++ b/src/time/zoneinfo_unix.go
@@ -74,11 +74,17 @@ func initLocal() {
}
func loadLocation(name string) (*Location, error) {
+ var firstErr error
for _, zoneDir := range zoneDirs {
if z, err := loadZoneFile(zoneDir, name); err == nil {
z.name = name
return z, nil
+ } else if firstErr == nil && !isNotExist(err) {
+ firstErr = err
}
}
+ if firstErr != nil {
+ return nil, firstErr
+ }
return nil, errors.New("unknown time zone " + name)
}
diff --git a/src/time/zoneinfo_windows.go b/src/time/zoneinfo_windows.go
index 02d8e0edcc..5077f4bd86 100644
--- a/src/time/zoneinfo_windows.go
+++ b/src/time/zoneinfo_windows.go
@@ -260,11 +260,12 @@ func initLocal() {
}
func loadLocation(name string) (*Location, error) {
- if z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name); err == nil {
- z.name = name
- return z, nil
+ z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name)
+ if err != nil {
+ return nil, err
}
- return nil, errors.New("unknown time zone " + name)
+ z.name = name
+ return z, nil
}
func forceZipFileForTesting(zipOnly bool) {