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(resultReg!=-1) require(resultFpReg==-1)
if(resultFpReg!=-1) require(resultReg==-1) if(resultFpReg!=-1) require(resultReg==-1)
} }
fun lastInstruction() = chunks.last().instructions.last()
} }
internal class ExpressionGen(private val codeGen: IRCodeGen) { internal class ExpressionGen(private val codeGen: IRCodeGen) {

View File

@ -1026,7 +1026,8 @@ class IRCodeGen(
val condition = ifElse.condition as PtBinaryExpression val condition = ifElse.condition as PtBinaryExpression
val leftTr = expressionEval.translateExpression(condition.left) val leftTr = expressionEval.translateExpression(condition.left)
addToResult(result, leftTr, leftTr.resultReg, -1) 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) { when(condition.operator) {
"==" -> { "==" -> {
if(requireCompareZero) if(requireCompareZero)

View File

@ -473,4 +473,17 @@ instructions {
compileText(VMTarget(), false, src, writeAssembly = true) shouldNotBe null 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: 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. - 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 - 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) (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) - (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? - 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: 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: 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) - 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: 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. - fix the problems in atari target, and flesh out its libraries.
- c128 target: make syslib more complete (missing kernal routines)? - c128 target: make syslib more complete (missing kernal routines)?
- pet32 target: make syslib more complete (missing kernal routines)? - pet32 target: make syslib more complete (missing kernal routines)?
@ -52,8 +55,6 @@ Libraries:
Optimizations: 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? - 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 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, - 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 Other language/syntax features to think about
--------------------------------------------- ---------------------------------------------
- module directive to set the text encoding for that whole file (iso, petscii, etc.) - add (rom/ram)bank support to romsub. A call will then automatically switch banks, use callfar and something else when in banked ram.
- chained assignments `x=y=z=99` challenges: how to not make this too X16 specific? How does the compiler know what bank to switch (ram/rom)?
- declare multiple variables `ubyte x,y,z` (if init value present, all get that init value) How to make it performant when we want to (i.e. NOT have it use callfar/auto bank switching) ?
- 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

View File

@ -1,118 +1,13 @@
%import textio %import textio
%zeropage dontuse %zeropage basicsafe
; Note: this program can be compiled for multiple target systems.
main { main {
sub start() { sub start() {
ubyte @shared x = 10 cx16.r0L=1
if value(12) < x < value(100) while cx16.r0L < 10 and cx16.r0L>0 {
txt.print("gottem") cx16.r0L++
sub value(ubyte v) -> ubyte {
cx16.r0++
txt.print("value(): ")
txt.print_ub(v)
txt.nl()
return v
} }
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
} }
} }