Move compileAssignmentExpressionWAT into compileAssignmentUpdateExpressionWAT

This commit is contained in:
MrLetsplay 2024-11-23 19:18:38 +01:00
parent 9e39936842
commit d8a80de37c
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
2 changed files with 71 additions and 87 deletions

View File

@ -214,12 +214,9 @@ func castPrimitiveWAT(from PrimitiveType, to PrimitiveType) (Code, error) {
return code, nil return code, nil
} }
func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpression) (Code, error) { func (c *Compiler) compileAssignmentUpdateExpressionWAT(lhs Expression, update bool, valueOrUpdateWAT Code, evaluateToOldValue bool) (Code, error) {
lhs := assignment.Lhs if !isValidLHS(lhs.Type) {
panic(fmt.Sprintf("invalid LHS type passed to compileAssignmentUpdateExpressionWAT(): %s", lhs.Type))
exprWAT, err := c.compileExpressionWAT(assignment.Value)
if err != nil {
return emptyCode(), err
} }
switch lhs.Type { switch lhs.Type {
@ -227,10 +224,40 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
ref := lhs.Value.(VariableReferenceExpression) ref := lhs.Value.(VariableReferenceExpression)
local := strconv.Itoa(getLocal(c.CurrentBlock, ref.Variable).Index) local := strconv.Itoa(getLocal(c.CurrentBlock, ref.Variable).Index)
exprWAT.add("local.tee $" + local + " (;" + ref.Variable + ";)") code := emptyCode()
return exprWAT, nil
// Load variable
if update || evaluateToOldValue {
exprWAT, err := c.compileExpressionWAT(lhs)
if err != nil {
return emptyCode(), err
}
code.addAll(exprWAT)
}
var tmpLocal Local
if update && evaluateToOldValue {
tmpLocal = Local{Name: "", Type: *lhs.ValueType, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, tmpLocal)
// dup old value
code.add("local.tee $" + strconv.Itoa(tmpLocal.Index))
code.add("local.get $" + strconv.Itoa(tmpLocal.Index))
}
code.addAll(valueOrUpdateWAT)
if evaluateToOldValue {
code.add("local.set $" + local + " (;" + ref.Variable + ";)")
} else {
code.add("local.tee $" + local + " (;" + ref.Variable + ";)")
}
return code, nil
case Expression_ArrayAccess: case Expression_ArrayAccess:
array := lhs.Value.(ArrayAccessExpression) array := lhs.Value.(ArrayAccessExpression)
elementType := array.Array.ValueType.Value.(ArrayType).ElementType
localArray := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType(), Position: unknownPosition()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)} localArray := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType(), Position: unknownPosition()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localArray) c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localArray)
@ -238,7 +265,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
localIndex := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType(), Position: unknownPosition()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)} localIndex := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType(), Position: unknownPosition()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localIndex) c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localIndex)
localElement := Local{Name: "", Type: *assignment.Value.ValueType, IsParameter: false, Index: len(c.CurrentFunction.Locals)} localElement := Local{Name: "", Type: elementType, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localElement) c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localElement)
arrayWAT, err := c.compileExpressionWAT(array.Array) arrayWAT, err := c.compileExpressionWAT(array.Array)
@ -270,6 +297,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
// Error if index < 0 // Error if index < 0
wat.add( wat.add(
"block", "block",
"(;bounds check < 0;)",
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)", "local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
c.getAddressWATType()+".const 0", c.getAddressWATType()+".const 0",
c.getAddressWATType()+".ge_s", c.getAddressWATType()+".ge_s",
@ -281,6 +309,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
// Error if index >= array length // Error if index >= array length
wat.add( wat.add(
"block", "block",
"(;bounds check >= array length;)",
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)", "local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
"local.get $"+strconv.Itoa(localArray.Index)+" (;array base address;)", "local.get $"+strconv.Itoa(localArray.Index)+" (;array base address;)",
"i32.load", // Load array length "i32.load", // Load array length
@ -291,7 +320,6 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
) )
} }
elementType := array.Array.ValueType.Value.(ArrayType).ElementType
wat.add( wat.add(
"local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)", "local.get $"+strconv.Itoa(localIndex.Index)+" (;array index;)",
c.getAddressWATType()+".const "+strconv.Itoa(c.getTypeSizeBytes(elementType)), c.getAddressWATType()+".const "+strconv.Itoa(c.getTypeSizeBytes(elementType)),
@ -302,7 +330,7 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
c.getAddressWATType()+".add", c.getAddressWATType()+".add",
) )
wat.addAll(exprWAT) wat.addAll(valueOrUpdateWAT)
wat.add( wat.add(
"local.tee $"+strconv.Itoa(localElement.Index), "local.tee $"+strconv.Itoa(localElement.Index),
@ -314,63 +342,6 @@ func (c *Compiler) compileAssignmentExpressionWAT(assignment AssignmentExpressio
case Expression_RawMemoryReference: case Expression_RawMemoryReference:
raw := lhs.Value.(RawMemoryReferenceExpression) raw := lhs.Value.(RawMemoryReferenceExpression)
local := Local{Name: "", Type: *lhs.ValueType, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, local)
if raw.Type.Type != Type_Primitive {
panic("TODO") //TODO
}
addrWAT, err := c.compileExpressionWAT(raw.Address)
if err != nil {
return emptyCode(), err
}
// TODO: should leave a copy of the stored value on the stack
code := addrWAT.clone()
code.addAll(exprWAT)
code.add(
"local.tee $"+strconv.Itoa(local.Index),
c.getWATType(raw.Type)+".store",
"local.get $"+strconv.Itoa(local.Index),
)
return code, nil
}
panic("assignment expr not implemented")
}
func (c *Compiler) compileAssignmentUpdateExpressionWAT(lhs Expression, updateWAT Code, evaluateToOldValue bool) (Code, error) {
switch lhs.Type {
case Expression_VariableReference:
ref := lhs.Value.(VariableReferenceExpression)
local := strconv.Itoa(getLocal(c.CurrentBlock, ref.Variable).Index)
exprWAT, err := c.compileExpressionWAT(lhs)
if err != nil {
return emptyCode(), err
}
wat := exprWAT.clone()
if evaluateToOldValue {
wat.add("local.get $" + local + " (;" + ref.Variable + ";)")
}
wat.addAll(updateWAT)
if evaluateToOldValue {
wat.add("local.set $" + local + " (;" + ref.Variable + ";)")
} else {
wat.add("local.tee $" + local + " (;" + ref.Variable + ";)")
}
return wat, nil
case Expression_ArrayAccess:
panic("TODO") // TODO
case Expression_RawMemoryReference:
raw := lhs.Value.(RawMemoryReferenceExpression)
localAddress := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)} localAddress := Local{Name: "", Type: Type{Type: Type_Primitive, Value: c.getEffectiveAddressType()}, IsParameter: false, Index: len(c.CurrentFunction.Locals)}
c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localAddress) c.CurrentFunction.Locals = append(c.CurrentFunction.Locals, localAddress)
@ -388,27 +359,29 @@ func (c *Compiler) compileAssignmentUpdateExpressionWAT(lhs Expression, updateWA
wat := addrWAT wat := addrWAT
// dup address if update {
wat.add( // dup address
"local.tee $"+strconv.Itoa(localAddress.Index), wat.add(
"local.get $"+strconv.Itoa(localAddress.Index), "local.tee $"+strconv.Itoa(localAddress.Index)+" (;address;)",
) "local.get $"+strconv.Itoa(localAddress.Index)+" (;address;)",
)
wat.add(c.getWATType(raw.Type) + ".load") wat.add(c.getWATType(raw.Type) + ".load")
if evaluateToOldValue {
wat.add("local.tee $" + strconv.Itoa(localValue.Index))
} }
wat.addAll(updateWAT) if evaluateToOldValue {
wat.add("local.tee $" + strconv.Itoa(localValue.Index) + " (;temp storage for value;)")
}
wat.addAll(valueOrUpdateWAT)
if !evaluateToOldValue { if !evaluateToOldValue {
wat.add("local.tee $" + strconv.Itoa(localValue.Index)) wat.add("local.tee $" + strconv.Itoa(localValue.Index) + " (;temp storage for value;)")
} }
wat.add( wat.add(
c.getWATType(raw.Type)+".store", c.getWATType(raw.Type)+".store",
"local.get $"+strconv.Itoa(localValue.Index), "local.get $"+strconv.Itoa(localValue.Index)+" (;temp storage for value;)",
) )
return wat, nil return wat, nil
@ -424,10 +397,6 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (Code, error) {
case Expression_Assignment: case Expression_Assignment:
ass := expr.Value.(AssignmentExpression) ass := expr.Value.(AssignmentExpression)
if ass.Operation == Operation_Nop {
return c.compileAssignmentExpressionWAT(ass)
}
watRight, err := c.compileExpressionWAT(ass.Value) watRight, err := c.compileExpressionWAT(ass.Value)
if err != nil { if err != nil {
return emptyCode(), err return emptyCode(), err
@ -436,7 +405,7 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (Code, error) {
updateOp := c.compileOperationWAT(ass.Operation, ass.Lhs.ValueType.Value.(PrimitiveType)) updateOp := c.compileOperationWAT(ass.Operation, ass.Lhs.ValueType.Value.(PrimitiveType))
watRight.addAll(updateOp) watRight.addAll(updateOp)
return c.compileAssignmentUpdateExpressionWAT(ass.Lhs, watRight, false) return c.compileAssignmentUpdateExpressionWAT(ass.Lhs, ass.Operation != Operation_Nop, watRight, false)
case Expression_Literal: case Expression_Literal:
lit := expr.Value.(LiteralExpression) lit := expr.Value.(LiteralExpression)
switch lit.Literal.Type { switch lit.Literal.Type {
@ -600,7 +569,7 @@ func (c *Compiler) compileExpressionWAT(expr Expression) (Code, error) {
updateWAT.add(valueType + ".sub") updateWAT.add(valueType + ".sub")
} }
return c.compileAssignmentUpdateExpressionWAT(unary.Value, updateWAT, unary.Operation == UnaryOperation_PostIncrement || unary.Operation == UnaryOperation_PostDecrement) return c.compileAssignmentUpdateExpressionWAT(unary.Value, true, updateWAT, unary.Operation == UnaryOperation_PostIncrement || unary.Operation == UnaryOperation_PostDecrement)
} }
case Expression_Cast: case Expression_Cast:
cast := expr.Value.(CastExpression) cast := expr.Value.(CastExpression)
@ -721,6 +690,8 @@ func (c *Compiler) compileOperationWAT(operation Operation, operandType Primitiv
} }
switch operation { switch operation {
case Operation_Nop:
return emptyCode()
case Operation_Add: case Operation_Add:
op = getPrimitiveWATType(operandType) + ".add" op = getPrimitiveWATType(operandType) + ".add"
case Operation_Sub: case Operation_Sub:
@ -768,7 +739,7 @@ func (c *Compiler) compileStatementWAT(stmt Statement, block *Block) (Code, erro
} }
} }
for _ = range numItems { for range numItems {
wat.add("drop") wat.add("drop")
} }

View File

@ -128,6 +128,10 @@ func (t PrimitiveType) String() string {
return getPrimitiveTypeName(t) return getPrimitiveTypeName(t)
} }
func (t ExpressionType) String() string {
return strconv.Itoa(int(t))
}
func getOperation(operator Operator) Operation { func getOperation(operator Operator) Operation {
switch operator { switch operator {
case Operator_Greater: case Operator_Greater:
@ -186,3 +190,12 @@ func isBooleanOperation(operation Operation) bool {
func isArithmeticOperation(operation Operation) bool { func isArithmeticOperation(operation Operation) bool {
return !isBooleanOperation(operation) return !isBooleanOperation(operation)
} }
func isValidLHS(expressionType ExpressionType) bool {
switch expressionType {
case Expression_ArrayAccess, Expression_VariableReference, Expression_RawMemoryReference:
return true
default:
return false
}
}