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 // 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
} }
} }

View File

@ -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
} }

View File

@ -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:

View File

@ -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 {
fals, err = this.generateExpressionLoc(ifelse.False)
} else {
fals, err = this.generateExpression(ifelse.False)
}
if err != nil { return nil, err }
previous.NewCondBr(condition, trueBlock, falseBlock)
exitBlock := this.blockManager.newBlock()
falseBlock.NewBr(exitBlock)
trueBlock.NewBr(exitBlock)
return nil, nil
} else { } else {
fals, err = this.generateExpression(ifelse.False) falseBlock = this.blockManager.newBlock()
} if loc {
if err != nil { return nil, err } fals, err = this.generateExpressionLoc(ifelse.False)
} else {
fals, err = this.generateExpression(ifelse.False)
}
if err != nil { return nil, err }
trueIncoming := &llvm.Incoming { trueIncoming := &llvm.Incoming {
X: tru, X: tru,
Predecessor: trueBlock, Predecessor: trueBlock,
} }
falseIncoming := &llvm.Incoming { falseIncoming := &llvm.Incoming {
X: fals, X: fals,
Predecessor: falseBlock, Predecessor: falseBlock,
} }
previous.NewCondBr(condition, trueBlock, falseBlock) previous.NewCondBr(condition, trueBlock, falseBlock)
this.blockManager.newBlock() exitBlock := this.blockManager.newBlock()
return this.blockManager.NewPhi(trueIncoming, falseIncoming), nil falseBlock.NewBr(exitBlock)
trueBlock.NewBr(exitBlock)
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
} }
} }