Commit 87de9ce2 authored by Russ Cox's avatar Russ Cox

[dev.cc] all: merge master (5f1efe73) into dev.cc

Conflicts:
	src/cmd/dist/build.go

Change-Id: I98a4b5e010bee91507b85bb8efd9c74e1a1f649c
parents 01925bd3 5f1efe73
......@@ -40,7 +40,7 @@ is mirrored to the <code>gcc/go/gofrontend</code> directory in the GCC
repository, and the <code>gofrontend</code> <code>libgo</code>
directory is mirrored to the GCC <code>libgo</code> directory. In
addition, the <code>test</code> directory
from <a href="//code.google.com/p/go">the main Go repository</a>
from <a href="//go.googlesource.com/go">the main Go repository</a>
is mirrored to the <code>gcc/testsuite/go.test/test</code> directory
in the GCC repository.
</p>
......@@ -65,7 +65,7 @@ from <code>gcc/go/gofrontend</code> to <code>gcc/go</code>.
<p>
The run-time library for gccgo is mostly the same as the library
in <a href="//code.google.com/p/go">the main Go repository</a>.
in <a href="//go.googlesource.com/go">the main Go repository</a>.
The library code in the Go repository is periodically merged into
the <code>libgo/go</code> directory of the <code>gofrontend</code> and
then the GCC repositories, using the shell
......
......@@ -2,6 +2,9 @@ Overall:
build: Go 1.4 required to build (https://golang.org/cl/2470, https://golang.org/cl/2993)
New Ports:
Darwin/ARM, a.k.a iOS. (https://golang.org/cl/2118, 2119, 3273, 2121, 2122, ..., 2127)
API additions and behavior changes:
bufio: add Reader.Discard (https://golang.org/cl/2260)
......@@ -19,6 +22,7 @@ testing/quick: support generation of arrays (https://golang.org/cl/3865)
Tools:
cmd/vet: better validation of struct tags (https://golang.org/cl/2685)
cmd/ld: no longer record build timestamp in Windows PE file header (https://golang.org/cl/3740)
Performance:
......
......@@ -77,12 +77,25 @@ The full set of supported combinations is listed in the discussion of
</div>
<h2 id="ctools">Install C tools, if needed</h2>
<h2 id="go14">Install Go compiler binaries</h2>
<p>
The Go tool chain is written in C. To build it, you need a C compiler installed.
Please refer to the <a href="//golang.org/wiki/InstallFromSource#install-c-tools">InstallFromSource</a>
page on the Go community Wiki for operating system specific instructions.
The Go tool chain is written in Go. To build it, you need a Go compiler installed.
The scripts that do the initial build of the tools look for an existing Go tool
chain in <code>$HOME/go1.4</code>.
(This path may be overridden by setting the <code>GOROOT_BOOTSTRAP</code>
environment variable.)
</p>
<p>
Build the tools with Go version 1.4 or a point release (1.4.1, 1.4.2 etc.).
Go 1.4 binaries can be found at <a href="/dl/">the downloads page</a>.
</p>
<p>
Download the zip or tarball of Go 1.4 for your platform and extract it to
<code>$HOME/go1.4</code> (or your nominated <code>GOROOT_BOOTSTRAP</code>
location).
</p>
<h2 id="git">Install Git, if needed</h2>
......
......@@ -278,6 +278,9 @@ enum {
A_ARCHSPECIFIC, // first architecture-specific opcode value
};
void nopout(Prog*);
void nocache(Prog*);
// prevent incompatible type signatures between liblink and 8l on Plan 9
#pragma incomplete struct Section
......
......@@ -42,7 +42,7 @@ extern "C" {
#define _NETBSD_SOURCE 1 /* NetBSD */
#define _DEFAULT_SOURCE 1 /* glibc > 2.19 */
#define _SVID_SOURCE 1
#if !defined(__APPLE__) && !defined(__OpenBSD__)
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__sun__)
# define _XOPEN_SOURCE 1000
# define _XOPEN_SOURCE_EXTENDED 1
#endif
......
......@@ -4,7 +4,7 @@
// Test that the #cgo CFLAGS directive works,
// with and without platform filters.
// See http://code.google.com/p/go/issues/detail?id=5224 for details.
// See http://golang.org/issue/5224 for details.
package cgotest
/*
......
......@@ -12,9 +12,23 @@ package cgotest
void issue7978cb(void);
#if defined(__APPLE__) && defined(__arm__)
// on Darwin/ARM, libSystem doesn't provide implementation of the __sync_fetch_and_add
// primitive, and although gcc supports it, it doesn't inline its definition.
// Clang could inline its definition, so we require clang on Darwin/ARM.
#if defined(__clang__)
#define HAS_SYNC_FETCH_AND_ADD 1
#else
#define HAS_SYNC_FETCH_AND_ADD 0
#endif
#else
#define HAS_SYNC_FETCH_AND_ADD 1
#endif
// use ugly atomic variable sync since that doesn't require calling back into
// Go code or OS dependencies
static void issue7978c(uint32_t *sync) {
#if HAS_SYNC_FETCH_AND_ADD
while(__sync_fetch_and_add(sync, 0) != 0)
;
__sync_fetch_and_add(sync, 1);
......@@ -24,6 +38,7 @@ static void issue7978c(uint32_t *sync) {
__sync_fetch_and_add(sync, 1);
while(__sync_fetch_and_add(sync, 0) != 6)
;
#endif
}
*/
import "C"
......@@ -85,6 +100,9 @@ func test7978(t *testing.T) {
if runtime.Compiler == "gccgo" {
t.Skip("gccgo can not do stack traces of C code")
}
if C.HAS_SYNC_FETCH_AND_ADD == 0 {
t.Skip("clang required for __sync_fetch_and_add support on darwin/arm")
}
if os.Getenv("GOTRACEBACK") != "2" {
t.Fatalf("GOTRACEBACK must be 2")
}
......
......@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Test that setgid does not hang on GNU/Linux.
// See http://code.google.com/p/go/issues/detail?id=3871 for details.
// See http://golang.org/issue/3871 for details.
package cgotest
......
For information about plugins and other support for Go in editors and shells,
see this page on the Go Wiki:
https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins
https://golang.org/wiki/IDEsAndTextEditorPlugins
Go on iOS
=========
To build a cross compiling toolchain for iOS on OS X, first modify clangwrap.sh
in misc/ios to match your setup. And then run:
GOARM=7 CGO_ENABLED=1 GOARCH=arm CC_FOR_TARGET=`pwd`/../misc/ios/clangwrap.sh \
CXX_FOR_TARGET=`pwd`/../misc/ios/clangwrap.sh ./make.bash
To build a program, use the normal go build command:
CGO_ENABLED=1 GOARCH=arm go build import/path
To run a program on an iDevice, first make sure you have a valid developer
certificate and have setup your iDevice properly to run apps signed by your
developer certificate. Then install https://github.com/phonegap/ios-deploy.
At a first step, you can try building the famous hello world program to run
on your test device.
(The needed files are provided at https://github.com/minux/go-ios-examples.)
# assume your program binary is helloworld.go, build it into the
# example hello.app bundle.
CGO_ENABLED=1 GOARCH=arm go build -o hello.app/hello helloworld.go
# sign the executable using your developer certificate
codesign -f -s "iPhone Developer" --entitlements hello.app/Entitlements.plist hello.app/hello
# run the program inside lldb on iDevice, run `ios-deploy` for more
# command options
ios-deploy --debug --uninstall --bundle hello.app
# Depending on your ios-deploy version, you might need to enter "run"
# into lldb to run your program, and its output will be shown by lldb.
Notes:
- A dummy hello.app bundle is provided in this directory to help you get started.
- Running the program on an iDevice requires code sign and thus external linking,
if your program uses cgo, then it will automatically use external linking.
However, if your program does not use cgo, please make sure to add
import _ "runtime/cgo"
so that external linking will be used.
Known issues
============
- crypto/x509 won't build, I don't yet know how to get system root on iOS.
- Because I still want to be able to do native build, CGO_ENABLED=1 is not the
default, yet.
#!/bin/sh
# This uses the latest available iOS SDK, which is recommended.
# To select a specific SDK, run 'xcodebuild -showsdks'
# to see the available SDKs and replace iphoneos with one of them.
SDK=iphoneos
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
export IPHONEOS_DEPLOYMENT_TARGET=5.1
# cmd/cgo doesn't support llvm-gcc-4.2, so we have to use clang.
CLANG=`xcrun --sdk $SDK --find clang`
exec $CLANG -arch armv7 -isysroot $SDK_PATH "$@"
......@@ -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:
......
......@@ -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);
......
......@@ -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.
......
......@@ -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);
}
......@@ -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*);
......@@ -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;
......@@ -486,147 +437,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
......
// 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;
}
This diff is collapsed.
// 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*);
......@@ -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);
}
......@@ -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;
}
}
This diff is collapsed.
......@@ -91,6 +91,7 @@ enum
REGG = REGEXT-0,
REGM = REGEXT-1,
REGCTXT = REG_R7,
REGTMP = REG_R11,
REGSP = REG_R13,
REGLINK = REG_R14,
......
......@@ -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;
}
......@@ -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
......
......@@ -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;
}
......@@ -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",
......
......@@ -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;
......
......@@ -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);
}
......@@ -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*);
......@@ -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
......@@ -477,159 +431,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:
......
This diff is collapsed.
This diff is collapsed.
......@@ -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;
}
......
......@@ -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))
......
This diff is collapsed.
......@@ -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 */
......
This diff is collapsed.
This diff is collapsed.
......@@ -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;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -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))
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment