mirror of
https://github.com/irmen/prog8.git
synced 2025-10-30 08:16:22 +00:00
type check tuning
This commit is contained in:
@@ -67,6 +67,7 @@ val BaseDataType.isPassByValue get() = !this.isIterable || this.isPointer
|
||||
|
||||
interface ISubType {
|
||||
val scopedNameString: String
|
||||
fun memsize(sizer: IMemSizer): Int
|
||||
}
|
||||
|
||||
class DataType private constructor(val base: BaseDataType, val sub: BaseDataType?, var subType: ISubType?, var subTypeFromAntlr: List<String>?=null) {
|
||||
@@ -296,6 +297,14 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType
|
||||
fun largerSizeThan(other: DataType): Boolean = base.largerSizeThan(other.base)
|
||||
fun equalsSize(other: DataType): Boolean = base.equalsSize(other.base)
|
||||
|
||||
fun size(memsizer: IMemSizer): Int = if(sub!=null) {
|
||||
memsizer.memorySize(sub)
|
||||
} else if(subType!=null) {
|
||||
subType!!.memsize(memsizer)
|
||||
} else {
|
||||
memsizer.memorySize(base)
|
||||
}
|
||||
|
||||
val isBasic = sub==null && subType==null && subTypeFromAntlr==null
|
||||
val isUndefined = base == BaseDataType.UNDEFINED
|
||||
val isByte = base.isByte
|
||||
@@ -382,7 +391,7 @@ enum class RegisterOrPair {
|
||||
BaseDataType.BYTE -> "sL"
|
||||
BaseDataType.WORD -> "s"
|
||||
BaseDataType.UWORD, null -> ""
|
||||
else -> throw kotlin.IllegalArgumentException("invalid register param type")
|
||||
else -> throw IllegalArgumentException("invalid register param type")
|
||||
}
|
||||
return listOf("cx16", name.lowercase()+suffix)
|
||||
}
|
||||
|
||||
@@ -985,32 +985,32 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
addInstr(result, if (constAddress != null)
|
||||
IRInstruction(Opcode.INCM, vmDt, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) , null)
|
||||
IRInstruction(Opcode.INCM, vmDt, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) , null)
|
||||
}
|
||||
else {
|
||||
val tr = expressionEval.translateExpression(operand)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
addInstr(result, if (constAddress != null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.ADDM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) , null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, fpReg1 = tr.resultFpReg, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.ADDM, vmDt, fpReg1 = tr.resultFpReg, labelSymbol = symbol) , null)
|
||||
}
|
||||
} else {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
addInstr(result, if (constAddress != null)
|
||||
IRInstruction(Opcode.INCM, vmDt, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) , null)
|
||||
IRInstruction(Opcode.INCM, vmDt, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol) , null)
|
||||
}
|
||||
else {
|
||||
val tr = expressionEval.translateExpression(operand)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, if (constAddress != null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, reg1 = tr.resultReg, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.ADDM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) , null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, reg1 = tr.resultReg, address = constAddress)
|
||||
else
|
||||
IRInstruction(Opcode.ADDM, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) , null)
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -1454,10 +1454,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val rightTr = translateExpression(binExpr.right)
|
||||
addToResult(result, rightTr, -1, rightTr.resultFpReg)
|
||||
addInstr(result, if(signed)
|
||||
IRInstruction(Opcode.DIVSR, vmDt, fpReg1 = leftTr.resultFpReg, fpReg2=rightTr.resultFpReg)
|
||||
else
|
||||
IRInstruction(Opcode.DIVR, vmDt, fpReg1 = leftTr.resultFpReg, fpReg2=rightTr.resultFpReg)
|
||||
, null)
|
||||
IRInstruction(Opcode.DIVSR, vmDt, fpReg1 = leftTr.resultFpReg, fpReg2=rightTr.resultFpReg)
|
||||
else
|
||||
IRInstruction(Opcode.DIVR, vmDt, fpReg1 = leftTr.resultFpReg, fpReg2=rightTr.resultFpReg)
|
||||
, null)
|
||||
return ExpressionCodeResult(result, vmDt, -1, leftTr.resultFpReg)
|
||||
}
|
||||
} else {
|
||||
@@ -1472,10 +1472,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val leftTr = translateExpression(binExpr.left)
|
||||
addToResult(result, leftTr, leftTr.resultReg, -1)
|
||||
addInstr(result, if (signed)
|
||||
IRInstruction(Opcode.DIVS, vmDt, reg1 = leftTr.resultReg, immediate = (binExpr.right as PtNumber).number.toInt())
|
||||
else
|
||||
IRInstruction(Opcode.DIV, vmDt, reg1 = leftTr.resultReg, immediate = (binExpr.right as PtNumber).number.toInt())
|
||||
, null)
|
||||
IRInstruction(Opcode.DIVS, vmDt, reg1 = leftTr.resultReg, immediate = (binExpr.right as PtNumber).number.toInt())
|
||||
else
|
||||
IRInstruction(Opcode.DIV, vmDt, reg1 = leftTr.resultReg, immediate = (binExpr.right as PtNumber).number.toInt())
|
||||
, null)
|
||||
ExpressionCodeResult(result, vmDt, leftTr.resultReg, -1)
|
||||
} else {
|
||||
val leftTr = translateExpression(binExpr.left)
|
||||
@@ -1483,10 +1483,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val rightTr = translateExpression(binExpr.right)
|
||||
addToResult(result, rightTr, rightTr.resultReg, -1)
|
||||
addInstr(result, if (signed)
|
||||
IRInstruction(Opcode.DIVSR, vmDt, reg1 = leftTr.resultReg, reg2 = rightTr.resultReg)
|
||||
else
|
||||
IRInstruction(Opcode.DIVR, vmDt, reg1 = leftTr.resultReg, reg2 = rightTr.resultReg)
|
||||
, null)
|
||||
IRInstruction(Opcode.DIVSR, vmDt, reg1 = leftTr.resultReg, reg2 = rightTr.resultReg)
|
||||
else
|
||||
IRInstruction(Opcode.DIVR, vmDt, reg1 = leftTr.resultReg, reg2 = rightTr.resultReg)
|
||||
, null)
|
||||
ExpressionCodeResult(result, vmDt, leftTr.resultReg, -1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1304,7 +1304,7 @@ internal class AstChecker(private val program: Program,
|
||||
errors.err("defer cannot contain jumps or returns", defer.position)
|
||||
}
|
||||
|
||||
private val supportedPointerOperatorsVirtual: Set<String> = emptySet()
|
||||
private val supportedPointerOperatorsVirtual: Set<String> = setOf("+")
|
||||
private val supportedPointerOperators6502: Set<String> = emptySet()
|
||||
|
||||
override fun visit(expr: BinaryExpression) {
|
||||
@@ -1437,12 +1437,22 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
if(!leftDt.isNumeric && !leftDt.isString && !leftDt.isBool)
|
||||
errors.err("left operand is not numeric or str", expr.left.position)
|
||||
if(!rightDt.isNumeric && !rightDt.isString && !rightDt.isBool)
|
||||
errors.err("right operand is not numeric or str", expr.right.position)
|
||||
if(!leftDt.isNumeric && !leftDt.isString && !leftDt.isBool && !leftDt.isPointer)
|
||||
errors.err("invalid left operand type", expr.left.position)
|
||||
if(!rightDt.isNumeric && !rightDt.isString && !rightDt.isBool && !rightDt.isPointer)
|
||||
errors.err("invalid right operand type", expr.right.position)
|
||||
if(leftDt!=rightDt) {
|
||||
if(leftDt.isString && rightDt.isInteger && expr.operator=="*") {
|
||||
if(leftDt.isPointer) {
|
||||
if(!rightDt.isUnsignedWord) {
|
||||
errors.err("pointer arithmetic requires unsigned word operand", expr.right.position)
|
||||
}
|
||||
}
|
||||
else if(rightDt.isPointer) {
|
||||
if(!leftDt.isUnsignedWord) {
|
||||
errors.err("pointer arithmetic requires unsigned word operand", expr.left.position)
|
||||
}
|
||||
}
|
||||
else if(leftDt.isString && rightDt.isInteger && expr.operator=="*") {
|
||||
// exception allowed: str * constvalue
|
||||
if(expr.right.constValue(program)==null)
|
||||
errors.err("can only use string repeat with a constant number value", expr.left.position)
|
||||
|
||||
@@ -180,6 +180,38 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
|
||||
else -> Pair("", null)
|
||||
}
|
||||
if(augmentedValue!=null) {
|
||||
|
||||
if(srcAssign.target.inferType(program).isPointer) {
|
||||
val expr = srcExpr as BinaryExpression
|
||||
if(expr.operator=="+") {
|
||||
// pointer arithmetic: add the size of the struct times the argument
|
||||
val leftDt = expr.left.inferType(program).getOrUndef()
|
||||
require(leftDt.isPointer && !expr.right.inferType(program).isPointer)
|
||||
val structSize = leftDt.size(program.memsizer)
|
||||
val constValue = augmentedValue.constValue(program)
|
||||
if(constValue!=null) {
|
||||
val total = constValue.number*structSize
|
||||
if (total == 0.0)
|
||||
return PtNop(srcAssign.position)
|
||||
else {
|
||||
val assign = PtAugmentedAssign(operator, srcAssign.position)
|
||||
assign.add(transform(srcAssign.target))
|
||||
assign.add(PtNumber(BaseDataType.UWORD, total, srcAssign.position))
|
||||
return assign
|
||||
}
|
||||
} else {
|
||||
val multiplication = PtBinaryExpression("*", DataType.UWORD, srcAssign.position)
|
||||
multiplication.add(transformExpression(augmentedValue))
|
||||
multiplication.add(PtNumber(BaseDataType.UWORD, structSize.toDouble(), srcAssign.position))
|
||||
val assign = PtAugmentedAssign(operator, srcAssign.position)
|
||||
assign.add(transform(srcAssign.target))
|
||||
assign.add(multiplication)
|
||||
return assign
|
||||
}
|
||||
} else
|
||||
throw FatalAstException("unexpected augmented assignment operator on pointer ${expr.operator}")
|
||||
}
|
||||
|
||||
val assign = PtAugmentedAssign(operator, srcAssign.position)
|
||||
assign.add(transform(srcAssign.target))
|
||||
assign.add(transformExpression(augmentedValue))
|
||||
@@ -706,10 +738,53 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
|
||||
else -> throw FatalAstException("unknown deref at ${srcExpr.position}")
|
||||
}
|
||||
} else {
|
||||
val expr = PtBinaryExpression(srcExpr.operator, type, srcExpr.position)
|
||||
expr.add(transformExpression(srcExpr.left))
|
||||
expr.add(transformExpression(srcExpr.right))
|
||||
return expr
|
||||
if(srcExpr.left.inferType(program).isPointer || srcExpr.right.inferType(program).isPointer) {
|
||||
if(srcExpr.operator=="+") {
|
||||
// pointer arithmetic: ptr + value
|
||||
val leftDt = srcExpr.left.inferType(program).getOrUndef()
|
||||
val rightDt = srcExpr.right.inferType(program).getOrUndef()
|
||||
if(leftDt.isPointer && !rightDt.isPointer) {
|
||||
val structSize = leftDt.size(program.memsizer)
|
||||
val constValue = srcExpr.right.constValue(program)
|
||||
if(constValue!=null) {
|
||||
TODO("ptr + $constValue * $structSize")
|
||||
} else {
|
||||
TODO("ptr + ${srcExpr.right} * $structSize")
|
||||
}
|
||||
} else if(!leftDt.isPointer && rightDt.isPointer) {
|
||||
val structSize = rightDt.size(program.memsizer)
|
||||
val constValue = srcExpr.left.constValue(program)
|
||||
if(constValue!=null) {
|
||||
val total = constValue.number*structSize
|
||||
if (total == 0.0)
|
||||
return transformExpression(srcExpr.left)
|
||||
else {
|
||||
TODO("ptr + $constValue * $structSize")
|
||||
// val assign = PtAugmentedAssign(operator, srcAssign.position)
|
||||
// assign.add(transform(srcAssign.target))
|
||||
// assign.add(PtNumber(BaseDataType.UWORD, total, srcAssign.position))
|
||||
// return assign
|
||||
}
|
||||
} else {
|
||||
val total = PtBinaryExpression("*", DataType.UWORD, srcExpr.position)
|
||||
total.add(transformExpression(srcExpr.left))
|
||||
total.add(PtNumber(BaseDataType.UWORD, structSize.toDouble(), srcExpr.position))
|
||||
val addition = PtBinaryExpression("+", DataType.UWORD, srcExpr.position)
|
||||
addition.add(transformExpression(srcExpr.right))
|
||||
addition.add(total)
|
||||
return addition
|
||||
}
|
||||
} else {
|
||||
throw FatalAstException("weird pointer arithmetic ${srcExpr.position}")
|
||||
}
|
||||
} else
|
||||
throw FatalAstException("unsupported operator on pointer: ${srcExpr.operator} at ${srcExpr.position}")
|
||||
} else {
|
||||
val expr = PtBinaryExpression(srcExpr.operator, type, srcExpr.position)
|
||||
expr.add(transformExpression(srcExpr.left))
|
||||
expr.add(transformExpression(srcExpr.right))
|
||||
return expr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -211,6 +211,16 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
}
|
||||
return modifications
|
||||
}
|
||||
|
||||
|
||||
// pointer arithmetic
|
||||
if(leftDt.isPointer) {
|
||||
val cast = TypecastExpression(expr.right, DataType.UWORD, true, expr.right.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr.right, cast, expr))
|
||||
} else if(rightDt.isPointer) {
|
||||
val cast = TypecastExpression(expr.left, DataType.UWORD, true, expr.left.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr.left, cast, expr))
|
||||
}
|
||||
}
|
||||
|
||||
// check if shifts have a positive integer shift type
|
||||
|
||||
@@ -353,12 +353,13 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
||||
|
||||
override fun visit(assignment: Assignment) {
|
||||
val binExpr = assignment.value as? BinaryExpression
|
||||
if(binExpr!=null && assignment.isAugmentable) {
|
||||
if(binExpr!=null && binExpr.left isSameAs assignment.target && binExpr.operator !in ComparisonOperators) {
|
||||
// we only support the inplace assignments of the form A = A <operator> <value>
|
||||
// don't use assignment.isAugmentable here! That one is a more general check, and not suitable for printing the AST like here
|
||||
assignment.target.accept(this)
|
||||
output(" ${binExpr.operator}= ")
|
||||
binExpr.right.accept(this)
|
||||
} else {
|
||||
val whyNot = assignment.isAugmentable
|
||||
assignment.target.accept(this)
|
||||
output(" = ")
|
||||
assignment.value.accept(this)
|
||||
|
||||
@@ -386,7 +386,7 @@ class StructDecl(override val name: String, val fields: List<Pair<DataType, Stri
|
||||
override fun copy() = StructDecl(name, fields.toList(), position)
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
fun memsize(sizer: IMemSizer): Int = fields.sumOf { sizer.memorySize(it.first, 1) }
|
||||
override fun memsize(sizer: IMemSizer): Int = fields.sumOf { sizer.memorySize(it.first, 1) }
|
||||
fun getFieldType(name: String): DataType? = fields.firstOrNull { it.second==name }?.first
|
||||
override val scopedNameString by lazy { scopedName.joinToString(".") }
|
||||
}
|
||||
@@ -503,6 +503,7 @@ class Assignment(var target: AssignTarget, var value: Expression, var origin: As
|
||||
|
||||
/**
|
||||
* Is the assigment value an expression that references the assignment target itself?
|
||||
* Note it doesn't have to be the first term in the expression!
|
||||
* The expression can be a BinaryExpression, PrefixExpression or TypecastExpression (possibly with one sub-cast).
|
||||
*/
|
||||
val isAugmentable: Boolean
|
||||
|
||||
@@ -34,6 +34,7 @@ STRUCTS and TYPED POINTERS
|
||||
- DONE: pointer arrays are split-words only, enforce this (variable dt + initializer array dt)
|
||||
- DONE: make an error message for all pointer expressions (prefixed, binary) so we can start implementing the ones we need one by one.
|
||||
- start by making ptr.value++ work , and ptr.value = ptr.value+20, and ptr.value = cx16.r0L+20+ptr.value Likewise for -- DON'T FORGET C POINTER SEMANTICS
|
||||
- don't do pointer arith in the codegen, do it in Pt translation!
|
||||
- fix actual _msb/_lsb storage of the split-words pointer-arrays
|
||||
- support @dirty on pointer vars -> uninitialized pointer placed in BSS_noclear segment
|
||||
- pointer types in subroutine signatures (both normal and asm-subs)
|
||||
@@ -49,6 +50,7 @@ STRUCTS and TYPED POINTERS
|
||||
- pointer-to-array syntax = TBD
|
||||
- what about pointers to subroutines? should these be typed as well now?
|
||||
- What about static initialization of an array of struct pointers? -> impossible right now because the pointer values are not contants
|
||||
- 6502 codegen should warn about writing to initialized struct instances when using romable code, like with arrays "can only be used as read-only in ROMable code"
|
||||
- 6502 asm symbol name prefixing should work for dereferences too.
|
||||
|
||||
|
||||
|
||||
@@ -20,10 +20,50 @@ main {
|
||||
|
||||
; TODO (Borked:)
|
||||
^^Node @shared ptr = 2000
|
||||
ptr++
|
||||
ptr += 2
|
||||
ptr = cx16.r0 + ptr
|
||||
; ^^bool bptr = 3000
|
||||
; ^^float fptr = 3000
|
||||
;
|
||||
; bptr++
|
||||
; fptr++
|
||||
;
|
||||
; txt.print_uw(ptr)
|
||||
; txt.nl()
|
||||
;
|
||||
; ptr++
|
||||
; txt.print_uw(ptr)
|
||||
; txt.nl()
|
||||
;
|
||||
; ptr += 2
|
||||
; txt.print_uw(ptr)
|
||||
; txt.nl()
|
||||
;
|
||||
; cx16.r0 = 5
|
||||
; ptr = cx16.r0 + ptr
|
||||
; txt.print_uw(ptr)
|
||||
; txt.nl()
|
||||
|
||||
cx16.r0 = 4
|
||||
|
||||
ptr = cx16.r0 + ptr + 1
|
||||
txt.print_uw(ptr)
|
||||
txt.nl()
|
||||
ptr = cx16.r0 + 1 + ptr
|
||||
txt.print_uw(ptr)
|
||||
txt.nl()
|
||||
ptr = ptr + 1 + cx16.r0
|
||||
txt.print_uw(ptr)
|
||||
txt.nl()
|
||||
|
||||
ptr = cx16.r0 + ptr + 10
|
||||
txt.print_uw(ptr)
|
||||
txt.nl()
|
||||
ptr = cx16.r0 + 10 + ptr
|
||||
txt.print_uw(ptr)
|
||||
txt.nl()
|
||||
ptr = ptr + 10 + cx16.r0
|
||||
txt.print_uw(ptr)
|
||||
txt.nl()
|
||||
|
||||
; ptr.value++
|
||||
; ptr.value += 30
|
||||
; ptr.value = ptr.value + 20
|
||||
|
||||
@@ -540,8 +540,8 @@ class IRInlineBinaryChunk(label: String?,
|
||||
typealias IRCodeChunks = List<IRCodeChunkBase>
|
||||
|
||||
|
||||
internal class IRSubtypePlaceholder(val name: String): ISubType {
|
||||
override val scopedNameString = name
|
||||
internal class IRSubtypePlaceholder(override val scopedNameString: String, val size: Int = 999999999): ISubType {
|
||||
override fun memsize(sizer: IMemSizer) = size
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -295,6 +295,8 @@ class StStruct(
|
||||
}
|
||||
throw NoSuchElementException("field $name not found in struct ${this.name}")
|
||||
}
|
||||
|
||||
override fun memsize(sizer: IMemSizer): Int = size.toInt()
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user