1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-12-23 23:30:22 +00:00

8080: Fix some stack-related optimizations

This commit is contained in:
Karol Stasiak 2020-04-06 12:00:10 +02:00
parent f04f5ec111
commit 5b3e812bb1
2 changed files with 31 additions and 9 deletions

View File

@ -419,7 +419,7 @@ object AlwaysGoodI80Optimizations {
}, },
//20 //20
(Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~ (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~
(Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer)).* ~ (Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer) & Not(Changes(DE))).* ~
(Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.DE)) ~~> { code => (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.DE)) ~~> { code =>
ZLine.ld8(ZRegister.D, ZRegister.H) :: ZLine.ld8(ZRegister.D, ZRegister.H) ::
ZLine.ld8(ZRegister.E, ZRegister.L) :: ZLine.ld8(ZRegister.E, ZRegister.L) ::
@ -427,7 +427,7 @@ object AlwaysGoodI80Optimizations {
}, },
//21 //21
(Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.BC)) ~ (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.HL) & DoesntMatterWhatItDoesWith(ZRegister.BC)) ~
(Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer)).* ~ (Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer) & Not(Changes(BC))).* ~
(Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.BC)) ~~> { code => (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.BC)) ~~> { code =>
ZLine.ld8(ZRegister.B, ZRegister.H) :: ZLine.ld8(ZRegister.B, ZRegister.H) ::
ZLine.ld8(ZRegister.C, ZRegister.L) :: ZLine.ld8(ZRegister.C, ZRegister.L) ::
@ -435,7 +435,7 @@ object AlwaysGoodI80Optimizations {
}, },
//22 //22
(Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~ (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~
(Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer)).* ~ (Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer) & Not(Changes(HL))).* ~
(Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.HL)) ~~> { code => (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.HL)) ~~> { code =>
ZLine.ld8(ZRegister.H, ZRegister.D) :: ZLine.ld8(ZRegister.H, ZRegister.D) ::
ZLine.ld8(ZRegister.L, ZRegister.E) :: ZLine.ld8(ZRegister.L, ZRegister.E) ::
@ -443,7 +443,7 @@ object AlwaysGoodI80Optimizations {
}, },
//23 //23
(Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~ (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.HL)) ~
(Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer)).* ~ (Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer) & Not(Changes(HL))).* ~
(Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.HL)) ~~> { code => (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.HL)) ~~> { code =>
ZLine.ld8(ZRegister.H, ZRegister.B) :: ZLine.ld8(ZRegister.H, ZRegister.B) ::
ZLine.ld8(ZRegister.L, ZRegister.C) :: ZLine.ld8(ZRegister.L, ZRegister.C) ::
@ -451,7 +451,7 @@ object AlwaysGoodI80Optimizations {
}, },
//24 //24
(Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~ (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.BC) & DoesntMatterWhatItDoesWith(ZRegister.DE)) ~
(Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer)).* ~ (Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer) & Not(Changes(DE))).* ~
(Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.DE)) ~~> { code => (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.DE)) ~~> { code =>
ZLine.ld8(ZRegister.D, ZRegister.B) :: ZLine.ld8(ZRegister.D, ZRegister.B) ::
ZLine.ld8(ZRegister.E, ZRegister.C) :: ZLine.ld8(ZRegister.E, ZRegister.C) ::
@ -459,7 +459,7 @@ object AlwaysGoodI80Optimizations {
}, },
//25 //25
(Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.BC)) ~ (Elidable & HasOpcode(PUSH) & HasRegisterParam(ZRegister.DE) & DoesntMatterWhatItDoesWith(ZRegister.BC)) ~
(Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer)).* ~ (Linear & Not(HasOpcodeIn(Set(POP, PUSH))) & Not(ReadsStackPointer) & Not(Changes(BC))).* ~
(Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.BC)) ~~> { code => (Elidable & HasOpcode(POP) & HasRegisterParam(ZRegister.BC)) ~~> { code =>
ZLine.ld8(ZRegister.B, ZRegister.D) :: ZLine.ld8(ZRegister.B, ZRegister.D) ::
ZLine.ld8(ZRegister.C, ZRegister.E) :: ZLine.ld8(ZRegister.C, ZRegister.E) ::

View File

@ -99,8 +99,10 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
} }
// generic warnings: // generic warnings:
stmt match { stmt match {
case ExpressionStatement(expr@FunctionCallExpression("strzlen" | "putstrz" | "strzcmp" | "strzcopy", params)) => case ExpressionStatement(expr@FunctionCallExpression("strzlen" | "putstrz" | "strzcmp" | "strzcopy" | "strzpaste", params)) =>
for (param <- params) checkIfNullTerminated(ctx, stmt, param) for (param <- params) checkIfNullTerminated(ctx, stmt, param)
case ExpressionStatement(expr@FunctionCallExpression("pstrlen" | "putpstr" | "pstrcmp" | "pstrcopy" | "pstrpaste", params)) =>
for (param <- params) checkIfLengthPrefixed(ctx, stmt, param)
case ExpressionStatement(expr@FunctionCallExpression(f, List(VariableExpression(v)))) if hiddenEffectFreeFunctions(f)=> case ExpressionStatement(expr@FunctionCallExpression(f, List(VariableExpression(v)))) if hiddenEffectFreeFunctions(f)=>
val volatile = ctx.env.maybeGet[ThingInMemory](v).fold(false)(_.isVolatile) val volatile = ctx.env.maybeGet[ThingInMemory](v).fold(false)(_.isVolatile)
@ -276,14 +278,34 @@ abstract class AbstractStatementPreprocessor(protected val ctx: CompilationConte
val TERMINATOR = ctx.options.platform.defaultCodec.stringTerminator.head val TERMINATOR = ctx.options.platform.defaultCodec.stringTerminator.head
param match { param match {
case TextLiteralExpression(ch) => case TextLiteralExpression(ch) =>
ch.last match { ch.lastOption match {
case LiteralExpression(TERMINATOR, _) => //ok case Some(LiteralExpression(TERMINATOR, _)) => //ok
case _ => ctx.log.warn("Passing a non-null-terminated string to a function that expects a null-terminated string.", stmt.position) case _ => ctx.log.warn("Passing a non-null-terminated string to a function that expects a null-terminated string.", stmt.position)
} }
case _ => case _ =>
} }
} }
private def checkIfLengthPrefixed(ctx: CompilationContext, stmt: ExecutableStatement, param: Expression): Unit = {
if (!ctx.options.flag(CompilationFlag.BuggyCodeWarning)) return
val TERMINATOR = ctx.options.platform.defaultCodec.stringTerminator.head
param match {
case TextLiteralExpression(ch) =>
if (ch.headOption match {
case Some(LiteralExpression(length, _)) if length == ch.size - 1 => false
case Some(LiteralExpression(length, _)) if length == ch.size + 2 =>
ch.lastOption match {
case Some(LiteralExpression(TERMINATOR, _)) => false
case _ => true
}
case _ => true
}) {
ctx.log.warn("Passing a non-length-prefixed string to a function that expects a length-prefixed string.", stmt.position)
}
case _ =>
}
}
def search(expr: Expression, cv: VV): VV = { def search(expr: Expression, cv: VV): VV = {
expr match { expr match {
case FunctionCallExpression(op, List(VariableExpression(v), arg)) if op.endsWith("=") && op != "<=" && op != ">=" => case FunctionCallExpression(op, List(VariableExpression(v), arg)) if op.endsWith("=") && op != "<=" && op != ">=" =>