mirror of
https://github.com/irmen/prog8.git
synced 2024-12-26 14:29:35 +00:00
got rid of unnecessary cast of boolean expressions by making their type dynamically adjust to byte or word
This commit is contained in:
parent
1d342cc6af
commit
036d9dbe59
@ -3,6 +3,7 @@ package prog8.codegen.virtual
|
|||||||
import prog8.code.ast.PtBuiltinFunctionCall
|
import prog8.code.ast.PtBuiltinFunctionCall
|
||||||
import prog8.code.ast.PtNumber
|
import prog8.code.ast.PtNumber
|
||||||
import prog8.code.ast.PtString
|
import prog8.code.ast.PtString
|
||||||
|
import prog8.code.core.WordDatatypes
|
||||||
import prog8.vm.Opcode
|
import prog8.vm.Opcode
|
||||||
import prog8.vm.Syscall
|
import prog8.vm.Syscall
|
||||||
import prog8.vm.VmDataType
|
import prog8.vm.VmDataType
|
||||||
@ -82,6 +83,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
|||||||
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||||
}
|
}
|
||||||
"peek" -> {
|
"peek" -> {
|
||||||
|
// should just be a memory read
|
||||||
val addressReg = codeGen.vmRegisters.nextFree()
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
code += exprGen.translateExpression(call.args.single(), addressReg)
|
code += exprGen.translateExpression(call.args.single(), addressReg)
|
||||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg)
|
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg)
|
||||||
@ -91,6 +93,21 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
|||||||
code += exprGen.translateExpression(call.args.single(), addressReg)
|
code += exprGen.translateExpression(call.args.single(), addressReg)
|
||||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)
|
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)
|
||||||
}
|
}
|
||||||
|
"poke" -> {
|
||||||
|
// should just be a memory write
|
||||||
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
|
val valueReg = codeGen.vmRegisters.nextFree()
|
||||||
|
code += exprGen.translateExpression(call.args[0], addressReg)
|
||||||
|
code += exprGen.translateExpression(call.args[1], valueReg)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = addressReg, reg2=valueReg)
|
||||||
|
}
|
||||||
|
"pokew" -> {
|
||||||
|
val addressReg = codeGen.vmRegisters.nextFree()
|
||||||
|
val valueReg = codeGen.vmRegisters.nextFree()
|
||||||
|
code += exprGen.translateExpression(call.args[0], addressReg)
|
||||||
|
code += exprGen.translateExpression(call.args[1], valueReg)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = addressReg, reg2=valueReg)
|
||||||
|
}
|
||||||
"mkword" -> {
|
"mkword" -> {
|
||||||
val msbReg = codeGen.vmRegisters.nextFree()
|
val msbReg = codeGen.vmRegisters.nextFree()
|
||||||
val lsbReg = codeGen.vmRegisters.nextFree()
|
val lsbReg = codeGen.vmRegisters.nextFree()
|
||||||
|
@ -3,10 +3,7 @@ package prog8.optimizer
|
|||||||
import prog8.ast.IStatementContainer
|
import prog8.ast.IStatementContainer
|
||||||
import prog8.ast.Node
|
import prog8.ast.Node
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.expressions.AugmentAssignmentOperators
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.expressions.BinaryExpression
|
|
||||||
import prog8.ast.expressions.IdentifierReference
|
|
||||||
import prog8.ast.expressions.TypecastExpression
|
|
||||||
import prog8.ast.getTempVar
|
import prog8.ast.getTempVar
|
||||||
import prog8.ast.statements.AssignTarget
|
import prog8.ast.statements.AssignTarget
|
||||||
import prog8.ast.statements.Assignment
|
import prog8.ast.statements.Assignment
|
||||||
@ -97,7 +94,8 @@ X = BinExpr X = LeftExpr
|
|||||||
// we can see if we can unwrap the binary expression by working on a new temporary variable
|
// we can see if we can unwrap the binary expression by working on a new temporary variable
|
||||||
// (that has the type of the expression), and then finally doing the typecast.
|
// (that has the type of the expression), and then finally doing the typecast.
|
||||||
// Once it's outside the typecast, the regular splitting can commence.
|
// Once it's outside the typecast, the regular splitting can commence.
|
||||||
val (tempVarName, _) = program.getTempVar(origExpr.inferType(program).getOr(DataType.UNDEFINED))
|
val tempvarDt = origExpr.inferType(program).getOr(DataType.UNDEFINED)
|
||||||
|
val (tempVarName, _) = program.getTempVar(tempvarDt)
|
||||||
val assignTempVar = Assignment(
|
val assignTempVar = Assignment(
|
||||||
AssignTarget(IdentifierReference(tempVarName, typecast.position), null, null, typecast.position),
|
AssignTarget(IdentifierReference(tempVarName, typecast.position), null, null, typecast.position),
|
||||||
typecast.expression, AssignmentOrigin.OPTIMIZER, typecast.position
|
typecast.expression, AssignmentOrigin.OPTIMIZER, typecast.position
|
||||||
|
@ -114,6 +114,10 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
|||||||
if(valuetype in IterableDatatypes && targettype==DataType.UWORD)
|
if(valuetype in IterableDatatypes && targettype==DataType.UWORD)
|
||||||
// special case, don't typecast STR/arrays to UWORD, we support those assignments "directly"
|
// special case, don't typecast STR/arrays to UWORD, we support those assignments "directly"
|
||||||
return noModifications
|
return noModifications
|
||||||
|
if((assignment.value as? BinaryExpression)?.operator in ComparisonOperators) {
|
||||||
|
// special case, treat a boolean comparison result as the same type as the target value to avoid needless casts later
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
val modifications = mutableListOf<IAstModification>()
|
val modifications = mutableListOf<IAstModification>()
|
||||||
addTypecastOrCastedValueModification(modifications, assignment.value, targettype, assignment)
|
addTypecastOrCastedValueModification(modifications, assignment.value, targettype, assignment)
|
||||||
return modifications
|
return modifications
|
||||||
|
@ -253,7 +253,7 @@ class TestOptimization: FunSpec({
|
|||||||
(initY2.value as NumericLiteral).number shouldBe 11.0
|
(initY2.value as NumericLiteral).number shouldBe 11.0
|
||||||
}
|
}
|
||||||
|
|
||||||
test("typecasted assignment from ubyte logical expressoin to uword var") {
|
test("not-typecasted assignment from ubyte logical expression to uword var") {
|
||||||
val src = """
|
val src = """
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
@ -265,13 +265,11 @@ class TestOptimization: FunSpec({
|
|||||||
"""
|
"""
|
||||||
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
||||||
|
|
||||||
// ww = ((( not bb as uword) or not ww) as uword)
|
|
||||||
val wwAssign = result.program.entrypoint.statements.last() as Assignment
|
val wwAssign = result.program.entrypoint.statements.last() as Assignment
|
||||||
val expr = wwAssign.value as TypecastExpression
|
val expr = wwAssign.value as BinaryExpression
|
||||||
|
|
||||||
wwAssign.target.identifier?.nameInSource shouldBe listOf("ww")
|
wwAssign.target.identifier?.nameInSource shouldBe listOf("ww")
|
||||||
expr.type shouldBe DataType.UWORD
|
expr.inferType(result.program) istype DataType.UWORD shouldBe true
|
||||||
expr.expression.inferType(result.program) istype DataType.UBYTE shouldBe true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test("intermediate assignment steps have correct types for codegen phase (BeforeAsmGenerationAstChanger)") {
|
test("intermediate assignment steps have correct types for codegen phase (BeforeAsmGenerationAstChanger)") {
|
||||||
|
@ -195,8 +195,21 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex
|
|||||||
|
|
||||||
override fun referencesIdentifier(nameInSource: List<String>) = left.referencesIdentifier(nameInSource) || right.referencesIdentifier(nameInSource)
|
override fun referencesIdentifier(nameInSource: List<String>) = left.referencesIdentifier(nameInSource) || right.referencesIdentifier(nameInSource)
|
||||||
override fun inferType(program: Program): InferredTypes.InferredType {
|
override fun inferType(program: Program): InferredTypes.InferredType {
|
||||||
|
|
||||||
val leftDt = left.inferType(program)
|
val leftDt = left.inferType(program)
|
||||||
val rightDt = right.inferType(program)
|
val rightDt = right.inferType(program)
|
||||||
|
|
||||||
|
fun dynamicBooleanType(): InferredTypes.InferredType {
|
||||||
|
// as a special case, an expression yielding a boolean result, adapts the result
|
||||||
|
// type to what is required (byte or word), to avoid useless type casting
|
||||||
|
return if(parent is TypecastExpression)
|
||||||
|
InferredTypes.InferredType.known((parent as TypecastExpression).type)
|
||||||
|
else if(parent is Assignment)
|
||||||
|
(parent as Assignment).target.inferType(program)
|
||||||
|
else
|
||||||
|
InferredTypes.InferredType.known(DataType.UBYTE)
|
||||||
|
}
|
||||||
|
|
||||||
return when (operator) {
|
return when (operator) {
|
||||||
"+", "-", "*", "%", "/" -> {
|
"+", "-", "*", "%", "/" -> {
|
||||||
if (!leftDt.isKnown || !rightDt.isKnown)
|
if (!leftDt.isKnown || !rightDt.isKnown)
|
||||||
@ -221,13 +234,14 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex
|
|||||||
"and", "or", "xor",
|
"and", "or", "xor",
|
||||||
"<", ">",
|
"<", ">",
|
||||||
"<=", ">=",
|
"<=", ">=",
|
||||||
"==", "!=" -> InferredTypes.knownFor(DataType.UBYTE)
|
"==", "!=" -> dynamicBooleanType()
|
||||||
"<<", ">>" -> leftDt
|
"<<", ">>" -> leftDt
|
||||||
"in" -> InferredTypes.knownFor(DataType.UBYTE)
|
"in" -> dynamicBooleanType()
|
||||||
else -> throw FatalAstException("resulting datatype check for invalid operator $operator")
|
else -> throw FatalAstException("resulting datatype check for invalid operator $operator")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun commonDatatype(leftDt: DataType, rightDt: DataType,
|
fun commonDatatype(leftDt: DataType, rightDt: DataType,
|
||||||
left: Expression?, right: Expression?): Pair<DataType, Expression?> {
|
left: Expression?, right: Expression?): Pair<DataType, Expression?> {
|
||||||
|
@ -3,7 +3,6 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- vm: implement all operators in the virtualmachine
|
|
||||||
- vm: codegen: more optimal code for loops ending on 0 (BNZ?)
|
- vm: codegen: more optimal code for loops ending on 0 (BNZ?)
|
||||||
- pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls.
|
- pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls.
|
||||||
- writeAssembly(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
|
- writeAssembly(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
|
||||||
|
@ -6,27 +6,15 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
ubyte global = 42
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
uword begin = c64.RDTIM16()
|
ubyte value1 = 99
|
||||||
|
ubyte value2 = 222
|
||||||
|
|
||||||
ubyte shift
|
uword @shared result = $ffff
|
||||||
repeat 60 {
|
result = value1 != value2
|
||||||
ubyte yy
|
|
||||||
for yy in 0 to 59 {
|
|
||||||
ubyte xx
|
|
||||||
for xx in 0 to 79 {
|
|
||||||
ubyte color = yy+xx+shift
|
|
||||||
txt.setcc2(xx,yy,81,color) ; 356
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shift++
|
|
||||||
}
|
|
||||||
|
|
||||||
uword duration = c64.RDTIM16()-begin
|
txt.print_uwhex(result, true)
|
||||||
txt.print_uw(duration)
|
txt.nl()
|
||||||
txt.print(" \n")
|
|
||||||
|
|
||||||
; a "pixelshader":
|
; a "pixelshader":
|
||||||
; syscall1(8, 0) ; enable lo res creen
|
; syscall1(8, 0) ; enable lo res creen
|
||||||
|
@ -713,7 +713,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
VmDataType.BYTE -> {
|
VmDataType.BYTE -> {
|
||||||
val value = registers.getUW(i.reg1!!)
|
val value = registers.getUW(i.reg1!!)
|
||||||
val newValue = 0xea31 // value.toUByte()*256u + (value.toInt() ushr 8).toUInt()
|
val newValue = value.toUByte()*256u + (value.toInt() ushr 8).toUInt()
|
||||||
registers.setUW(i.reg1, newValue.toUShort())
|
registers.setUW(i.reg1, newValue.toUShort())
|
||||||
}
|
}
|
||||||
VmDataType.WORD -> TODO("swap.w requires 32-bits registers")
|
VmDataType.WORD -> TODO("swap.w requires 32-bits registers")
|
||||||
|
Loading…
Reference in New Issue
Block a user