1
0
mirror of https://github.com/golang/go synced 2024-11-23 18:50:05 -07:00

cmd/internal/obj/ppc64: add a test for long branch fixups

Cribbed and modified from arm64, verify each transformation
rewrites a too-far conditional branch as expected.

Change-Id: I87d35085158ed7d7478aa9725b273401fcd0bd01
Reviewed-on: https://go-review.googlesource.com/c/go/+/347049
Trust: David Chase <drchase@google.com>
Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com>
This commit is contained in:
Paul E. Murphy 2021-08-30 11:56:58 -05:00 committed by Lynn Boger
parent 6e5dd0b59b
commit 516d75ccf1

View File

@ -5,6 +5,8 @@
package ppc64
import (
"bytes"
"fmt"
"internal/testenv"
"io/ioutil"
"os"
@ -35,6 +37,131 @@ ADD $4, R8
RET
`
var platformEnvs = [][]string{
{"GOOS=aix", "GOARCH=ppc64"},
{"GOOS=linux", "GOARCH=ppc64"},
{"GOOS=linux", "GOARCH=ppc64le"},
}
// TestLarge generates a very large file to verify that large
// program builds successfully, and branches which exceed the
// range of BC are rewritten to reach.
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)
// A few interesting test cases for long conditional branch fixups
tests := []struct {
jmpinsn string
backpattern []string
fwdpattern []string
}{
// Test the interesting cases of conditional branch rewrites for too-far targets. Simple conditional
// branches can be made to reach with one JMP insertion, compound conditionals require two.
//
// TODO: BI is interpreted as a register (the R???x/R0 should be $x)
// beq <-> bne conversion (insert one jump)
{"BEQ",
[]string{``,
`0x20030 131120\s\(.*\)\tBC\t\$4,\sR\?\?\?2,\s131128`,
`0x20034 131124\s\(.*\)\tJMP\t0`},
[]string{``,
`0x0000 00000\s\(.*\)\tBC\t\$4,\sR\?\?\?2,\s8`,
`0x0004 00004\s\(.*\)\tJMP\t131128`},
},
{"BNE",
[]string{``,
`0x20030 131120\s\(.*\)\tBC\t\$12,\sR\?\?\?2,\s131128`,
`0x20034 131124\s\(.*\)\tJMP\t0`},
[]string{``,
`0x0000 00000\s\(.*\)\tBC\t\$12,\sR\?\?\?2,\s8`,
`0x0004 00004\s\(.*\)\tJMP\t131128`}},
// bdnz (BC 16,0,tgt) <-> bdz (BC 18,0,+4) conversion (insert one jump)
{"BC 16,0,",
[]string{``,
`0x20030 131120\s\(.*\)\tBC\t\$18,\s131128`,
`0x20034 131124\s\(.*\)\tJMP\t0`},
[]string{``,
`0x0000 00000\s\(.*\)\tBC\t\$18,\s8`,
`0x0004 00004\s\(.*\)\tJMP\t131128`}},
{"BC 18,0,",
[]string{``,
`0x20030 131120\s\(.*\)\tBC\t\$16,\s131128`,
`0x20034 131124\s\(.*\)\tJMP\t0`},
[]string{``,
`0x0000 00000\s\(.*\)\tBC\t\$16,\s8`,
`0x0004 00004\s\(.*\)\tJMP\t131128`}},
// bdnzt (BC 8,0,tgt) <-> bdnzt (BC 8,0,+4) conversion (insert two jumps)
{"BC 8,0,",
[]string{``,
`0x20034 131124\s\(.*\)\tBC\t\$8,\sR0,\s131132`,
`0x20038 131128\s\(.*\)\tJMP\t131136`,
`0x2003c 131132\s\(.*\)\tJMP\t0\n`},
[]string{``,
`0x0000 00000\s\(.*\)\tBC\t\$8,\sR0,\s8`,
`0x0004 00004\s\(.*\)\tJMP\t12`,
`0x0008 00008\s\(.*\)\tJMP\t131136\n`}},
}
for _, test := range tests {
// generate a very large function
buf := bytes.NewBuffer(make([]byte, 0, 7000000))
gen(buf, test.jmpinsn)
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)
}
// Test on all supported ppc64 platforms
for _, platenv := range platformEnvs {
cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
cmd.Env = append(os.Environ(), platenv...)
out, err := cmd.CombinedOutput()
if err != nil {
t.Errorf("Assemble failed (%v): %v, output: %s", platenv, err, out)
}
matched, err := regexp.MatchString(strings.Join(test.fwdpattern, "\n\t*"), string(out))
if err != nil {
t.Fatal(err)
}
if !matched {
t.Errorf("Failed to detect long foward BC fixup in (%v):%s\n", platenv, out)
}
matched, err = regexp.MatchString(strings.Join(test.backpattern, "\n\t*"), string(out))
if err != nil {
t.Fatal(err)
}
if !matched {
t.Errorf("Failed to detect long backward BC fixup in (%v):%s\n", platenv, out)
}
}
}
}
// gen generates a very large program with a very long forward and backwards conditional branch.
func gen(buf *bytes.Buffer, jmpinsn string) {
fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
fmt.Fprintln(buf, "label_start:")
fmt.Fprintln(buf, jmpinsn, "label_end")
for i := 0; i < (1<<15 + 10); i++ {
fmt.Fprintln(buf, "MOVD R0, R1")
}
fmt.Fprintln(buf, jmpinsn, "label_start")
fmt.Fprintln(buf, "label_end:")
fmt.Fprintln(buf, "MOVD R0, R1")
fmt.Fprintln(buf, "RET")
}
// TestPCalign generates two asm files containing the
// PCALIGN directive, to verify correct values are and
// accepted, and incorrect values are flagged in error.