mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
preparing for more optimizations
This commit is contained in:
parent
53ac11983b
commit
75a06d2a40
@ -146,7 +146,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
|
override fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> {
|
||||||
// see if we can remove superfluous typecasts (outside of expressions)
|
// see if we can remove redundant typecasts (outside of expressions)
|
||||||
// such as casting byte<->ubyte, word<->uword
|
// such as casting byte<->ubyte, word<->uword
|
||||||
// Also the special typecast of a reference type (str, array) to an UWORD will be changed into address-of,
|
// Also the special typecast of a reference type (str, array) to an UWORD will be changed into address-of,
|
||||||
// UNLESS it's a str parameter in the containing subroutine - then we remove the typecast altogether
|
// UNLESS it's a str parameter in the containing subroutine - then we remove the typecast altogether
|
||||||
|
@ -47,7 +47,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk
|
|||||||
val rightDt = expr.right.inferType(program)
|
val rightDt = expr.right.inferType(program)
|
||||||
if(leftDt.isKnown && rightDt.isKnown && leftDt!=rightDt) {
|
if(leftDt.isKnown && rightDt.isKnown && leftDt!=rightDt) {
|
||||||
// determine common datatype and add typecast as required to make left and right equal types
|
// determine common datatype and add typecast as required to make left and right equal types
|
||||||
val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt.getOr(DataType.UNDEFINED), rightDt.getOr(DataType.UNDEFINED), expr.left, expr.right)
|
val (commonDt, toFix) = BinaryExpression.commonDatatype(leftDt.getOr(DataType.UNDEFINED), rightDt.getOr(DataType.UNDEFINED), expr.left, expr.operator, expr.right)
|
||||||
if(toFix!=null) {
|
if(toFix!=null) {
|
||||||
return when {
|
return when {
|
||||||
toFix===expr.left -> listOf(IAstModification.ReplaceNode(
|
toFix===expr.left -> listOf(IAstModification.ReplaceNode(
|
||||||
|
@ -74,6 +74,19 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter)
|
|||||||
if(sourceDt istype typecast.type)
|
if(sourceDt istype typecast.type)
|
||||||
return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
|
return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
|
||||||
|
|
||||||
|
// TODO finish this; get rid of redundant final typecast to variable's type if they are the same
|
||||||
|
// if(parent is Assignment) {
|
||||||
|
// val targetDt = (parent).target.inferType(program).getOrElse { throw FatalAstException("invalid dt") }
|
||||||
|
// if(sourceDt istype targetDt) {
|
||||||
|
// // we can get rid of this typecast because the type is already
|
||||||
|
// // TODO REMOVE IT
|
||||||
|
// println("TYPECAST IN ASSIGNMENT $parent") // TODO DEBUG
|
||||||
|
// } else {
|
||||||
|
// // TODO
|
||||||
|
// println("${typecast.expression} : source=$sourceDt to $targetDt")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +190,39 @@ class TestOptimization: FunSpec({
|
|||||||
asm.valid shouldBe true
|
asm.valid shouldBe true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("intermediate assignment steps 2 have correct types for codegen phase (BeforeAsmGenerationAstChanger)") {
|
||||||
|
val src = """
|
||||||
|
main {
|
||||||
|
sub start() {
|
||||||
|
ubyte r
|
||||||
|
ubyte @shared bb = (cos8(r)/2 + 100) as ubyte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
val result = compileText(C64Target, true, src, writeAssembly = false).assertSuccess()
|
||||||
|
|
||||||
|
// bb = (cos8(r)/2 + 100) as ubyte
|
||||||
|
val bbAssign = result.program.entrypoint.statements.last() as Assignment
|
||||||
|
val texpr = bbAssign.value as TypecastExpression
|
||||||
|
texpr.type shouldBe DataType.UBYTE
|
||||||
|
texpr.expression shouldBe instanceOf<BinaryExpression>()
|
||||||
|
texpr.expression.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.BYTE
|
||||||
|
|
||||||
|
val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, true, C64Target)
|
||||||
|
val changer = BeforeAsmGenerationAstChanger(result.program,
|
||||||
|
options,
|
||||||
|
ErrorReporterForTests()
|
||||||
|
)
|
||||||
|
|
||||||
|
changer.visit(result.program)
|
||||||
|
while(changer.applyModifications()>0) {
|
||||||
|
changer.visit(result.program)
|
||||||
|
}
|
||||||
|
|
||||||
|
// printAst(result.program)
|
||||||
|
// TODO finish this test
|
||||||
|
}
|
||||||
|
|
||||||
test("asmgen correctly deals with float typecasting in augmented assignment") {
|
test("asmgen correctly deals with float typecasting in augmented assignment") {
|
||||||
val src="""
|
val src="""
|
||||||
%option enable_floats
|
%option enable_floats
|
||||||
|
@ -170,7 +170,7 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex
|
|||||||
commonDatatype(
|
commonDatatype(
|
||||||
leftDt.getOr(DataType.BYTE),
|
leftDt.getOr(DataType.BYTE),
|
||||||
rightDt.getOr(DataType.BYTE),
|
rightDt.getOr(DataType.BYTE),
|
||||||
null, null
|
null, "", null
|
||||||
).first
|
).first
|
||||||
)
|
)
|
||||||
} catch (x: FatalAstException) {
|
} catch (x: FatalAstException) {
|
||||||
@ -192,7 +192,7 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex
|
|||||||
|
|
||||||
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?, operator: String, right: Expression?): Pair<DataType, Expression?> {
|
||||||
// byte + byte -> byte
|
// byte + byte -> byte
|
||||||
// byte + word -> word
|
// byte + word -> word
|
||||||
// word + byte -> word
|
// word + byte -> word
|
||||||
|
@ -675,4 +675,51 @@ class TestProg8Parser: FunSpec( {
|
|||||||
expr.right.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UWORD
|
expr.right.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UWORD
|
||||||
expr.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
expr.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("inferred type for typecasted expressions with logical operators") {
|
||||||
|
val src=SourceCode.Text("""
|
||||||
|
main {
|
||||||
|
ubyte bb
|
||||||
|
uword ww
|
||||||
|
uword qq = (not bb as uword)
|
||||||
|
uword zz = not bb or not ww
|
||||||
|
ubyte bb2 = not bb or not ww
|
||||||
|
uword zz2 = (not bb as uword) or not ww
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
val module = parseModule(src)
|
||||||
|
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
||||||
|
module.linkIntoProgram(program)
|
||||||
|
val stmts = (module.statements.single() as Block).statements
|
||||||
|
stmts.size shouldBe 6
|
||||||
|
val qq = (stmts[2] as VarDecl).value as TypecastExpression
|
||||||
|
val zz = (stmts[3] as VarDecl).value as BinaryExpression
|
||||||
|
val bb2 = (stmts[4] as VarDecl).value as BinaryExpression
|
||||||
|
val zz2 = (stmts[5] as VarDecl).value as BinaryExpression
|
||||||
|
qq.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UWORD
|
||||||
|
zz.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||||
|
bb2.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||||
|
|
||||||
|
zz2.operator shouldBe "or"
|
||||||
|
val left = zz2.left as TypecastExpression
|
||||||
|
val right = zz2.right as PrefixExpression
|
||||||
|
left.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UWORD
|
||||||
|
right.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UWORD
|
||||||
|
zz2.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UBYTE // 'or' causes UBYTE result
|
||||||
|
}
|
||||||
|
|
||||||
|
test("type cast from byte to ubyte as desired target type") {
|
||||||
|
val src = SourceCode.Text("""
|
||||||
|
main {
|
||||||
|
ubyte r
|
||||||
|
ubyte ub = (cos8(r)/2 + 100) as ubyte
|
||||||
|
}""")
|
||||||
|
val module = parseModule(src)
|
||||||
|
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
||||||
|
module.linkIntoProgram(program)
|
||||||
|
val stmts = (module.statements.single() as Block).statements
|
||||||
|
stmts.size shouldBe 2
|
||||||
|
val ubexpr = (stmts[1] as VarDecl).value as TypecastExpression
|
||||||
|
ubexpr.inferType(program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
@ -7,7 +7,7 @@ main {
|
|||||||
sub start() {
|
sub start() {
|
||||||
ubyte bb
|
ubyte bb
|
||||||
uword ww
|
uword ww
|
||||||
ww = not bb or not ww ; TODO WHY DOES THIS USE STACK EVAL
|
uword @shared zz = not bb or not ww ; TODO WHY DOES THIS USE STACK EVAL-because of typecastings?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user