Merge pull request 'generator-reduce-redundant-ir' (#2) from generator-reduce-redundant-ir into main

Reviewed-on: sashakoshka/fspl#2
This commit is contained in:
Sasha Koshka 2024-01-27 17:40:37 +00:00
commit 15541b8675
10 changed files with 885 additions and 760 deletions

View File

@ -69,7 +69,7 @@ func (this *generator) generateAssignmentSource (
// conversion from pointer to interface
case *entity.TypePointer:
// assign data
source, err := this.generateExpression(from)
source, err := this.generateExpressionVal(from)
if err != nil { return nil, err }
fromData := this.blockManager.NewLoad(new(llvm.TypePointer), source)
this.blockManager.NewStore(fromData, toDataField)
@ -119,13 +119,13 @@ func (this *generator) generateAssignmentSource (
case *entity.TypeSlice:
switch fromBase := analyzer.ReduceToBase(from.Type()).(type) {
case *entity.TypeArray:
source, err := this.generateExpression(from)
source, err := this.generateExpressionVal(from)
if err != nil { return nil, err }
return this.generateSliceDefinedLength(to, source, int64(fromBase.Length))
}
}
source, err := this.generateExpression(from)
source, err := this.generateExpressionVal(from)
if err != nil { return nil, err }
return source, nil
}

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

@ -8,11 +8,10 @@ testString (test,
define void @main() {
0:
%1 = alloca { ptr, %Index }
%2 = load { ptr, %Index }, ptr %1
%3 = getelementptr { ptr, %Index }, ptr %1, i32 0, i32 0
%4 = load ptr, ptr %3
%5 = alloca ptr
store ptr %4, ptr %5
%2 = getelementptr { ptr, %Index }, ptr %1, i32 0, i32 0
%3 = load ptr, ptr %2
%4 = alloca ptr
store ptr %3, ptr %4
ret void
}
`,
@ -54,9 +53,8 @@ define void @main() {
0:
%1 = alloca { ptr, %Index }
%2 = load { ptr, %Index }, ptr %1
%3 = load { ptr, %Index }, ptr %1
%4 = alloca %String
store { ptr, %Index } %3, ptr %4
%3 = alloca %String
store { ptr, %Index } %2, ptr %3
ret void
}
`,
@ -76,9 +74,8 @@ define void @main() {
0:
%1 = alloca { ptr, %Index }
%2 = load { ptr, %Index }, ptr %1
%3 = load { ptr, %Index }, ptr %1
%4 = alloca %String
store { ptr, %Index } %3, ptr %4
%3 = alloca %String
store { ptr, %Index } %2, ptr %3
ret void
}
`,

View File

@ -24,11 +24,11 @@ func (this *generator) generateSliceLoc (slice *entity.Slice) (llvm.Value, error
}
if slice.Start != nil {
start, err = this.generateExpression(slice.Start)
start, err = this.generateExpressionVal(slice.Start)
if err != nil { return nil, err }
}
if slice.End != nil {
end, err = this.generateExpression(slice.End)
end, err = this.generateExpressionVal(slice.End)
if err != nil { return nil, err }
}
@ -93,7 +93,7 @@ func (this *generator) generateSliceLoc (slice *entity.Slice) (llvm.Value, error
func (this *generator) generateSubscriptLoc (subscript *entity.Subscript) (llvm.Value, error) {
source, err := this.generateExpressionLoc(subscript.Slice)
if err != nil { return nil, err }
offset, err := this.generateExpression(subscript.Offset)
offset, err := this.generateExpressionVal(subscript.Offset)
if err != nil { return nil, err }
var elementType entity.Type
@ -127,7 +127,7 @@ func (this *generator) generateSubscriptLoc (subscript *entity.Subscript) (llvm.
}
func (this *generator) generateDereferenceLoc (dereference *entity.Dereference) (llvm.Value, error) {
return this.generateExpression(dereference.Pointer)
return this.generateExpressionVal(dereference.Pointer)
}
func (this *generator) generateMemberAccessLoc (access *entity.MemberAccess) (llvm.Value, error) {
@ -164,19 +164,3 @@ func (this *generator) generateMemberAccessLoc (access *entity.MemberAccess) (ll
access.Source))
}
}
func (this *generator) generateBlockLoc (block *entity.Block) (llvm.Value, error) {
var last llvm.Value
var err error
for index, step := range block.Steps {
// prefer generating a normal statement to avoid allocations
if index == len(block.Steps) - 1 {
last, err = this.generateStatementLoc(step)
} else {
last, err = this.generateStatement(step)
}
if err != nil { return nil, err }
}
return last, nil
}

View File

@ -4,6 +4,21 @@ 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 (mode ResultMode) String () string {
switch(mode) {
case ResultModeAny: return "ResultModeLoc"
case ResultModeVal: return "ResultModeVal"
case ResultModeLoc: return "ResultModeAny"
default: return fmt.Sprintf("ResultMode(%d)", mode)
}
}
func (this *generator) valueToLocation (value llvm.Value) llvm.Value {
pointer := this.blockManager.newAllocaFront(value.Type())
this.blockManager.NewStore(value, pointer)
@ -16,9 +31,82 @@ func (this *generator) locationToValue (pointer llvm.Value, ty entity.Type) (llv
return this.blockManager.NewLoad(irType, pointer), nil
}
// generateExpression generates an expression and returns a register
func (this *generator) generateExpression (
expression entity.Expression,
mode ResultMode,
) (
register llvm.Value,
location bool,
err error,
) {
switch mode {
case ResultModeAny:
return this.generateExpressionAny(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
// "location" will be true.
func (this *generator) generateExpressionAny (expression entity.Expression) (register llvm.Value, location bool, err error) {
// TODO: some of these could stand to know that they have a choice in
// the matter.
switch expression := expression.(type) {
// these give us an address
case *entity.Dereference,
*entity.MemberAccess,
*entity.Slice,
*entity.Subscript,
*entity.LiteralArray,
*entity.LiteralString,
*entity.LiteralStruct,
*entity.Variable,
*entity.Declaration,
*entity.IfElse,
*entity.Loop:
pointer, err := this.generateExpressionLoc(expression)
return pointer, true, err
// these give us a value
case *entity.Call,
*entity.MethodCall,
*entity.Reference,
*entity.Length,
*entity.ValueCast,
*entity.BitCast,
*entity.Operation,
*entity.LiteralInt,
*entity.LiteralFloat,
*entity.LiteralBoolean,
*entity.LiteralNil:
value, err := this.generateExpressionVal(expression)
return value, true, err
// these are capable of giving us both
case *entity.Block:
return this.generateBlock(expression, ResultModeAny)
default:
panic(fmt.Sprintf (
"BUG: generator doesnt know about expression %v, ty: %T",
expression, expression))
}
}
// generateExpressionVal generates an expression and returns a register
// representing the result.
func (this *generator) generateExpression (expression entity.Expression) (llvm.Value, error) {
func (this *generator) generateExpressionVal (expression entity.Expression) (llvm.Value, error) {
// we get an address from these, so we need to load the value
switch expression := expression.(type) {
case *entity.Dereference,
@ -35,34 +123,32 @@ func (this *generator) generateExpression (expression entity.Expression) (llvm.V
// we get a value from these, so we can return them as-is
case *entity.Variable:
return this.generateVariable(expression)
return this.generateVariableVal(expression)
case *entity.Declaration:
return this.generateDeclaration(expression)
return this.generateDeclarationVal(expression)
case *entity.Call:
return this.generateCall(expression)
return this.generateCallVal(expression)
case *entity.MethodCall:
return this.generateMethodCall(expression)
return this.generateMethodCallVal(expression)
case *entity.Reference:
return this.generateReference(expression)
return this.generateReferenceVal(expression)
case *entity.Length:
return this.generateLength(expression)
return this.generateLengthVal(expression)
case *entity.ValueCast:
return this.generateValueCast(expression)
return this.generateValueCastVal(expression)
case *entity.BitCast:
return this.generateBitCast(expression)
return this.generateBitCastVal(expression)
case *entity.Operation:
return this.generateOperation(expression)
return this.generateOperationVal(expression)
case *entity.Block:
return this.generateBlock(expression)
loc, _, err := this.generateBlock(expression, ResultModeVal)
return loc, err
case *entity.IfElse:
return this.generateIfElse(expression, false)
loc, _, err := this.generateIfElse(expression, ResultModeVal)
return loc, err
case *entity.Loop:
return this.generateLoop(expression, false)
case *entity.Break:
return this.generateBreak(expression)
case *entity.Return:
return this.generateReturn(expression)
loc, _, err := this.generateLoop(expression, ResultModeVal)
return loc, err
case *entity.LiteralInt:
return this.generateLiteralInt(expression)
case *entity.LiteralFloat:
@ -71,9 +157,15 @@ func (this *generator) generateExpression (expression entity.Expression) (llvm.V
return this.generateLiteralBoolean(expression)
case *entity.LiteralNil:
return this.generateLiteralNil(expression)
// we get nothing from these
case *entity.Break:
return this.generateBreak(expression)
case *entity.Return:
return this.generateReturn(expression)
default:
panic(fmt.Sprintf (
"BUG: generator doesnt know about expression %v, ty: %T",
"BUG: generator doesnt know about value expression %v, ty: %T",
expression, expression))
}
}
@ -98,7 +190,7 @@ func (this *generator) generateExpressionLoc (expression entity.Expression) (llv
*entity.LiteralBoolean,
*entity.LiteralNil:
value, err := this.generateExpression(expression)
value, err := this.generateExpressionVal(expression)
if err != nil { return nil, err }
return this.valueToLocation(value), nil
@ -116,34 +208,61 @@ 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:
return this.generateIfElse(expression, true)
loc, _, err := this.generateIfElse(expression, ResultModeLoc)
return loc, err
case *entity.Loop:
return this.generateLoop(expression, true)
case *entity.Break:
return this.generateBreak(expression)
case *entity.Return:
return this.generateReturn(expression)
loc, _, err := this.generateLoop(expression, ResultModeLoc)
return loc, err
case *entity.LiteralArray:
return this.generateLiteralArrayLoc(expression)
case *entity.LiteralString:
return this.generateLiteralStringLoc(expression)
case *entity.LiteralStruct:
return this.generateLiteralStructLoc(expression)
// we get nothing from these
case *entity.Break:
return this.generateBreak(expression)
case *entity.Return:
return this.generateReturn(expression)
default:
panic(fmt.Sprintf (
"BUG: generator doesnt know about expression %v, ty: %T",
"BUG: generator doesnt know about location expression %v, ty: %T",
expression, expression))
}
}
func (this *generator) generateStatement (statement entity.Statement) (llvm.Value, error) {
func (this *generator) generateStatement (
statement entity.Statement,
mode ResultMode,
) (
register llvm.Value,
location bool,
err error,
) {
switch mode {
case ResultModeAny:
return this.generateStatementAny(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) generateStatementAny (statement entity.Statement) (register llvm.Value, location bool, err error) {
switch statement := statement.(type) {
case *entity.Assignment:
return this.generateAssignment(statement)
_, err := this.generateAssignment(statement)
return nil, false, err
case entity.Expression:
return this.generateExpression(statement)
return this.generateExpressionAny(statement)
default:
panic(fmt.Sprintf (
"BUG: generator doesnt know about statement %v, ty: %T",
@ -151,13 +270,30 @@ func (this *generator) generateStatement (statement entity.Statement) (llvm.Valu
}
}
func (this *generator) generateStatementVal (statement entity.Statement) (llvm.Value, error) {
switch statement := statement.(type) {
case *entity.Assignment:
_, err := this.generateAssignment(statement)
return nil, err
case entity.Expression:
return this.generateExpressionVal(statement)
default:
panic(fmt.Sprintf (
"BUG: generator doesnt know about value statement %v, ty: %T",
statement, statement))
}
}
func (this *generator) generateStatementLoc (statement entity.Statement) (llvm.Value, error) {
switch statement := statement.(type) {
case *entity.Assignment:
_, err := this.generateAssignment(statement)
return nil, err
case entity.Expression:
return this.generateExpressionLoc(statement)
default:
panic(fmt.Sprintf (
"BUG: generator doesnt know about statement %v, ty: %T",
"BUG: generator doesnt know about location statement %v, ty: %T",
statement, statement))
}
}

620
generator/expression-val.go Normal file
View File

@ -0,0 +1,620 @@
package generator
import "fmt"
import "errors"
import "git.tebibyte.media/sashakoshka/fspl/llvm"
import "git.tebibyte.media/sashakoshka/fspl/entity"
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
func (this *generator) generateVariableVal (variable *entity.Variable) (llvm.Value, error) {
location, err := this.generateVariableLoc(variable)
if err != nil { return nil, err }
irType, err := this.generateType(variable.Type())
if err != nil { return nil, err }
return this.blockManager.NewLoad(irType, location), nil
}
func (this *generator) generateDeclarationVal (declaration *entity.Declaration) (llvm.Value, error) {
location, err := this.blockManager.addDeclaration(declaration, nil)
if err != nil { return nil, err }
irType, err := this.generateType(declaration.Type())
if err != nil { return nil, err }
return this.blockManager.NewLoad(irType, location), nil
}
func (this *generator) generateCallVal (call *entity.Call) (llvm.Value, error) {
function, err := this.function(call.Name)
if err != nil { return nil, err }
args := make([]llvm.Value, len(call.Arguments))
for index, argument := range call.Arguments {
irArgument, err := this.generateAssignmentSource (
argument,
call.Function.Signature.Arguments[index].Type())
if err != nil { return nil, err }
args[index] = irArgument
}
return this.blockManager.NewCall(function, function.Signature, args...), nil
}
func (this *generator) generateMethodCallVal (call *entity.MethodCall) (llvm.Value, error) {
var signature *entity.Signature
if call.Method != nil { signature = call.Method.Signature }
if call.Behavior != nil { signature = call.Behavior }
// build list of args
args := make([]llvm.Value, len(call.Arguments) + 1)
for index, argument := range call.Arguments {
irArgument, err := this.generateAssignmentSource (
argument,
signature.Arguments[index].Type())
if err != nil { return nil, err }
args[index + 1] = irArgument
}
// check for methods on named type
if sourceType, ok := call.Source.Type().(*entity.TypeNamed); ok {
method, err := this.method(sourceType.Name, call.Name)
if err != errNotFound {
source, err := this.generateExpressionLoc(call.Source)
if err != nil { return nil, err }
args[0] = source
return this.blockManager.NewCall(method, method.Signature, args...), nil
}
}
// check for methods on pointer to named type
if pointerType, ok := call.Source.Type().(*entity.TypePointer); ok {
if sourceType, ok := pointerType.Referenced.(*entity.TypeNamed); ok {
method, err := this.method(sourceType.Name, call.Name)
if err != errNotFound {
source, err := this.generateExpressionVal(call.Source)
if err != nil { return nil, err }
args[0] = source
return this.blockManager.NewCall(method, method.Signature, args...), nil
}
}
}
// check for interface behaviors
if sourceType := getInterface(call.Source.Type()); sourceType != nil {
irSourceType, err := this.generateType(call.Source.Type())
if err != nil { return nil, err }
source, err := this.generateExpressionLoc(call.Source)
if err != nil { return nil, err }
irBehavior := this.getInterfaceBehavior(sourceType, source, irSourceType, call.Name)
if irBehavior != nil {
irValue := this.getInterfaceData(source, irSourceType)
signature, err := this.getInterfaceBehaviorSignature(sourceType, call.Name)
if err != nil { return nil, err }
args[0] = this.blockManager.NewLoad(irValue.Type(), irValue)
irBehavior := this.blockManager.NewLoad(llvm.Pointer, irBehavior)
return this.blockManager.NewCall (
irBehavior,
signature.(*llvm.TypeFunction),
args...), nil
}
}
return nil, errors.New(fmt.Sprintln("no method", call.Name, "for", call.Source))
}
func (this *generator) generateReferenceVal (reference *entity.Reference) (llvm.Value, error) {
return this.generateExpressionLoc(reference.Value)
}
func (this *generator) generateLengthVal (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 }
lengthFieldAddress := this.blockManager.NewGetElementPtr (
irSourceType,
source,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, 1))
return this.blockManager.NewLoad(sizeType, lengthFieldAddress), 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) generateValueCastVal (cast *entity.ValueCast) (llvm.Value, error) {
generateFrom := func () (llvm.Value, error) {
return this.generateExpressionVal(cast.Value)
}
generateFromLoc := func () (llvm.Value, error) {
return this.generateExpressionLoc(cast.Value)
}
irFromType, err := this.generateType(cast.Value.Type())
if err != nil { return nil, err }
irToType, err := this.generateType(cast.Type())
if err != nil { return nil, err }
// Attempt to short circuit if types are equal to avoid LLVM bitching at
// us
if llvm.TypesEqual(irFromType, irToType) {
return this.generateExpressionVal(cast.Value)
}
fail := func () (llvm.Value, error) {
return nil, errors.New(fmt.Sprintf (
"cant convert %v to %v",
cast.Value.Type(), cast.Type()))
}
fromType := analyzer.ReduceToBase(cast.Value.Type())
toType := analyzer.ReduceToBase(cast.Type())
switch toType.(type) {
case *entity.TypeInt, *entity.TypeWord:
from, err := generateFrom()
if err != nil { return nil, err }
switch fromType := fromType.(type) {
case *entity.TypeInt, *entity.TypeWord:
// cast from integer to integer:
// basic truncated value assignment
return this.blockManager.NewTrunc(from, irToType), nil
case *entity.TypeFloat:
if analyzer.IsUnsigned(fromType) {
// cast from float to unsigned integer:
// convert float to unsigned integer
return this.blockManager.NewFPToUI(from, irToType), nil
} else {
// cast from float to signed integer:
// convert float to signed integer
return this.blockManager.NewFPToSI(from, irToType), nil
}
default: return fail()
}
case *entity.TypeFloat:
from, err := generateFrom()
if err != nil { return nil, err }
switch fromType := fromType.(type) {
case *entity.TypeFloat:
// cast from float to float:
// basic truncated value assignment
return this.blockManager.NewFPTrunc(from, irToType), nil
case *entity.TypeInt, *entity.TypeWord:
if analyzer.IsUnsigned(fromType) {
// cast from unsigned integer to float:
// convert unsigned integer to float
return this.blockManager.NewUIToFP(from, irToType), nil
} else {
// cast from signed integer to float:
// convert signed integer to float
return this.blockManager.NewSIToFP(from, irToType), nil
}
default: return fail()
}
case *entity.TypePointer:
switch fromType := fromType.(type) {
case *entity.TypeSlice:
// cast from slice to pointer:
// pointer will point to the first element of the slice
from, err := generateFromLoc()
if err != nil { return nil, err }
irFromType, err := this.generateType(fromType)
return this.getSliceDataAddress(from, irFromType), nil
case *entity.TypePointer:
// cast from pointer to pointer:
// basic forceful value assignment
// (all IR pointer types are equal)
return this.generateExpressionVal(cast.Value)
default: return fail()
}
case *entity.TypeSlice:
switch fromType.(type) {
case *entity.TypeSlice:
// cast from slice to slice:
// basic forceful value assignment
// (assume structural equivalence)
return this.generateExpressionVal(cast.Value)
default: return fail()
}
case *entity.TypeArray:
switch fromType.(type) {
case *entity.TypeArray:
// cast from array to array:
// basic forceful value assignment
// (assume structural equivalence)
return this.generateExpressionVal(cast.Value)
default: return fail()
}
case *entity.TypeStruct:
switch fromType.(type) {
case *entity.TypeArray:
// cast from struct to struct:
// basic forceful value assignment
// (assume structural equivalence)
return this.generateExpressionVal(cast.Value)
default: return fail()
}
default: return fail()
}
}
func (this *generator) generateBitCastVal (cast *entity.BitCast) (llvm.Value, error) {
irFromType, err := this.generateType(cast.Value.Type())
if err != nil { return nil, err }
irToType, err := this.generateType(cast.Type())
if err != nil { return nil, err }
// Attempt to short circuit if types are equal to avoid LLVM bitching at
// us
if llvm.TypesEqual(irFromType, irToType) {
return this.generateExpressionVal(cast.Value)
}
from, err := this.generateExpressionVal(cast.Value)
if err != nil { return nil, err }
return this.blockManager.NewBitCast(from, irToType), nil
}
func (this *generator) generateOperationVal (operation *entity.Operation) (llvm.Value, error) {
nSameType := func (binary func (x, y llvm.Value) llvm.Value) (llvm.Value, error) {
irX, err := this.generateExpressionVal(operation.Arguments[0])
if err != nil { return nil, err }
for _, argument := range operation.Arguments[1:] {
irY, err := this.generateExpressionVal(argument)
if err != nil { return nil, err }
irX = binary(irX, irY)
}
return irX, nil
}
ty := analyzer.ReduceToBase(operation.Arguments[0].Type())
irType, err := this.generateType(ty)
if err != nil { return nil, err }
switch operation.Operator {
// math
case entity.OperatorAdd:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewAdd(x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFAdd(x, y)
})
}
case entity.OperatorSubtract:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewSub(x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFSub(x, y)
})
}
case entity.OperatorMultiply:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewMul(x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFMul(x, y)
})
}
case entity.OperatorDivide:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
if analyzer.IsUnsigned(ty) {
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewUDiv(x, y)
})
} else {
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewSDiv(x, y)
})
}
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFDiv(x, y)
})
}
case entity.OperatorIncrement:
irX, err := this.generateExpressionVal(operation.Arguments[0])
if err != nil { return nil, err }
irType := irType.(*llvm.TypeInt)
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return this.blockManager.NewAdd (
irX,
llvm.NewConstInt(irType, 1)), nil
case *entity.TypeFloat:
return this.blockManager.NewFAdd (
irX,
llvm.NewConstInt(irType, 1)), nil
}
case entity.OperatorDecrement:
irX, err := this.generateExpressionVal(operation.Arguments[0])
if err != nil { return nil, err }
irType := irType.(*llvm.TypeInt)
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return this.blockManager.NewSub (
irX,
llvm.NewConstInt(irType, 1)), nil
case *entity.TypeFloat:
return this.blockManager.NewFSub (
irX,
llvm.NewConstInt(irType, 1)), nil
}
case entity.OperatorModulo:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
if analyzer.IsUnsigned(ty) {
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewURem(x, y)
})
} else {
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewSRem(x, y)
})
}
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFDiv(x, y)
})
}
// logic
case entity.OperatorLogicalNot:
irX, err := this.generateExpressionVal(operation.Arguments[0])
if err != nil { return nil, err }
return this.blockManager.NewICmp(llvm.IPredicateEQ, irX, llvm.NewConstBool(false)), nil
case entity.OperatorLogicalOr:
incomings := make([]*llvm.Incoming, len(operation.Arguments) + 1)
exit := this.blockManager.newBlock()
for index, argument := range operation.Arguments {
irX, err := this.generateExpressionVal(argument)
if err != nil { return nil, err }
incomings[index] = &llvm.Incoming {
X: llvm.NewConstBool(true),
Predecessor: this.blockManager.Block,
}
previous := this.blockManager.Block
block := this.blockManager.newBlock()
previous.NewCondBr(irX, exit, block)
}
this.blockManager.NewBr(exit)
incomings[len(incomings) - 1] = &llvm.Incoming {
X: llvm.NewConstBool(false),
Predecessor: this.blockManager.Block,
}
this.blockManager.Block = exit
return this.blockManager.NewPhi(incomings...), nil
case entity.OperatorLogicalAnd:
incomings := make([]*llvm.Incoming, len(operation.Arguments) + 1)
exit := this.blockManager.newBlock()
for index, argument := range operation.Arguments {
irX, err := this.generateExpressionVal(argument)
if err != nil { return nil, err }
incomings[index] = &llvm.Incoming {
X: llvm.NewConstBool(false),
Predecessor: this.blockManager.Block,
}
previous := this.blockManager.Block
block := this.blockManager.newBlock()
previous.NewCondBr(irX, block, exit)
}
this.blockManager.NewBr(exit)
incomings[len(incomings) - 1] = &llvm.Incoming {
X: llvm.NewConstBool(true),
Predecessor: this.blockManager.Block,
}
this.blockManager.Block = exit
return this.blockManager.NewPhi(incomings...), nil
case entity.OperatorLogicalXor:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp (
llvm.IPredicateNE,
this.blockManager.NewICmp(llvm.IPredicateEQ, x, llvm.NewConstBool(true)),
this.blockManager.NewICmp(llvm.IPredicateEQ, x, llvm.NewConstBool(true)))
})
// bit manipulation
case entity.OperatorNot:
irX, err := this.generateExpressionVal(operation.Arguments[0])
if err != nil { return nil, err }
return this.blockManager.NewXor (
irX,
llvm.NewConstInt(irType.(*llvm.TypeInt), -1)), nil
case entity.OperatorOr:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewOr(x, y)
})
case entity.OperatorAnd:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewAnd(x, y)
})
case entity.OperatorXor:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewXor(x, y)
})
case entity.OperatorLeftShift:
irX, err := this.generateExpressionVal(operation.Arguments[0])
if err != nil { return nil, err }
irY, err := this.generateExpressionVal(operation.Arguments[1])
if err != nil { return nil, err }
return this.blockManager.NewShl(irX, irY), nil
case entity.OperatorRightShift:
irX, err := this.generateExpressionVal(operation.Arguments[0])
if err != nil { return nil, err }
irY, err := this.generateExpressionVal(operation.Arguments[1])
if err != nil { return nil, err }
if analyzer.IsUnsigned(ty) {
return this.blockManager.NewLShr(irX, irY), nil
} else {
return this.blockManager.NewAShr(irX, irY), nil
}
// comparison
case entity.OperatorLess:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
var predicate llvm.IPredicate
if analyzer.IsUnsigned(ty) {
predicate = llvm.IPredicateULT
} else {
predicate = llvm.IPredicateSLT
}
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp(predicate, x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFCmp (
llvm.FPredicateOLT,
x, y)
})
}
case entity.OperatorGreater:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
var predicate llvm.IPredicate
if analyzer.IsUnsigned(ty) {
predicate = llvm.IPredicateUGT
} else {
predicate = llvm.IPredicateSGT
}
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp(predicate, x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFCmp (
llvm.FPredicateOGT,
x, y)
})
}
case entity.OperatorLessEqual:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
var predicate llvm.IPredicate
if analyzer.IsUnsigned(ty) {
predicate = llvm.IPredicateULE
} else {
predicate = llvm.IPredicateSLE
}
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp(predicate, x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFCmp (
llvm.FPredicateOLE,
x, y)
})
}
case entity.OperatorGreaterEqual:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
var predicate llvm.IPredicate
if analyzer.IsUnsigned(ty) {
predicate = llvm.IPredicateUGE
} else {
predicate = llvm.IPredicateSGE
}
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp(predicate, x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFCmp (
llvm.FPredicateOGE,
x, y)
})
}
case entity.OperatorEqual:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp (
llvm.IPredicateEQ,
x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFCmp (
llvm.FPredicateOEQ,
x, y)
})
}
default:
panic(fmt.Sprint (
"BUG: generator doesnt know about operator",
operation.Operator))
}
panic(fmt.Sprint (
"BUG: generator failed to generate operation",
operation))
}

View File

@ -1,677 +1,90 @@
package generator
import "fmt"
import "errors"
// import "fmt"
import "git.tebibyte.media/sashakoshka/fspl/llvm"
import "git.tebibyte.media/sashakoshka/fspl/entity"
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
// import "git.tebibyte.media/sashakoshka/fspl/analyzer"
func (this *generator) generateVariable (variable *entity.Variable) (llvm.Value, error) {
location, err := this.generateVariableLoc(variable)
if err != nil { return nil, err }
irType, err := this.generateType(variable.Type())
if err != nil { return nil, err }
return this.blockManager.NewLoad(irType, location), nil
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
for _, step := range block.Steps[:lastIndex] {
_, _, err := this.generateStatementAny(step)
if err != nil { return nil, false, err }
}
return this.generateStatement(block.Steps[lastIndex], mode)
}
func (this *generator) generateDeclaration (declaration *entity.Declaration) (llvm.Value, error) {
location, err := this.blockManager.addDeclaration(declaration, nil)
if err != nil { return nil, err }
irType, err := this.generateType(declaration.Type())
if err != nil { return nil, err }
return this.blockManager.NewLoad(irType, location), nil
func (this *generator) generateBreak (brk *entity.Break) (llvm.Value, error) {
loopEntry := this.blockManager.topLoop()
if brk.Value != nil {
value, loc, err := this.generateExpression(brk.Value, loopEntry.mode)
if err != nil { return nil, err }
loopEntry.value = value
loopEntry.loc = loc
}
loopEntry.stub = this.blockManager.Block
return nil, nil
}
func (this *generator) generateCall (call *entity.Call) (llvm.Value, error) {
function, err := this.function(call.Name)
if err != nil { return nil, err }
args := make([]llvm.Value, len(call.Arguments))
for index, argument := range call.Arguments {
irArgument, err := this.generateAssignmentSource (
argument,
call.Function.Signature.Arguments[index].Type())
func (this *generator) generateReturn (ret *entity.Return) (llvm.Value, error) {
if ret.Value == nil {
this.blockManager.NewRet(nil)
} else {
value, err := this.generateExpressionVal(ret.Value)
if err != nil { return nil, err }
args[index] = irArgument
this.blockManager.NewRet(value)
}
return this.blockManager.NewCall(function, function.Signature, args...), nil
return nil, nil
}
func (this *generator) generateMethodCall (call *entity.MethodCall) (llvm.Value, error) {
var signature *entity.Signature
if call.Method != nil { signature = call.Method.Signature }
if call.Behavior != nil { signature = call.Behavior }
// build list of args
args := make([]llvm.Value, len(call.Arguments) + 1)
for index, argument := range call.Arguments {
irArgument, err := this.generateAssignmentSource (
argument,
signature.Arguments[index].Type())
if err != nil { return nil, err }
args[index + 1] = irArgument
}
// check for methods on named type
if sourceType, ok := call.Source.Type().(*entity.TypeNamed); ok {
method, err := this.method(sourceType.Name, call.Name)
if err != errNotFound {
source, err := this.generateExpressionLoc(call.Source)
if err != nil { return nil, err }
args[0] = source
return this.blockManager.NewCall(method, method.Signature, args...), nil
}
}
// check for methods on pointer to named type
if pointerType, ok := call.Source.Type().(*entity.TypePointer); ok {
if sourceType, ok := pointerType.Referenced.(*entity.TypeNamed); ok {
method, err := this.method(sourceType.Name, call.Name)
if err != errNotFound {
source, err := this.generateExpression(call.Source)
if err != nil { return nil, err }
args[0] = source
return this.blockManager.NewCall(method, method.Signature, args...), nil
}
}
}
// check for interface behaviors
if sourceType := getInterface(call.Source.Type()); sourceType != nil {
irSourceType, err := this.generateType(call.Source.Type())
if err != nil { return nil, err }
source, err := this.generateExpressionLoc(call.Source)
if err != nil { return nil, err }
irBehavior := this.getInterfaceBehavior(sourceType, source, irSourceType, call.Name)
if irBehavior != nil {
irValue := this.getInterfaceData(source, irSourceType)
signature, err := this.getInterfaceBehaviorSignature(sourceType, call.Name)
if err != nil { return nil, err }
args[0] = this.blockManager.NewLoad(irValue.Type(), irValue)
irBehavior := this.blockManager.NewLoad(llvm.Pointer, irBehavior)
return this.blockManager.NewCall (
irBehavior,
signature.(*llvm.TypeFunction),
args...), nil
}
}
return nil, errors.New(fmt.Sprintln("no method", call.Name, "for", call.Source))
}
func (this *generator) generateReference (reference *entity.Reference) (llvm.Value, error) {
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 }
lengthFieldAddress := this.blockManager.NewGetElementPtr (
irSourceType,
source,
llvm.NewConstInt(llvm.I32, 0),
llvm.NewConstInt(llvm.I32, 1))
return this.blockManager.NewLoad(sizeType, lengthFieldAddress), 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, error) {
return this.generateExpression(cast.Value)
}
generateFromLoc := func () (llvm.Value, error) {
return this.generateExpressionLoc(cast.Value)
}
irFromType, err := this.generateType(cast.Value.Type())
if err != nil { return nil, err }
irToType, err := this.generateType(cast.Type())
if err != nil { return nil, err }
// Attempt to short circuit if types are equal to avoid LLVM bitching at
// us
if llvm.TypesEqual(irFromType, irToType) {
return this.generateExpression(cast.Value)
}
fail := func () (llvm.Value, error) {
return nil, errors.New(fmt.Sprintf (
"cant convert %v to %v",
cast.Value.Type(), cast.Type()))
}
fromType := analyzer.ReduceToBase(cast.Value.Type())
toType := analyzer.ReduceToBase(cast.Type())
switch toType.(type) {
case *entity.TypeInt, *entity.TypeWord:
from, err := generateFrom()
if err != nil { return nil, err }
switch fromType := fromType.(type) {
case *entity.TypeInt, *entity.TypeWord:
// cast from integer to integer:
// basic truncated value assignment
return this.blockManager.NewTrunc(from, irToType), nil
case *entity.TypeFloat:
if analyzer.IsUnsigned(fromType) {
// cast from float to unsigned integer:
// convert float to unsigned integer
return this.blockManager.NewFPToUI(from, irToType), nil
} else {
// cast from float to signed integer:
// convert float to signed integer
return this.blockManager.NewFPToSI(from, irToType), nil
}
default: return fail()
}
case *entity.TypeFloat:
from, err := generateFrom()
if err != nil { return nil, err }
switch fromType := fromType.(type) {
case *entity.TypeFloat:
// cast from float to float:
// basic truncated value assignment
return this.blockManager.NewFPTrunc(from, irToType), nil
case *entity.TypeInt, *entity.TypeWord:
if analyzer.IsUnsigned(fromType) {
// cast from unsigned integer to float:
// convert unsigned integer to float
return this.blockManager.NewUIToFP(from, irToType), nil
} else {
// cast from signed integer to float:
// convert signed integer to float
return this.blockManager.NewSIToFP(from, irToType), nil
}
default: return fail()
}
case *entity.TypePointer:
switch fromType := fromType.(type) {
case *entity.TypeSlice:
// cast from slice to pointer:
// pointer will point to the first element of the slice
from, err := generateFromLoc()
if err != nil { return nil, err }
irFromType, err := this.generateType(fromType)
return this.getSliceDataAddress(from, irFromType), nil
case *entity.TypePointer:
// cast from pointer to pointer:
// basic forceful value assignment
// (all IR pointer types are equal)
return this.generateExpression(cast.Value)
default: return fail()
}
case *entity.TypeSlice:
switch fromType.(type) {
case *entity.TypeSlice:
// cast from slice to slice:
// basic forceful value assignment
// (assume structural equivalence)
return this.generateExpression(cast.Value)
default: return fail()
}
case *entity.TypeArray:
switch fromType.(type) {
case *entity.TypeArray:
// cast from array to array:
// basic forceful value assignment
// (assume structural equivalence)
return this.generateExpression(cast.Value)
default: return fail()
}
case *entity.TypeStruct:
switch fromType.(type) {
case *entity.TypeArray:
// cast from struct to struct:
// basic forceful value assignment
// (assume structural equivalence)
return this.generateExpression(cast.Value)
default: return fail()
}
default: return fail()
}
}
func (this *generator) generateBitCast (cast *entity.BitCast) (llvm.Value, error) {
irFromType, err := this.generateType(cast.Value.Type())
if err != nil { return nil, err }
irToType, err := this.generateType(cast.Type())
if err != nil { return nil, err }
// Attempt to short circuit if types are equal to avoid LLVM bitching at
// us
if llvm.TypesEqual(irFromType, irToType) {
return this.generateExpression(cast.Value)
}
from, err := this.generateExpression(cast.Value)
if err != nil { return nil, err }
return this.blockManager.NewBitCast(from, irToType), nil
}
func (this *generator) generateOperation (operation *entity.Operation) (llvm.Value, error) {
nSameType := func (binary func (x, y llvm.Value) llvm.Value) (llvm.Value, error) {
irX, err := this.generateExpression(operation.Arguments[0])
if err != nil { return nil, err }
for _, argument := range operation.Arguments[1:] {
irY, err := this.generateExpression(argument)
if err != nil { return nil, err }
irX = binary(irX, irY)
}
return irX, nil
}
ty := analyzer.ReduceToBase(operation.Arguments[0].Type())
irType, err := this.generateType(ty)
if err != nil { return nil, err }
switch operation.Operator {
// math
case entity.OperatorAdd:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewAdd(x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFAdd(x, y)
})
}
case entity.OperatorSubtract:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewSub(x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFSub(x, y)
})
}
case entity.OperatorMultiply:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewMul(x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFMul(x, y)
})
}
case entity.OperatorDivide:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
if analyzer.IsUnsigned(ty) {
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewUDiv(x, y)
})
} else {
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewSDiv(x, y)
})
}
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFDiv(x, y)
})
}
case entity.OperatorIncrement:
irX, err := this.generateExpression(operation.Arguments[0])
if err != nil { return nil, err }
irType := irType.(*llvm.TypeInt)
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return this.blockManager.NewAdd (
irX,
llvm.NewConstInt(irType, 1)), nil
case *entity.TypeFloat:
return this.blockManager.NewFAdd (
irX,
llvm.NewConstInt(irType, 1)), nil
}
case entity.OperatorDecrement:
irX, err := this.generateExpression(operation.Arguments[0])
if err != nil { return nil, err }
irType := irType.(*llvm.TypeInt)
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return this.blockManager.NewSub (
irX,
llvm.NewConstInt(irType, 1)), nil
case *entity.TypeFloat:
return this.blockManager.NewFSub (
irX,
llvm.NewConstInt(irType, 1)), nil
}
case entity.OperatorModulo:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
if analyzer.IsUnsigned(ty) {
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewURem(x, y)
})
} else {
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewSRem(x, y)
})
}
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFDiv(x, y)
})
}
// logic
case entity.OperatorLogicalNot:
irX, err := this.generateExpression(operation.Arguments[0])
if err != nil { return nil, err }
return this.blockManager.NewICmp(llvm.IPredicateEQ, irX, llvm.NewConstBool(false)), nil
case entity.OperatorLogicalOr:
incomings := make([]*llvm.Incoming, len(operation.Arguments) + 1)
exit := this.blockManager.newBlock()
for index, argument := range operation.Arguments {
irX, err := this.generateExpression(argument)
if err != nil { return nil, err }
incomings[index] = &llvm.Incoming {
X: llvm.NewConstBool(true),
Predecessor: this.blockManager.Block,
}
previous := this.blockManager.Block
block := this.blockManager.newBlock()
previous.NewCondBr(irX, exit, block)
}
this.blockManager.NewBr(exit)
incomings[len(incomings) - 1] = &llvm.Incoming {
X: llvm.NewConstBool(false),
Predecessor: this.blockManager.Block,
}
this.blockManager.Block = exit
return this.blockManager.NewPhi(incomings...), nil
case entity.OperatorLogicalAnd:
incomings := make([]*llvm.Incoming, len(operation.Arguments) + 1)
exit := this.blockManager.newBlock()
for index, argument := range operation.Arguments {
irX, err := this.generateExpression(argument)
if err != nil { return nil, err }
incomings[index] = &llvm.Incoming {
X: llvm.NewConstBool(false),
Predecessor: this.blockManager.Block,
}
previous := this.blockManager.Block
block := this.blockManager.newBlock()
previous.NewCondBr(irX, block, exit)
}
this.blockManager.NewBr(exit)
incomings[len(incomings) - 1] = &llvm.Incoming {
X: llvm.NewConstBool(true),
Predecessor: this.blockManager.Block,
}
this.blockManager.Block = exit
return this.blockManager.NewPhi(incomings...), nil
case entity.OperatorLogicalXor:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp (
llvm.IPredicateNE,
this.blockManager.NewICmp(llvm.IPredicateEQ, x, llvm.NewConstBool(true)),
this.blockManager.NewICmp(llvm.IPredicateEQ, x, llvm.NewConstBool(true)))
})
// bit manipulation
case entity.OperatorNot:
irX, err := this.generateExpression(operation.Arguments[0])
if err != nil { return nil, err }
return this.blockManager.NewXor (
irX,
llvm.NewConstInt(irType.(*llvm.TypeInt), -1)), nil
case entity.OperatorOr:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewOr(x, y)
})
case entity.OperatorAnd:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewAnd(x, y)
})
case entity.OperatorXor:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewXor(x, y)
})
case entity.OperatorLeftShift:
irX, err := this.generateExpression(operation.Arguments[0])
if err != nil { return nil, err }
irY, err := this.generateExpression(operation.Arguments[1])
if err != nil { return nil, err }
return this.blockManager.NewShl(irX, irY), nil
case entity.OperatorRightShift:
irX, err := this.generateExpression(operation.Arguments[0])
if err != nil { return nil, err }
irY, err := this.generateExpression(operation.Arguments[1])
if err != nil { return nil, err }
if analyzer.IsUnsigned(ty) {
return this.blockManager.NewLShr(irX, irY), nil
} else {
return this.blockManager.NewAShr(irX, irY), nil
}
// comparison
case entity.OperatorLess:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
var predicate llvm.IPredicate
if analyzer.IsUnsigned(ty) {
predicate = llvm.IPredicateULT
} else {
predicate = llvm.IPredicateSLT
}
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp(predicate, x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFCmp (
llvm.FPredicateOLT,
x, y)
})
}
case entity.OperatorGreater:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
var predicate llvm.IPredicate
if analyzer.IsUnsigned(ty) {
predicate = llvm.IPredicateUGT
} else {
predicate = llvm.IPredicateSGT
}
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp(predicate, x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFCmp (
llvm.FPredicateOGT,
x, y)
})
}
case entity.OperatorLessEqual:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
var predicate llvm.IPredicate
if analyzer.IsUnsigned(ty) {
predicate = llvm.IPredicateULE
} else {
predicate = llvm.IPredicateSLE
}
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp(predicate, x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFCmp (
llvm.FPredicateOLE,
x, y)
})
}
case entity.OperatorGreaterEqual:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
var predicate llvm.IPredicate
if analyzer.IsUnsigned(ty) {
predicate = llvm.IPredicateUGE
} else {
predicate = llvm.IPredicateSGE
}
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp(predicate, x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFCmp (
llvm.FPredicateOGE,
x, y)
})
}
case entity.OperatorEqual:
switch ty.(type) {
case *entity.TypeInt, *entity.TypeWord:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewICmp (
llvm.IPredicateEQ,
x, y)
})
case *entity.TypeFloat:
return nSameType(func (x, y llvm.Value) llvm.Value {
return this.blockManager.NewFCmp (
llvm.FPredicateOEQ,
x, y)
})
}
default:
panic(fmt.Sprint (
"BUG: generator doesnt know about operator",
operation.Operator))
}
panic(fmt.Sprint (
"BUG: generator failed to generate operation",
operation))
}
func (this *generator) generateBlock (block *entity.Block) (llvm.Value, error) {
var last llvm.Value
var err error
for _, step := range block.Steps {
last, err = this.generateStatement(step)
if err != nil { return nil, err }
}
return last, nil
}
func (this *generator) generateIfElse (ifelse *entity.IfElse, loc bool) (llvm.Value, error) {
condition, err := this.generateExpression(ifelse.Condition)
if err != nil { return nil, err }
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
if loc {
tru, err = this.generateExpressionLoc(ifelse.True)
} else {
tru, err = this.generateExpression(ifelse.True)
tru, loc, err = this.generateExpression(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 err != nil { return nil, err }
if !this.blockManager.Terminated() { this.blockManager.NewBr(exitBlock) }
if ifelse.False != nil {
if ifelse.Type() == nil {
if mode == ResultModeAny {
// discard results of statements
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 }
fals, _, err = this.generateExpression(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, nil
return nil, loc, nil
} else {
// obtain results of statements
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 }
fals, _, err = this.generateExpression(ifelse.False, mode)
if err != nil { return nil, false, err }
if !this.blockManager.Terminated() { this.blockManager.NewBr(exitBlock) }
// set up phi to capture results
trueIncoming := &llvm.Incoming {
X: tru,
Predecessor: trueBlock,
@ -683,25 +96,25 @@ func (this *generator) generateIfElse (ifelse *entity.IfElse, loc bool) (llvm.Va
previous.NewCondBr(condition, trueBlock, falseBlock)
this.blockManager.Block = exitBlock
return this.blockManager.NewPhi(trueIncoming, falseIncoming), nil
return this.blockManager.NewPhi(trueIncoming, falseIncoming), loc, nil
}
} else {
previous.NewCondBr(condition, trueBlock, exitBlock)
this.blockManager.Block = exitBlock
return nil, nil
return nil, loc, nil
}
}
func (this *generator) generateLoop (loop *entity.Loop, loc bool) (llvm.Value, error) {
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(loc)
loopEntry := this.blockManager.pushLoop(mode)
defer this.blockManager.popLoop()
_, err := this.generateExpression(loop.Body)
if err != nil { return nil, err }
_, _, err := this.generateExpressionAny(loop.Body)
if err != nil { return nil, false, err }
this.blockManager.NewBr(body)
exit := this.blockManager.newBlock()
@ -711,28 +124,5 @@ func (this *generator) generateLoop (loop *entity.Loop, loc bool) (llvm.Value, e
Target: exit,
})
}
return loopEntry.value, nil
}
func (this *generator) generateBreak (brk *entity.Break) (llvm.Value, error) {
loopEntry := this.blockManager.topLoop()
if brk.Value != nil {
value, err := this.generateExpression(brk.Value)
if err != nil { return nil, err }
loopEntry.value = value
}
loopEntry.stub = this.blockManager.Block
return nil, nil
}
func (this *generator) generateReturn (ret *entity.Return) (llvm.Value, error) {
if ret.Value == nil {
this.blockManager.NewRet(nil)
} else {
value, err := this.generateExpression(ret.Value)
if err != nil { return nil, err }
this.blockManager.NewRet(value)
}
return nil, nil
return loopEntry.value, loopEntry.loc, nil
}

View File

@ -32,12 +32,14 @@ func (this *generator) generateFunction (
defer this.popBlockManager()
this.blockManager.addFunctionArgumentDeclarations(function)
body, err := this.generateExpression(function.Body)
if err != nil { return nil, err }
if function.Signature.Return == nil {
_, _, err := this.generateExpressionAny(function.Body)
if err != nil { return nil, err }
this.blockManager.NewRet(nil)
} else {
body, err := this.generateExpressionVal(function.Body)
if err != nil { return nil, err }
this.blockManager.NewRet(body)
}
}
@ -76,12 +78,14 @@ func (this *generator) generateMethod (
defer this.popBlockManager()
this.blockManager.addFunctionArgumentDeclarations(method)
body, err := this.generateExpression(method.Body)
if err != nil { return nil, err }
if method.Signature.Return == nil {
_, _, err := this.generateExpressionAny(method.Body)
if err != nil { return nil, err }
this.blockManager.NewRet(nil)
} else {
body, err := this.generateExpressionVal(method.Body)
if err != nil { return nil, err }
this.blockManager.NewRet(body)
}
}

View File

@ -206,7 +206,7 @@ func (this *generator) generateLiteralStructLoc (literal *entity.LiteralStruct)
for index, member := range ty.Members {
var irMember llvm.Value
if pair, ok := literal.MemberMap[member.Name]; ok {
irMember, err = this.generateExpression(pair.Value)
irMember, err = this.generateExpressionVal(pair.Value)
if err != nil { return nil, err }
} else {
irMemberType, err := this.generateType(member.Type())

View File

@ -70,11 +70,8 @@ testString (test,
define void @main() {
0:
%1 = alloca %A
%2 = load %A, ptr %1
%3 = alloca %B
%4 = load %B, ptr %3
%5 = alloca %C
%6 = load %C, ptr %5
%2 = alloca %B
%3 = alloca %C
ret void
}
`,
@ -96,11 +93,8 @@ testString (test,
define void @main() {
0:
%1 = alloca %A
%2 = load %A, ptr %1
%3 = alloca %B
%4 = load %B, ptr %3
%5 = alloca %C
%6 = load %C, ptr %5
%2 = alloca %B
%3 = alloca %C
ret void
}
`,
@ -121,9 +115,8 @@ testString (test,
define void @main() {
0:
%1 = alloca %B
%2 = load %B, ptr %1
%3 = getelementptr { i64 }, ptr %1, i32 0, i32 0
store i64 5, ptr %3
%2 = getelementptr { i64 }, ptr %1, i32 0, i32 0
store i64 5, ptr %2
ret void
}
`,