Completed operations

This commit is contained in:
Sasha Koshka 2023-12-01 01:18:10 -05:00
parent 635add38e6
commit 31d5317dc8
4 changed files with 310 additions and 8 deletions

View File

@ -29,7 +29,7 @@ func (this *generator) generateAssignmentSource (
if err != nil { return nil, err }
ty := analyzer.ReduceToBase(to)
switch ty := ty.(type) {
switch /*ty := */ty.(type) {
case *entity.TypeInterface:
// TODO: assign to interface
// sourceTy := analyzer.ReduceToBase(from.Type())
@ -42,9 +42,9 @@ func (this *generator) generateAssignmentSource (
// if err != nil { return nil, err }
// pointer := this.
case *entity.TypeSlice:
if fromType, ok := analyzer.ReduceToBase(from.Type()).(*entity.TypeArray); ok {
/*if fromType, ok := analyzer.ReduceToBase(from.Type()).(*entity.TypeArray); ok {
// TODO: convert array to slice
}
}*/
}
return source, nil
}

View File

@ -205,42 +205,341 @@ func (this *generator) generateBitCast (cast *entity.BitCast) (llvm.Value, error
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:
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.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:
case entity.OperatorGreaterEqual:
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 ",
"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) {

View File

@ -28,7 +28,10 @@ func testReader (test *testing.T, correct string, inputs ...io.Reader) {
return
}
module, err := NativeTarget().Generate(tree)
module, err := (&Target {
WordSize: 64,
Arch: "x86_64",
}).Generate(tree)
if err != nil {
test.Error("generator returned error:", err)
return

View File

@ -1478,7 +1478,7 @@ type InstructionXor struct {
AbstractInstructionBinary
}
func (this *Block) AddXor (x, y Value) *InstructionXor {
func (this *Block) NewXor (x, y Value) *InstructionXor {
instruction := &InstructionXor { }
instruction.Token = "xor"
instruction.X = x