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("", 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 }