Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/cmd/compile/internal/ssa/_gen/ARM64.rules
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,17 @@
(MOVWstoreidx4 ptr idx (MOVWreg x) mem) => (MOVWstoreidx4 ptr idx x mem)
(MOVWstoreidx4 ptr idx (MOVWUreg x) mem) => (MOVWstoreidx4 ptr idx x mem)

// Replace extend after sign-extending load with unsigned load,
// so a following zero-extension is unnecessary.
(MOVBUreg <t> x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVBUload <t> [off] {sym} ptr mem)
(MOVHUreg <t> x:(MOVHload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVHUload <t> [off] {sym} ptr mem)
(MOVWUreg <t> x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVWUload <t> [off] {sym} ptr mem)
(MOVBUreg <t> x:(MOVBloadidx ptr idx mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVBUloadidx <t> ptr idx mem)
(MOVHUreg <t> x:(MOVHloadidx ptr idx mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVHUloadidx <t> ptr idx mem)
(MOVWUreg <t> x:(MOVWloadidx ptr idx mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVWUloadidx <t> ptr idx mem)
(MOVHUreg <t> x:(MOVHloadidx2 ptr idx mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVHUloadidx2 <t> ptr idx mem)
(MOVWUreg <t> x:(MOVWloadidx4 ptr idx mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVWUloadidx4 <t> ptr idx mem)

// if a register move has only 1 use, just use the same register without emitting instruction
// MOVDnop doesn't emit instruction, only for ensuring the type.
(MOVDreg x) && x.Uses == 1 => (MOVDnop x)
Expand Down
180 changes: 180 additions & 0 deletions src/cmd/compile/internal/ssa/rewriteARM64.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 50 additions & 1 deletion test/codegen/noextend.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

package codegen

import "math/bits"
import (
"math/bits"
"unsafe"
)

var sval64 [8]int64
var sval32 [8]int32
Expand Down Expand Up @@ -283,3 +286,49 @@ func noIntermediateExtension(a, b, c uint32) uint32 {
// arm64:-"MOVWU"
return a*b*9 + c
}

// When a sign-extending load feeds a single zero-extension, the load itself
// can be switched to its unsigned form, eliminating the extension instruction.

func zextSignLoadInt8(p *int8) bool {
// arm64:-`MOVBU\sR[0-9]+, R[0-9]+`
return *p == 0x5d
}

func zextSignLoadInt16(p *int16) bool {
// arm64:-`MOVHU\sR[0-9]+, R[0-9]+`
return *p == 0x5d
}

func zextSignLoadInt32(p *int32) uint64 {
// arm64:-`MOVWU\sR[0-9]+, R[0-9]+`
return uint64(uint32(*p))
}

func zextSignLoadIdxInt8(s []int8, i int) bool {
// arm64:-`MOVBU\sR[0-9]+, R[0-9]+`
return s[i] == 0x5d
}

func zextSignLoadIdxInt16(s []int16, i int) bool {
// arm64:-`MOVHU\sR[0-9]+, R[0-9]+`
return s[i] == 0x5d
}

func zextSignLoadIdxInt32(s []int32, i int) uint64 {
// arm64:-`MOVWU\sR[0-9]+, R[0-9]+`
return uint64(uint32(s[i]))
}

// Unscaled (byte-offset) indexed loads, which slice indexing does not
// produce, cover the MOVHloadidx/MOVWloadidx variants of the rewrite.

func zextSignLoadIdxUnscaledInt16(p *int16, i int) bool {
// arm64:-`MOVHU\sR[0-9]+, R[0-9]+`
return *(*int16)(unsafe.Add(unsafe.Pointer(p), i)) == 0x5d
}

func zextSignLoadIdxUnscaledInt32(p *int32, i int) uint64 {
// arm64:-`MOVWU\sR[0-9]+, R[0-9]+`
return uint64(uint32(*(*int32)(unsafe.Add(unsafe.Pointer(p), i))))
}