From: Cherry Zhang Date: Wed, 16 Nov 2016 15:43:54 +0000 (-0500) Subject: cmd/internal/obj/arm64: fix branch too far for CBZ (and like) X-Git-Tag: go1.8beta1~136 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=1e3c57c2cc1500b12a35a859f3d6e8aa27aeebc5;p=gostls13.git cmd/internal/obj/arm64: fix branch too far for CBZ (and like) 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 Reviewed-by: David Chase --- diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index b282c1e0af..3409957112 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -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 index 0000000000..369c48f510 --- /dev/null +++ b/src/cmd/internal/obj/arm64/asm_test.go @@ -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") +}