Skip to content

Commit

Permalink
build: mov deduction for booleans (#341)
Browse files Browse the repository at this point in the history
Updates #336
  • Loading branch information
mmcloughlin authored Nov 27, 2022
1 parent ef60a33 commit 127528d
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 146 deletions.
278 changes: 150 additions & 128 deletions build/zmov.go

Large diffs are not rendered by default.

44 changes: 26 additions & 18 deletions internal/gen/mov.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package gen
import (
"errors"
"fmt"
"sort"
"strings"

"github.com/mmcloughlin/avo/internal/api"
Expand Down Expand Up @@ -48,7 +47,7 @@ func (m *mov) Generate(is []inst.Instruction) ([]byte, error) {
}

func (m *mov) instruction(i inst.Instruction) {
f := flags(i)
tcs := typecases(i)
mfs, err := movforms(i)
if err != nil {
m.AddError(err)
Expand All @@ -61,14 +60,12 @@ func (m *mov) instruction(i inst.Instruction) {
fmt.Sprintf("bn == %d", opsize[mf.B]),
fmt.Sprintf("%s(b)", api.CheckerName(mf.B)),
}
for c, on := range f {
cmp := map[bool]string{true: "!=", false: "=="}
cond := fmt.Sprintf("(t.Info() & %s) %s 0", c, cmp[on])
conds = append(conds, cond)

for _, tc := range tcs {
typecase := fmt.Sprintf("(t.Info() & %s) %s %s", tc.Mask, tc.Op, tc.Value)
m.Printf("case %s && %s:\n", strings.Join(conds, " && "), typecase)
m.Printf("c.%s(a, b)\n", i.Opcode)
}
sort.Strings(conds)
m.Printf("case %s:\n", strings.Join(conds, " && "))
m.Printf("c.%s(a, b)\n", i.Opcode)
}
}

Expand Down Expand Up @@ -100,21 +97,32 @@ func ismov(i inst.Instruction) bool {
return true
}

func flags(i inst.Instruction) map[string]bool {
f := map[string]bool{}
type typecase struct {
Mask string
Op string
Value string
}

func typecases(i inst.Instruction) []typecase {
switch {
case strings.Contains(i.Summary, "Floating-Point"):
f["types.IsFloat"] = true
return []typecase{
{"types.IsFloat", "!=", "0"},
}
case strings.Contains(i.Summary, "Zero-Extend"):
f["types.IsInteger"] = true
f["types.IsUnsigned"] = true
return []typecase{
{"(types.IsInteger|types.IsUnsigned)", "==", "(types.IsInteger|types.IsUnsigned)"},
{"types.IsBoolean", "!=", "0"},
}
case strings.Contains(i.Summary, "Sign-Extension"):
f["types.IsInteger"] = true
f["types.IsUnsigned"] = false
return []typecase{
{"(types.IsInteger|types.IsUnsigned)", "==", "types.IsInteger"},
}
default:
f["types.IsInteger"] = true
return []typecase{
{"(types.IsInteger|types.IsBoolean)", "!=", "0"},
}
}
return f
}

type movform struct{ A, B string }
Expand Down
38 changes: 38 additions & 0 deletions tests/fixedbugs/issue336/asm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//go:build ignore
// +build ignore

package main

import (
"fmt"

. "github.com/mmcloughlin/avo/build"
. "github.com/mmcloughlin/avo/operand"
. "github.com/mmcloughlin/avo/reg"
)

func main() {
variants := []struct {
Size int
Register func() GPVirtual
XOR func(Op, Op)
}{
{8, GP8L, XORB},
{16, GP16, XORW},
{32, GP32, XORL},
{64, GP64, XORQ},
}

for _, v := range variants {
name := fmt.Sprintf("Not%d", v.Size)
TEXT(name, NOSPLIT, "func(x bool) bool")
Doc(fmt.Sprintf("%s returns the boolean negation of x using a %d-bit intermediate.", name, v.Size))
x := v.Register()
Load(Param("x"), x)
v.XOR(U8(1), x)
Store(x.As8L(), ReturnIndex(0))
RET()
}

Generate()
}
4 changes: 4 additions & 0 deletions tests/fixedbugs/issue336/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package issue336 tests boolean arguments and return values.
//
// Issue #336 pointed out that move deduction for boolean types was not present.
package issue336
31 changes: 31 additions & 0 deletions tests/fixedbugs/issue336/issue336.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Code generated by command: go run asm.go -out issue336.s -stubs stub.go. DO NOT EDIT.

#include "textflag.h"

// func Not8(x bool) bool
TEXT ·Not8(SB), NOSPLIT, $0-9
MOVB x+0(FP), AL
XORB $0x01, AL
MOVB AL, ret+8(FP)
RET

// func Not16(x bool) bool
TEXT ·Not16(SB), NOSPLIT, $0-9
MOVBWZX x+0(FP), AX
XORW $0x01, AX
MOVB AL, ret+8(FP)
RET

// func Not32(x bool) bool
TEXT ·Not32(SB), NOSPLIT, $0-9
MOVBLZX x+0(FP), AX
XORL $0x01, AX
MOVB AL, ret+8(FP)
RET

// func Not64(x bool) bool
TEXT ·Not64(SB), NOSPLIT, $0-9
MOVBQZX x+0(FP), AX
XORQ $0x01, AX
MOVB AL, ret+8(FP)
RET
16 changes: 16 additions & 0 deletions tests/fixedbugs/issue336/issue336_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package issue336

import "testing"

//go:generate go run asm.go -out issue336.s -stubs stub.go

func TestNot(t *testing.T) {
nots := []func(bool) bool{Not8, Not16, Not32, Not64}
for _, not := range nots {
for _, x := range []bool{true, false} {
if not(x) != !x {
t.Fail()
}
}
}
}
15 changes: 15 additions & 0 deletions tests/fixedbugs/issue336/stub.go

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

0 comments on commit 127528d

Please sign in to comment.