Introducing ResultMode! time to got to bed.

This commit is contained in:
Sasha Koshka 2024-01-27 10:43:27 +00:00
parent a423d572ad
commit 8e9b5e0613
5 changed files with 173 additions and 126 deletions

View File

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

View File

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

View File

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

View File

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

View File

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