fix expericodegen crash related to shortcircuiting

This commit is contained in:
Irmen de Jong 2023-12-31 01:02:33 +01:00
parent 1e1f444cab
commit 75fd263e85
5 changed files with 28 additions and 123 deletions

View File

@ -17,8 +17,6 @@ internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType
if(resultReg!=-1) require(resultFpReg==-1)
if(resultFpReg!=-1) require(resultReg==-1)
}
fun lastInstruction() = chunks.last().instructions.last()
}
internal class ExpressionGen(private val codeGen: IRCodeGen) {

View File

@ -1026,7 +1026,8 @@ class IRCodeGen(
val condition = ifElse.condition as PtBinaryExpression
val leftTr = expressionEval.translateExpression(condition.left)
addToResult(result, leftTr, leftTr.resultReg, -1)
val requireCompareZero = leftTr.lastInstruction().opcode !in OpcodesThatSetStatusbits
val lastInstruction = leftTr.chunks.last().instructions.lastOrNull()
val requireCompareZero = lastInstruction?.opcode !in OpcodesThatSetStatusbits
when(condition.operator) {
"==" -> {
if(requireCompareZero)

View File

@ -473,4 +473,17 @@ instructions {
compileText(VMTarget(), false, src, writeAssembly = true) shouldNotBe null
}
test("IR codegen for while loop with shortcircuit") {
val src="""
main {
sub start() {
cx16.r0L=1
while cx16.r0L < 10 and cx16.r0L>0 {
cx16.r0L++
}
}
}"""
compileText(VMTarget(), true, src, writeAssembly = true) shouldNotBe null
}
})

View File

@ -9,6 +9,8 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Compiler:
- get rid of the noshortcircuit fallback option and code.
- What happens when we make all subs return a boolean not as ubyte in A, but in the cpu's Carry flag?
- Multidimensional arrays and chained indexing, purely as syntactic sugar over regular arrays.
- make a form of "manual generics" possible like: varsub routine(T arg)->T where T is expanded to a specific type
(this is already done hardcoded for several of the builtin functions)
@ -24,6 +26,7 @@ Compiler:
- (need separate step in codegen and IR to write the "golden" variables)
- do we need (array)variable alignment tag instead of block alignment tag? You want to align the data, not the code in the block?
- ir: proper code gen for the CALLI instruction and that it (optionally) returns a word value that needs to be assigned to a reg
- ir: getting it in shape for code generation
- ir: related to the one above: block alignment doesn't translate well to variables in the block (the actual stuff that needs to be aligned in memory) but: need variable alignment tag instead of block alignment tag, really
- ir: idea: (but LLVM IR simply keeps the variables, so not a good idea then?...): replace all scalar variables by an allocated register. Keep a table of the variable to register mapping (including the datatype)
@ -44,7 +47,7 @@ Compiler:
Libraries:
- once a VAL_1 implementation is merged into the X16 kernal properly, remove all the workarounds in cx16 floats.parse_f()
- once a VAL_1 implementation is merged into the X16 kernal properly, remove all the workarounds in cx16 floats.parse_f() . Prototype parse routine in examples/cx16/floatparse.p8
- fix the problems in atari target, and flesh out its libraries.
- c128 target: make syslib more complete (missing kernal routines)?
- pet32 target: make syslib more complete (missing kernal routines)?
@ -52,8 +55,6 @@ Libraries:
Optimizations:
- give a warning for variables that could be a const - or even make them a const (if not @shared)?
- treat every scalar variable decl with initialization value, as const by default, unless the variable gets assigned to somewhere (or has its address taken, or is @shared)
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served?
for instance, vars used inside loops first, then loopvars, then uwords used as pointers, then the rest
- various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once 6502-codegen is done from IR code,
@ -76,9 +77,6 @@ What if we were to re-introduce Structs in prog8? Some thoughts:
Other language/syntax features to think about
---------------------------------------------
- module directive to set the text encoding for that whole file (iso, petscii, etc.)
- chained assignments `x=y=z=99`
- declare multiple variables `ubyte x,y,z` (if init value present, all get that init value)
- chained comparisons `10<x<20` , `x==y==z` (desugars to `10<x and x<20`, `x==y and y==z`)
- postincrdecr as expression, preincrdecr expression (`y = x++`, `y = ++x`) .... is this even possible, expression with side effects like this?
- negative array index to refer to an element from the end of the array. Python `[-1]` or Raku syntax `[\*-1]` , `[\*/2]` .... \*=size of the array
- add (rom/ram)bank support to romsub. A call will then automatically switch banks, use callfar and something else when in banked ram.
challenges: how to not make this too X16 specific? How does the compiler know what bank to switch (ram/rom)?
How to make it performant when we want to (i.e. NOT have it use callfar/auto bank switching) ?

View File

@ -1,118 +1,13 @@
%import textio
%zeropage dontuse
%zeropage basicsafe
; Note: this program can be compiled for multiple target systems.
main {
sub start() {
ubyte @shared x = 10
if value(12) < x < value(100)
txt.print("gottem")
sub value(ubyte v) -> ubyte {
cx16.r0++
txt.print("value(): ")
txt.print_ub(v)
txt.nl()
return v
cx16.r0L=1
while cx16.r0L < 10 and cx16.r0L>0 {
cx16.r0L++
}
bigtest()
}
ubyte @shared a1 = 10
ubyte @shared a2 = 20
ubyte @shared x1 = 30
ubyte @shared x2 = 40
ubyte @shared zero = 0
sub bigtest () {
txt.print("1a:\n")
if calc_a1()<calc_x1() and calc_a2()<=calc_x2()
txt.print("* 1a and ok\n")
txt.print("\n1b:\n")
if calc_a1()<calc_x1() and calc_a2()>calc_x2()
txt.print("* 1b and fail\n")
txt.print("\n1c:\n")
if calc_a1()>calc_x1() and calc_a2()<=calc_x2()
txt.print("* 1c and fail\n")
txt.print("\n2a:\n")
if calc_a1()<calc_x1() or calc_a2()<=calc_x2()
txt.print("* 2a or ok\n")
txt.print("\n2b:\n")
if calc_a1()<calc_x1() or calc_a2()>calc_x2()
txt.print("* 2b or ok\n")
txt.print("\n3a:\n")
if calc_a1()>calc_x1() or calc_a2()<=calc_x2()
txt.print("* 3a or ok\n")
txt.print("\n3b:\n")
if calc_a1()>calc_x1() or calc_a2()>calc_x2()
txt.print("* 3b or fail\n")
txt.print("\n4a:\n")
bool result = calc_a1()<calc_x1() or calc_a2()>calc_x2()
txt.print_ub(result)
txt.nl()
txt.print("\n4b:\n")
result = calc_a1()>=calc_x1() and calc_a2()>calc_x2()
txt.print_ub(result)
txt.nl()
@($4000) &= 22
txt.print("\n5a:\n")
result = bool_true() or bool_false()
txt.print("\n5b:\n")
result = bool_true() and bool_false()
txt.print("\n5c:\n")
result = bool_false() and bool_true()
txt.print("\n5d:\n")
result = bool_false() xor bool_true()
txt.print("augmented and shortcut:\n")
bool @shared b1 = false
cx16.r0++
b1 = b1 and bool_true()
txt.print("augmented and no shortcut:\n")
b1 = true
cx16.r0++
b1 = b1 and bool_true()
txt.print("augmented or shortcut:\n")
b1 = true
cx16.r0++
b1 = b1 or bool_true()
txt.print("augmented or no shortcut:\n")
b1 = false
cx16.r0++
b1 = b1 or bool_true()
}
sub bool_true() -> bool {
txt.print("bool_true\n")
return true
}
sub bool_false() -> bool {
txt.print("bool_false\n")
return false
}
sub calc_a1() -> ubyte {
txt.print("calc_a1\n")
return a1+zero
}
sub calc_a2() -> ubyte {
txt.print("calc_a2\n")
return a2+zero
}
sub calc_x1() -> ubyte {
txt.print("calc_x1\n")
return x1+zero
}
sub calc_x2() -> ubyte {
txt.print("calc_x2\n")
return x2+zero
}
}