Skip to content

Commit

Permalink
operand: const types
Browse files Browse the repository at this point in the history
  • Loading branch information
mmcloughlin committed Dec 27, 2018
1 parent b3644ec commit abd300c
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 24 deletions.
25 changes: 10 additions & 15 deletions operand/checks.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package operand

import (
"math"

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

Expand All @@ -14,53 +12,50 @@ func IsRegister(op Op) bool { _, ok := op.(reg.Register); return ok }
// IsMem returns whether op has type Mem.
func IsMem(op Op) bool { _, ok := op.(Mem); return ok }

// IsImm returns whether op has type Imm.
func IsImm(op Op) bool { _, ok := op.(Imm); return ok }

// IsRel returns whether op has type Rel.
func IsRel(op Op) bool { _, ok := op.(Rel); return ok }

// Checks corresponding to specific operand types in the Intel Manual:

// Is1 returns true if op is the immediate constant 1.
func Is1(op Op) bool {
i, ok := op.(Imm)
i, ok := op.(U8)
return ok && i == 1
}

// Is3 returns true if op is the immediate constant 3.
func Is3(op Op) bool {
i, ok := op.(Imm)
i, ok := op.(U8)
return ok && i == 3
}

// IsImm2u returns true if op is a 2-bit unsigned immediate (less than 4).
func IsImm2u(op Op) bool {
i, ok := op.(Imm)
i, ok := op.(U8)
return ok && i < 4
}

// IsImm8 returns true is op is an 8-bit immediate.
func IsImm8(op Op) bool {
i, ok := op.(Imm)
return ok && i <= math.MaxUint8
_, ok := op.(U8)
return ok
}

// IsImm16 returns true is op is a 16-bit immediate.
func IsImm16(op Op) bool {
i, ok := op.(Imm)
return ok && i <= math.MaxUint16
_, ok := op.(U16)
return ok
}

// IsImm32 returns true is op is a 32-bit immediate.
func IsImm32(op Op) bool {
i, ok := op.(Imm)
return ok && i <= math.MaxUint32
_, ok := op.(U32)
return ok
}

// IsImm64 returns true is op is a 64-bit immediate.
func IsImm64(op Op) bool {
_, ok := op.(Imm)
_, ok := op.(U64)
return ok
}

Expand Down
32 changes: 32 additions & 0 deletions operand/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package operand

import "fmt"

type Constant interface {
Op
Bytes() int
constant()
}

//go:generate go run make_const.go -output zconst.go

// String is a string constant.
type String string

func (s String) Asm() string { return fmt.Sprintf("$%q", s) }
func (s String) Bytes() int { return len(s) }
func (s String) constant() {}

// Imm returns an unsigned integer constant with size guessed from x.
func Imm(x uint64) Constant {
// TODO(mbm): remove this function
switch {
case uint64(uint8(x)) == x:
return U8(x)
case uint64(uint16(x)) == x:
return U16(x)
case uint64(uint32(x)) == x:
return U32(x)
}
return U64(x)
}
32 changes: 32 additions & 0 deletions operand/const_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package operand

import "testing"

func TestConstants(t *testing.T) {
cases := []struct {
Const Constant
Asm string
Bytes int
}{
{F32(3.1415), "$(3.1415)", 4},
{F64(3.1415), "$(3.1415)", 8},
{U8(42), "$0x2a", 1},
{U16(42), "$0x002a", 2},
{U32(42), "$0x0000002a", 4},
{U64(42), "$0x000000000000002a", 8},
{I8(-42), "$-42", 1},
{I16(-42), "$-42", 2},
{I32(-42), "$-42", 4},
{I64(-42), "$-42", 8},
{String("hello"), "$\"hello\"", 5},
{String("quot:\"q\""), "$\"quot:\\\"q\\\"\"", 8},
}
for _, c := range cases {
if c.Const.Asm() != c.Asm {
t.Errorf("%v.Asm() = %v; expect %v", c.Const, c.Const.Asm(), c.Asm)
}
if c.Const.Bytes() != c.Bytes {
t.Errorf("%v.Bytes() = %v; expect %v", c.Const, c.Const.Bytes(), c.Bytes)
}
}
}
75 changes: 75 additions & 0 deletions operand/make_const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// +build ignore

package main

import (
"bytes"
"flag"
"fmt"
"go/format"
"io"
"log"
"os"
"path/filepath"
"runtime"
"strconv"
)

var (
output = flag.String("output", "", "path to output file (default stdout)")
)

func PrintConstType(w io.Writer, name, typ, format string, size int, doc string) {
r := typ[0]
fmt.Fprintf(w, "// %s\n", doc)
fmt.Fprintf(w, "type %s %s\n", name, typ)
fmt.Fprintf(w, "\n")
fmt.Fprintf(w, "func (%c %s) Asm() string { return fmt.Sprintf(\"$%s\", %c) }\n", r, name, format, r)
fmt.Fprintf(w, "func (%c %s) Bytes() int { return %d }\n", r, name, size)
fmt.Fprintf(w, "func (%c %s) constant() {}\n", r, name)
fmt.Fprintf(w, "\n")
}

func PrintConstTypes(w io.Writer) {
_, self, _, _ := runtime.Caller(0)
fmt.Fprintf(w, "// Code generated by %s. DO NOT EDIT.\n\n", filepath.Base(self))
fmt.Fprintf(w, "package operand\n\n")
fmt.Fprintf(w, "import \"fmt\"\n\n")
for n := 1; n <= 8; n *= 2 {
bits := n * 8
bs := strconv.Itoa(bits)

if n >= 4 {
PrintConstType(w, "F"+bs, "float"+bs, "(%#v)", n, fmt.Sprintf("F%d is a %d-bit floating point constant.", bits, bits))
}
PrintConstType(w, "I"+bs, "int"+bs, "%+d", n, fmt.Sprintf("I%d is a %d-bit signed integer constant.", bits, bits))
PrintConstType(w, "U"+bs, "uint"+bs, "%#0"+strconv.Itoa(2*n)+"x", n, fmt.Sprintf("U%d is a %d-bit unsigned integer constant.", bits, bits))
}
}

func main() {
flag.Parse()

w := os.Stdout
if *output != "" {
f, err := os.Create(*output)
if err != nil {
log.Fatal(err)
}
defer f.Close()
w = f
}

buf := bytes.NewBuffer(nil)
PrintConstTypes(buf)

src, err := format.Source(buf.Bytes())
if err != nil {
log.Fatal(err)
}

_, err = w.Write(src)
if err != nil {
log.Fatal(err)
}
}
8 changes: 1 addition & 7 deletions operand/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,6 @@ func (m Mem) Asm() string {
return a
}

type Imm uint64

func (i Imm) Asm() string {
return fmt.Sprintf("$%#x", i)
}

// Rel is an offset relative to the instruction pointer.
type Rel int32

Expand Down Expand Up @@ -109,7 +103,7 @@ func Registers(op Op) []reg.Register {
r = append(r, op.Index)
}
return r
case Imm, Rel, LabelRef:
case Constant, Rel, LabelRef:
return nil
}
panic("unknown operand type")
Expand Down
75 changes: 75 additions & 0 deletions operand/zconst.go

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

4 changes: 2 additions & 2 deletions pass/reg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ func TestLivenessBasic(t *testing.T) {
ctx.Function("add")
a := ctx.GP64v()
b := ctx.GP64v()
ctx.MOVQ(operand.Imm(1), a)
ctx.MOVQ(operand.Imm(2), b)
ctx.MOVQ(operand.U64(1), a)
ctx.MOVQ(operand.U64(2), b)
ctx.ADDQ(a, b)

AssertLiveness(t, ctx,
Expand Down

0 comments on commit abd300c

Please sign in to comment.