moved initialvalues to asmgen, fixed sgn bug and internal float 0.0 variable disappearing bug

This commit is contained in:
Irmen de Jong 2020-03-22 16:06:34 +01:00
parent 3a99115070
commit f0d4c3aba9
13 changed files with 135 additions and 102 deletions

View File

@ -10,8 +10,8 @@
c64flt {
; ---- this block contains C-64 floating point related functions ----
const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586
const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586
; ---- C64 basic and kernal ROM float constants and functions ----
@ -34,7 +34,8 @@ c64flt {
&float FL_PIHALF = $e2e0 ; PI / 2
&float FL_TWOPI = $e2e5 ; 2 * PI
&float FL_FR4 = $e2ea ; .25
float FL_ZERO = 0.0 ; oddly enough 0.0 isn't available in the kernel
; oddly enough, 0.0 isn't available in the kernel.
float FL_ZERO = 0.0 ; oddly enough 0.0 isn't available in the kernel
; note: fac1/2 might get clobbered even if not mentioned in the function's name.
@ -209,8 +210,8 @@ sub print_fln (float value) {
; ---- prints the floating point value (with a newline at the end) using basic rom routines
%asm {{
stx c64.SCRATCH_ZPREGX
lda #<print_fln_value
ldy #>print_fln_value
lda #<value
ldy #>value
jsr MOVFM ; load float into fac1
jsr FPRINTLN ; print fac1 with newline
ldx c64.SCRATCH_ZPREGX

View File

@ -308,7 +308,7 @@ class GlobalNamespace(val modules: List<Module>): Node, INameScope {
return when (val stmt = localContext.definingModule().lookup(scopedName, localContext)) {
is Label, is VarDecl, is Block, is Subroutine -> stmt
null -> null
else -> throw SyntaxError("wrong identifier target: $stmt", stmt.position)
else -> throw SyntaxError("wrong identifier target for $scopedName: $stmt", stmt.position)
}
}
}

View File

@ -3,7 +3,11 @@ package prog8.ast.base
import prog8.ast.Module
import prog8.ast.Program
import prog8.ast.processing.*
import prog8.ast.statements.Block
import prog8.ast.statements.VarDecl
import prog8.compiler.CompilationOptions
import prog8.compiler.target.AsmInitialValuesGatherer
import prog8.compiler.target.AsmVariablePreparer
import prog8.optimizer.FlattenAnonymousScopesAndNopRemover
@ -12,12 +16,18 @@ internal fun Program.checkValid(compilerOptions: CompilationOptions, errors: Err
checker.visit(this)
}
internal fun Program.moveAnonScopeVarsToSubroutine(errors: ErrorReporter) {
val mover = AnonScopeVarsToSubroutineMover(errors)
internal fun Program.prepareAsmVariables(errors: ErrorReporter) {
val mover = AsmVariablePreparer(this, errors)
mover.visit(this)
mover.applyModifications()
}
internal fun Program.gatherInitialValues(): Map<Block, Map<String, VarDecl>> {
val gather = AsmInitialValuesGatherer(this)
gather.visit(this)
return gather.initialValues
}
internal fun Program.reorderStatements() {
val initvalueCreator = AddressOfInserter(this)
initvalueCreator.visit(this)

View File

@ -16,20 +16,6 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
* (this includes function call arguments)
*/
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
// collect all variables that have an initialisation value
val declValue = decl.value
if(declValue!=null
&& decl.type== VarDeclType.VAR
&& decl.datatype in NumericDatatypes
&& declValue.constValue(program)!=null) {
decl.definingBlock().initialValues[decl.scopedname] = decl
}
return emptyList()
}
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
val leftDt = expr.left.inferType(program)
val rightDt = expr.right.inferType(program)

View File

@ -73,7 +73,6 @@ class Block(override val name: String,
val idx = statements.indexOf(node)
statements[idx] = replacement
}
val initialValues = mutableMapOf<String, VarDecl>() // will be gathered by one of the Ast processing steps
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
@ -271,8 +270,6 @@ class VarDecl(val type: VarDeclType,
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
val scopedname: String by lazy { makeScopedName(name) }
override fun toString(): String {
return "VarDecl(name=$name, vartype=$type, datatype=$datatype, struct=$structName, value=$value, pos=$position)"
}

View File

@ -116,11 +116,17 @@ fun compileProgram(filepath: Path,
// printAst(programAst)
if(writeAssembly) {
// asm generation directly from the Ast, no need for intermediate code
// asm generation directly from the Ast,
val zeropage = CompilationTarget.machine.getZeropage(compilerOptions)
programAst.moveAnonScopeVarsToSubroutine(errors)
programAst.prepareAsmVariables(errors)
errors.handle()
val assembly = CompilationTarget.asmGenerator(programAst, zeropage, compilerOptions, outputDir).compileToAssembly(optimize)
val initialValues = programAst.gatherInitialValues()
val assembly = CompilationTarget.asmGenerator(
programAst,
zeropage,
initialValues,
compilerOptions,
outputDir).compileToAssembly(optimize)
assembly.assemble(compilerOptions)
programName = assembly.name
}

View File

@ -0,0 +1,31 @@
package prog8.compiler.target
import prog8.ast.Program
import prog8.ast.base.NumericDatatypes
import prog8.ast.base.VarDeclType
import prog8.ast.processing.IAstVisitor
import prog8.ast.statements.Block
import prog8.ast.statements.VarDecl
internal class AsmInitialValuesGatherer(val program: Program): IAstVisitor {
val initialValues = mutableMapOf<Block, MutableMap<String, VarDecl>>()
override fun visit(decl: VarDecl) {
// collect all variables that have an initialisation value
super.visit(decl)
val declValue = decl.value
if(declValue!=null
&& decl.type== VarDeclType.VAR
&& decl.datatype in NumericDatatypes
&& declValue.constValue(program)!=null) {
val block = decl.definingBlock()
var blockInits = initialValues[block]
if(blockInits==null) {
blockInits = mutableMapOf()
initialValues[block] = blockInits
}
blockInits[decl.makeScopedName(decl.name)] = decl
}
}
}

View File

@ -1,13 +1,17 @@
package prog8.ast.processing
package prog8.compiler.target
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.ErrorReporter
import prog8.ast.processing.AstWalker
import prog8.ast.processing.IAstModification
import prog8.ast.statements.AnonymousScope
import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
class AnonScopeVarsToSubroutineMover(val errors: ErrorReporter): AstWalker() {
class AsmVariablePreparer(val program: Program, val errors: ErrorReporter): AstWalker() {
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
val decls = scope.statements.filterIsInstance<VarDecl>()
val sub = scope.definingSubroutine()

View File

@ -1,16 +1,22 @@
package prog8.compiler.target
import prog8.ast.Program
import prog8.ast.statements.Block
import prog8.ast.statements.VarDecl
import prog8.compiler.CompilationOptions
import prog8.compiler.Zeropage
import java.nio.file.Path
typealias InitialValues = Map<Block, Map<String, VarDecl>>
internal interface CompilationTarget {
companion object {
lateinit var name: String
lateinit var machine: IMachineDefinition
lateinit var encodeString: (str: String, altEncoding: Boolean) -> List<Short>
lateinit var decodeString: (bytes: List<Short>, altEncoding: Boolean) -> String
lateinit var asmGenerator: (Program, Zeropage, CompilationOptions, Path) -> IAssemblyGenerator
lateinit var asmGenerator: (Program, Zeropage, InitialValues, CompilationOptions, Path) -> IAssemblyGenerator
}
}

View File

@ -9,6 +9,7 @@ import prog8.ast.statements.*
import prog8.compiler.*
import prog8.compiler.target.IAssemblyGenerator
import prog8.compiler.target.IAssemblyProgram
import prog8.compiler.target.InitialValues
import prog8.compiler.target.c64.AssemblyProgram
import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX
@ -26,9 +27,10 @@ import kotlin.math.absoluteValue
internal class AsmGen(private val program: Program,
private val zeropage: Zeropage,
private val options: CompilationOptions,
private val outputDir: Path): IAssemblyGenerator {
private val zeropage: Zeropage,
private val initialValues: InitialValues,
private val options: CompilationOptions,
private val outputDir: Path): IAssemblyGenerator {
private val assemblyLines = mutableListOf<String>()
private val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname)
@ -126,7 +128,7 @@ internal class AsmGen(private val program: Program,
out(" ldx #\$ff\t; init estack pointer")
out(" ; initialize the variables in each block")
program.allBlocks().filter { it.initialValues.any() }.forEach { out(" jsr ${it.name}.prog8_init_vars") }
program.allBlocks().filter { it in initialValues }.forEach { out(" jsr ${it.name}.prog8_init_vars") }
out(" clc")
when (zeropage.exitProgramStrategy) {
@ -173,10 +175,12 @@ internal class AsmGen(private val program: Program,
// if any global vars need to be initialized, generate a subroutine that does this
// it will be called from program init.
if(block.initialValues.isNotEmpty()) {
if(block in initialValues) {
out("prog8_init_vars\t.proc\n")
block.initialValues.forEach { (scopedName, decl) ->
val target = AssignTarget(null, IdentifierReference(scopedName.split('.'), decl.position), null, null, decl.position)
initialValues.getValue(block).forEach { (scopedName, decl) ->
val scopedFullName = scopedName.split('.')
require(scopedFullName.first()==block.name)
val target = AssignTarget(null, IdentifierReference(scopedFullName.drop(1), decl.position), null, null, decl.position)
val assign = Assignment(target, null, decl.value!!, decl.position)
assign.linkParents(decl.parent)
assignmentAsmGen.translate(assign)
@ -229,7 +233,7 @@ internal class AsmGen(private val program: Program,
val variables = statements.filterIsInstance<VarDecl>().filter { it.type==VarDeclType.VAR }
for(variable in variables) {
// should NOT allocate subroutine parameters on the zero page
val fullName = variable.scopedname
val fullName = variable.makeScopedName(variable.name)
val zpVar = allocatedZeropageVariables[fullName]
if(zpVar==null) {
// This var is not on the ZP yet. Attempt to move it there (if it's not a float, those take up too much space)
@ -305,7 +309,14 @@ internal class AsmGen(private val program: Program,
}
}
DataType.ARRAY_F -> {
val array = (decl.value as ArrayLiteralValue).value
val array =
if(decl.value!=null)
(decl.value as ArrayLiteralValue).value
else {
// no init value, use zeros
val zero = decl.asDefaultValueDecl(decl.parent).value!!
Array(decl.arraysize!!.size()!!) { zero }
}
val floatFills = array.map {
val number = (it as NumericLiteralValue).number
makeFloatFill(C64MachineDefinition.Mflpt5.fromNumber(number))
@ -359,7 +370,7 @@ internal class AsmGen(private val program: Program,
// non-string variables
normalVars.filter{ it.datatype != DataType.STR }.sortedBy { it.datatype }.forEach {
if(it.scopedname !in allocatedZeropageVariables)
if(it.makeScopedName(it.name) !in allocatedZeropageVariables)
vardecl2asm(it)
}
}

View File

@ -127,7 +127,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
}
override fun visit(decl: VarDecl) {
if (decl.autogeneratedDontRemove || (decl.definingModule().isLibraryModule && decl.type != VarDeclType.VAR)) {
if (decl.autogeneratedDontRemove || decl.definingModule().isLibraryModule) {
// make sure autogenerated vardecls are in the used symbols
addNodeAndParentScopes(decl)
}

View File

@ -79,10 +79,10 @@ main {
uw1 = 2222
uw2 = 999
if sgn(uw2 as word - uw1 as word) != -1
c64scr.print("sgn2 error6\n")
if sgn(uw2 - uw1) != -1
c64scr.print("sgn2 error6\n")
if sgn((uw2 as word) - (uw1 as word)) != -1
c64scr.print("sgn2 error6a\n")
if sgn(uw2 - uw1) != 1 ; always 0 or 1 if unsigned
c64scr.print("sgn2 error6b\n")
f1 = 3.45
f2 = 1.11

View File

@ -5,64 +5,45 @@
main {
sub subje() {
ubyte xyz = 123
ubyte foo
c64scr.print_ub(xyz)
c64.CHROUT('\n')
c64scr.print_ub(foo)
c64.CHROUT('\n')
xyz++
foo++
}
sub start() {
ubyte xyz = 99 ; TODO fix compiler error when removing unused var
word wcosa = cos8(xyz)
word wcosa_sinb = wcosa / 128
ubyte ub1
ubyte ub2 = 99
uword uw1
uword uw2 = 9999
ubyte[5] array1
ubyte[5] array2 = [22,33,44,55,66]
subje()
subje()
subje()
c64scr.print_ub(ub1)
c64.CHROUT(',')
c64scr.print_ub(ub2)
c64.CHROUT(',')
c64scr.print_uw(uw1)
c64.CHROUT(',')
c64scr.print_uw(uw2)
c64.CHROUT(',')
c64scr.print_ub(array1[0])
c64.CHROUT(',')
c64scr.print_ub(array2[0])
c64.CHROUT('\n')
; ubyte ub1
; ubyte ub2 = 99
; uword uw1
; uword uw2 = 9999
; ubyte[5] array1
; ubyte[5] array2 = [22,33,44,55,66]
;
; c64scr.print_ub(ub1)
; c64.CHROUT(',')
; c64scr.print_ub(ub2)
; c64.CHROUT(',')
; c64scr.print_uw(uw1)
; c64.CHROUT(',')
; c64scr.print_uw(uw2)
; c64.CHROUT(',')
; c64scr.print_ub(array1[0])
; c64.CHROUT(',')
; c64scr.print_ub(array2[0])
; c64.CHROUT('\n')
;
; ub1++
; ub2++
; uw1++
; uw2++
; array1[0]++
; array2[0]++
;
; c64scr.print_ub(ub1)
; c64.CHROUT(',')
; c64scr.print_ub(ub2)
; c64.CHROUT(',')
; c64scr.print_uw(uw1)
; c64.CHROUT(',')
; c64scr.print_uw(uw2)
; c64.CHROUT(',')
; c64scr.print_ub(array1[0])
; c64.CHROUT(',')
; c64scr.print_ub(array2[0])
; c64.CHROUT('\n')
ub1++
ub2++
uw1++
uw2++
array1[0]++
array2[0]++
c64scr.print_ub(ub1)
c64.CHROUT(',')
c64scr.print_ub(ub2)
c64.CHROUT(',')
c64scr.print_uw(uw1)
c64.CHROUT(',')
c64scr.print_uw(uw2)
c64.CHROUT(',')
c64scr.print_ub(array1[0])
c64.CHROUT(',')
c64scr.print_ub(array2[0])
c64.CHROUT('\n')
}
}