preparing for more optimizations

This commit is contained in:
Irmen de Jong 2021-11-12 02:17:37 +01:00
parent 53ac11983b
commit 75a06d2a40
7 changed files with 98 additions and 5 deletions

View File

@ -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

View File

@ -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(

View File

@ -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
} }

View File

@ -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

View File

@ -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

View File

@ -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
}
}) })

View File

@ -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?
} }