621 lines
18 KiB
Go
621 lines
18 KiB
Go
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.getInterfaceBehaviorFieldLoc(sourceType, source, irSourceType, call.Name)
|
|
|
|
if irBehavior != nil {
|
|
irValue := this.getInterfaceDataFieldLoc(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))
|
|
}
|