Fixed several cases where the generator would output invalid IR
This commit is contained in:
parent
a7fe9a592b
commit
b0c3839ed9
@ -309,69 +309,66 @@ func (this *Tree) areStructurallyEquivalent (left, right entity.Type) bool {
|
|||||||
// isLocationExpression returns whether or not an expression is a valid location
|
// isLocationExpression returns whether or not an expression is a valid location
|
||||||
// expression.
|
// expression.
|
||||||
func (this *Tree) isLocationExpression (expression entity.Expression) error {
|
func (this *Tree) isLocationExpression (expression entity.Expression) error {
|
||||||
switch expression.(type) {
|
switch expression := expression.(type) {
|
||||||
case *entity.Variable:
|
case *entity.Variable:
|
||||||
return nil
|
return nil
|
||||||
case *entity.Declaration:
|
case *entity.Declaration:
|
||||||
return nil
|
return nil
|
||||||
case *entity.Call:
|
case *entity.Call:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.Call).Pos,
|
expression.Pos,
|
||||||
"cannot assign to function call")
|
"cannot assign to function call")
|
||||||
case *entity.MethodCall:
|
case *entity.MethodCall:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.MethodCall).Pos,
|
expression.Pos,
|
||||||
"cannot assign to method call")
|
"cannot assign to method call")
|
||||||
case *entity.Subscript:
|
case *entity.Subscript:
|
||||||
return this.isLocationExpression (
|
return this.isLocationExpression(expression.Slice)
|
||||||
expression.(*entity.Subscript).Slice)
|
|
||||||
case *entity.Slice:
|
case *entity.Slice:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.MethodCall).Pos,
|
expression.Pos,
|
||||||
"cannot assign to slice operation")
|
"cannot assign to slice operation")
|
||||||
case *entity.Dereference:
|
case *entity.Dereference:
|
||||||
return this.isLocationExpression (
|
return this.isLocationExpression(expression.Pointer)
|
||||||
expression.(*entity.Dereference).Pointer)
|
|
||||||
case *entity.Reference:
|
case *entity.Reference:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.Reference).Pos,
|
expression.Pos,
|
||||||
"cannot assign to reference operation")
|
"cannot assign to reference operation")
|
||||||
case *entity.ValueCast:
|
case *entity.ValueCast:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.ValueCast).Pos,
|
expression.Pos,
|
||||||
"cannot assign to value cast")
|
"cannot assign to value cast")
|
||||||
case *entity.BitCast:
|
case *entity.BitCast:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.BitCast).Pos,
|
expression.Pos,
|
||||||
"cannot assign to bit cast")
|
"cannot assign to bit cast")
|
||||||
case *entity.Operation:
|
case *entity.Operation:
|
||||||
expression := expression.(*entity.Operation)
|
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.Pos,
|
expression.Pos,
|
||||||
"cannot assign to %v operation",
|
"cannot assign to %v operation",
|
||||||
expression.Operator)
|
expression.Operator)
|
||||||
case *entity.Block:
|
case *entity.Block:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.Block).Pos,
|
expression.Pos,
|
||||||
"cannot assign to block")
|
"cannot assign to block")
|
||||||
case *entity.MemberAccess:
|
case *entity.MemberAccess:
|
||||||
return this.isLocationExpression (
|
return this.isLocationExpression (
|
||||||
expression.(*entity.MemberAccess).Source)
|
expression.Source)
|
||||||
case *entity.IfElse:
|
case *entity.IfElse:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.Block).Pos,
|
expression.Pos,
|
||||||
"cannot assign to if/else")
|
"cannot assign to if/else")
|
||||||
case *entity.Loop:
|
case *entity.Loop:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.Block).Pos,
|
expression.Pos,
|
||||||
"cannot assign to loop")
|
"cannot assign to loop")
|
||||||
case *entity.Break:
|
case *entity.Break:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.Block).Pos,
|
expression.Pos,
|
||||||
"cannot assign to break statement")
|
"cannot assign to break statement")
|
||||||
case *entity.Return:
|
case *entity.Return:
|
||||||
return participle.Errorf (
|
return participle.Errorf (
|
||||||
expression.(*entity.Block).Pos,
|
expression.Pos,
|
||||||
"cannot assign to return statement")
|
"cannot assign to return statement")
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprint (
|
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.
|
// IsUnsigned returns whether or not the specified type is an unsigned integer.
|
||||||
func IsUnsigned (ty entity.Type) bool {
|
func IsUnsigned (ty entity.Type) bool {
|
||||||
switch ReduceToBase(ty).(type) {
|
switch ty := ReduceToBase(ty).(type) {
|
||||||
case *entity.TypeInt: return ty.(*entity.TypeInt).Signed
|
case *entity.TypeInt: return ty.Signed
|
||||||
case *entity.TypeWord: return ty.(*entity.TypeInt).Signed
|
case *entity.TypeWord: return ty.Signed
|
||||||
default: return false
|
default: return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -614,7 +614,6 @@ func (this *Tree) analyzeIfElse (
|
|||||||
ifelse.False = falseBranch
|
ifelse.False = falseBranch
|
||||||
}
|
}
|
||||||
|
|
||||||
ifelse.Ty = ifelse.True.Type()
|
|
||||||
return ifelse, nil
|
return ifelse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ func (this *generator) generateExpression (expression entity.Expression) (llvm.V
|
|||||||
return this.generateMethodCall(expression)
|
return this.generateMethodCall(expression)
|
||||||
case *entity.Reference:
|
case *entity.Reference:
|
||||||
return this.generateReference(expression)
|
return this.generateReference(expression)
|
||||||
// case *entity.Length:
|
case *entity.Length:
|
||||||
// return this.generateLength(expression)
|
return this.generateLength(expression)
|
||||||
case *entity.ValueCast:
|
case *entity.ValueCast:
|
||||||
return this.generateValueCast(expression)
|
return this.generateValueCast(expression)
|
||||||
case *entity.BitCast:
|
case *entity.BitCast:
|
||||||
|
@ -94,6 +94,48 @@ func (this *generator) generateReference (reference *entity.Reference) (llvm.Val
|
|||||||
return this.generateExpressionLoc(reference.Value)
|
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) {
|
func (this *generator) generateValueCast (cast *entity.ValueCast) (llvm.Value, error) {
|
||||||
generateFrom := func () (llvm.Value, llvm.Type, error) {
|
generateFrom := func () (llvm.Value, llvm.Type, error) {
|
||||||
from, err := this.generateExpression(cast.Value)
|
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 err != nil { return nil, err }
|
||||||
|
|
||||||
if ifelse.False != nil {
|
if ifelse.False != nil {
|
||||||
falseBlock = this.blockManager.newBlock()
|
if ifelse.Type() == nil {
|
||||||
if loc {
|
falseBlock = this.blockManager.newBlock()
|
||||||
fals, err = this.generateExpressionLoc(ifelse.False)
|
if loc {
|
||||||
} else {
|
fals, err = this.generateExpressionLoc(ifelse.False)
|
||||||
fals, err = this.generateExpression(ifelse.False)
|
} else {
|
||||||
}
|
fals, err = this.generateExpression(ifelse.False)
|
||||||
if err != nil { return nil, err }
|
}
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
trueIncoming := &llvm.Incoming {
|
previous.NewCondBr(condition, trueBlock, falseBlock)
|
||||||
X: tru,
|
exitBlock := this.blockManager.newBlock()
|
||||||
Predecessor: trueBlock,
|
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 {
|
} else {
|
||||||
exitBlock := this.blockManager.newBlock()
|
exitBlock := this.blockManager.newBlock()
|
||||||
falseBlock.NewBr(exitBlock)
|
trueBlock.NewBr(exitBlock)
|
||||||
previous.NewCondBr(condition, trueBlock, falseBlock)
|
if falseBlock == nil {
|
||||||
|
previous.NewCondBr(condition, trueBlock, exitBlock)
|
||||||
|
} else {
|
||||||
|
previous.NewCondBr(condition, trueBlock, falseBlock)
|
||||||
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -596,7 +660,9 @@ func (this *generator) generateLoop (loop *entity.Loop, loc bool) (llvm.Value, e
|
|||||||
exit := this.blockManager.newBlock()
|
exit := this.blockManager.newBlock()
|
||||||
|
|
||||||
if loopEntry.stub != nil {
|
if loopEntry.stub != nil {
|
||||||
loopEntry.stub.NewBr(exit)
|
loopEntry.stub.SetTerminator(&llvm.TerminatorBr {
|
||||||
|
Target: exit,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return loopEntry.value, nil
|
return loopEntry.value, nil
|
||||||
}
|
}
|
||||||
@ -610,7 +676,6 @@ func (this *generator) generateBreak (brk *entity.Break) (llvm.Value, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loopEntry.stub = this.blockManager.Block
|
loopEntry.stub = this.blockManager.Block
|
||||||
this.blockManager.newBlock()
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,24 +8,20 @@ testString (test,
|
|||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
[puts string: *Byte]: Index
|
[puts string: *Byte]: Index
|
||||||
|
[write file:I32 buffer:*Byte count:Index]: Index
|
||||||
|
|
||||||
Greeter: (message: String)
|
[firstByte str:String]: *Byte = [@[.str 0]]
|
||||||
Greeter.[greet] = [puts [@[.this.message 0]]]
|
|
||||||
|
|
||||||
[main] = {
|
[print string: String] = loop {
|
||||||
greeter: Greeter = (
|
if [< [#string] 1] then {break}
|
||||||
message: 'hello\0'
|
byte: Byte = [. string 0]
|
||||||
)
|
[write 1 [@byte] 1]
|
||||||
greeter.[doNothing]
|
string = [\string 1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
Greeter.[doNothing] = { }
|
[main] = {
|
||||||
|
str:String = 'xx'
|
||||||
Greeter.[getMessage]: String = {
|
[print str]
|
||||||
[puts 'getting']
|
|
||||||
this.message
|
|
||||||
[puts 'got']
|
|
||||||
this.message
|
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
@ -61,3 +57,35 @@ Greeter.[getMessage]: String = {
|
|||||||
// [.string 15] = 0
|
// [.string 15] = 0
|
||||||
// [puts [.[@string]]]
|
// [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]
|
||||||
|
// }
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ func (this *generator) generateSliceLoc (slice *entity.Slice) (llvm.Value, error
|
|||||||
sourceType := analyzer.ReduceToBase(slice.Slice.Type())
|
sourceType := analyzer.ReduceToBase(slice.Slice.Type())
|
||||||
switch sourceType := sourceType.(type) {
|
switch sourceType := sourceType.(type) {
|
||||||
case *entity.TypeSlice:
|
case *entity.TypeSlice:
|
||||||
source, err := this.generateExpression(slice.Slice)
|
source, err := this.generateExpressionLoc(slice.Slice)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
irSourceType, err := this.generateType(sourceType)
|
irSourceType, err := this.generateType(sourceType)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
@ -84,9 +84,9 @@ func (this *generator) generateSliceLoc (slice *entity.Slice) (llvm.Value, error
|
|||||||
newSlice,
|
newSlice,
|
||||||
llvm.NewConstInt(llvm.I32, 0),
|
llvm.NewConstInt(llvm.I32, 0),
|
||||||
llvm.NewConstInt(llvm.I32, 2))
|
llvm.NewConstInt(llvm.I32, 2))
|
||||||
this.blockManager.NewStore(dataAddressFieldAddress, dataAddress)
|
this.blockManager.NewStore(dataAddress, dataAddressFieldAddress)
|
||||||
this.blockManager.NewStore(startFieldAddress, start)
|
this.blockManager.NewStore(start, startFieldAddress)
|
||||||
this.blockManager.NewStore(endFieldAddress, end)
|
this.blockManager.NewStore(end, endFieldAddress)
|
||||||
|
|
||||||
return newSlice, nil
|
return newSlice, nil
|
||||||
}
|
}
|
||||||
|
@ -167,6 +167,14 @@ func (this *Block) Terminated () bool {
|
|||||||
return ok
|
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) {
|
func (this *Block) assignIDs (counter *int) {
|
||||||
for _, instruction := range this.Instructions {
|
for _, instruction := range this.Instructions {
|
||||||
if instruction, ok := instruction.(ValueInstruction); ok {
|
if instruction, ok := instruction.(ValueInstruction); ok {
|
||||||
|
Loading…
Reference in New Issue
Block a user