390 lines
8.3 KiB
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
|
|
}
|