fspl/llvm/type.go

390 lines
8.3 KiB
Go

package llvm
import "fmt"
import "strings"
type Type interface {
fmt.Stringer
LLString () string
Name () string
SetName (name string)
Equals (Type) bool
}
type AbstractType struct {
name string
}
func (this *AbstractType) Name () string {
return this.name
}
func (this *AbstractType) SetName (name string) {
this.name = name
}
func (this *AbstractType) Named () bool {
return this.name != ""
}
type TypeDefined struct {
AbstractType
Source Type
}
func (this *TypeDefined) LLString () string {
return this.Source.String()
}
func (this *TypeDefined) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeDefined) Equals (ty Type) bool {
return this.Source.Equals(ty)
}
type TypeArray struct {
AbstractType
Element Type
Length uint64
}
func (this *TypeArray) LLString () string {
return fmt.Sprintf("[%d x %v]", this.Length, this.Element)
}
func (this *TypeArray) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeArray) Equals (ty Type) bool {
if ty, ok := ty.(*TypeArray); ok {
return this.Length == ty.Length &&
TypesEqual(this.Element, ty.Element)
}
return false
}
type FloatKind uint8; const (
// 16-bit floating-point type (IEEE 754 half precision).
FloatKindHalf FloatKind = iota // half
// 32-bit floating-point type (IEEE 754 single precision).
FloatKindFloat // float
// 64-bit floating-point type (IEEE 754 double precision).
FloatKindDouble // double
// 128-bit floating-point type (IEEE 754 quadruple precision).
FloatKindFP128 // fp128
// 80-bit floating-point type (x86 extended precision).
FloatKindX86_FP80 // x86_fp80
// 128-bit floating-point type (PowerPC double-double arithmetic).
FloatKindPPC_FP128 // ppc_fp128
)
func (kind FloatKind) String () string {
switch kind {
case FloatKindHalf: return "half"
case FloatKindFloat: return "float"
case FloatKindDouble: return "double"
case FloatKindFP128: return "fp128"
case FloatKindX86_FP80: return "x86_fp80"
case FloatKindPPC_FP128: return "ppc_fp128"
default: return fmt.Sprintf("FloatKind(%d)", kind)
}
}
type TypeFloat struct {
AbstractType
Kind FloatKind
}
func (this *TypeFloat) LLString () string {
return this.Kind.String()
}
func (this *TypeFloat) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeFloat) Equals (ty Type) bool {
if ty, ok := ty.(*TypeFloat); ok {
return this.Kind == ty.Kind
}
return false
}
type TypeFunction struct {
AbstractType
Return Type
Parameters []Type
Variadic bool
}
func (this *TypeFunction) LLString () string {
buffer := &strings.Builder { }
fmt.Fprintf(buffer, "%s (", this.Return)
for index, param := range this.Parameters {
if index > 0 { buffer.WriteString(", ") }
buffer.WriteString(param.String())
}
if this.Variadic {
if len(this.Parameters) > 0 { buffer.WriteString(", ") }
buffer.WriteString("...")
}
buffer.WriteString(")")
return buffer.String()
}
func (this *TypeFunction) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeFunction) Equals (ty Type) bool {
if ty, ok := ty.(*TypeFunction); ok {
if len(this.Parameters) != len(ty.Parameters) { return false }
for index, parameter := range this.Parameters {
if !TypesEqual(parameter, ty.Parameters[index]) { return false }
}
return TypesEqual(this.Return, ty.Return) &&
this.Variadic == ty.Variadic
}
return false
}
type TypeInt struct {
AbstractType
BitSize uint64
}
func (this *TypeInt) LLString () string {
return fmt.Sprintf("i%d", this.BitSize)
}
func (this *TypeInt) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeInt) Equals (ty Type) bool {
if ty, ok := ty.(*TypeInt); ok {
return this.BitSize == ty.BitSize
}
return false
}
type TypeLabel struct {
AbstractType
}
func (this *TypeLabel) LLString () string {
return "label"
}
func (this *TypeLabel) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeLabel) Equals (ty Type) bool {
_, ok := ty.(*TypeLabel)
return ok
}
type TypeMMX struct {
AbstractType
}
func (this *TypeMMX) LLString () string {
return "x86_mmx"
}
func (this *TypeMMX) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeMMX) Equals (ty Type) bool {
_, ok := ty.(*TypeMMX)
return ok
}
type TypeMetadata struct {
AbstractType
}
func (this *TypeMetadata) LLString () string {
return "metadata"
}
func (this *TypeMetadata) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeMetadata) Equals (ty Type) bool {
_, ok := ty.(*TypeMetadata)
return ok
}
type TypePointer struct {
AbstractType
AddressSpace AddressSpace
}
func (this *TypePointer) LLString () string {
if this.AddressSpace == 0 {
return fmt.Sprintf("ptr")
} else {
return fmt.Sprintf("ptr %v", this.AddressSpace)
}
}
func (this *TypePointer) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypePointer) Equals (ty Type) bool {
_, ok := ty.(*TypePointer)
return ok
}
type TypeStruct struct {
AbstractType
Fields []Type
Packed bool
Opaque bool
}
func (this *TypeStruct) LLString () string {
if this.Opaque { return "opaque" }
buffer := &strings.Builder { }
if this.Packed { buffer.WriteString("<") }
buffer.WriteString("{ ")
for index, field := range this.Fields {
if index > 0 { buffer.WriteString(", ") }
buffer.WriteString(field.String())
}
buffer.WriteString(" }")
if this.Packed { buffer.WriteString(">") }
return buffer.String()
}
func (this *TypeStruct) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeStruct) Equals (ty Type) bool {
if ty, ok := ty.(*TypeStruct); ok {
if len(this.Fields) != len(ty.Fields) { return false }
for index, field := range this.Fields {
if !TypesEqual(field, ty.Fields[index]) { return false }
}
return this.Packed == ty.Packed && this.Opaque == ty.Opaque
}
return false
}
type TypeToken struct {
AbstractType
}
func (this *TypeToken) LLString () string {
return "token"
}
func (this *TypeToken) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeToken) Equals (ty Type) bool {
_, ok := ty.(*TypeToken)
return ok
}
type TypeVector struct {
AbstractType
Element Type
Length uint64
Scalable bool
}
func (this *TypeVector) LLString () string {
if this.Scalable {
return fmt.Sprintf("<vscale x %d x %s>", this.Length, this.Element)
} else {
return fmt.Sprintf("<%d x %s>", this.Length, this.Element)
}
}
func (this *TypeVector) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeVector) Equals (ty Type) bool {
if ty, ok := ty.(*TypeVector); ok {
return this.Length == ty.Length &&
this.Scalable == ty.Scalable &&
TypesEqual(this.Element, ty.Element)
}
return false
}
type TypeVoid struct {
AbstractType
}
func (this *TypeVoid) LLString () string {
return "void"
}
func (this *TypeVoid) String () string {
if this.Named() { return EncodeTypeName(this.Name()) }
return this.LLString()
}
func (this *TypeVoid) Equals (ty Type) bool {
_, ok := ty.(*TypeVoid)
return ok
}
func aggregateElemType (t Type, indices []uint64) Type {
// Base case.
if len(indices) == 0 {
return t
}
switch t := t.(type) {
case *TypeArray:
return aggregateElemType(t.Element, indices[1:])
case *TypeStruct:
return aggregateElemType(t.Fields[indices[0]], indices[1:])
default:
panic(fmt.Errorf("support for aggregate type %T not yet implemented", t))
}
}
// TypesEqual checks if two types are equal to eachother, even if one or both
// are nil.
func TypesEqual (left, right Type) bool {
left = ReduceToBase(left)
right = ReduceToBase(right)
if (left == nil) != (right == nil) { return false }
if left == nil { return true }
return left.Equals(right)
}
func ReduceToBase (ty Type) Type {
if ty, ok := ty.(*TypeDefined); ok { return ty.Source }
return ty
}