mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
fix RPN comparison exprs
This commit is contained in:
parent
374464a1f8
commit
df2d7d4734
@ -6,7 +6,7 @@ import prog8.code.core.*
|
|||||||
* Produces readable text from a [PtNode] (AST node, usually starting with PtProgram as root),
|
* Produces readable text from a [PtNode] (AST node, usually starting with PtProgram as root),
|
||||||
* passing it as a String to the specified receiver function.
|
* passing it as a String to the specified receiver function.
|
||||||
*/
|
*/
|
||||||
fun printAst(root: PtNode, output: (text: String) -> Unit) {
|
fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Unit) {
|
||||||
fun type(dt: DataType) = "!${dt.name.lowercase()}!"
|
fun type(dt: DataType) = "!${dt.name.lowercase()}!"
|
||||||
fun txt(node: PtNode): String {
|
fun txt(node: PtNode): String {
|
||||||
return when(node) {
|
return when(node) {
|
||||||
@ -136,16 +136,22 @@ fun printAst(root: PtNode, output: (text: String) -> Unit) {
|
|||||||
root.children.forEach {
|
root.children.forEach {
|
||||||
walkAst(it) { node, depth ->
|
walkAst(it) { node, depth ->
|
||||||
val txt = txt(node)
|
val txt = txt(node)
|
||||||
if(txt.isNotEmpty())
|
val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true
|
||||||
output(" ".repeat(depth) + txt(node))
|
if(!library || !skipLibraries) {
|
||||||
|
if (txt.isNotEmpty())
|
||||||
|
output(" ".repeat(depth) + txt(node))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println()
|
println()
|
||||||
} else {
|
} else {
|
||||||
walkAst(root) { node, depth ->
|
walkAst(root) { node, depth ->
|
||||||
val txt = txt(node)
|
val txt = txt(node)
|
||||||
if(txt.isNotEmpty())
|
val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true
|
||||||
output(" ".repeat(depth) + txt(node))
|
if(!library || !skipLibraries) {
|
||||||
|
if (txt.isNotEmpty())
|
||||||
|
output(" ".repeat(depth) + txt(node))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ class AsmGen6502: ICodeGeneratorBackend {
|
|||||||
errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY)
|
errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// printAst(program, true) { println(it) }
|
||||||
|
|
||||||
val asmgen = AsmGen6502Internal(program, symbolTable, options, errors)
|
val asmgen = AsmGen6502Internal(program, symbolTable, options, errors)
|
||||||
return asmgen.compileToAssembly()
|
return asmgen.compileToAssembly()
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,28 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
|||||||
RegisterOrPair.R15 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, pos, register = registers)
|
RegisterOrPair.R15 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, pos, register = registers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isSameAs(left: PtExpression): Boolean =
|
||||||
|
when(kind) {
|
||||||
|
TargetStorageKind.VARIABLE -> {
|
||||||
|
val scopedName: String = if('.' in asmVarname)
|
||||||
|
asmVarname
|
||||||
|
else {
|
||||||
|
val scopeName = (scope as? PtNamedNode)?.scopedName
|
||||||
|
if (scopeName == null) asmVarname else "$scopeName.$asmVarname"
|
||||||
|
}
|
||||||
|
left is PtIdentifier && left.name==scopedName
|
||||||
|
}
|
||||||
|
TargetStorageKind.ARRAY -> {
|
||||||
|
left is PtArrayIndexer && left isSameAs array!!
|
||||||
|
}
|
||||||
|
TargetStorageKind.MEMORY -> {
|
||||||
|
left isSameAs memory!!
|
||||||
|
}
|
||||||
|
TargetStorageKind.REGISTER, TargetStorageKind.STACK -> {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AsmAssignSource(val kind: SourceStorageKind,
|
internal class AsmAssignSource(val kind: SourceStorageKind,
|
||||||
|
@ -366,7 +366,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
val value = assign.source.expression as PtRpn
|
val value = assign.source.expression as PtRpn
|
||||||
val (left, oper, right) = value.finalOperation()
|
val (left, oper, right) = value.finalOperation()
|
||||||
|
|
||||||
// TODO RPN the fallthrough if size>3 seems to generate not 100% correct code... (balls example fills the screen weird)
|
// TODO RPN the fallthrough if size>3 seems to generate very inefficient code...
|
||||||
if(value.children.size==3 && oper.operator in ComparisonOperators) {
|
if(value.children.size==3 && oper.operator in ComparisonOperators) {
|
||||||
assignRPNComparison(assign, value)
|
assignRPNComparison(assign, value)
|
||||||
return true
|
return true
|
||||||
@ -564,20 +564,46 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
val rightNum = right as? PtNumber
|
val rightNum = right as? PtNumber
|
||||||
val jumpIfFalseLabel = asmgen.makeLabel("cmp")
|
val jumpIfFalseLabel = asmgen.makeLabel("cmp")
|
||||||
|
|
||||||
when(assign.target.datatype) {
|
if(assign.target.isSameAs(left)) {
|
||||||
in ByteDatatypes -> assignConstantByte(assign.target, 0)
|
// In-place comparison Target = Target <compare> Right
|
||||||
in WordDatatypes -> assignConstantWord(assign.target, 0)
|
// NOTE : this generates pretty inefficient code.... TODO RPN optimize?
|
||||||
DataType.FLOAT -> assignConstantFloat(assign.target, 0.0)
|
val targetDt = assign.target.datatype
|
||||||
else -> throw AssemblyError("invalid dt")
|
val tempVar = asmgen.getTempVarName(assign.target.datatype)
|
||||||
|
val tempTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, targetDt, comparison.definingISub(), comparison.position, variableAsmName = tempVar)
|
||||||
|
when (assign.target.datatype) {
|
||||||
|
in ByteDatatypes -> assignConstantByte(tempTarget, 0)
|
||||||
|
in WordDatatypes -> assignConstantWord(tempTarget, 0)
|
||||||
|
DataType.FLOAT -> assignConstantFloat(tempTarget, 0.0)
|
||||||
|
else -> throw AssemblyError("invalid dt")
|
||||||
|
}
|
||||||
|
asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum)
|
||||||
|
when (assign.target.datatype) {
|
||||||
|
in ByteDatatypes -> assignConstantByte(tempTarget, 1)
|
||||||
|
in WordDatatypes -> assignConstantWord(tempTarget, 1)
|
||||||
|
DataType.FLOAT -> assignConstantFloat(tempTarget, 1.0)
|
||||||
|
else -> throw AssemblyError("invalid dt")
|
||||||
|
}
|
||||||
|
asmgen.out(jumpIfFalseLabel)
|
||||||
|
val tempLeft = PtIdentifier(tempVar, targetDt, comparison.position)
|
||||||
|
tempLeft.parent=comparison
|
||||||
|
asmgen.assignExpressionTo(tempLeft, assign.target)
|
||||||
|
} else {
|
||||||
|
// Normal comparison Target = Left <compare> Right
|
||||||
|
when (assign.target.datatype) {
|
||||||
|
in ByteDatatypes -> assignConstantByte(assign.target, 0)
|
||||||
|
in WordDatatypes -> assignConstantWord(assign.target, 0)
|
||||||
|
DataType.FLOAT -> assignConstantFloat(assign.target, 0.0)
|
||||||
|
else -> throw AssemblyError("invalid dt")
|
||||||
|
}
|
||||||
|
asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum)
|
||||||
|
when (assign.target.datatype) {
|
||||||
|
in ByteDatatypes -> assignConstantByte(assign.target, 1)
|
||||||
|
in WordDatatypes -> assignConstantWord(assign.target, 1)
|
||||||
|
DataType.FLOAT -> assignConstantFloat(assign.target, 1.0)
|
||||||
|
else -> throw AssemblyError("invalid dt")
|
||||||
|
}
|
||||||
|
asmgen.out(jumpIfFalseLabel)
|
||||||
}
|
}
|
||||||
asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum)
|
|
||||||
when(assign.target.datatype) {
|
|
||||||
in ByteDatatypes -> assignConstantByte(assign.target, 1)
|
|
||||||
in WordDatatypes -> assignConstantWord(assign.target, 1)
|
|
||||||
DataType.FLOAT -> assignConstantFloat(assign.target, 1.0)
|
|
||||||
else -> throw AssemblyError("invalid dt")
|
|
||||||
}
|
|
||||||
asmgen.out(jumpIfFalseLabel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
|
||||||
|
@ -120,7 +120,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
|||||||
// println("*********** COMPILER AST RIGHT BEFORE ASM GENERATION *************")
|
// println("*********** COMPILER AST RIGHT BEFORE ASM GENERATION *************")
|
||||||
// printProgram(program)
|
// printProgram(program)
|
||||||
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
||||||
// printAst(intermediateAst, ::println)
|
// printAst(intermediateAst, true, ::println)
|
||||||
|
|
||||||
if(!createAssemblyAndAssemble(intermediateAst, args.errors, compilationOptions)) {
|
if(!createAssemblyAndAssemble(intermediateAst, args.errors, compilationOptions)) {
|
||||||
System.err.println("Error in codegeneration or assembler")
|
System.err.println("Error in codegeneration or assembler")
|
||||||
|
@ -66,7 +66,7 @@ class TestIntermediateAst: FunSpec({
|
|||||||
val fcall = (entry.children[4] as PtAssignment).value as PtFunctionCall
|
val fcall = (entry.children[4] as PtAssignment).value as PtFunctionCall
|
||||||
fcall.void shouldBe false
|
fcall.void shouldBe false
|
||||||
fcall.type shouldBe DataType.UBYTE
|
fcall.type shouldBe DataType.UBYTE
|
||||||
printAst(ast, ::println)
|
printAst(ast, false, ::println)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
@ -1,7 +1,6 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
BRANCH: balls.p8 directions are wrong since the comparison operator fallthrough in attemptAssignOptimizedExprRPN
|
|
||||||
BRANCH: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt
|
BRANCH: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt
|
||||||
BRANCH: check BinExprSplitter disablement any effect for RPN?
|
BRANCH: check BinExprSplitter disablement any effect for RPN?
|
||||||
BRANCH: Implement RPN codegen for IR.
|
BRANCH: Implement RPN codegen for IR.
|
||||||
|
@ -43,7 +43,7 @@ main {
|
|||||||
DX[lp] = true
|
DX[lp] = true
|
||||||
else
|
else
|
||||||
BX[lp]=BX[lp]-1
|
BX[lp]=BX[lp]-1
|
||||||
} else if DX[lp] {
|
} else {
|
||||||
if (BX[lp] == txt.DEFAULT_WIDTH-1) {
|
if (BX[lp] == txt.DEFAULT_WIDTH-1) {
|
||||||
BX[lp] = txt.DEFAULT_WIDTH-2
|
BX[lp] = txt.DEFAULT_WIDTH-2
|
||||||
DX[lp] = false
|
DX[lp] = false
|
||||||
@ -56,7 +56,7 @@ main {
|
|||||||
DY[lp] = true
|
DY[lp] = true
|
||||||
else
|
else
|
||||||
BY[lp]=BY[lp]-1
|
BY[lp]=BY[lp]-1
|
||||||
} else if DY[lp] == 1 {
|
} else {
|
||||||
if (BY[lp] == txt.DEFAULT_HEIGHT-1) {
|
if (BY[lp] == txt.DEFAULT_HEIGHT-1) {
|
||||||
BY[lp] = txt.DEFAULT_HEIGHT-2
|
BY[lp] = txt.DEFAULT_HEIGHT-2
|
||||||
DY[lp] = false
|
DY[lp] = false
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
%import math
|
%import math
|
||||||
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
; Note: this program is compatible with C64 and CX16.
|
; Note: this program is compatible with C64 and CX16.
|
||||||
@ -6,15 +7,15 @@
|
|||||||
main {
|
main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
; ubyte[255] BC
|
bool x
|
||||||
; bool[255] DX
|
ubyte y
|
||||||
|
repeat 20 {
|
||||||
if math.rnd() & 22 {
|
x = math.rnd() & 1
|
||||||
cx16.r0L++
|
y = ((math.rnd()&1)!=0)
|
||||||
|
txt.print_ub(x)
|
||||||
|
txt.spc()
|
||||||
|
txt.print_ub(y)
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
; BC[2] = math.rnd() & 15
|
|
||||||
; BC[3] = math.rnd() & 15
|
|
||||||
; BC[4] = math.rnd() & 15
|
|
||||||
;DX[2] = math.rnd() & 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user