go/test/codegen/bool.go

316 lines
7.3 KiB
Go
Raw Normal View History

// asmcheck
// Copyright 2020 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 codegen
import (
"math/bits"
)
// This file contains codegen tests related to boolean simplifications/optimizations.
func convertNeq0B(x uint8, c bool) bool {
// amd64:"ANDL\t[$]1",-"SETNE"
// ppc64x:"RLDICL",-"CMPW",-"ISEL"
b := x&1 != 0
return c && b
}
func convertNeq0W(x uint16, c bool) bool {
// amd64:"ANDL\t[$]1",-"SETNE"
// ppc64x:"RLDICL",-"CMPW",-"ISEL"
b := x&1 != 0
return c && b
}
func convertNeq0L(x uint32, c bool) bool {
// amd64:"ANDL\t[$]1",-"SETB"
// ppc64x:"RLDICL",-"CMPW",-"ISEL"
b := x&1 != 0
return c && b
}
func convertNeq0Q(x uint64, c bool) bool {
cmd/compile: use ANDL for small immediates We can rewrite ANDQ with an immediate fitting in 32bit with an ANDL, which is shorter to encode. Looking at Go binary itself, before the change there was: ANDL: 2337 ANDQ: 4476 After the change: ANDL: 3790 ANDQ: 3024 So we got rid of 1452 ANDQs This makes the Linux x86_64 binary 0.03% smaller. There seems to be an impact on performance. Intel Cascade Lake benchmarks (with perflock): name old time/op new time/op delta BinaryTree17-8 1.91s ± 1% 1.89s ± 1% -1.22% (p=0.000 n=21+18) Fannkuch11-8 2.34s ± 0% 2.34s ± 0% ~ (p=0.052 n=20+20) FmtFprintfEmpty-8 27.7ns ± 1% 27.4ns ± 3% ~ (p=0.497 n=21+21) FmtFprintfString-8 53.2ns ± 0% 51.5ns ± 0% -3.21% (p=0.000 n=20+19) FmtFprintfInt-8 57.3ns ± 0% 55.7ns ± 0% -2.89% (p=0.000 n=19+19) FmtFprintfIntInt-8 92.3ns ± 0% 88.4ns ± 1% -4.23% (p=0.000 n=20+21) FmtFprintfPrefixedInt-8 103ns ± 0% 103ns ± 0% +0.23% (p=0.000 n=20+21) FmtFprintfFloat-8 147ns ± 0% 148ns ± 0% +0.75% (p=0.000 n=20+21) FmtManyArgs-8 384ns ± 0% 381ns ± 0% -0.63% (p=0.000 n=21+21) GobDecode-8 3.86ms ± 1% 3.88ms ± 1% +0.52% (p=0.000 n=20+21) GobEncode-8 2.77ms ± 1% 2.77ms ± 0% ~ (p=0.078 n=21+21) Gzip-8 168ms ± 1% 168ms ± 0% +0.24% (p=0.000 n=20+20) Gunzip-8 25.1ms ± 0% 24.3ms ± 0% -3.03% (p=0.000 n=21+21) HTTPClientServer-8 61.4µs ± 8% 59.1µs ±10% ~ (p=0.088 n=20+21) JSONEncode-8 6.86ms ± 0% 6.70ms ± 0% -2.29% (p=0.000 n=20+19) JSONDecode-8 30.8ms ± 1% 30.6ms ± 1% -0.82% (p=0.000 n=20+20) Mandelbrot200-8 3.85ms ± 0% 3.85ms ± 0% ~ (p=0.191 n=16+17) GoParse-8 2.61ms ± 2% 2.60ms ± 1% ~ (p=0.561 n=21+20) RegexpMatchEasy0_32-8 48.5ns ± 2% 45.9ns ± 3% -5.26% (p=0.000 n=20+21) RegexpMatchEasy0_1K-8 139ns ± 0% 139ns ± 0% +0.27% (p=0.000 n=18+20) RegexpMatchEasy1_32-8 41.3ns ± 0% 42.1ns ± 4% +1.95% (p=0.000 n=17+21) RegexpMatchEasy1_1K-8 216ns ± 2% 216ns ± 0% +0.17% (p=0.020 n=21+19) RegexpMatchMedium_32-8 790ns ± 7% 803ns ± 8% ~ (p=0.178 n=21+21) RegexpMatchMedium_1K-8 23.5µs ± 5% 23.7µs ± 5% ~ (p=0.421 n=21+21) RegexpMatchHard_32-8 1.09µs ± 1% 1.09µs ± 1% -0.53% (p=0.000 n=19+18) RegexpMatchHard_1K-8 33.0µs ± 0% 33.0µs ± 0% ~ (p=0.610 n=21+20) Revcomp-8 348ms ± 0% 353ms ± 0% +1.38% (p=0.000 n=17+18) Template-8 42.0ms ± 1% 41.9ms ± 1% -0.30% (p=0.049 n=20+20) TimeParse-8 185ns ± 0% 185ns ± 0% ~ (p=0.387 n=20+18) TimeFormat-8 237ns ± 1% 241ns ± 1% +1.57% (p=0.000 n=21+21) [Geo mean] 35.4µs 35.2µs -0.66% name old speed new speed delta GobDecode-8 199MB/s ± 1% 198MB/s ± 1% -0.52% (p=0.000 n=20+21) GobEncode-8 277MB/s ± 1% 277MB/s ± 0% ~ (p=0.075 n=21+21) Gzip-8 116MB/s ± 1% 115MB/s ± 0% -0.25% (p=0.000 n=20+20) Gunzip-8 773MB/s ± 0% 797MB/s ± 0% +3.12% (p=0.000 n=21+21) JSONEncode-8 283MB/s ± 0% 290MB/s ± 0% +2.35% (p=0.000 n=20+19) JSONDecode-8 63.0MB/s ± 1% 63.5MB/s ± 1% +0.82% (p=0.000 n=20+20) GoParse-8 22.2MB/s ± 2% 22.3MB/s ± 1% ~ (p=0.539 n=21+20) RegexpMatchEasy0_32-8 660MB/s ± 2% 697MB/s ± 3% +5.57% (p=0.000 n=20+21) RegexpMatchEasy0_1K-8 7.36GB/s ± 0% 7.34GB/s ± 0% -0.26% (p=0.000 n=18+20) RegexpMatchEasy1_32-8 775MB/s ± 0% 761MB/s ± 4% -1.88% (p=0.000 n=17+21) RegexpMatchEasy1_1K-8 4.74GB/s ± 2% 4.74GB/s ± 0% -0.18% (p=0.020 n=21+19) RegexpMatchMedium_32-8 40.6MB/s ± 7% 39.9MB/s ± 9% ~ (p=0.191 n=21+21) RegexpMatchMedium_1K-8 43.7MB/s ± 5% 43.2MB/s ± 5% ~ (p=0.435 n=21+21) RegexpMatchHard_32-8 29.3MB/s ± 1% 29.4MB/s ± 1% +0.53% (p=0.000 n=19+18) RegexpMatchHard_1K-8 31.0MB/s ± 0% 31.0MB/s ± 0% ~ (p=0.572 n=21+20) Revcomp-8 730MB/s ± 0% 720MB/s ± 0% -1.36% (p=0.000 n=17+18) Template-8 46.2MB/s ± 1% 46.3MB/s ± 1% +0.30% (p=0.041 n=20+20) [Geo mean] 204MB/s 205MB/s +0.30% Change-Id: Iac75d0ec184a515ce0e65e19559d5fe2e9840514 Reviewed-on: https://go-review.googlesource.com/c/go/+/354970 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com> Trust: Josh Bleecher Snyder <josharian@gmail.com> Trust: Keith Randall <khr@golang.org> Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-10-10 17:56:16 +02:00
// amd64:"ANDL\t[$]1",-"SETB"
// ppc64x:"RLDICL",-"CMP",-"ISEL"
b := x&1 != 0
return c && b
}
func convertNeqBool32(x uint32) bool {
// ppc64x:"RLDICL",-"CMPW",-"ISEL"
return x&1 != 0
}
func convertEqBool32(x uint32) bool {
// ppc64x:"RLDICL",-"CMPW","XOR",-"ISEL"
// amd64:"ANDL","XORL",-"BTL",-"SETCC"
return x&1 == 0
}
func convertNeqBool64(x uint64) bool {
// ppc64x:"RLDICL",-"CMP",-"ISEL"
return x&1 != 0
}
func convertEqBool64(x uint64) bool {
// ppc64x:"RLDICL","XOR",-"CMP",-"ISEL"
// amd64:"ANDL","XORL",-"BTL",-"SETCC"
return x&1 == 0
}
cmd/compile: add 2 phiopt cases Add 2 more cases: if a { x = value } else { x = a } => x = a && value if a { x = a } else { x = value } => x = a || value AND case goes from: 00006 (8) TESTB AX, AX 00007 (8) JNE 9 00008 (13) MOVL AX, BX 00009 (13) MOVL BX, AX 00010 (13) RET to: 00006 (13) ANDL BX, AX 00007 (13) RET OR goes from: 00006 (19) TESTB AX, AX 00007 (19) JNE 9 00008 (24) MOVL BX, AX 00009 (24) RET to: 00006 (24) ORL BX, AX 00007 (24) RET compilecmp linux/amd64: runtime runtime.lock2 847 -> 869 (+2.60%) runtime.addspecial 542 -> 517 (-4.61%) runtime.tracebackPCs changed runtime.scanstack changed runtime.mallocinit changed runtime.traceback2 2238 -> 2206 (-1.43%) runtime [cmd/compile] runtime.lock2 860 -> 882 (+2.56%) runtime.scanstack changed runtime.addspecial 542 -> 517 (-4.61%) runtime.traceback2 2238 -> 2206 (-1.43%) runtime.lockWithRank 870 -> 890 (+2.30%) runtime.tracebackPCs changed runtime.mallocinit changed strconv strconv.ryuFtoaFixed32 changed strconv.ryuFtoaFixed64 639 -> 638 (-0.16%) strconv.readFloat changed strconv.ryuFtoaShortest changed strings strings.(*Replacer).build changed strconv [cmd/compile] strconv.readFloat changed strconv.ryuFtoaFixed64 639 -> 638 (-0.16%) strconv.ryuFtoaFixed32 changed strconv.ryuFtoaShortest changed strings [cmd/compile] strings.(*Replacer).build changed regexp regexp.makeOnePass.func1 changed regexp [cmd/compile] regexp.makeOnePass.func1 changed encoding/json encoding/json.indirect changed database/sql database/sql.driverArgsConnLocked changed vendor/golang.org/x/text/unicode/norm vendor/golang.org/x/text/unicode/norm.Form.transform changed go/doc/comment go/doc/comment.parseSpans changed internal/diff internal/diff.tgs changed log/slog log/slog.(*handleState).appendNonBuiltIns 1898 -> 1877 (-1.11%) testing/fstest testing/fstest.(*fsTester).checkGlob changed runtime/pprof runtime/pprof.(*profileBuilder).build changed cmd/internal/dwarf cmd/internal/dwarf.isEmptyInlinedCall 254 -> 244 (-3.94%) go/printer go/printer.keepTypeColumn 302 -> 270 (-10.60%) go/printer.(*printer).binaryExpr changed cmd/compile/internal/syntax cmd/compile/internal/syntax.(*scanner).rune changed cmd/compile/internal/syntax.(*scanner).number 2137 -> 2153 (+0.75%) Change-Id: I7f95f54b03a35d0b616c40f38b415a7feb71be73 Reviewed-on: https://go-review.googlesource.com/c/go/+/666835 Reviewed-by: Keith Randall <khr@golang.org> Auto-Submit: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com> Run-TryBot: Jakub Ciolek <jakub@ciolek.dev> TryBot-Bypass: Keith Randall <khr@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-04-19 12:31:26 +02:00
func phiAnd(a, b bool) bool {
var x bool
// amd64:-"TESTB"
if a {
x = b
} else {
x = a
}
// amd64:"ANDL"
return x
}
func phiOr(a, b bool) bool {
var x bool
// amd64:-"TESTB"
if a {
x = a
} else {
x = b
}
// amd64:"ORL"
return x
}
func TestSetEq64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBC\tCR0EQ",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBC\tCR0EQ"
// ppc64x/power8:"CMP","ISEL",-"SETBC\tCR0EQ"
b := x == y
return b
}
func TestSetNeq64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBCR\tCR0EQ",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBCR\tCR0EQ"
// ppc64x/power8:"CMP","ISEL",-"SETBCR\tCR0EQ"
b := x != y
return b
}
func TestSetLt64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBC\tCR0GT",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBC\tCR0GT"
// ppc64x/power8:"CMP","ISEL",-"SETBC\tCR0GT"
b := x < y
return b
}
func TestSetLe64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBCR\tCR0LT",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBCR\tCR0LT"
// ppc64x/power8:"CMP","ISEL",-"SETBCR\tCR0LT"
b := x <= y
return b
}
func TestSetGt64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBC\tCR0LT",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBC\tCR0LT"
// ppc64x/power8:"CMP","ISEL",-"SETBC\tCR0LT"
b := x > y
return b
}
func TestSetGe64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBCR\tCR0GT",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBCR\tCR0GT"
// ppc64x/power8:"CMP","ISEL",-"SETBCR\tCR0GT"
b := x >= y
return b
}
func TestSetLtFp64(x float64, y float64) bool {
// ppc64x/power10:"SETBC\tCR0LT",-"ISEL"
// ppc64x/power9:"FCMP","ISEL",-"SETBC\tCR0LT"
// ppc64x/power8:"FCMP","ISEL",-"SETBC\tCR0LT"
b := x < y
return b
}
func TestSetLeFp64(x float64, y float64) bool {
// ppc64x/power10:"SETBC\tCR0LT","SETBC\tCR0EQ","OR",-"ISEL",-"ISEL"
// ppc64x/power9:"ISEL","ISEL",-"SETBC\tCR0LT",-"SETBC\tCR0EQ","OR"
// ppc64x/power8:"ISEL","ISEL",-"SETBC\tCR0LT",-"SETBC\tCR0EQ","OR"
b := x <= y
return b
}
func TestSetGtFp64(x float64, y float64) bool {
// ppc64x/power10:"SETBC\tCR0LT",-"ISEL"
// ppc64x/power9:"FCMP","ISEL",-"SETBC\tCR0LT"
// ppc64x/power8:"FCMP","ISEL",-"SETBC\tCR0LT"
b := x > y
return b
}
func TestSetGeFp64(x float64, y float64) bool {
// ppc64x/power10:"SETBC\tCR0LT","SETBC\tCR0EQ","OR",-"ISEL",-"ISEL"
// ppc64x/power9:"ISEL","ISEL",-"SETBC\tCR0LT",-"SETBC\tCR0EQ","OR"
// ppc64x/power8:"ISEL","ISEL",-"SETBC\tCR0LT",-"SETBC\tCR0EQ","OR"
b := x >= y
return b
}
func TestSetInvEq64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBCR\tCR0EQ",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBCR\tCR0EQ"
// ppc64x/power8:"CMP","ISEL",-"SETBCR\tCR0EQ"
b := !(x == y)
return b
}
func TestSetInvNeq64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBC\tCR0EQ",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBC\tCR0EQ"
// ppc64x/power8:"CMP","ISEL",-"SETBC\tCR0EQ"
b := !(x != y)
return b
}
func TestSetInvLt64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBCR\tCR0GT",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBCR\tCR0GT"
// ppc64x/power8:"CMP","ISEL",-"SETBCR\tCR0GT"
b := !(x < y)
return b
}
func TestSetInvLe64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBC\tCR0LT",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBC\tCR0LT"
// ppc64x/power8:"CMP","ISEL",-"SETBC\tCR0LT"
b := !(x <= y)
return b
}
func TestSetInvGt64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBCR\tCR0LT",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBCR\tCR0LT"
// ppc64x/power8:"CMP","ISEL",-"SETBCR\tCR0LT"
b := !(x > y)
return b
}
func TestSetInvGe64(x uint64, y uint64) bool {
// ppc64x/power10:"SETBC\tCR0GT",-"ISEL"
// ppc64x/power9:"CMP","ISEL",-"SETBC\tCR0GT"
// ppc64x/power8:"CMP","ISEL",-"SETBC\tCR0GT"
b := !(x >= y)
return b
}
func TestSetInvEqFp64(x float64, y float64) bool {
// ppc64x/power10:"SETBCR\tCR0EQ",-"ISEL"
// ppc64x/power9:"FCMP","ISEL",-"SETBCR\tCR0EQ"
// ppc64x/power8:"FCMP","ISEL",-"SETBCR\tCR0EQ"
b := !(x == y)
return b
}
func TestSetInvNeqFp64(x float64, y float64) bool {
// ppc64x/power10:"SETBC\tCR0EQ",-"ISEL"
// ppc64x/power9:"FCMP","ISEL",-"SETBC\tCR0EQ"
// ppc64x/power8:"FCMP","ISEL",-"SETBC\tCR0EQ"
b := !(x != y)
return b
}
func TestSetInvLtFp64(x float64, y float64) bool {
// ppc64x/power10:"SETBCR\tCR0LT",-"ISEL"
// ppc64x/power9:"FCMP","ISEL",-"SETBCR\tCR0LT"
// ppc64x/power8:"FCMP","ISEL",-"SETBCR\tCR0LT"
b := !(x < y)
return b
}
func TestSetInvLeFp64(x float64, y float64) bool {
// ppc64x/power10:"SETBC\tCR0LT",-"ISEL"
// ppc64x/power9:"FCMP","ISEL",-"SETBC\tCR0LT"
// ppc64x/power8:"FCMP","ISEL",-"SETBC\tCR0LT"
b := !(x <= y)
return b
}
func TestSetInvGtFp64(x float64, y float64) bool {
// ppc64x/power10:"SETBCR\tCR0LT",-"ISEL"
// ppc64x/power9:"FCMP","ISEL",-"SETBCR\tCR0LT"
// ppc64x/power8:"FCMP","ISEL",-"SETBCR\tCR0LT"
b := !(x > y)
return b
}
func TestSetInvGeFp64(x float64, y float64) bool {
// ppc64x/power10:"SETBC\tCR0LT",-"ISEL"
// ppc64x/power9:"FCMP","ISEL",-"SETBC\tCR0LT"
// ppc64x/power8:"FCMP","ISEL",-"SETBC\tCR0LT"
b := !(x >= y)
return b
}
func TestLogicalCompareZero(x *[64]uint64) {
// ppc64x:"ANDCC",^"AND"
b := x[0] & 3
if b != 0 {
x[0] = b
}
// ppc64x:"ANDCC",^"AND"
b = x[1] & x[2]
if b != 0 {
x[1] = b
}
// ppc64x:"ANDNCC",^"ANDN"
b = x[1] &^ x[2]
if b != 0 {
x[1] = b
}
// ppc64x:"ORCC",^"OR"
b = x[3] | x[4]
if b != 0 {
x[3] = b
}
// ppc64x:"SUBCC",^"SUB"
b = x[5] - x[6]
if b != 0 {
x[5] = b
}
// ppc64x:"NORCC",^"NOR"
b = ^(x[5] | x[6])
if b != 0 {
x[5] = b
}
// ppc64x:"XORCC",^"XOR"
b = x[7] ^ x[8]
if b != 0 {
x[7] = b
}
// ppc64x:"ADDCC",^"ADD"
b = x[9] + x[10]
if b != 0 {
x[9] = b
}
// ppc64x:"NEGCC",^"NEG"
b = -x[11]
if b != 0 {
x[11] = b
}
// ppc64x:"CNTLZDCC",^"CNTLZD"
b = uint64(bits.LeadingZeros64(x[12]))
if b != 0 {
x[12] = b
}
// ppc64x:"ADDCCC\t[$]4,"
c := int64(x[12]) + 4
if c <= 0 {
x[12] = uint64(c)
}
// ppc64x:"MULHDUCC",^"MULHDU"
hi, _ := bits.Mul64(x[13], x[14])
if hi != 0 {
x[14] = hi
}
}
func constantWrite(b bool, p *bool) {
if b {
// amd64:`MOVB\t[$]1, \(`
*p = b
}
}