diff options
| author | Cherry Mui <cherryyz@google.com> | 2025-11-24 11:03:06 -0500 |
|---|---|---|
| committer | Cherry Mui <cherryyz@google.com> | 2025-11-24 11:03:06 -0500 |
| commit | 220d73cc44a0c580dc8ee10df6395c8e517e118f (patch) | |
| tree | d072aab20229f5489f43a0ce13ab52ff867ba38c /src/cmd/internal/obj | |
| parent | 0c69e7734308f36de7acbeda4cabced8018c04e3 (diff) | |
| parent | 8dd5b13abcb64993959ea02c3f664654af6367a9 (diff) | |
| download | go-220d73cc44a0c580dc8ee10df6395c8e517e118f.tar.xz | |
[dev.simd] all: merge master (8dd5b13) into dev.simd
Merge List:
+ 2025-11-24 8dd5b13abc cmd/compile: relax stmtline_test on amd64
+ 2025-11-23 feae743bdb cmd/compile: use 32x32->64 multiplies on loong64
+ 2025-11-23 e88be8a128 runtime: fix stale comment for mheap/malloc
+ 2025-11-23 a318843a2a cmd/internal/obj/loong64: optimize duplicate optab entries
+ 2025-11-23 a18294bb6a cmd/internal/obj/arm64, image/gif, runtime, sort: use math/bits to calculate log2
+ 2025-11-23 437323ef7b slices: fix incorrect comment in slices.Insert function documentation
+ 2025-11-23 1993dca400 doc/next: pre-announce end of support for macOS 12 in Go 1.27
+ 2025-11-22 337f7b1f5d cmd/go: update default go directive in mod or work init
+ 2025-11-21 3c26aef8fb cmd/internal/obj/riscv: improve large branch/call/jump tests
+ 2025-11-21 31aa9f800b crypto/tls: use inner hello for earlyData when using QUIC and ECH
+ 2025-11-21 d68aec8db1 runtime: replace trace seqlock with write flag
+ 2025-11-21 8d9906cd34 runtime/trace: add Log benchmark
+ 2025-11-21 6aeacdff38 cmd/go: support sha1 repos when git default is sha256
+ 2025-11-21 9570036ca5 crypto/sha3: make the zero value of SHAKE useable
+ 2025-11-21 155efbbeeb crypto/sha3: make the zero value of SHA3 useable
+ 2025-11-21 6f16669e34 database/sql: don't ignore ColumnConverter for unknown input count
+ 2025-11-21 121bc3e464 runtime/pprof: remove hard-coded sleep in CPU profile reader
+ 2025-11-21 b604148c4e runtime: fix double wakeup in CPU profile buffer
+ 2025-11-21 22f24f90b5 cmd/compile: change testing.B.Loop keep alive semantic
+ 2025-11-21 cfb9d2eb73 net: remove unused linknames
+ 2025-11-21 65ef314f89 net/http: remove unused linknames
+ 2025-11-21 0f32fbc631 net/http: populate Response.Request when using NewFileTransport
+ 2025-11-21 3e0a8e7867 net/http: preserve original path encoding in redirects
+ 2025-11-21 831af61120 net/http: use HTTP 307 redirects in ServeMux
+ 2025-11-21 87269224cb net/http: update Response.Request.URL after redirects on GOOS=js
+ 2025-11-21 7aa9ca729f net/http/cookiejar: treat localhost as secure origin
+ 2025-11-21 f870a1d398 net/url: warn that JoinPath arguments should be escaped
+ 2025-11-21 9962d95fed crypto/internal/fips140/mldsa: unroll NTT and inverseNTT
+ 2025-11-21 f821fc46c5 crypto/internal/fisp140test: update acvptool, test data
+ 2025-11-21 b59efc38a0 crypto/internal/fips140/mldsa: new package
+ 2025-11-21 62741480b8 runtime: remove linkname for gopanic
+ 2025-11-21 7db2f0bb9a crypto/internal/hpke: separate KEM and PublicKey/PrivateKey interfaces
+ 2025-11-21 e15800c0ec crypto/internal/hpke: add ML-KEM and hybrid KEMs, and SHAKE KDFs
+ 2025-11-21 7c985a2df4 crypto/internal/hpke: modularize API and support more ciphersuites
+ 2025-11-21 e7d47ac33d cmd/compile: simplify negative on multiplication
+ 2025-11-21 35d2712b32 net/http: fix typo in Transport docs
+ 2025-11-21 90c970cd0f net: remove unnecessary loop variable copies in tests
+ 2025-11-21 9772d3a690 cmd/cgo: strip top-level const qualifier from argument frame struct
+ 2025-11-21 1903782ade errors: add examples for custom Is/As matching
+ 2025-11-21 ec92bc6d63 cmd/compile: rewrite Rsh to RshU if arguments are proved positive
+ 2025-11-21 3820f94c1d cmd/compile: propagate unsigned relations for Rsh if arguments are positive
+ 2025-11-21 d474f1fd21 cmd/compile: make dse track multiple shadowed ranges
+ 2025-11-21 d0d0a72980 cmd/compile/internal/ssa: correct type of ARM64 conditional instructions
+ 2025-11-21 a9704f89ea internal/runtime/gc/scan: add AVX512 impl of filterNil.
+ 2025-11-21 ccd389036a cmd/internal/objabi: remove -V=goexperiment internal special case
+ 2025-11-21 e7787b9eca runtime: go fmt
+ 2025-11-21 17b3b98796 internal/strconv: go fmt
+ 2025-11-21 c851827c68 internal/trace: go fmt
+ 2025-11-21 f87aaec53d cmd/compile: fix integer overflow in prove pass
+ 2025-11-21 dbd2ab9992 cmd/compile/internal: fix typos
+ 2025-11-21 b9d86baae3 cmd/compile/internal/devirtualize: fix typos
+ 2025-11-20 4b0e3cc1d6 cmd/link: support loading R_LARCH_PCREL20_S2 and R_LARCH_CALL36 relocs
+ 2025-11-20 cdba82c7d6 cmd/internal/obj/loong64: add {,X}VSLT.{B/H/W/V}{,U} instructions support
+ 2025-11-20 bd2b117c2c crypto/tls: add QUICErrorEvent
+ 2025-11-20 3ad2e113fc net/http/httputil: wrap ReverseProxy's outbound request body so Close is a noop
+ 2025-11-20 d58b733646 runtime: track goroutine location until actual STW
+ 2025-11-20 1bc54868d4 cmd/vendor: update to x/tools@68724af
+ 2025-11-20 8c3195973b runtime: disable stack allocation tests on sanitizers
+ 2025-11-20 ff654ea100 net/url: permit colons in the host of postgresql:// URLs
+ 2025-11-20 a662badab9 encoding/json: remove linknames
+ 2025-11-20 5afe237d65 mime: add missing path for mime types in godoc
+ 2025-11-20 c1b7112af8 os/signal: make NotifyContext cancel the context with a cause
Change-Id: Ib93ef643be610dfbdd83ff45095a7b1ca2537b8b
Diffstat (limited to 'src/cmd/internal/obj')
| -rw-r--r-- | src/cmd/internal/obj/arm64/asm7.go | 27 | ||||
| -rw-r--r-- | src/cmd/internal/obj/fips140.go | 6 | ||||
| -rw-r--r-- | src/cmd/internal/obj/loong64/a.out.go | 17 | ||||
| -rw-r--r-- | src/cmd/internal/obj/loong64/anames.go | 16 | ||||
| -rw-r--r-- | src/cmd/internal/obj/loong64/asm.go | 143 | ||||
| -rw-r--r-- | src/cmd/internal/obj/riscv/asm_test.go | 181 |
6 files changed, 303 insertions, 87 deletions
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index ccf8eda495..7addf0ddad 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -1674,32 +1674,7 @@ func log2(x uint64) uint32 { if x == 0 { panic("log2 of 0") } - n := uint32(0) - if x >= 1<<32 { - x >>= 32 - n += 32 - } - if x >= 1<<16 { - x >>= 16 - n += 16 - } - if x >= 1<<8 { - x >>= 8 - n += 8 - } - if x >= 1<<4 { - x >>= 4 - n += 4 - } - if x >= 1<<2 { - x >>= 2 - n += 2 - } - if x >= 1<<1 { - x >>= 1 - n += 1 - } - return n + return uint32(bits.Len64(x) - 1) } func autoclass(l int64) int { diff --git a/src/cmd/internal/obj/fips140.go b/src/cmd/internal/obj/fips140.go index da18b64178..8f5b0c4b82 100644 --- a/src/cmd/internal/obj/fips140.go +++ b/src/cmd/internal/obj/fips140.go @@ -354,8 +354,10 @@ func (s *LSym) checkFIPSReloc(ctxt *Link, rel Reloc) { objabi.R_CALLLOONG64, objabi.R_CALLPOWER, objabi.R_GOTPCREL, - objabi.R_LOONG64_ADDR_LO, // used with PC-relative load - objabi.R_LOONG64_ADDR_HI, // used with PC-relative load + objabi.R_LOONG64_ADDR_LO, // used with PC-relative load + objabi.R_LOONG64_ADDR_HI, // used with PC-relative load + objabi.R_LOONG64_ADDR_PCREL20_S2, // used with PC-relative load + objabi.R_LOONG64_CALL36, objabi.R_LOONG64_TLS_LE_HI, objabi.R_LOONG64_TLS_LE_LO, objabi.R_LOONG64_TLS_IE_HI, diff --git a/src/cmd/internal/obj/loong64/a.out.go b/src/cmd/internal/obj/loong64/a.out.go index 5b8bffc9f1..2eabe9bda8 100644 --- a/src/cmd/internal/obj/loong64/a.out.go +++ b/src/cmd/internal/obj/loong64/a.out.go @@ -912,6 +912,23 @@ const ( AVSEQV AXVSEQV + AVSLTB + AVSLTH + AVSLTW + AVSLTV + AVSLTBU + AVSLTHU + AVSLTWU + AVSLTVU + AXVSLTB + AXVSLTH + AXVSLTW + AXVSLTV + AXVSLTBU + AXVSLTHU + AXVSLTWU + AXVSLTVU + // LSX and LASX integer div and mod instructions AVDIVB AVDIVH diff --git a/src/cmd/internal/obj/loong64/anames.go b/src/cmd/internal/obj/loong64/anames.go index 1749b43bf6..92e3cab950 100644 --- a/src/cmd/internal/obj/loong64/anames.go +++ b/src/cmd/internal/obj/loong64/anames.go @@ -400,6 +400,22 @@ var Anames = []string{ "XVSEQW", "VSEQV", "XVSEQV", + "VSLTB", + "VSLTH", + "VSLTW", + "VSLTV", + "VSLTBU", + "VSLTHU", + "VSLTWU", + "VSLTVU", + "XVSLTB", + "XVSLTH", + "XVSLTW", + "XVSLTV", + "XVSLTBU", + "XVSLTHU", + "XVSLTWU", + "XVSLTVU", "VDIVB", "VDIVH", "VDIVW", diff --git a/src/cmd/internal/obj/loong64/asm.go b/src/cmd/internal/obj/loong64/asm.go index b35e49a1b6..857ef31ca3 100644 --- a/src/cmd/internal/obj/loong64/asm.go +++ b/src/cmd/internal/obj/loong64/asm.go @@ -65,26 +65,19 @@ var optab = []Optab{ {AMOVWU, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 12, 4, 0, 0}, {ASUB, C_REG, C_REG, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, - {ASUBV, C_REG, C_REG, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {AADD, C_REG, C_REG, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {AADDV, C_REG, C_REG, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {AAND, C_REG, C_REG, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {ASUB, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, - {ASUBV, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {AADD, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {AADDV, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {AAND, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {ANEGW, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, - {ANEGV, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {AMASKEQZ, C_REG, C_REG, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {ASLL, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {ASLL, C_REG, C_REG, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {ASLLV, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {ASLLV, C_REG, C_REG, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, - {AMUL, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, - {AMUL, C_REG, C_REG, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, - {AMULV, C_REG, C_NONE, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, - {AMULV, C_REG, C_REG, C_NONE, C_REG, C_NONE, 2, 4, 0, 0}, {AADDF, C_FREG, C_NONE, C_NONE, C_FREG, C_NONE, 2, 4, 0, 0}, {AADDF, C_FREG, C_FREG, C_NONE, C_FREG, C_NONE, 2, 4, 0, 0}, {ACMPEQF, C_FREG, C_FREG, C_NONE, C_FCCREG, C_NONE, 2, 4, 0, 0}, @@ -93,6 +86,14 @@ var optab = []Optab{ {AXVSEQB, C_XREG, C_XREG, C_NONE, C_XREG, C_NONE, 2, 4, 0, 0}, {AVSEQB, C_S5CON, C_VREG, C_NONE, C_VREG, C_NONE, 22, 4, 0, 0}, {AXVSEQB, C_S5CON, C_XREG, C_NONE, C_XREG, C_NONE, 22, 4, 0, 0}, + + {AVSLTB, C_VREG, C_VREG, C_NONE, C_VREG, C_NONE, 2, 4, 0, 0}, + {AXVSLTB, C_XREG, C_XREG, C_NONE, C_XREG, C_NONE, 2, 4, 0, 0}, + {AVSLTB, C_S5CON, C_VREG, C_NONE, C_VREG, C_NONE, 22, 4, 0, 0}, + {AXVSLTB, C_S5CON, C_XREG, C_NONE, C_XREG, C_NONE, 22, 4, 0, 0}, + {AVSLTB, C_U5CON, C_VREG, C_NONE, C_VREG, C_NONE, 31, 4, 0, 0}, + {AXVSLTB, C_U5CON, C_XREG, C_NONE, C_XREG, C_NONE, 31, 4, 0, 0}, + {AVANDV, C_VREG, C_VREG, C_NONE, C_VREG, C_NONE, 2, 4, 0, 0}, {AVANDV, C_VREG, C_NONE, C_NONE, C_VREG, C_NONE, 2, 4, 0, 0}, {AXVANDV, C_XREG, C_XREG, C_NONE, C_XREG, C_NONE, 2, 4, 0, 0}, @@ -1495,26 +1496,6 @@ func buildop(ctxt *obj.Link) { opset(ALL, r0) opset(ALLV, r0) - case AMUL: - opset(AMULU, r0) - opset(AMULH, r0) - opset(AMULHU, r0) - opset(AREM, r0) - opset(AREMU, r0) - opset(ADIV, r0) - opset(ADIVU, r0) - opset(AMULWVW, r0) - opset(AMULWVWU, r0) - - case AMULV: - opset(AMULVU, r0) - opset(AMULHV, r0) - opset(AMULHVU, r0) - opset(AREMV, r0) - opset(AREMVU, r0) - opset(ADIVV, r0) - opset(ADIVVU, r0) - case ASLL: opset(ASRL, r0) opset(ASRA, r0) @@ -1533,9 +1514,26 @@ func buildop(ctxt *obj.Link) { case ASUB: opset(ASUBU, r0) opset(ANOR, r0) - - case ASUBV: + opset(ASUBV, r0) opset(ASUBVU, r0) + opset(AMUL, r0) + opset(AMULU, r0) + opset(AMULH, r0) + opset(AMULHU, r0) + opset(AREM, r0) + opset(AREMU, r0) + opset(ADIV, r0) + opset(ADIVU, r0) + opset(AMULV, r0) + opset(AMULVU, r0) + opset(AMULHV, r0) + opset(AMULHVU, r0) + opset(AREMV, r0) + opset(AREMVU, r0) + opset(ADIVV, r0) + opset(ADIVVU, r0) + opset(AMULWVW, r0) + opset(AMULWVWU, r0) case ASYSCALL: opset(ADBAR, r0) @@ -1555,6 +1553,9 @@ func buildop(ctxt *obj.Link) { opset(AALSLW, r0) opset(AALSLWU, r0) + case ANEGW: + opset(ANEGV, r0) + case AMOVW, AMOVD, AMOVF, @@ -1567,8 +1568,6 @@ func buildop(ctxt *obj.Link) { AXVMOVQ, AVSHUFB, AXVSHUFB, - ANEGW, - ANEGV, AWORD, APRELD, APRELDX, @@ -1784,6 +1783,24 @@ func buildop(ctxt *obj.Link) { opset(AXVSHUFW, r0) opset(AXVSHUFV, r0) + case AVSLTB: + opset(AVSLTH, r0) + opset(AVSLTW, r0) + opset(AVSLTV, r0) + opset(AVSLTBU, r0) + opset(AVSLTHU, r0) + opset(AVSLTWU, r0) + opset(AVSLTVU, r0) + + case AXVSLTB: + opset(AXVSLTH, r0) + opset(AXVSLTW, r0) + opset(AXVSLTV, r0) + opset(AXVSLTBU, r0) + opset(AXVSLTHU, r0) + opset(AXVSLTWU, r0) + opset(AXVSLTVU, r0) + case AVANDB: opset(AVORB, r0) opset(AVXORB, r0) @@ -3379,6 +3396,38 @@ func (c *ctxt0) oprrr(a obj.As) uint32 { return 0x0e003 << 15 // vseq.d case AXVSEQV: return 0x0e803 << 15 // xvseq.d + case AVSLTB: + return 0x0E00C << 15 // vslt.b + case AVSLTH: + return 0x0E00D << 15 // vslt.h + case AVSLTW: + return 0x0E00E << 15 // vslt.w + case AVSLTV: + return 0x0E00F << 15 // vslt.d + case AVSLTBU: + return 0x0E010 << 15 // vslt.bu + case AVSLTHU: + return 0x0E011 << 15 // vslt.hu + case AVSLTWU: + return 0x0E012 << 15 // vslt.wu + case AVSLTVU: + return 0x0E013 << 15 // vslt.du + case AXVSLTB: + return 0x0E80C << 15 // xvslt.b + case AXVSLTH: + return 0x0E80D << 15 // xvslt.h + case AXVSLTW: + return 0x0E80E << 15 // xvslt.w + case AXVSLTV: + return 0x0E80F << 15 // xvslt.d + case AXVSLTBU: + return 0x0E810 << 15 // xvslt.bu + case AXVSLTHU: + return 0x0E811 << 15 // xvslt.hu + case AXVSLTWU: + return 0x0E812 << 15 // xvslt.wu + case AXVSLTVU: + return 0x0E813 << 15 // xvslt.du case AVANDV: return 0x0E24C << 15 // vand.v case AVORV: @@ -4399,6 +4448,38 @@ func (c *ctxt0) opirr(a obj.As) uint32 { return 0x0ED02 << 15 // xvseqi.w case AXVSEQV: return 0x0ED03 << 15 // xvseqi.d + case AVSLTB: + return 0x0E50C << 15 // vslti.b + case AVSLTH: + return 0x0E50D << 15 // vslti.h + case AVSLTW: + return 0x0E50E << 15 // vslti.w + case AVSLTV: + return 0x0E50F << 15 // vslti.d + case AVSLTBU: + return 0x0E510 << 15 // vslti.bu + case AVSLTHU: + return 0x0E511 << 15 // vslti.hu + case AVSLTWU: + return 0x0E512 << 15 // vslti.wu + case AVSLTVU: + return 0x0E513 << 15 // vslti.du + case AXVSLTB: + return 0x0ED0C << 15 // xvslti.b + case AXVSLTH: + return 0x0ED0D << 15 // xvslti.h + case AXVSLTW: + return 0x0ED0E << 15 // xvslti.w + case AXVSLTV: + return 0x0ED0F << 15 // xvslti.d + case AXVSLTBU: + return 0x0ED10 << 15 // xvslti.bu + case AXVSLTHU: + return 0x0ED11 << 15 // xvslti.hu + case AXVSLTWU: + return 0x0ED12 << 15 // xvslti.wu + case AXVSLTVU: + return 0x0ED13 << 15 // xvslti.du case AVROTRB: return 0x1ca8<<18 | 0x1<<13 // vrotri.b case AVROTRH: diff --git a/src/cmd/internal/obj/riscv/asm_test.go b/src/cmd/internal/obj/riscv/asm_test.go index 5b50d1533a..f143e70103 100644 --- a/src/cmd/internal/obj/riscv/asm_test.go +++ b/src/cmd/internal/obj/riscv/asm_test.go @@ -17,7 +17,8 @@ import ( ) // TestLargeBranch generates a large function with a very far conditional -// branch, in order to ensure that it assembles successfully. +// branch, in order to ensure that it assembles correctly. This requires +// inverting the branch and using a jump to reach the target. func TestLargeBranch(t *testing.T) { if testing.Short() { t.Skip("Skipping test in short mode") @@ -26,6 +27,23 @@ func TestLargeBranch(t *testing.T) { dir := t.TempDir() + if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module largecall"), 0644); err != nil { + t.Fatalf("Failed to write file: %v\n", err) + } + main := `package main + +import "fmt" + +func main() { + fmt.Print(x()) +} + +func x() uint64 +` + if err := os.WriteFile(filepath.Join(dir, "x.go"), []byte(main), 0644); err != nil { + t.Fatalf("failed to write main: %v\n", err) + } + // Generate a very large function. buf := bytes.NewBuffer(make([]byte, 0, 7000000)) genLargeBranch(buf) @@ -36,27 +54,62 @@ func TestLargeBranch(t *testing.T) { } // Assemble generated file. - cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile) + cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), "-S", tmpfile) cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux") out, err := cmd.CombinedOutput() if err != nil { + t.Errorf("Failed to assemble: %v\n%s", err, out) + } + + // The expected instruction sequence for the long branch is: + // BNEZ + // AUIPC $..., X31 + // JALR X0, $..., X31 + want := regexp.MustCompile(`\sBNEZ\s.*\s.*\n.*\n.*AUIPC\s\$\d+, X31.*\n.*JALR\sX0, \$\d+, ?X31`) + if !want.Match(out) { + t.Error("Missing assembly instructions") + } + + // Build generated files. + cmd = testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "x.exe", "-ldflags=-linkmode=internal") + cmd.Dir = dir + cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux") + out, err = cmd.CombinedOutput() + if err != nil { t.Errorf("Build failed: %v, output: %s", err, out) } + + if runtime.GOARCH == "riscv64" && runtime.GOOS == "linux" { + cmd = testenv.Command(t, filepath.Join(dir, "x.exe")) + out, err = cmd.CombinedOutput() + if err != nil { + t.Errorf("Failed to run test binary: %v", err) + } + if string(out) != "1" { + t.Errorf(`Got test output %q, want "2"`, string(out)) + } + } } func genLargeBranch(buf *bytes.Buffer) { - fmt.Fprintln(buf, "TEXT f(SB),0,$0-0") - fmt.Fprintln(buf, "BEQ X0, X0, label") - for i := 0; i < 1<<19; i++ { + fmt.Fprintln(buf, "TEXT ·x(SB),0,$0-8") + fmt.Fprintln(buf, "MOV X0, X10") + fmt.Fprintln(buf, "BEQZ X10, label") + for i := 0; i < 1<<18; i++ { + // Use a non-compressable instruction. fmt.Fprintln(buf, "ADD $0, X5, X0") } + fmt.Fprintln(buf, "ADD $1, X10, X10") fmt.Fprintln(buf, "label:") - fmt.Fprintln(buf, "ADD $0, X5, X0") + fmt.Fprintln(buf, "ADD $1, X10, X10") + fmt.Fprintln(buf, "MOV X10, r+0(FP)") + fmt.Fprintln(buf, "RET") } // TestLargeCall generates a large function (>1MB of text) with a call to // a following function, in order to ensure that it assembles and links -// correctly. +// correctly. This requires the use of AUIPC+JALR instruction sequences, +// which are fixed up by the linker. func TestLargeCall(t *testing.T) { if testing.Short() { t.Skip("Skipping test in short mode") @@ -69,12 +122,15 @@ func TestLargeCall(t *testing.T) { t.Fatalf("Failed to write file: %v\n", err) } main := `package main + +import "fmt" + func main() { - x() + fmt.Print(x()) } -func x() -func y() +func x() uint64 +func y() uint64 ` if err := os.WriteFile(filepath.Join(dir, "x.go"), []byte(main), 0644); err != nil { t.Fatalf("failed to write main: %v\n", err) @@ -84,51 +140,94 @@ func y() buf := bytes.NewBuffer(make([]byte, 0, 7000000)) genLargeCall(buf) - if err := os.WriteFile(filepath.Join(dir, "x.s"), buf.Bytes(), 0644); err != nil { + tmpfile := filepath.Join(dir, "x.s") + if err := os.WriteFile(tmpfile, buf.Bytes(), 0644); err != nil { t.Fatalf("Failed to write file: %v\n", err) } + // Assemble generated file. + cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), "-S", tmpfile) + cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux") + out, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("Failed to assemble: %v\n%s", err, out) + } + + // The expected instruction sequence for the long call is: + // AUIPC $0, $0, X31 + // JALR X.., X31 + want := regexp.MustCompile(`\sAUIPC\s\$0, \$0, X31.*\n.*\sJALR\sX.*, X31`) + if !want.Match(out) { + t.Error("Missing assembly instructions") + } + // Build generated files. - cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-linkmode=internal") + cmd = testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "x.exe", "-ldflags=-linkmode=internal") cmd.Dir = dir cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux") - out, err := cmd.CombinedOutput() + out, err = cmd.CombinedOutput() if err != nil { t.Errorf("Build failed: %v, output: %s", err, out) } + if runtime.GOARCH == "riscv64" && runtime.GOOS == "linux" { + cmd = testenv.Command(t, filepath.Join(dir, "x.exe")) + out, err = cmd.CombinedOutput() + if err != nil { + t.Errorf("Failed to run test binary: %v", err) + } + if string(out) != "2" { + t.Errorf(`Got test output %q, want "2"`, string(out)) + } + } + if runtime.GOARCH == "riscv64" && testenv.HasCGO() { - cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-linkmode=external") + cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "x.exe", "-ldflags=-linkmode=external") cmd.Dir = dir cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux") out, err := cmd.CombinedOutput() if err != nil { t.Errorf("Build failed: %v, output: %s", err, out) } + + if runtime.GOARCH == "riscv64" && runtime.GOOS == "linux" { + cmd = testenv.Command(t, filepath.Join(dir, "x.exe")) + out, err = cmd.CombinedOutput() + if err != nil { + t.Errorf("Failed to run test binary: %v", err) + } + if string(out) != "2" { + t.Errorf(`Got test output %q, want "2"`, string(out)) + } + } } } func genLargeCall(buf *bytes.Buffer) { - fmt.Fprintln(buf, "TEXT ·x(SB),0,$0-0") + fmt.Fprintln(buf, "TEXT ·x(SB),0,$0-8") + fmt.Fprintln(buf, "MOV X0, X10") fmt.Fprintln(buf, "CALL ·y(SB)") - for i := 0; i < 1<<19; i++ { + fmt.Fprintln(buf, "ADD $1, X10, X10") + fmt.Fprintln(buf, "MOV X10, r+0(FP)") + fmt.Fprintln(buf, "RET") + for i := 0; i < 1<<18; i++ { + // Use a non-compressable instruction. fmt.Fprintln(buf, "ADD $0, X5, X0") } + fmt.Fprintln(buf, "ADD $1, X10, X10") fmt.Fprintln(buf, "RET") fmt.Fprintln(buf, "TEXT ·y(SB),0,$0-0") - fmt.Fprintln(buf, "ADD $0, X5, X0") + fmt.Fprintln(buf, "ADD $1, X10, X10") fmt.Fprintln(buf, "RET") } // TestLargeJump generates a large jump (>1MB of text) with a JMP to the // end of the function, in order to ensure that it assembles correctly. +// This requires the use of AUIPC+JALR instruction sequences. func TestLargeJump(t *testing.T) { if testing.Short() { t.Skip("Skipping test in short mode") } - if runtime.GOARCH != "riscv64" { - t.Skip("Require riscv64 to run") - } testenv.MustHaveGoBuild(t) dir := t.TempDir() @@ -154,22 +253,46 @@ func x() uint64 buf := bytes.NewBuffer(make([]byte, 0, 7000000)) genLargeJump(buf) - if err := os.WriteFile(filepath.Join(dir, "x.s"), buf.Bytes(), 0644); err != nil { + tmpfile := filepath.Join(dir, "x.s") + if err := os.WriteFile(tmpfile, buf.Bytes(), 0644); err != nil { t.Fatalf("Failed to write file: %v\n", err) } + // Assemble generated file. + cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), "-S", tmpfile) + cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux") + out, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("Failed to assemble: %v\n%s", err, out) + } + + // The expected instruction sequence for the long call is: + // AUIPC $..., X31 + // JALR X0, $.., X31 + want := regexp.MustCompile(`\sAUIPC\s\$\d+, X31.*\n.*\sJALR\sX0, \$\d+, ?X31`) + if !want.Match(out) { + t.Error("Missing assembly instructions") + t.Errorf("%s", out) + } + // Build generated files. - cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "x.exe") + cmd = testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "x.exe") cmd.Dir = dir - out, err := cmd.CombinedOutput() + cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux") + out, err = cmd.CombinedOutput() if err != nil { t.Errorf("Build failed: %v, output: %s", err, out) } - cmd = testenv.Command(t, filepath.Join(dir, "x.exe")) - out, err = cmd.CombinedOutput() - if string(out) != "1" { - t.Errorf(`Got test output %q, want "1"`, string(out)) + if runtime.GOARCH == "riscv64" && runtime.GOOS == "linux" { + cmd = testenv.Command(t, filepath.Join(dir, "x.exe")) + out, err = cmd.CombinedOutput() + if err != nil { + t.Errorf("Failed to run test binary: %v", err) + } + if string(out) != "1" { + t.Errorf(`Got test output %q, want "1"`, string(out)) + } } } @@ -178,8 +301,10 @@ func genLargeJump(buf *bytes.Buffer) { fmt.Fprintln(buf, "MOV X0, X10") fmt.Fprintln(buf, "JMP end") for i := 0; i < 1<<18; i++ { - fmt.Fprintln(buf, "ADD $1, X10, X10") + // Use a non-compressable instruction. + fmt.Fprintln(buf, "ADD $0, X5, X0") } + fmt.Fprintln(buf, "ADD $1, X10, X10") fmt.Fprintln(buf, "end:") fmt.Fprintln(buf, "ADD $1, X10, X10") fmt.Fprintln(buf, "MOV X10, r+0(FP)") |
