operand: const types
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
package operand
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/mmcloughlin/avo/reg"
|
||||
)
|
||||
|
||||
@@ -14,9 +12,6 @@ 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 }
|
||||
|
||||
@@ -24,43 +19,43 @@ func IsRel(op Op) bool { _, ok := op.(Rel); return ok }
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
||||
32
operand/const.go
Normal file
32
operand/const.go
Normal file
@@ -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
operand/const_test.go
Normal file
32
operand/const_test.go
Normal file
@@ -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
operand/make_const.go
Normal file
75
operand/make_const.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
75
operand/zconst.go
Normal file
75
operand/zconst.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// Code generated by make_const.go. DO NOT EDIT.
|
||||
|
||||
package operand
|
||||
|
||||
import "fmt"
|
||||
|
||||
// I8 is a 8-bit signed integer constant.
|
||||
type I8 int8
|
||||
|
||||
func (i I8) Asm() string { return fmt.Sprintf("$%+d", i) }
|
||||
func (i I8) Bytes() int { return 1 }
|
||||
func (i I8) constant() {}
|
||||
|
||||
// U8 is a 8-bit unsigned integer constant.
|
||||
type U8 uint8
|
||||
|
||||
func (u U8) Asm() string { return fmt.Sprintf("$%#02x", u) }
|
||||
func (u U8) Bytes() int { return 1 }
|
||||
func (u U8) constant() {}
|
||||
|
||||
// I16 is a 16-bit signed integer constant.
|
||||
type I16 int16
|
||||
|
||||
func (i I16) Asm() string { return fmt.Sprintf("$%+d", i) }
|
||||
func (i I16) Bytes() int { return 2 }
|
||||
func (i I16) constant() {}
|
||||
|
||||
// U16 is a 16-bit unsigned integer constant.
|
||||
type U16 uint16
|
||||
|
||||
func (u U16) Asm() string { return fmt.Sprintf("$%#04x", u) }
|
||||
func (u U16) Bytes() int { return 2 }
|
||||
func (u U16) constant() {}
|
||||
|
||||
// F32 is a 32-bit floating point constant.
|
||||
type F32 float32
|
||||
|
||||
func (f F32) Asm() string { return fmt.Sprintf("$(%#v)", f) }
|
||||
func (f F32) Bytes() int { return 4 }
|
||||
func (f F32) constant() {}
|
||||
|
||||
// I32 is a 32-bit signed integer constant.
|
||||
type I32 int32
|
||||
|
||||
func (i I32) Asm() string { return fmt.Sprintf("$%+d", i) }
|
||||
func (i I32) Bytes() int { return 4 }
|
||||
func (i I32) constant() {}
|
||||
|
||||
// U32 is a 32-bit unsigned integer constant.
|
||||
type U32 uint32
|
||||
|
||||
func (u U32) Asm() string { return fmt.Sprintf("$%#08x", u) }
|
||||
func (u U32) Bytes() int { return 4 }
|
||||
func (u U32) constant() {}
|
||||
|
||||
// F64 is a 64-bit floating point constant.
|
||||
type F64 float64
|
||||
|
||||
func (f F64) Asm() string { return fmt.Sprintf("$(%#v)", f) }
|
||||
func (f F64) Bytes() int { return 8 }
|
||||
func (f F64) constant() {}
|
||||
|
||||
// I64 is a 64-bit signed integer constant.
|
||||
type I64 int64
|
||||
|
||||
func (i I64) Asm() string { return fmt.Sprintf("$%+d", i) }
|
||||
func (i I64) Bytes() int { return 8 }
|
||||
func (i I64) constant() {}
|
||||
|
||||
// U64 is a 64-bit unsigned integer constant.
|
||||
type U64 uint64
|
||||
|
||||
func (u U64) Asm() string { return fmt.Sprintf("$%#016x", u) }
|
||||
func (u U64) Bytes() int { return 8 }
|
||||
func (u U64) constant() {}
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user