Fixed several cases where the generator would output invalid IR

This commit is contained in:
Sasha Koshka 2023-12-03 22:23:04 -05:00
parent a7fe9a592b
commit b0c3839ed9
7 changed files with 161 additions and 64 deletions

View File

@ -309,69 +309,66 @@ func (this *Tree) areStructurallyEquivalent (left, right entity.Type) bool {
// isLocationExpression returns whether or not an expression is a valid location
// expression.
func (this *Tree) isLocationExpression (expression entity.Expression) error {
switch expression.(type) {
switch expression := expression.(type) {
case *entity.Variable:
return nil
case *entity.Declaration:
return nil
case *entity.Call:
return participle.Errorf (
expression.(*entity.Call).Pos,
expression.Pos,
"cannot assign to function call")
case *entity.MethodCall:
return participle.Errorf (
expression.(*entity.MethodCall).Pos,
expression.Pos,
"cannot assign to method call")
case *entity.Subscript:
return this.isLocationExpression (
expression.(*entity.Subscript).Slice)
return this.isLocationExpression(expression.Slice)
case *entity.Slice:
return participle.Errorf (
expression.(*entity.MethodCall).Pos,
expression.Pos,
"cannot assign to slice operation")
case *entity.Dereference:
return this.isLocationExpression (
expression.(*entity.Dereference).Pointer)
return this.isLocationExpression(expression.Pointer)
case *entity.Reference:
return participle.Errorf (
expression.(*entity.Reference).Pos,
expression.Pos,
"cannot assign to reference operation")
case *entity.ValueCast:
return participle.Errorf (
expression.(*entity.ValueCast).Pos,
expression.Pos,
"cannot assign to value cast")
case *entity.BitCast:
return participle.Errorf (
expression.(*entity.BitCast).Pos,
expression.Pos,
"cannot assign to bit cast")
case *entity.Operation:
expression := expression.(*entity.Operation)
return participle.Errorf (
expression.Pos,
"cannot assign to %v operation",
expression.Operator)
case *entity.Block:
return participle.Errorf (
expression.(*entity.Block).Pos,
expression.Pos,
"cannot assign to block")
case *entity.MemberAccess:
return this.isLocationExpression (
expression.(*entity.MemberAccess).Source)
expression.Source)
case *entity.IfElse:
return participle.Errorf (
expression.(*entity.Block).Pos,
expression.Pos,
"cannot assign to if/else")
case *entity.Loop:
return participle.Errorf (
expression.(*entity.Block).Pos,
expression.Pos,
"cannot assign to loop")
case *entity.Break:
return participle.Errorf (
expression.(*entity.Block).Pos,
expression.Pos,
"cannot assign to break statement")
case *entity.Return:
return participle.Errorf (
expression.(*entity.Block).Pos,
expression.Pos,
"cannot assign to return statement")
default:
panic(fmt.Sprint (
@ -442,9 +439,9 @@ func isFloat (ty entity.Type) bool {
// IsUnsigned returns whether or not the specified type is an unsigned integer.
func IsUnsigned (ty entity.Type) bool {
switch ReduceToBase(ty).(type) {
case *entity.TypeInt: return ty.(*entity.TypeInt).Signed
case *entity.TypeWord: return ty.(*entity.TypeInt).Signed
switch ty := ReduceToBase(ty).(type) {
case *entity.TypeInt: return ty.Signed
case *entity.TypeWord: return ty.Signed
default: return false
}
}

View File

@ -614,7 +614,6 @@ func (this *Tree) analyzeIfElse (
ifelse.False = falseBranch
}
ifelse.Ty = ifelse.True.Type()
return ifelse, nil
}

View File

@ -42,8 +42,8 @@ func (this *generator) generateExpression (expression entity.Expression) (llvm.V
return this.generateMethodCall(expression)
case *entity.Reference:
return this.generateReference(expression)
// case *entity.Length:
// return this.generateLength(expression)
case *entity.Length:
return this.generateLength(expression)
case *entity.ValueCast:
return this.generateValueCast(expression)
case *entity.BitCast:

View File

@ -94,6 +94,48 @@ func (this *generator) generateReference (reference *entity.Reference) (llvm.Val
return this.generateExpressionLoc(reference.Value)
}
func (this *generator) generateLength (length *entity.Length) (llvm.Value, error) {
var sizeType *llvm.TypeInt; {
ty, err := this.typedef("Index")
if err != nil { return nil, err }
sizeType = ty.(*llvm.TypeInt)
}
source, err := this.generateExpressionLoc(length.Slice)
if err != nil { return nil, err }
sourceType := analyzer.ReduceToBase(length.Slice.Type())
switch sourceType := sourceType.(type) {
case *entity.TypeSlice:
irSourceType, err := this.generateType(sourceType)
if err != nil { return nil, err }
startFieldAddress := this.blockManager.NewGetElementPtr (
irSourceType,
source,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, 1))
start := this.blockManager.NewLoad(sizeType, startFieldAddress)
endFieldAddress := this.blockManager.NewGetElementPtr (
irSourceType,
source,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, 2))
end := this.blockManager.NewLoad(sizeType, endFieldAddress)
return this.blockManager.NewSub(end, start), nil
case *entity.TypeArray:
return llvm.NewConstInt(sizeType, int64(sourceType.Length)), nil
default:
panic(fmt.Sprint (
"BUG: generator can't get length of expression ",
length.Slice))
}
}
func (this *generator) generateValueCast (cast *entity.ValueCast) (llvm.Value, error) {
generateFrom := func () (llvm.Value, llvm.Type, error) {
from, err := this.generateExpression(cast.Value)
@ -553,30 +595,52 @@ func (this *generator) generateIfElse (ifelse *entity.IfElse, loc bool) (llvm.Va
if err != nil { return nil, err }
if ifelse.False != nil {
falseBlock = this.blockManager.newBlock()
if loc {
fals, err = this.generateExpressionLoc(ifelse.False)
} else {
fals, err = this.generateExpression(ifelse.False)
}
if err != nil { return nil, err }
if ifelse.Type() == nil {
falseBlock = this.blockManager.newBlock()
if loc {
fals, err = this.generateExpressionLoc(ifelse.False)
} else {
fals, err = this.generateExpression(ifelse.False)
}
if err != nil { return nil, err }
trueIncoming := &llvm.Incoming {
X: tru,
Predecessor: trueBlock,
previous.NewCondBr(condition, trueBlock, falseBlock)
exitBlock := this.blockManager.newBlock()
falseBlock.NewBr(exitBlock)
trueBlock.NewBr(exitBlock)
return nil, nil
} else {
falseBlock = this.blockManager.newBlock()
if loc {
fals, err = this.generateExpressionLoc(ifelse.False)
} else {
fals, err = this.generateExpression(ifelse.False)
}
if err != nil { return nil, err }
trueIncoming := &llvm.Incoming {
X: tru,
Predecessor: trueBlock,
}
falseIncoming := &llvm.Incoming {
X: fals,
Predecessor: falseBlock,
}
previous.NewCondBr(condition, trueBlock, falseBlock)
exitBlock := this.blockManager.newBlock()
falseBlock.NewBr(exitBlock)
trueBlock.NewBr(exitBlock)
return this.blockManager.NewPhi(trueIncoming, falseIncoming), nil
}
falseIncoming := &llvm.Incoming {
X: fals,
Predecessor: falseBlock,
}
previous.NewCondBr(condition, trueBlock, falseBlock)
this.blockManager.newBlock()
return this.blockManager.NewPhi(trueIncoming, falseIncoming), nil
} else {
exitBlock := this.blockManager.newBlock()
falseBlock.NewBr(exitBlock)
previous.NewCondBr(condition, trueBlock, falseBlock)
trueBlock.NewBr(exitBlock)
if falseBlock == nil {
previous.NewCondBr(condition, trueBlock, exitBlock)
} else {
previous.NewCondBr(condition, trueBlock, falseBlock)
}
return nil, nil
}
}
@ -596,7 +660,9 @@ func (this *generator) generateLoop (loop *entity.Loop, loc bool) (llvm.Value, e
exit := this.blockManager.newBlock()
if loopEntry.stub != nil {
loopEntry.stub.NewBr(exit)
loopEntry.stub.SetTerminator(&llvm.TerminatorBr {
Target: exit,
})
}
return loopEntry.value, nil
}
@ -610,7 +676,6 @@ func (this *generator) generateBreak (brk *entity.Break) (llvm.Value, error) {
}
loopEntry.stub = this.blockManager.Block
this.blockManager.newBlock()
return nil, nil
}

View File

@ -8,24 +8,20 @@ testString (test,
`,
`
[puts string: *Byte]: Index
[write file:I32 buffer:*Byte count:Index]: Index
Greeter: (message: String)
Greeter.[greet] = [puts [@[.this.message 0]]]
[firstByte str:String]: *Byte = [@[.str 0]]
[main] = {
greeter: Greeter = (
message: 'hello\0'
)
greeter.[doNothing]
[print string: String] = loop {
if [< [#string] 1] then {break}
byte: Byte = [. string 0]
[write 1 [@byte] 1]
string = [\string 1:]
}
Greeter.[doNothing] = { }
Greeter.[getMessage]: String = {
[puts 'getting']
this.message
[puts 'got']
this.message
[main] = {
str:String = 'xx'
[print str]
}
`)
}
@ -61,3 +57,35 @@ Greeter.[getMessage]: String = {
// [.string 15] = 0
// [puts [.[@string]]]
// }
// [puts string: *Byte]: Index
//
// Greeter: (message: String)
// Greeter.[greet] = [puts [@[.this.message 0]]]
//
// [main] = {
// greeter: Greeter = (
// message: 'hello\0'
// )
// greeter.[doNothing]
// }
//
// Greeter.[doNothing] = { }
//
// Greeter.[getMessage]: String = {
// [puts 'getting']
// this.message
// [puts 'got']
// this.message
// }
// [puts string: *Byte]: Index
// [firstByte str:String]: *Byte = [@[.str 0]]
// [main] = {
// str:String = 'xx'
// [.str 2] = 0
// if [= [.str 2] 0] then [puts 'zero'] else [puts 'nonzero']
// first:*Byte = [firstByte str]
// [puts first]
// }

View File

@ -32,7 +32,7 @@ func (this *generator) generateSliceLoc (slice *entity.Slice) (llvm.Value, error
sourceType := analyzer.ReduceToBase(slice.Slice.Type())
switch sourceType := sourceType.(type) {
case *entity.TypeSlice:
source, err := this.generateExpression(slice.Slice)
source, err := this.generateExpressionLoc(slice.Slice)
if err != nil { return nil, err }
irSourceType, err := this.generateType(sourceType)
if err != nil { return nil, err }
@ -84,9 +84,9 @@ func (this *generator) generateSliceLoc (slice *entity.Slice) (llvm.Value, error
newSlice,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, 2))
this.blockManager.NewStore(dataAddressFieldAddress, dataAddress)
this.blockManager.NewStore(startFieldAddress, start)
this.blockManager.NewStore(endFieldAddress, end)
this.blockManager.NewStore(dataAddress, dataAddressFieldAddress)
this.blockManager.NewStore(start, startFieldAddress)
this.blockManager.NewStore(end, endFieldAddress)
return newSlice, nil
}

View File

@ -167,6 +167,14 @@ func (this *Block) Terminated () bool {
return ok
}
func (this *Block) SetTerminator (terminator Terminator) {
if this.Terminated() {
this.Instructions[len(this.Instructions) - 1] = terminator
} else {
this.AddInstruction(terminator)
}
}
func (this *Block) assignIDs (counter *int) {
for _, instruction := range this.Instructions {
if instruction, ok := instruction.(ValueInstruction); ok {