mirror of
https://github.com/KarolS/millfork.git
synced 2024-12-23 23:30:22 +00:00
hi()/lo() builtins; identity table for using index registers as operands
This commit is contained in:
parent
f31086e686
commit
3dc526bcb7
@ -54,6 +54,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
TRB, TSB)
|
||||
|
||||
private val opcodesCommutative = Set(AND, ORA, EOR, ADC)
|
||||
private val opcodesIdentityTable = Set(AND, ORA, EOR, CMP, ADC, SBC)
|
||||
|
||||
private val LdxAddrModes = Set(ZeroPage, Absolute, Immediate, AbsoluteY, ZeroPageY)
|
||||
private val LdyAddrModes = Set(ZeroPage, Absolute, Immediate, AbsoluteX, ZeroPageX)
|
||||
@ -94,13 +95,15 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
)
|
||||
|
||||
val importances = ReverseFlowAnalyzer.analyze(f, code)
|
||||
val blastProcessing = options.flag(CompilationFlag.OptimizeForSonicSpeed)
|
||||
val identityArray = f.environment.maybeGet[ThingInMemory]("identity$").map(MemoryAddressConstant).getOrElse(Constant.Zero)
|
||||
|
||||
val xCandidates = variablesWithLifetimes.filter {
|
||||
case (vName, range) =>
|
||||
importances(range.start).x != Important
|
||||
}.flatMap {
|
||||
case (vName, range) =>
|
||||
canBeInlined(Some(vName), None, code.zip(importances).slice(range.start, range.end)).map { score =>
|
||||
canBeInlined(Some(vName), None, blastProcessing, code.zip(importances).slice(range.start, range.end)).map { score =>
|
||||
(vName, range, if (variablesWithRegisterHint(vName)) score + 16 else score)
|
||||
}
|
||||
}
|
||||
@ -110,7 +113,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
importances(range.start).y != Important
|
||||
}.flatMap {
|
||||
case (vName, range) =>
|
||||
canBeInlined(None, Some(vName), code.zip(importances).slice(range.start, range.end)).map { score =>
|
||||
canBeInlined(None, Some(vName), blastProcessing, code.zip(importances).slice(range.start, range.end)).map { score =>
|
||||
(vName, range, if (variablesWithRegisterHint(vName)) score + 16 else score)
|
||||
}
|
||||
}
|
||||
@ -171,7 +174,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
case (v, range, _) =>
|
||||
ErrorReporting.debug(s"Inlining $v to register X")
|
||||
val oldCode = code.zip(importances).slice(range.start, range.end)
|
||||
val newCode = inlineVars(Some(v), None, None, oldCode)
|
||||
val newCode = inlineVars(Some(v), None, None, identityArray, oldCode)
|
||||
reportOptimizedBlock(oldCode, newCode)
|
||||
output ++= newCode
|
||||
i = range.end
|
||||
@ -182,7 +185,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
case (v, range, _) =>
|
||||
ErrorReporting.debug(s"Inlining $v to register Y")
|
||||
val oldCode = code.zip(importances).slice(range.start, range.end)
|
||||
val newCode = inlineVars(None, Some(v), None, oldCode)
|
||||
val newCode = inlineVars(None, Some(v), None, identityArray, oldCode)
|
||||
reportOptimizedBlock(oldCode, newCode)
|
||||
output ++= newCode
|
||||
i = range.end
|
||||
@ -194,7 +197,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
case (v, range, _) =>
|
||||
ErrorReporting.debug(s"Inlining $v to register A")
|
||||
val oldCode = code.zip(importances).slice(range.start, range.end)
|
||||
val newCode = inlineVars(None, None, Some(v), oldCode)
|
||||
val newCode = inlineVars(None, None, Some(v), identityArray, oldCode)
|
||||
reportOptimizedBlock(oldCode, newCode)
|
||||
output ++= newCode
|
||||
i = range.end
|
||||
@ -213,7 +216,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
}
|
||||
|
||||
|
||||
def canBeInlined(xCandidate: Option[String], yCandidate: Option[String], lines: List[(AssemblyLine, CpuImportance)]): Option[Int] = {
|
||||
def canBeInlined(xCandidate: Option[String], yCandidate: Option[String], blastProcessing: Boolean, lines: List[(AssemblyLine, CpuImportance)]): Option[Int] = {
|
||||
val vx = xCandidate.getOrElse("-")
|
||||
val vy = yCandidate.getOrElse("-")
|
||||
lines match {
|
||||
@ -231,7 +234,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
if (th.name == vx || th.name == vy) {
|
||||
None
|
||||
} else {
|
||||
canBeInlined(xCandidate, yCandidate, xs)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(opcode, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
@ -250,9 +253,9 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
// removing LDX saves 3 cycles
|
||||
if (elidable && th.name == vx) {
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
canBeInlined(xCandidate, yCandidate, xs).map(_ + 3)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs).map(_ + 3)
|
||||
} else {
|
||||
canBeInlined(xCandidate, yCandidate, xs).map(_ + 1)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs).map(_ + 1)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
@ -263,7 +266,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
// LAX = LDX-LDA, and since LDX simplifies to nothing and LDA simplifies to TXA,
|
||||
// LAX simplifies to TXA, saving two bytes
|
||||
if (elidable && th.name == vx) {
|
||||
canBeInlined(xCandidate, yCandidate, xs).map(_ + 2)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs).map(_ + 2)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -274,9 +277,9 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
// sometimes that LDX has to be converted into CPX#0
|
||||
if (elidable && th.name == vy) {
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
canBeInlined(xCandidate, yCandidate, xs).map(_ + 3)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs).map(_ + 3)
|
||||
} else {
|
||||
canBeInlined(xCandidate, yCandidate, xs).map(_ + 1)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs).map(_ + 1)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
@ -290,26 +293,33 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
// if a register is populated with something else than a variable, then no variable cannot be assigned to that register
|
||||
None
|
||||
|
||||
case (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable),_) :: xs
|
||||
if opcodesIdentityTable(op) =>
|
||||
if (th.name == vx || th.name == vy) {
|
||||
if (elidable) canBeInlined(xCandidate, yCandidate, blastProcessing, xs)
|
||||
else None
|
||||
} else canBeInlined(xCandidate, yCandidate, blastProcessing, xs)
|
||||
|
||||
case (AssemblyLine(LDA, _, _, elidable),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable2),_) :: xs
|
||||
if opcodesCommutative(op) =>
|
||||
if (th.name == vx || th.name == vy) {
|
||||
if (elidable && elidable2) canBeInlined(xCandidate, yCandidate, xs).map(_ + 2)
|
||||
if (elidable && elidable2) canBeInlined(xCandidate, yCandidate, blastProcessing, xs).map(_ + 2)
|
||||
else None
|
||||
} else canBeInlined(xCandidate, yCandidate, xs)
|
||||
} else canBeInlined(xCandidate, yCandidate, blastProcessing, xs)
|
||||
|
||||
case (AssemblyLine(LDA, _, _, elidable),_) :: (AssemblyLine(CLC, _, _, _),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable2),_) :: xs
|
||||
if opcodesCommutative(op) =>
|
||||
if (th.name == vx || th.name == vy) {
|
||||
if (elidable && elidable2) canBeInlined(xCandidate, yCandidate, xs).map(_ + 2)
|
||||
if (elidable && elidable2) canBeInlined(xCandidate, yCandidate, blastProcessing, xs).map(_ + 2)
|
||||
else None
|
||||
} else canBeInlined(xCandidate, yCandidate, xs)
|
||||
} else canBeInlined(xCandidate, yCandidate, blastProcessing, xs)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), _) :: (AssemblyLine(TAX, _, _, elidable2), _) :: xs
|
||||
if xCandidate.isDefined =>
|
||||
// a variable cannot be inlined if there is TAX not after LDA of that variable
|
||||
// but LDA-TAX can be simplified to TXA
|
||||
if (elidable && elidable2 && th.name == vx) {
|
||||
canBeInlined(xCandidate, yCandidate, xs).map(_ + 3)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs).map(_ + 3)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -319,7 +329,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
// a variable cannot be inlined if there is TAY not after LDA of that variable
|
||||
// but LDA-TAY can be simplified to TYA
|
||||
if (elidable && elidable2 && th.name == vy) {
|
||||
canBeInlined(xCandidate, yCandidate, xs).map(_ + 3)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs).map(_ + 3)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -328,12 +338,12 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
// changing LDA->TXA, STA->TAX, INC->INX, DEC->DEX, STZ->LDA saves 2 bytes
|
||||
if (th.name == vy || th.name == vx) {
|
||||
if (elidable) {
|
||||
canBeInlined(xCandidate, yCandidate, xs).map(_ + 2)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs).map(_ + 2)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
canBeInlined(xCandidate, yCandidate, xs)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(TAX, _, _, _), _) :: xs if xCandidate.isDefined =>
|
||||
@ -346,7 +356,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
|
||||
case (AssemblyLine(LABEL, _, _, _), _) :: xs =>
|
||||
// labels always end the initial section
|
||||
canBeInlined(xCandidate, yCandidate, xs)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs)
|
||||
|
||||
case (x, _) :: xs =>
|
||||
if (xCandidate.isDefined && opcodesThatAlwaysPrecludeXAllocation(x.opcode)) {
|
||||
@ -354,7 +364,7 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
} else if (yCandidate.isDefined && opcodesThatAlwaysPrecludeYAllocation(x.opcode)) {
|
||||
None
|
||||
} else {
|
||||
canBeInlined(xCandidate, yCandidate, xs)
|
||||
canBeInlined(xCandidate, yCandidate, blastProcessing, xs)
|
||||
}
|
||||
|
||||
case Nil => Some(0)
|
||||
@ -498,170 +508,178 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
}
|
||||
}
|
||||
|
||||
def inlineVars(xCandidate: Option[String], yCandidate: Option[String], aCandidate: Option[String], lines: List[(AssemblyLine, CpuImportance)]): List[AssemblyLine] = {
|
||||
def inlineVars(xCandidate: Option[String], yCandidate: Option[String], aCandidate: Option[String], identityArray: Constant, lines: List[(AssemblyLine, CpuImportance)]): List[AssemblyLine] = {
|
||||
val vx = xCandidate.getOrElse("-")
|
||||
val vy = yCandidate.getOrElse("-")
|
||||
val va = aCandidate.getOrElse("-")
|
||||
lines match {
|
||||
case (AssemblyLine(INC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vx =>
|
||||
AssemblyLine.implied(INX) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(INX) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(INC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vy =>
|
||||
AssemblyLine.implied(INY) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(INY) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(DEC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vx =>
|
||||
AssemblyLine.implied(DEX) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(DEX) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(DEC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vy =>
|
||||
AssemblyLine.implied(DEY) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(DEY) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(opcode@(DEC | INC | ROL | ROR | ASL | LSR), Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == va =>
|
||||
AssemblyLine.implied(opcode) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(opcode) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), _), imp) :: xs
|
||||
if th.name == vx =>
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
} else {
|
||||
AssemblyLine.immediate(CPX, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.immediate(CPX, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(LAX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vx =>
|
||||
AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (l@AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if opcodesIdentityTable(op) && th.name == vx =>
|
||||
l.copy(addrMode = AbsoluteX, parameter = identityArray) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (l@AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if opcodesIdentityTable(op) && th.name == vy =>
|
||||
l.copy(addrMode = AbsoluteY, parameter = identityArray) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == va =>
|
||||
l.copy(opcode = op) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
l.copy(opcode = op) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (clc@AssemblyLine(CLC, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == va =>
|
||||
l.copy(opcode = op) :: clc :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
l.copy(opcode = op) :: clc :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == vx =>
|
||||
AssemblyLine.implied(TXA) :: l.copy(opcode = op) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TXA) :: l.copy(opcode = op) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (clc@AssemblyLine(CLC, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == vx =>
|
||||
AssemblyLine.implied(TXA) :: l.copy(opcode = op) :: clc :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TXA) :: l.copy(opcode = op) :: clc :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == vy =>
|
||||
AssemblyLine.implied(TYA) :: l.copy(opcode = op) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TYA) :: l.copy(opcode = op) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (clc@AssemblyLine(CLC, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == vy =>
|
||||
AssemblyLine.implied(TYA) :: l.copy(opcode = op) :: clc :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TYA) :: l.copy(opcode = op) :: clc :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDA | STA, Absolute | ZeroPage, MemoryAddressConstant(th), _), imp) :: xs
|
||||
if th.name == va =>
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
} else {
|
||||
AssemblyLine.immediate(CMP, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.immediate(CMP, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(LAX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == va =>
|
||||
AssemblyLine.implied(TAX) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TAX) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), _), imp) :: xs
|
||||
if th.name == vy =>
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
} else {
|
||||
AssemblyLine.immediate(CPY, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.immediate(CPY, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: (AssemblyLine(TAX, _, _, true), _) :: xs
|
||||
if th.name == vx =>
|
||||
// these TXA's may get optimized away by a different optimization
|
||||
AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: (AssemblyLine(TAY, _, _, true), _) :: xs
|
||||
if th.name == vy =>
|
||||
// these TYA's may get optimized away by a different optimization
|
||||
AssemblyLine.implied(TYA) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TYA) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: (AssemblyLine(TXA, _, _, true), _) :: xs
|
||||
if th.name == va =>
|
||||
// these TAX's may get optimized away by a different optimization
|
||||
AssemblyLine.implied(TAX) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TAX) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: (AssemblyLine(TYA, _, _, true), _) :: xs
|
||||
if th.name == va =>
|
||||
// these TAY's may get optimized away by a different optimization
|
||||
AssemblyLine.implied(TAY) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TAY) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDA, am, param, true), _) :: (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: xs
|
||||
if th.name == vx && LdxAddrModes(am) =>
|
||||
// these TXA's may get optimized away by a different optimization
|
||||
AssemblyLine(LDX, am, param) :: AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine(LDX, am, param) :: AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDA, am, param, true), _) :: (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: xs
|
||||
if th.name == vy && LdyAddrModes(am) =>
|
||||
// these TYA's may get optimized away by a different optimization
|
||||
AssemblyLine(LDY, am, param) :: AssemblyLine.implied(TYA) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine(LDY, am, param) :: AssemblyLine.implied(TYA) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: (AssemblyLine(CMP, am, param, true), _) :: xs
|
||||
if th.name == vx && doesntUseXOrY(am) =>
|
||||
// ditto
|
||||
AssemblyLine.implied(TXA) :: AssemblyLine(CPX, am, param) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TXA) :: AssemblyLine(CPX, am, param) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: (AssemblyLine(CMP, am, param, true), _) :: xs
|
||||
if th.name == vy && doesntUseXOrY(am) =>
|
||||
// ditto
|
||||
AssemblyLine.implied(TYA) :: AssemblyLine(CPY, am, param) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TYA) :: AssemblyLine(CPY, am, param) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vx =>
|
||||
AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vy =>
|
||||
AssemblyLine.implied(TYA) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TYA) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == va =>
|
||||
AssemblyLine.implied(TAX) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TAX) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == va =>
|
||||
AssemblyLine.implied(TAY) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TAY) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vx =>
|
||||
AssemblyLine.implied(TAX) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TAX) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vy =>
|
||||
AssemblyLine.implied(TAY) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TAY) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(STX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == va =>
|
||||
AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TXA) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(STY, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == va =>
|
||||
AssemblyLine.implied(TYA) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.implied(TYA) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vx =>
|
||||
AssemblyLine.immediate(LDX, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.immediate(LDX, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == vy =>
|
||||
AssemblyLine.immediate(LDY, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.immediate(LDY, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
if th.name == va =>
|
||||
AssemblyLine.immediate(LDA, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.immediate(LDA, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(TAX, _, _, _), _) :: xs if xCandidate.isDefined =>
|
||||
ErrorReporting.fatal("Unexpected TAX")
|
||||
@ -670,12 +688,12 @@ object VariableToRegisterOptimization extends AssemblyOptimization {
|
||||
ErrorReporting.fatal("Unexpected TAY")
|
||||
|
||||
case (AssemblyLine(TXA, _, _, _), _) :: xs if aCandidate.isDefined =>
|
||||
AssemblyLine.immediate(CPX, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.immediate(CPX, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (AssemblyLine(TYA, _, _, _), _) :: xs if aCandidate.isDefined =>
|
||||
AssemblyLine.immediate(CPY, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
AssemblyLine.immediate(CPY, 0) :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case (x, _) :: xs => x :: inlineVars(xCandidate, yCandidate, aCandidate, xs)
|
||||
case (x, _) :: xs => x :: inlineVars(xCandidate, yCandidate, aCandidate, identityArray, xs)
|
||||
|
||||
case Nil => Nil
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ object ExpressionCompiler {
|
||||
w
|
||||
case SumExpression(params, _) => b
|
||||
case FunctionCallExpression("not", params) => bool
|
||||
case FunctionCallExpression("hi", params) => bool
|
||||
case FunctionCallExpression("lo", params) => bool
|
||||
case FunctionCallExpression("*", params) => b
|
||||
case FunctionCallExpression("|", params) => b
|
||||
case FunctionCallExpression("&", params) => b
|
||||
@ -376,13 +378,8 @@ object ExpressionCompiler {
|
||||
case RegisterVariable(Register.AX, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label),
|
||||
AssemblyLine.implied(PHA)) ++ signExtendA() ++ List(
|
||||
AssemblyLine.implied(TAX),
|
||||
AssemblyLine.implied(PLA))
|
||||
} else AssemblyLine.variable(ctx, LDA, source) :+ AssemblyLine.immediate(LDX, 0)
|
||||
@ -392,13 +389,8 @@ object ExpressionCompiler {
|
||||
case RegisterVariable(Register.AY, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
AssemblyLine.variable(ctx, LDA, source) ++ List(
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label),
|
||||
AssemblyLine.implied(PHA)) ++ signExtendA() ++ List(
|
||||
AssemblyLine.implied(TAY),
|
||||
AssemblyLine.implied(PLA))
|
||||
} else {
|
||||
@ -410,13 +402,7 @@ object ExpressionCompiler {
|
||||
case RegisterVariable(Register.XA, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
AssemblyLine.variable(ctx, LDX, source) ++ List(
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label))
|
||||
AssemblyLine.variable(ctx, LDX, source) ++ List(AssemblyLine.implied(TXA)) ++ signExtendA()
|
||||
} else
|
||||
AssemblyLine.variable(ctx, LDX, source) :+ AssemblyLine.immediate(LDA, 0)
|
||||
case 2 =>
|
||||
@ -425,13 +411,7 @@ object ExpressionCompiler {
|
||||
case RegisterVariable(Register.YA, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
AssemblyLine.variable(ctx, LDY, source) ++ List(
|
||||
AssemblyLine.implied(TYA),
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label))
|
||||
AssemblyLine.variable(ctx, LDY, source) ++ List(AssemblyLine.implied(TYA)) ++ signExtendA()
|
||||
} else
|
||||
AssemblyLine.variable(ctx, LDY, source) :+ AssemblyLine.immediate(LDA, 0)
|
||||
case 2 =>
|
||||
@ -444,13 +424,7 @@ object ExpressionCompiler {
|
||||
} else {
|
||||
val copy = List.tabulate(exprType.size)(i => AssemblyLine.variable(ctx, LDA, source, i) ++ AssemblyLine.variable(ctx, STA, target, i))
|
||||
val extend = if (exprType.size == target.typ.size) Nil else if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
List(
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label)) ++
|
||||
List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.variable(ctx, STA, target, i + exprType.size)).flatten
|
||||
signExtendA() ++ List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.variable(ctx, STA, target, i + exprType.size)).flatten
|
||||
} else {
|
||||
AssemblyLine.immediate(LDA, 0) ::
|
||||
List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.variable(ctx, STA, target, i + exprType.size)).flatten
|
||||
@ -464,13 +438,7 @@ object ExpressionCompiler {
|
||||
} else {
|
||||
val copy = List.tabulate(exprType.size)(i => AssemblyLine.variable(ctx, LDA, source, i) :+ AssemblyLine.absoluteX(STA, target.baseOffset + ctx.extraStackOffset + i))
|
||||
val extend = if (exprType.size == target.typ.size) Nil else if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
List(
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label)) ++
|
||||
List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.absoluteX(STA, target.baseOffset + ctx.extraStackOffset + i + exprType.size))
|
||||
signExtendA() ++ List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.absoluteX(STA, target.baseOffset + ctx.extraStackOffset + i + exprType.size))
|
||||
} else {
|
||||
AssemblyLine.immediate(LDA, 0) ::
|
||||
List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.absoluteX(STA, target.baseOffset + ctx.extraStackOffset + i + exprType.size))
|
||||
@ -486,15 +454,10 @@ object ExpressionCompiler {
|
||||
case RegisterVariable(Register.AX, _) =>
|
||||
exprType.size match {
|
||||
case 1 => if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
List(
|
||||
AssemblyLine.implied(TSX),
|
||||
AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset),
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label),
|
||||
AssemblyLine.implied(PHA)) ++ signExtendA() ++ List(
|
||||
AssemblyLine.implied(TAX),
|
||||
AssemblyLine.implied(PLA))
|
||||
} else List(
|
||||
@ -550,13 +513,7 @@ object ExpressionCompiler {
|
||||
} else {
|
||||
val copy = List.tabulate(exprType.size)(i => AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset + i) :: AssemblyLine.variable(ctx, STA, target, i))
|
||||
val extend = if (exprType.size == target.typ.size) Nil else if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
List(
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label)) ++
|
||||
List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.variable(ctx, STA, target, i + exprType.size)).flatten
|
||||
signExtendA() ++ List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.variable(ctx, STA, target, i + exprType.size)).flatten
|
||||
} else {
|
||||
AssemblyLine.immediate(LDA, 0) ::
|
||||
List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.variable(ctx, STA, target, i + exprType.size)).flatten
|
||||
@ -570,13 +527,7 @@ object ExpressionCompiler {
|
||||
} else {
|
||||
val copy = List.tabulate(exprType.size)(i => List(AssemblyLine.absoluteX(LDA, offset + ctx.extraStackOffset + i), AssemblyLine.absoluteX(STA, target.baseOffset + i)))
|
||||
val extend = if (exprType.size == target.typ.size) Nil else if (exprType.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
List(
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label)) ++
|
||||
List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.absoluteX(STA, target.baseOffset + ctx.extraStackOffset + i + exprType.size))
|
||||
signExtendA() ++ List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.absoluteX(STA, target.baseOffset + ctx.extraStackOffset + i + exprType.size))
|
||||
} else {
|
||||
AssemblyLine.immediate(LDA, 0) ::
|
||||
List.tabulate(target.typ.size - exprType.size)(i => AssemblyLine.absoluteX(STA, target.baseOffset + ctx.extraStackOffset + i + exprType.size))
|
||||
@ -606,13 +557,7 @@ object ExpressionCompiler {
|
||||
AssemblyLine.variable(ctx, STA, target)
|
||||
}
|
||||
else if (target.typ.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
AssemblyLine.variable(ctx, STA, target) ++
|
||||
List(
|
||||
AssemblyLine.immediate(ORA, 0x7f),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label)) ++
|
||||
AssemblyLine.variable(ctx, STA, target) ++ signExtendA() ++
|
||||
List.tabulate(target.typ.size - 1)(i => AssemblyLine.variable(ctx, STA, target, i + 1)).flatten
|
||||
} else {
|
||||
AssemblyLine.variable(ctx, STA, target) ++
|
||||
@ -734,6 +679,26 @@ object ExpressionCompiler {
|
||||
case "not" =>
|
||||
assertBool(ctx, params, 1)
|
||||
compile(ctx, params.head, exprTypeAndVariable, branches.flip)
|
||||
case "hi" | "lo" =>
|
||||
val hi = name == "hi"
|
||||
if (params.length != 1) {
|
||||
ErrorReporting.error("Too many parameters for hi/lo", f.position)
|
||||
Nil
|
||||
} else {
|
||||
val param = params.head
|
||||
val typ = getExpressionType(ctx, param)
|
||||
if (typ.size < 1 || typ.size > 2) {
|
||||
ErrorReporting.error("Invalid parameter type for hi/lo", param.position)
|
||||
compile(ctx, param, None, BranchSpec.None)
|
||||
} else {
|
||||
val compilation = compile(ctx, param, Some(w -> RegisterVariable(Register.AX, w)), BranchSpec.None)
|
||||
if (hi) {
|
||||
if (typ.size == 2) compilation :+ AssemblyLine.implied(TXA)
|
||||
else if (typ.isSigned) compilation ++ signExtendA()
|
||||
else List(AssemblyLine.immediate(LDA, 0))
|
||||
} else compilation
|
||||
}
|
||||
}
|
||||
case "&&" =>
|
||||
assertBool(ctx, params, 2)
|
||||
val a = params.head
|
||||
@ -1151,12 +1116,7 @@ object ExpressionCompiler {
|
||||
AssemblyLine.variable(ctx, STA, v)
|
||||
case s if s > 1 =>
|
||||
if (t.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
AssemblyLine.variable(ctx, STA, v)++List(
|
||||
AssemblyLine.immediate(ORA, 0x7f),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label)) ++ List.tabulate(s - 1)(i => AssemblyLine.variable(ctx, STA, v, i + 1)).flatten
|
||||
AssemblyLine.variable(ctx, STA, v) ++ signExtendA() ++ List.tabulate(s - 1)(i => AssemblyLine.variable(ctx, STA, v, i + 1)).flatten
|
||||
} else {
|
||||
AssemblyLine.variable(ctx, STA, v) ++ List(AssemblyLine.immediate(LDA, 0)) ++
|
||||
List.tabulate(s - 1)(i => AssemblyLine.variable(ctx, STA, v, i + 1)).flatten
|
||||
@ -1170,13 +1130,11 @@ object ExpressionCompiler {
|
||||
AssemblyLine.variable(ctx, STA, v) ++ AssemblyLine.variable(ctx, STX, v, 1)
|
||||
case s if s > 2 =>
|
||||
if (t.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
AssemblyLine.variable(ctx, STA, v) ++ AssemblyLine.variable(ctx, STX, v, 1) ++ List(
|
||||
AssemblyLine.implied(TXA),
|
||||
AssemblyLine.immediate(ORA, 0x7f),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label)) ++ List.tabulate(s - 2)(i => AssemblyLine.variable(ctx, STA, v, i + 2)).flatten
|
||||
AssemblyLine.variable(ctx, STA, v) ++
|
||||
AssemblyLine.variable(ctx, STX, v, 1) ++
|
||||
List(AssemblyLine.implied(TXA)) ++
|
||||
signExtendA() ++
|
||||
List.tabulate(s - 2)(i => AssemblyLine.variable(ctx, STA, v, i + 2)).flatten
|
||||
} else {
|
||||
AssemblyLine.variable(ctx, STA, v) ++ AssemblyLine.variable(ctx, STX, v, 1) ++ List(
|
||||
AssemblyLine.immediate(LDA, 0)) ++
|
||||
@ -1190,14 +1148,11 @@ object ExpressionCompiler {
|
||||
List(AssemblyLine.implied(TSX), AssemblyLine.absoluteX(STA, v.baseOffset + ctx.extraStackOffset))
|
||||
case s if s > 1 =>
|
||||
if (t.isSigned) {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
List(
|
||||
AssemblyLine.implied(TSX),
|
||||
AssemblyLine.absoluteX(STA, v.baseOffset + ctx.extraStackOffset),
|
||||
AssemblyLine.immediate(ORA, 0x7f),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label)) ++ List.tabulate(s - 1)(i => AssemblyLine.absoluteX(STA, v.baseOffset + ctx.extraStackOffset + i + 1))
|
||||
AssemblyLine.absoluteX(STA, v.baseOffset + ctx.extraStackOffset)) ++
|
||||
signExtendA() ++
|
||||
List.tabulate(s - 1)(i => AssemblyLine.absoluteX(STA, v.baseOffset + ctx.extraStackOffset + i + 1))
|
||||
} else {
|
||||
List(
|
||||
AssemblyLine.implied(TSX),
|
||||
@ -1297,4 +1252,13 @@ object ExpressionCompiler {
|
||||
Nil
|
||||
}
|
||||
}
|
||||
|
||||
private def signExtendA(): List[AssemblyLine] = {
|
||||
val label = MfCompiler.nextLabel("sx")
|
||||
List(
|
||||
AssemblyLine.immediate(ORA, 0x7F),
|
||||
AssemblyLine.relative(BMI, label),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.label(label))
|
||||
}
|
||||
}
|
||||
|
@ -723,6 +723,9 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
}
|
||||
|
||||
def collectDeclarations(program: Program, options: CompilationOptions): Unit = {
|
||||
if (options.flag(CompilationFlag.OptimizeForSonicSpeed)) {
|
||||
addThing(InitializedArray("identity$", None, List.tabulate(256)(n => NumericConstant(n, 1))), None)
|
||||
}
|
||||
program.declarations.foreach {
|
||||
case f: FunctionDeclarationStatement => registerFunction(f, options)
|
||||
case v: VariableDeclarationStatement => registerVariable(v, options)
|
||||
@ -774,9 +777,13 @@ class Environment(val parent: Option[Environment], val prefix: String) {
|
||||
case SumExpression(params, _) =>
|
||||
nameCheck(params.map(_._2))
|
||||
case FunctionCallExpression(name, params) =>
|
||||
if (name.exists(_.isLetter) && name != "not") {
|
||||
if (name.exists(_.isLetter) && !Environment.predefinedFunctions(name)) {
|
||||
checkName[CallableThing]("Function or type", name, node.position)
|
||||
}
|
||||
nameCheck(params)
|
||||
}
|
||||
}
|
||||
|
||||
object Environment {
|
||||
val predefinedFunctions = Set("not", "hi", "lo")
|
||||
}
|
||||
|
@ -100,4 +100,36 @@ class WordMathSuite extends FunSuite with Matchers {
|
||||
| }
|
||||
""".stripMargin)(m => ())
|
||||
}
|
||||
|
||||
test("hi()/lo()") {
|
||||
EmuBenchmarkRun("""
|
||||
| array output [7] @$c000
|
||||
| void main () {
|
||||
| output[0] = lo(33)
|
||||
| output[1] = hi(33)
|
||||
| output[2] = hi(w($504))
|
||||
| output[3] = lo(w($209))
|
||||
| output[4] = hi(s(-2))
|
||||
| output[5] = lo(s(-2))
|
||||
| output[6] = hi(b(200) + b(200))
|
||||
| }
|
||||
| word w(word w) {
|
||||
| return w
|
||||
| }
|
||||
| byte b(byte b) {
|
||||
| return b
|
||||
| }
|
||||
| sbyte s(sbyte s) {
|
||||
| return s
|
||||
| }
|
||||
""".stripMargin){ m =>
|
||||
m.readByte(0xc000) should equal(33)
|
||||
m.readByte(0xc001) should equal(0)
|
||||
m.readByte(0xc002) should equal(5)
|
||||
m.readByte(0xc003) should equal(9)
|
||||
m.readByte(0xc004) should equal(255)
|
||||
m.readByte(0xc005) should equal(254)
|
||||
m.readByte(0xc006) should equal(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,10 @@ object EmuOptimizedInlinedRun extends EmuRun(
|
||||
OptimizationPresets.Good ++ LaterOptimizations.Nmos ++
|
||||
OptimizationPresets.Good ++ LaterOptimizations.Nmos ++
|
||||
OptimizationPresets.Good,
|
||||
false)
|
||||
false) {
|
||||
override def inline: Boolean = true
|
||||
override def blastProcessing: Boolean = true
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -30,6 +30,8 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
|
||||
|
||||
def inline = false
|
||||
|
||||
def blastProcessing = false
|
||||
|
||||
private val timingNmos = Array[Int](
|
||||
7, 6, 0, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
|
||||
2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
|
||||
@ -96,6 +98,7 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
|
||||
CompilationFlag.InlineFunctions -> this.inline,
|
||||
CompilationFlag.CompactReturnDispatchParams -> true,
|
||||
CompilationFlag.EmitCmosOpcodes -> (platform.cpu == millfork.Cpu.Cmos),
|
||||
CompilationFlag.OptimizeForSonicSpeed -> blastProcessing
|
||||
// CompilationFlag.CheckIndexOutOfBounds -> true,
|
||||
))
|
||||
ErrorReporting.hasErrors = false
|
||||
|
Loading…
Reference in New Issue
Block a user