]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/arm64: fix branch too far for CBZ (and like)
authorCherry Zhang <cherryyz@google.com>
Wed, 16 Nov 2016 15:43:54 +0000 (10:43 -0500)
committerCherry Zhang <cherryyz@google.com>
Wed, 16 Nov 2016 20:31:40 +0000 (20:31 +0000)
The assembler backend fixes too-far conditional branches, but only
for BEQ and like. Add a case for CBZ and like.

Fixes #17925.

Change-Id: Ie516e6c5ca165b582367283a0110f7081e00c214
Reviewed-on: https://go-review.googlesource.com/33304
Run-TryBot: Cherry Zhang <cherryyz@google.com>
Reviewed-by: David Chase <drchase@google.com>
src/cmd/internal/obj/arm64/asm7.go
src/cmd/internal/obj/arm64/asm_test.go [new file with mode: 0644]

index b282c1e0af68b0e1ef7d7e8ceda9abb55b733e67..3409957112d27c3aa9071c13e44b1018cb12e6a3 100644 (file)
@@ -601,7 +601,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
                        o = oplook(ctxt, p)
 
                        /* very large branches */
-                       if o.type_ == 7 && p.Pcond != nil {
+                       if (o.type_ == 7 || o.type_ == 39) && p.Pcond != nil { // 7: BEQ and like, 39: CBZ and like
                                otxt := p.Pcond.Pc - c
                                if otxt <= -(1<<18)+10 || otxt >= (1<<18)-10 {
                                        q := ctxt.NewProg()
diff --git a/src/cmd/internal/obj/arm64/asm_test.go b/src/cmd/internal/obj/arm64/asm_test.go
new file mode 100644 (file)
index 0000000..369c48f
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2016 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 arm64
+
+import (
+       "bytes"
+       "fmt"
+       "internal/testenv"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "testing"
+)
+
+// TestLarge generates a very large file to verify that large
+// program builds successfully, in particular, too-far
+// conditional branches are fixed.
+func TestLarge(t *testing.T) {
+       if testing.Short() {
+               t.Skip("Skip in short mode")
+       }
+       testenv.MustHaveGoBuild(t)
+
+       dir, err := ioutil.TempDir("", "testlarge")
+       if err != nil {
+               t.Fatalf("could not create directory: %v", err)
+       }
+       defer os.RemoveAll(dir)
+
+       // generate a very large function
+       buf := bytes.NewBuffer(make([]byte, 0, 7000000))
+       gen(buf)
+
+       tmpfile := filepath.Join(dir, "x.s")
+       err = ioutil.WriteFile(tmpfile, buf.Bytes(), 0644)
+       if err != nil {
+               t.Fatalf("can't write output: %v\n", err)
+       }
+
+       // build generated file
+       cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
+       cmd.Env = []string{"GOARCH=arm64", "GOOS=linux"}
+       out, err := cmd.CombinedOutput()
+       if err != nil {
+               t.Errorf("Build failed: %v, output: %s", err, out)
+       }
+}
+
+// gen generates a very large program, with a very far conditional branch.
+func gen(buf *bytes.Buffer) {
+       fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
+       fmt.Fprintln(buf, "CBZ R0, label")
+       fmt.Fprintln(buf, "BEQ label")
+       for i := 0; i < 1<<19; i++ {
+               fmt.Fprintln(buf, "MOVD R0, R1")
+       }
+       fmt.Fprintln(buf, "label:")
+       fmt.Fprintln(buf, "RET")
+}