mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
tweak IR
This commit is contained in:
parent
7c1d5cadd7
commit
b55be093be
@ -383,10 +383,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
var resultFpReg = -1
|
||||
if(fcall.type==DataType.FLOAT) {
|
||||
resultFpReg = codeGen.registers.nextFreeFloat()
|
||||
addInstr(result, IRInstruction(Opcode.CALLRVAL, IRDataType.FLOAT, fpReg1=resultFpReg, labelSymbol=fcall.name), null)
|
||||
addInstr(result, IRInstruction(Opcode.CALLR, IRDataType.FLOAT, fpReg1=resultFpReg, labelSymbol=fcall.name), null)
|
||||
} else {
|
||||
resultReg = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.CALLRVAL, codeGen.irType(fcall.type), reg1=resultReg, labelSymbol=fcall.name), null)
|
||||
addInstr(result, IRInstruction(Opcode.CALLR, codeGen.irType(fcall.type), reg1=resultReg, labelSymbol=fcall.name), null)
|
||||
}
|
||||
ExpressionCodeResult(result, codeGen.irType(fcall.type), resultReg, resultFpReg)
|
||||
}
|
||||
|
@ -1458,12 +1458,12 @@ class IRCodeGen(
|
||||
if(value.type==DataType.FLOAT) {
|
||||
val tr = expressionEval.translateExpression(value)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
addInstr(result, IRInstruction(Opcode.RETURNREG, IRDataType.FLOAT, fpReg1 = tr.resultFpReg), null)
|
||||
addInstr(result, IRInstruction(Opcode.RETURNR, IRDataType.FLOAT, fpReg1 = tr.resultFpReg), null)
|
||||
}
|
||||
else {
|
||||
val tr = expressionEval.translateExpression(value)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.RETURNREG, irType(value.type) , reg1=tr.resultReg), null)
|
||||
addInstr(result, IRInstruction(Opcode.RETURNR, irType(value.type) , reg1=tr.resultReg), null)
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
@ -184,7 +184,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
}
|
||||
|
||||
// remove useless RETURN
|
||||
if(idx>0 && (ins.opcode == Opcode.RETURN || ins.opcode==Opcode.RETURNREG)) {
|
||||
if(idx>0 && (ins.opcode == Opcode.RETURN || ins.opcode==Opcode.RETURNR)) {
|
||||
val previous = chunk.instructions[idx-1]
|
||||
if(previous.opcode in OpcodesThatJump) {
|
||||
chunk.instructions.removeAt(idx)
|
||||
@ -204,7 +204,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
// replace call + return --> jump
|
||||
if(idx>0 && ins.opcode==Opcode.RETURN) {
|
||||
val previous = chunk.instructions[idx-1]
|
||||
if(previous.opcode==Opcode.CALL || previous.opcode==Opcode.CALLRVAL) {
|
||||
if(previous.opcode==Opcode.CALL || previous.opcode==Opcode.CALLR) {
|
||||
chunk.instructions[idx-1] = IRInstruction(Opcode.JUMP, address = previous.address, labelSymbol = previous.labelSymbol, branchTarget = previous.branchTarget)
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
|
@ -200,7 +200,7 @@ sub str2uword(str string) -> uword {
|
||||
push.w r65535
|
||||
syscall 11
|
||||
pop.w r0
|
||||
returnreg.w r0
|
||||
returnr.w r0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -213,7 +213,7 @@ sub str2word(str string) -> word {
|
||||
push.w r65535
|
||||
syscall 12
|
||||
pop.w r0
|
||||
returnreg.w r0
|
||||
returnr.w r0
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ sub pow(float value, float power) -> float {
|
||||
loadm.f fr0,floats.pow.value
|
||||
loadm.f fr1,floats.pow.power
|
||||
fpow.f fr0,fr1
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ sub fabs(float value) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.fabs.value
|
||||
fabs.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ sub sin(float angle) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.sin.angle
|
||||
fsin.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ sub cos(float angle) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.cos.angle
|
||||
fcos.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ sub tan(float value) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.tan.value
|
||||
ftan.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ sub atan(float value) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.atan.value
|
||||
fatan.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ sub ln(float value) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.ln.value
|
||||
fln.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ sub log2(float value) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.log2.value
|
||||
flog.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ sub sqrt(float value) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.sqrt.value
|
||||
sqrt.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ sub round(float value) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.round.value
|
||||
fround.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ sub floor(float value) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.floor.value
|
||||
ffloor.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ sub ceil(float value) -> float {
|
||||
%ir {{
|
||||
loadm.f fr0,floats.ceil.value
|
||||
fceil.f fr0,fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -129,7 +129,7 @@ sub rndf() -> float {
|
||||
%ir {{
|
||||
syscall 35
|
||||
pop.f fr0
|
||||
returnreg.f fr0
|
||||
returnr.f fr0
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ math {
|
||||
%ir {{
|
||||
syscall 33
|
||||
pop.b r0
|
||||
returnreg.b r0
|
||||
returnr.b r0
|
||||
}}
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ math {
|
||||
%ir {{
|
||||
syscall 34
|
||||
pop.w r0
|
||||
returnreg.w r0
|
||||
returnr.w r0
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ string {
|
||||
push.w r65535
|
||||
syscall 29
|
||||
pop.b r0
|
||||
returnreg.b r0
|
||||
returnr.b r0
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ sys {
|
||||
push.w r65535
|
||||
syscall 30
|
||||
pop.b r0
|
||||
returnreg.b r0
|
||||
returnr.b r0
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ sub input_chars (uword buffer) -> ubyte {
|
||||
push.b r65535
|
||||
syscall 6
|
||||
pop.b r0
|
||||
returnreg.b r0
|
||||
returnr.b r0
|
||||
}}
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,15 @@ TODO
|
||||
|
||||
For next minor release
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
- try to optimize newexpr a bit more
|
||||
|
||||
...
|
||||
|
||||
|
||||
For 9.0 major changes
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
- try to reintroduce builtin functions max/maxw/min/minw that take 2 args and return the largest/smallest of them.
|
||||
This is a major change because it will likely break existing code that is now using min and max as variable names.
|
||||
- get rid of the disknumber parameter everywhere in diskio, make it a configurable variable that defaults to 8.
|
||||
the large majority of users will only deal with a single disk drive so why not make it easier for them.
|
||||
- duplicate diskio for cx16 (get rid of cx16diskio, just copy diskio and tweak everything) + documentation
|
||||
@ -33,9 +37,9 @@ Future Things and Ideas
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Compiler:
|
||||
|
||||
- ir: investigate passing parameters to function calls using fixed set of regs r60000,r60001, etc.
|
||||
these have to be offset somehow by the subroutine number (?) somehow to have a unique list of them per subroutine.
|
||||
also only if we can optimize the subroutine to replace the parameter variables to those registers.
|
||||
- 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)
|
||||
global initialization values are simply a list of LOAD instructions.
|
||||
Variables replaced include all subroutine parameters! So the only variables that remain as variables are arrays and strings.
|
||||
- ir: can we determine for the loop variable in forloops if it could be kept in a (virtual) register instead of a real variable? Need to be able to check if the variable is used by another statement beside just the for loop.
|
||||
- ir: mechanism to determine for chunks which registers are getting input values from "outside"
|
||||
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)
|
||||
|
@ -17,8 +17,11 @@ Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by t
|
||||
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
|
||||
|
||||
Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly.
|
||||
Most instructions have an associated data type 'b','w','f'. (omitting it defaults to 'b' - byte).
|
||||
Currently NO support for 24 or 32 bits integers.
|
||||
|
||||
Value types: integers (.b=byte=8 bits, .w=word=16 bits) and float (.f=32 bits). Omitting it defaults to b.
|
||||
Currently ther is NO support for 24 or 32 bits integers.
|
||||
There is no distinction between signed and unsigned integers.
|
||||
Instead, a different instruction is used if a distinction should be made (for example div and divs).
|
||||
Floating point operations are just 'f' typed regular instructions, however there are a few unique fp conversion instructions.
|
||||
Instructions taking more than 1 register cannot take the same register multiple times! (to avoid confusing different datatypes)
|
||||
|
||||
@ -50,11 +53,11 @@ CONTROL FLOW
|
||||
------------
|
||||
jump location - continue running at instruction number given by location
|
||||
jumpa address - continue running at memory address (note: only used to encode a physical cpu jump to fixed address instruction)
|
||||
call location - save current instruction location+1, continue execution at instruction nr given by location. Expect no return value.
|
||||
callrval reg1, location - like call but expects a return value from a returnreg instruction, and puts that in reg1
|
||||
call location - save current instruction location+1, continue execution at instruction nr given by location. No return value is expected.
|
||||
callr reg1, location - like call but expects the routine to return a value with a returnr instruction, it then puts that in reg1
|
||||
syscall value - do a systemcall identified by call number, result value(s) are pushed on value stack so need to be POPped off (depends on syscall)
|
||||
return - restore last saved instruction location and continue at that instruction. No return value.
|
||||
returnreg reg1 - like return, but also returns a value to the caller via reg1
|
||||
returnr reg1 - like return, but also returns the value in reg1 to the caller
|
||||
|
||||
|
||||
BRANCHING and CONDITIONALS
|
||||
@ -112,12 +115,12 @@ dec reg1 - reg1 = reg1-1
|
||||
decm address - memory at address -= 1
|
||||
neg reg1 - reg1 = sign negation of reg1
|
||||
negm address - sign negate memory at address
|
||||
addr reg1, reg2 - reg1 += reg2 (unsigned + signed)
|
||||
add reg1, value - reg1 += value (unsigned + signed)
|
||||
addm reg1, address - memory at address += reg1 (unsigned + signed)
|
||||
subr reg1, reg2 - reg1 -= reg2 (unsigned + signed)
|
||||
sub reg1, value - reg1 -= value (unsigned + signed)
|
||||
subm reg1, address - memory at address -= reg1 (unsigned + signed)
|
||||
addr reg1, reg2 - reg1 += reg2
|
||||
add reg1, value - reg1 += value
|
||||
addm reg1, address - memory at address += reg1
|
||||
subr reg1, reg2 - reg1 -= reg2
|
||||
sub reg1, value - reg1 -= value
|
||||
subm reg1, address - memory at address -= reg1
|
||||
mulr reg1, reg2 - unsigned multiply reg1 *= reg2 note: byte*byte->byte, no type extension to word!
|
||||
mul reg1, value - unsigned multiply reg1 *= value note: byte*byte->byte, no type extension to word!
|
||||
mulm reg1, address - memory at address *= reg2 note: byte*byte->byte, no type extension to word!
|
||||
@ -235,10 +238,10 @@ enum class Opcode {
|
||||
JUMP,
|
||||
JUMPA,
|
||||
CALL,
|
||||
CALLRVAL,
|
||||
CALLR,
|
||||
SYSCALL,
|
||||
RETURN,
|
||||
RETURNREG,
|
||||
RETURNR,
|
||||
|
||||
BSTCC,
|
||||
BSTCS,
|
||||
@ -375,16 +378,16 @@ val OpcodesThatJump = setOf(
|
||||
Opcode.JUMP,
|
||||
Opcode.JUMPA,
|
||||
Opcode.RETURN,
|
||||
Opcode.RETURNREG
|
||||
Opcode.RETURNR
|
||||
)
|
||||
|
||||
val OpcodesThatBranch = setOf(
|
||||
Opcode.JUMP,
|
||||
Opcode.JUMPA,
|
||||
Opcode.RETURN,
|
||||
Opcode.RETURNREG,
|
||||
Opcode.RETURNR,
|
||||
Opcode.CALL,
|
||||
Opcode.CALLRVAL,
|
||||
Opcode.CALLR,
|
||||
Opcode.SYSCALL,
|
||||
Opcode.BSTCC,
|
||||
Opcode.BSTCS,
|
||||
@ -515,10 +518,10 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.JUMP to InstructionFormat.from("N,<a"),
|
||||
Opcode.JUMPA to InstructionFormat.from("N,<a"),
|
||||
Opcode.CALL to InstructionFormat.from("N,<a"),
|
||||
Opcode.CALLRVAL to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
|
||||
Opcode.CALLR to InstructionFormat.from("BW,>r1,<a | F,>fr1,<a"),
|
||||
Opcode.SYSCALL to InstructionFormat.from("N,<i"),
|
||||
Opcode.RETURN to InstructionFormat.from("N"),
|
||||
Opcode.RETURNREG to InstructionFormat.from("BW,>r1 | F,>fr1"),
|
||||
Opcode.RETURNR to InstructionFormat.from("BW,>r1 | F,>fr1"),
|
||||
Opcode.BSTCC to InstructionFormat.from("N,<a"),
|
||||
Opcode.BSTCS to InstructionFormat.from("N,<a"),
|
||||
Opcode.BSTEQ to InstructionFormat.from("N,<a"),
|
||||
|
@ -134,7 +134,7 @@ class IRProgram(val name: String,
|
||||
|
||||
// link all jump and branching instructions to their target
|
||||
chunk.instructions.forEach {
|
||||
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.RETURN && it.opcode!=Opcode.RETURNREG && it.labelSymbol!=null)
|
||||
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.RETURN && it.opcode!=Opcode.RETURNR && it.labelSymbol!=null)
|
||||
it.branchTarget = labeledChunks.getValue(it.labelSymbol)
|
||||
// note: branches with an address value cannot be linked to something...
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ internal class BitmapScreenPanel(private val drawImage: BufferedImage, val pixel
|
||||
|
||||
override fun paint(graphics: Graphics) {
|
||||
val g2d = graphics as Graphics2D
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
|
||||
g2d.drawImage(drawImage, 0, 0, size.width, size.height, null)
|
||||
Toolkit.getDefaultToolkit().sync()
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ Virtual machine specs:
|
||||
Program to execute is not stored in the system memory, it's just a separate list of instructions.
|
||||
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
|
||||
65536 virtual floating point registers (32 bits single precision floats) fr0-fr65535
|
||||
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
|
||||
65536 bytes of memory, thus memory pointers (addresses) are limited to 16 bits.
|
||||
Value stack, max 128 entries of 1 byte each.
|
||||
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC!!!
|
||||
logical or arithmetic operations DO NOT AFFECT THE STATUS FLAGS UNLESS EXPLICITLY NOTED!
|
||||
@ -176,11 +176,10 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
Opcode.STOREZI -> InsSTOREZI(ins)
|
||||
Opcode.JUMP -> InsJUMP(ins)
|
||||
Opcode.JUMPA -> throw IllegalArgumentException("vm program can't jump to system memory address (JUMPA)")
|
||||
Opcode.CALL -> InsCALL(ins)
|
||||
Opcode.CALLRVAL -> InsCALLRVAL(ins)
|
||||
Opcode.CALL, Opcode.CALLR -> InsCALL(ins)
|
||||
Opcode.SYSCALL -> InsSYSCALL(ins)
|
||||
Opcode.RETURN -> InsRETURN()
|
||||
Opcode.RETURNREG -> InsRETURNREG(ins)
|
||||
Opcode.RETURNR -> InsRETURNR(ins)
|
||||
Opcode.BSTCC -> InsBSTCC(ins)
|
||||
Opcode.BSTCS -> InsBSTCS(ins)
|
||||
Opcode.BSTEQ -> InsBSTEQ(ins)
|
||||
@ -591,11 +590,6 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
}
|
||||
|
||||
private fun InsCALL(i: IRInstruction) {
|
||||
callStack.push(CallSiteContext(pcChunk, pcIndex+1, null, null))
|
||||
branchTo(i)
|
||||
}
|
||||
|
||||
private fun InsCALLRVAL(i: IRInstruction) {
|
||||
callStack.push(CallSiteContext(pcChunk, pcIndex+1, i.reg1, i.fpReg1))
|
||||
branchTo(i)
|
||||
}
|
||||
@ -611,7 +605,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun InsRETURNREG(i: IRInstruction) {
|
||||
private fun InsRETURNR(i: IRInstruction) {
|
||||
if(callStack.isEmpty())
|
||||
exit(0)
|
||||
else {
|
||||
@ -2293,11 +2287,11 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
}
|
||||
|
||||
fun gfx_getpixel() {
|
||||
val y = valueStack.popw()
|
||||
val x = valueStack.popw()
|
||||
if(window==null)
|
||||
registers.setUB(0, 0u)
|
||||
valueStack.push(0u)
|
||||
else {
|
||||
val y = valueStack.popw()
|
||||
val x = valueStack.popw()
|
||||
val color = Color(window!!.getpixel(x.toInt(), y.toInt()))
|
||||
valueStack.push(color.green.toUByte()) // gets called from a syscall, return value via stack.
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user