Added array and struct constant generation

This commit is contained in:
Sasha Koshka 2024-04-22 21:13:08 -04:00
parent 86ad94f17d
commit 0c8a9d995b
3 changed files with 112 additions and 5 deletions

View File

@ -26,8 +26,16 @@ func (this *generator) generateConstantDeclaration (
// both. have single generateConstant method that converts if necessary
// by either loading or allocating a copy on the stack.
//
// have a Multivalue method of types and disallow referencing of
// non-multivalue constants.
// Have a ConstantSupport method of Type that returns either:
// - ConstantSupportLoc - multivalue, stored
// - ConstantSupportVal - singlevalue, not stored
// - ConstantSupportNone - cannot be used as a constant
//
// Pointers and anything with a pointer inside it must return
// ConstantSupportNone. Aggregate types (arrays, structs) must return
// ConstantSupportLoc if supported at all. Single value types must
// return ConstantSupportNone if supported at all. This should be
// checked recursively.
irGlobal := this.module.NewGlobal(key.LinkName(), irType)
irGlobal.Constant = true

View File

@ -99,3 +99,53 @@ E: Int
* -1
[f] = [plus4 E.two]
`)}
func TestConstantValueStruct (test *testing.T) {
testString (test,
`%"0zNZN147MN2wzMAQ6NS2dQ==::Cardinal" = type { i64, i64 }
0zNZN147MN2wzMAQ6NS2dQ==::Cardinal.east = constant %"0zNZN147MN2wzMAQ6NS2dQ==::Cardinal" { i64, i64 } { i64 1, i64 zeroinitializer }
0zNZN147MN2wzMAQ6NS2dQ==::Cardinal.north = constant %"0zNZN147MN2wzMAQ6NS2dQ==::Cardinal" { i64, i64 } { i64 zeroinitializer, i64 -1 }
0zNZN147MN2wzMAQ6NS2dQ==::Cardinal.south = constant %"0zNZN147MN2wzMAQ6NS2dQ==::Cardinal" { i64, i64 } { i64 zeroinitializer, i64 1 }
0zNZN147MN2wzMAQ6NS2dQ==::Cardinal.west = constant %"0zNZN147MN2wzMAQ6NS2dQ==::Cardinal" { i64, i64 } { i64 -1, i64 zeroinitializer }
define void @"0zNZN147MN2wzMAQ6NS2dQ==::[f]"() {
0:
%1 = alloca %"0zNZN147MN2wzMAQ6NS2dQ==::Cardinal"
%2 = load %"0zNZN147MN2wzMAQ6NS2dQ==::Cardinal", %"0zNZN147MN2wzMAQ6NS2dQ==::Cardinal" @"0zNZN147MN2wzMAQ6NS2dQ==::Cardinal.west"
store %"0zNZN147MN2wzMAQ6NS2dQ==::Cardinal" %2, ptr %1
ret void
}
`,
`
Cardinal: (.x:Int y:Int)
| north = (. y: -1)
| south = (. y: 1)
| west = (.x: -1 )
| east = (.x: 1 )
[f] = {
c:Cardinal = Cardinal.west
}
`)}
func TestConstantValueArray (test *testing.T) {
testString (test,
`%"0zNZN147MN2wzMAQ6NS2dQ==::Order" = type [3 x i64]
0zNZN147MN2wzMAQ6NS2dQ==::Order.backward = constant %"0zNZN147MN2wzMAQ6NS2dQ==::Order" [3 x i64] [i64 2, i64 1, i64 0]
0zNZN147MN2wzMAQ6NS2dQ==::Order.forward = constant %"0zNZN147MN2wzMAQ6NS2dQ==::Order" [3 x i64] [i64 0, i64 1, i64 2]
0zNZN147MN2wzMAQ6NS2dQ==::Order.none = constant %"0zNZN147MN2wzMAQ6NS2dQ==::Order" [3 x i64] [i64 0, i64 zeroinitializer, i64 zeroinitializer]
define void @"0zNZN147MN2wzMAQ6NS2dQ==::[f]"() {
0:
%1 = alloca %"0zNZN147MN2wzMAQ6NS2dQ==::Order"
%2 = load %"0zNZN147MN2wzMAQ6NS2dQ==::Order", %"0zNZN147MN2wzMAQ6NS2dQ==::Order" @"0zNZN147MN2wzMAQ6NS2dQ==::Order.forward"
store %"0zNZN147MN2wzMAQ6NS2dQ==::Order" %2, ptr %1
ret void
}
`,
`
Order: 3:Int
| none = (0)
| forward = (0 1 2)
| backward = (2 1 0)
[f] = {
o:Order = Order.forward
}
`)}

View File

@ -17,7 +17,7 @@ func (this *generator) generateEvaluatedInt (literal *entity.LiteralInt) (llvm.C
case *entity.TypeFloat:
return llvm.NewConstFloat(irType.(*llvm.TypeFloat), float64(literal.Value)), nil
default:
return nil, errors.New(fmt.Sprintln("int can't be used as", base))
return nil, errors.New(fmt.Sprintln("constant int can't be used as", base))
}
}
@ -28,15 +28,64 @@ func (this *generator) generateEvaluatedFloat (literal *entity.LiteralFloat) (ll
}
func (this *generator) generateEvaluatedString (literal *entity.LiteralString) (llvm.Const, error) {
// TODO
panic("BUG: not supported yet")
}
func (this *generator) generateEvaluatedArray (literal *entity.LiteralArray) (llvm.Const, error) {
panic("BUG: not supported yet")
baseAny := analyzer.ReduceToBase(literal.Type())
base, ok := baseAny.(*entity.TypeArray)
if !ok { return nil, errors.New(fmt.Sprintln("constant array can't be used as", baseAny)) }
irDestTypeAny, err := this.generateType(base)
if err != nil { return nil, err }
irDestType := irDestTypeAny.(*llvm.TypeArray)
irElementType, err := this.generateType(base.Element)
if err != nil { return nil, err }
irArray := &llvm.ConstArray {
Ty: irDestType,
Elements: make([]llvm.Const, base.Length),
}
for index := range irArray.Elements {
if index < len(literal.Elements) {
irElement, err := this.generateEvaluated(literal.Elements[index])
if err != nil { return nil, err }
irArray.Elements[index] = irElement
} else {
irArray.Elements[index] = llvm.NewConstZeroInitializer(irElementType)
}
}
return irArray, nil
}
func (this *generator) generateEvaluatedStruct (literal *entity.LiteralStruct) (llvm.Const, error) {
panic("BUG: not supported yet")
baseAny := analyzer.ReduceToBase(literal.Type())
base, ok := baseAny.(*entity.TypeStruct)
if !ok { return nil, errors.New(fmt.Sprintln("constant struct can't be used as", baseAny)) }
irDestTypeAny, err := this.generateType(base)
if err != nil { return nil, err }
irDestType := irDestTypeAny.(*llvm.TypeStruct)
irStruct := &llvm.ConstStruct {
Ty: irDestType,
Fields: make([]llvm.Const, len(base.Members)),
}
for index, member := range base.Members {
if pair, ok := literal.MemberMap[member.Name]; ok {
irMember, err := this.generateEvaluated(pair.Value)
if err != nil { return nil, err }
irStruct.Fields[index] = irMember
} else {
irMemberType, err := this.generateType(member.Type())
if err != nil { return nil, err }
irStruct.Fields[index] = llvm.NewConstZeroInitializer(irMemberType)
}
}
return irStruct, nil
}
func (this *generator) generateEvaluatedBoolean (literal *entity.LiteralBoolean) (llvm.Const, error) {