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
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
@ -614,7 +614,6 @@ func (this *Tree) analyzeIfElse (
|
||||
ifelse.False = falseBranch
|
||||
}
|
||||
|
||||
ifelse.Ty = ifelse.True.Type()
|
||||
return ifelse, nil
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
// }
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user