Introducing ResultMode! time to got to bed.
This commit is contained in:
parent
a423d572ad
commit
8e9b5e0613
|
@ -6,9 +6,10 @@ import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
|||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||
|
||||
type loopEntry struct {
|
||||
value llvm.Value
|
||||
stub *llvm.Block
|
||||
wantLocation bool
|
||||
value llvm.Value
|
||||
stub *llvm.Block
|
||||
mode ResultMode
|
||||
loc bool
|
||||
}
|
||||
|
||||
type blockManager struct {
|
||||
|
@ -45,8 +46,8 @@ func (this *generator) popBlockManager () {
|
|||
}
|
||||
}
|
||||
|
||||
func (this *blockManager) pushLoop (wantLocation bool) *loopEntry {
|
||||
entry := &loopEntry { wantLocation: wantLocation }
|
||||
func (this *blockManager) pushLoop (mode ResultMode) *loopEntry {
|
||||
entry := &loopEntry { mode: mode }
|
||||
this.loops = append(this.loops, entry)
|
||||
return entry
|
||||
}
|
||||
|
|
|
@ -164,15 +164,3 @@ func (this *generator) generateMemberAccessLoc (access *entity.MemberAccess) (ll
|
|||
access.Source))
|
||||
}
|
||||
}
|
||||
|
||||
func (this *generator) generateBlockLoc (block *entity.Block) (llvm.Value, error) {
|
||||
if len(block.Steps) == 0 { return nil, nil }
|
||||
|
||||
lastIndex := len(block.Steps) - 1
|
||||
for _, step := range block.Steps[:lastIndex] {
|
||||
_, _, err := this.generateStatement(step)
|
||||
if err != nil { return nil, err }
|
||||
}
|
||||
|
||||
return this.generateStatementLoc(block.Steps[lastIndex])
|
||||
}
|
||||
|
|
|
@ -4,6 +4,12 @@ import "fmt"
|
|||
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||
|
||||
type ResultMode int; const (
|
||||
ResultModeAny ResultMode = iota
|
||||
ResultModeVal
|
||||
ResultModeLoc
|
||||
)
|
||||
|
||||
func (this *generator) valueToLocation (value llvm.Value) llvm.Value {
|
||||
pointer := this.blockManager.newAllocaFront(value.Type())
|
||||
this.blockManager.NewStore(value, pointer)
|
||||
|
@ -16,6 +22,27 @@ func (this *generator) locationToValue (pointer llvm.Value, ty entity.Type) (llv
|
|||
return this.blockManager.NewLoad(irType, pointer), nil
|
||||
}
|
||||
|
||||
func (this *generator) generateExpressionMode (
|
||||
expression entity.Expression,
|
||||
mode ResultMode,
|
||||
) (
|
||||
register llvm.Value,
|
||||
location bool,
|
||||
err error,
|
||||
) {
|
||||
switch mode {
|
||||
case ResultModeAny:
|
||||
return this.generateExpression(expression)
|
||||
case ResultModeVal:
|
||||
val, err := this.generateExpressionVal(expression)
|
||||
return val, false, err
|
||||
case ResultModeLoc:
|
||||
loc, err := this.generateExpressionLoc(expression)
|
||||
return loc, true, err
|
||||
default: panic("unknown ResultMode")
|
||||
}
|
||||
}
|
||||
|
||||
// generateExpression generates an expression and either returns a register
|
||||
// representing the result, or a register containing the location of the result,
|
||||
// whichever will generate the least IR. In the latter case, the boolean
|
||||
|
@ -34,7 +61,9 @@ func (this *generator) generateExpression (expression entity.Expression) (regist
|
|||
*entity.LiteralString,
|
||||
*entity.LiteralStruct,
|
||||
*entity.Variable,
|
||||
*entity.Declaration:
|
||||
*entity.Declaration,
|
||||
*entity.IfElse,
|
||||
*entity.Loop:
|
||||
|
||||
pointer, err := this.generateExpressionLoc(expression)
|
||||
return pointer, true, err
|
||||
|
@ -57,7 +86,7 @@ func (this *generator) generateExpression (expression entity.Expression) (regist
|
|||
|
||||
// these are capable of giving us both
|
||||
case *entity.Block:
|
||||
return this.generateBlock(expression)
|
||||
return this.generateBlock(expression, ResultModeAny)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf (
|
||||
|
@ -103,11 +132,14 @@ func (this *generator) generateExpressionVal (expression entity.Expression) (llv
|
|||
case *entity.Operation:
|
||||
return this.generateOperationVal(expression)
|
||||
case *entity.Block:
|
||||
return this.generateBlockVal(expression)
|
||||
loc, _, err := this.generateBlock(expression, ResultModeVal)
|
||||
return loc, err
|
||||
case *entity.IfElse:
|
||||
return this.generateIfElseVal(expression, false)
|
||||
loc, _, err := this.generateIfElse(expression, ResultModeVal)
|
||||
return loc, err
|
||||
case *entity.Loop:
|
||||
return this.generateLoopVal(expression, false)
|
||||
loc, _, err := this.generateLoop(expression, ResultModeVal)
|
||||
return loc, err
|
||||
|
||||
case *entity.LiteralInt:
|
||||
return this.generateLiteralInt(expression)
|
||||
|
@ -142,9 +174,7 @@ func (this *generator) generateExpressionLoc (expression entity.Expression) (llv
|
|||
*entity.LiteralInt,
|
||||
*entity.LiteralFloat,
|
||||
*entity.LiteralBoolean,
|
||||
*entity.LiteralNil,
|
||||
*entity.IfElse,
|
||||
*entity.Loop:
|
||||
*entity.LiteralNil:
|
||||
|
||||
value, err := this.generateExpressionVal(expression)
|
||||
if err != nil { return nil, err }
|
||||
|
@ -164,7 +194,14 @@ func (this *generator) generateExpressionLoc (expression entity.Expression) (llv
|
|||
case *entity.MemberAccess:
|
||||
return this.generateMemberAccessLoc(expression)
|
||||
case *entity.Block:
|
||||
return this.generateBlockLoc(expression)
|
||||
loc, _, err := this.generateBlock(expression, ResultModeLoc)
|
||||
return loc, err
|
||||
case *entity.IfElse:
|
||||
loc, _, err := this.generateIfElse(expression, ResultModeLoc)
|
||||
return loc, err
|
||||
case *entity.Loop:
|
||||
loc, _, err := this.generateLoop(expression, ResultModeLoc)
|
||||
return loc, err
|
||||
case *entity.LiteralArray:
|
||||
return this.generateLiteralArrayLoc(expression)
|
||||
case *entity.LiteralString:
|
||||
|
@ -178,6 +215,27 @@ func (this *generator) generateExpressionLoc (expression entity.Expression) (llv
|
|||
}
|
||||
}
|
||||
|
||||
func (this *generator) generateStatementMode (
|
||||
statement entity.Statement,
|
||||
mode ResultMode,
|
||||
) (
|
||||
register llvm.Value,
|
||||
location bool,
|
||||
err error,
|
||||
) {
|
||||
switch mode {
|
||||
case ResultModeAny:
|
||||
return this.generateStatement(statement)
|
||||
case ResultModeVal:
|
||||
val, err := this.generateStatementVal(statement)
|
||||
return val, false, err
|
||||
case ResultModeLoc:
|
||||
loc, err := this.generateStatementLoc(statement)
|
||||
return loc, true, err
|
||||
default: panic("unknown ResultMode")
|
||||
}
|
||||
}
|
||||
|
||||
func (this *generator) generateStatement (statement entity.Statement) (register llvm.Value, location bool, err error) {
|
||||
switch statement := statement.(type) {
|
||||
case *entity.Assignment:
|
||||
|
|
|
@ -618,100 +618,3 @@ func (this *generator) generateOperationVal (operation *entity.Operation) (llvm.
|
|||
"BUG: generator failed to generate operation",
|
||||
operation))
|
||||
}
|
||||
|
||||
func (this *generator) generateBlockVal (block *entity.Block) (llvm.Value, error) {
|
||||
if len(block.Steps) == 0 { return nil, nil }
|
||||
|
||||
lastIndex := len(block.Steps) - 1
|
||||
for _, step := range block.Steps[:lastIndex] {
|
||||
_, _, err := this.generateStatement(step)
|
||||
if err != nil { return nil, err }
|
||||
}
|
||||
|
||||
return this.generateStatementVal(block.Steps[lastIndex])
|
||||
}
|
||||
|
||||
func (this *generator) generateIfElseVal (ifelse *entity.IfElse, loc bool) (llvm.Value, error) {
|
||||
condition, err := this.generateExpressionVal(ifelse.Condition)
|
||||
if err != nil { return nil, err }
|
||||
previous := this.blockManager.Block
|
||||
|
||||
var trueBlock, falseBlock *llvm.Block
|
||||
var tru, fals llvm.Value
|
||||
|
||||
trueBlock = this.blockManager.newBlock()
|
||||
exitBlock := this.blockManager.newBlock()
|
||||
this.blockManager.Block = trueBlock
|
||||
if loc {
|
||||
tru, err = this.generateExpressionLoc(ifelse.True)
|
||||
} else {
|
||||
tru, err = this.generateExpressionVal(ifelse.True)
|
||||
}
|
||||
if err != nil { return nil, err }
|
||||
if !this.blockManager.Terminated() { this.blockManager.NewBr(exitBlock) }
|
||||
|
||||
if ifelse.False != nil {
|
||||
if ifelse.Type() == nil {
|
||||
falseBlock = this.blockManager.newBlock()
|
||||
if loc {
|
||||
fals, err = this.generateExpressionLoc(ifelse.False)
|
||||
} else {
|
||||
fals, err = this.generateExpressionVal(ifelse.False)
|
||||
}
|
||||
if err != nil { return nil, err }
|
||||
if !this.blockManager.Terminated() { this.blockManager.NewBr(exitBlock) }
|
||||
|
||||
previous.NewCondBr(condition, trueBlock, falseBlock)
|
||||
this.blockManager.Block = exitBlock
|
||||
return nil, nil
|
||||
} else {
|
||||
falseBlock = this.blockManager.newBlock()
|
||||
if loc {
|
||||
fals, err = this.generateExpressionLoc(ifelse.False)
|
||||
} else {
|
||||
fals, err = this.generateExpressionVal(ifelse.False)
|
||||
}
|
||||
if err != nil { return nil, err }
|
||||
if !this.blockManager.Terminated() { this.blockManager.NewBr(exitBlock) }
|
||||
|
||||
trueIncoming := &llvm.Incoming {
|
||||
X: tru,
|
||||
Predecessor: trueBlock,
|
||||
}
|
||||
falseIncoming := &llvm.Incoming {
|
||||
X: fals,
|
||||
Predecessor: falseBlock,
|
||||
}
|
||||
|
||||
previous.NewCondBr(condition, trueBlock, falseBlock)
|
||||
this.blockManager.Block = exitBlock
|
||||
return this.blockManager.NewPhi(trueIncoming, falseIncoming), nil
|
||||
}
|
||||
} else {
|
||||
previous.NewCondBr(condition, trueBlock, exitBlock)
|
||||
this.blockManager.Block = exitBlock
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (this *generator) generateLoopVal (loop *entity.Loop, loc bool) (llvm.Value, error) {
|
||||
previous := this.blockManager.Block
|
||||
body := this.blockManager.newBlock()
|
||||
previous.NewBr(body)
|
||||
|
||||
loopEntry := this.blockManager.pushLoop(loc)
|
||||
defer this.blockManager.popLoop()
|
||||
|
||||
_, err := this.generateExpressionVal(loop.Body)
|
||||
if err != nil { return nil, err }
|
||||
|
||||
this.blockManager.NewBr(body)
|
||||
exit := this.blockManager.newBlock()
|
||||
|
||||
if loopEntry.stub != nil {
|
||||
loopEntry.stub.SetTerminator(&llvm.TerminatorBr {
|
||||
Target: exit,
|
||||
})
|
||||
}
|
||||
return loopEntry.value, nil
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
|||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||
// import "git.tebibyte.media/sashakoshka/fspl/analyzer"
|
||||
|
||||
func (this *generator) generateBlock (block *entity.Block) (llvm.Value, bool, error) {
|
||||
func (this *generator) generateBlock (block *entity.Block, mode ResultMode) (llvm.Value, bool, error) {
|
||||
if len(block.Steps) == 0 { return nil, false, nil }
|
||||
|
||||
lastIndex := len(block.Steps) - 1
|
||||
|
@ -14,13 +14,25 @@ func (this *generator) generateBlock (block *entity.Block) (llvm.Value, bool, er
|
|||
if err != nil { return nil, false, err }
|
||||
}
|
||||
|
||||
return this.generateStatement(block.Steps[lastIndex])
|
||||
return this.generateStatementMode(block.Steps[lastIndex], mode)
|
||||
}
|
||||
|
||||
func (this *generator) generateBreak (brk *entity.Break) (llvm.Value, error) {
|
||||
loopEntry := this.blockManager.topLoop()
|
||||
if brk.Value != nil {
|
||||
value, err := this.generateExpressionVal(brk.Value)
|
||||
var value llvm.Value
|
||||
var err error
|
||||
switch loopEntry.mode {
|
||||
case ResultModeAny:
|
||||
value, loopEntry.loc, err = this.generateStatement(brk.Value)
|
||||
case ResultModeVal:
|
||||
value, err = this.generateStatementVal(brk.Value)
|
||||
loopEntry.loc = false
|
||||
case ResultModeLoc:
|
||||
value, err = this.generateStatementLoc(brk.Value)
|
||||
loopEntry.loc = true
|
||||
default: panic("unknown ResultMode")
|
||||
}
|
||||
if err != nil { return nil, err }
|
||||
loopEntry.value = value
|
||||
}
|
||||
|
@ -39,3 +51,88 @@ func (this *generator) generateReturn (ret *entity.Return) (llvm.Value, error) {
|
|||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (this *generator) generateIfElse (ifelse *entity.IfElse, mode ResultMode) (llvm.Value, bool, error) {
|
||||
condition, err := this.generateExpressionVal(ifelse.Condition)
|
||||
if err != nil { return nil, false, err }
|
||||
previous := this.blockManager.Block
|
||||
|
||||
var trueBlock, falseBlock *llvm.Block
|
||||
var tru, fals llvm.Value
|
||||
var loc bool
|
||||
|
||||
trueBlock = this.blockManager.newBlock()
|
||||
exitBlock := this.blockManager.newBlock()
|
||||
this.blockManager.Block = trueBlock
|
||||
|
||||
tru, loc, err = this.generateExpressionMode(ifelse.True, mode)
|
||||
if err != nil { return nil, false, err }
|
||||
// force false case to conform to mode of true case
|
||||
if mode == ResultModeAny {
|
||||
if loc {
|
||||
mode = ResultModeLoc
|
||||
} else {
|
||||
mode = ResultModeVal
|
||||
}
|
||||
}
|
||||
if !this.blockManager.Terminated() { this.blockManager.NewBr(exitBlock) }
|
||||
|
||||
if ifelse.False != nil {
|
||||
if mode == ResultModeAny {
|
||||
// discard results of statements
|
||||
falseBlock = this.blockManager.newBlock()
|
||||
fals, _, err = this.generateExpressionMode(ifelse.False, mode)
|
||||
if err != nil { return nil, false, err }
|
||||
if !this.blockManager.Terminated() { this.blockManager.NewBr(exitBlock) }
|
||||
|
||||
previous.NewCondBr(condition, trueBlock, falseBlock)
|
||||
this.blockManager.Block = exitBlock
|
||||
return nil, loc, nil
|
||||
} else {
|
||||
// obtain results of statements
|
||||
falseBlock = this.blockManager.newBlock()
|
||||
fals, _, err = this.generateExpressionMode(ifelse.False, mode)
|
||||
if err != nil { return nil, false, err }
|
||||
if !this.blockManager.Terminated() { this.blockManager.NewBr(exitBlock) }
|
||||
|
||||
trueIncoming := &llvm.Incoming {
|
||||
X: tru,
|
||||
Predecessor: trueBlock,
|
||||
}
|
||||
falseIncoming := &llvm.Incoming {
|
||||
X: fals,
|
||||
Predecessor: falseBlock,
|
||||
}
|
||||
|
||||
previous.NewCondBr(condition, trueBlock, falseBlock)
|
||||
this.blockManager.Block = exitBlock
|
||||
return this.blockManager.NewPhi(trueIncoming, falseIncoming), loc, nil
|
||||
}
|
||||
} else {
|
||||
previous.NewCondBr(condition, trueBlock, exitBlock)
|
||||
this.blockManager.Block = exitBlock
|
||||
return nil, loc, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (this *generator) generateLoop (loop *entity.Loop, mode ResultMode) (llvm.Value, bool, error) {
|
||||
previous := this.blockManager.Block
|
||||
body := this.blockManager.newBlock()
|
||||
previous.NewBr(body)
|
||||
|
||||
loopEntry := this.blockManager.pushLoop(mode)
|
||||
defer this.blockManager.popLoop()
|
||||
|
||||
_, _, err := this.generateExpression(loop.Body)
|
||||
if err != nil { return nil, false, err }
|
||||
|
||||
this.blockManager.NewBr(body)
|
||||
exit := this.blockManager.newBlock()
|
||||
|
||||
if loopEntry.stub != nil {
|
||||
loopEntry.stub.SetTerminator(&llvm.TerminatorBr {
|
||||
Target: exit,
|
||||
})
|
||||
}
|
||||
return loopEntry.value, loopEntry.loc, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue