mirror of
https://github.com/irmen/prog8.git
synced 2024-11-18 19:12:44 +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.PtNumber
|
||||
import prog8.code.ast.PtString
|
||||
import prog8.code.core.WordDatatypes
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.Syscall
|
||||
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)
|
||||
}
|
||||
"peek" -> {
|
||||
// should just be a memory read
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), 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 += 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" -> {
|
||||
val msbReg = codeGen.vmRegisters.nextFree()
|
||||
val lsbReg = codeGen.vmRegisters.nextFree()
|
||||
|
@ -3,10 +3,7 @@ package prog8.optimizer
|
||||
import prog8.ast.IStatementContainer
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.expressions.AugmentAssignmentOperators
|
||||
import prog8.ast.expressions.BinaryExpression
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.expressions.TypecastExpression
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.getTempVar
|
||||
import prog8.ast.statements.AssignTarget
|
||||
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
|
||||
// (that has the type of the expression), and then finally doing the typecast.
|
||||
// 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(
|
||||
AssignTarget(IdentifierReference(tempVarName, typecast.position), null, null, 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)
|
||||
// special case, don't typecast STR/arrays to UWORD, we support those assignments "directly"
|
||||
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>()
|
||||
addTypecastOrCastedValueModification(modifications, assignment.value, targettype, assignment)
|
||||
return modifications
|
||||
|
@ -253,7 +253,7 @@ class TestOptimization: FunSpec({
|
||||
(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 = """
|
||||
main {
|
||||
sub start() {
|
||||
@ -265,13 +265,11 @@ class TestOptimization: FunSpec({
|
||||
"""
|
||||
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 expr = wwAssign.value as TypecastExpression
|
||||
val expr = wwAssign.value as BinaryExpression
|
||||
|
||||
wwAssign.target.identifier?.nameInSource shouldBe listOf("ww")
|
||||
expr.type shouldBe DataType.UWORD
|
||||
expr.expression.inferType(result.program) istype DataType.UBYTE shouldBe true
|
||||
expr.inferType(result.program) istype DataType.UWORD shouldBe true
|
||||
}
|
||||
|
||||
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 inferType(program: Program): InferredTypes.InferredType {
|
||||
|
||||
val leftDt = left.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) {
|
||||
"+", "-", "*", "%", "/" -> {
|
||||
if (!leftDt.isKnown || !rightDt.isKnown)
|
||||
@ -221,13 +234,14 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex
|
||||
"and", "or", "xor",
|
||||
"<", ">",
|
||||
"<=", ">=",
|
||||
"==", "!=" -> InferredTypes.knownFor(DataType.UBYTE)
|
||||
"==", "!=" -> dynamicBooleanType()
|
||||
"<<", ">>" -> leftDt
|
||||
"in" -> InferredTypes.knownFor(DataType.UBYTE)
|
||||
"in" -> dynamicBooleanType()
|
||||
else -> throw FatalAstException("resulting datatype check for invalid operator $operator")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
fun commonDatatype(leftDt: DataType, rightDt: DataType,
|
||||
left: Expression?, right: Expression?): Pair<DataType, Expression?> {
|
||||
|
@ -3,7 +3,6 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- vm: implement all operators in the virtualmachine
|
||||
- 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.
|
||||
- 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 {
|
||||
|
||||
ubyte global = 42
|
||||
|
||||
sub start() {
|
||||
uword begin = c64.RDTIM16()
|
||||
ubyte value1 = 99
|
||||
ubyte value2 = 222
|
||||
|
||||
ubyte shift
|
||||
repeat 60 {
|
||||
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 @shared result = $ffff
|
||||
result = value1 != value2
|
||||
|
||||
uword duration = c64.RDTIM16()-begin
|
||||
txt.print_uw(duration)
|
||||
txt.print(" \n")
|
||||
txt.print_uwhex(result, true)
|
||||
txt.nl()
|
||||
|
||||
; a "pixelshader":
|
||||
; syscall1(8, 0) ; enable lo res creen
|
||||
|
@ -713,7 +713,7 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
||||
when(i.type!!) {
|
||||
VmDataType.BYTE -> {
|
||||
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())
|
||||
}
|
||||
VmDataType.WORD -> TODO("swap.w requires 32-bits registers")
|
||||
|
Loading…
Reference in New Issue
Block a user