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:
commit
15541b8675
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
`,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
620
generator/expression-val.go
Normal 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))
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
}
|
||||
`,
|
||||
|
Loading…
Reference in New Issue
Block a user