mirror of
https://github.com/irmen/prog8.git
synced 2026-04-20 11:17:01 +00:00
fix long argument @R0R1 register usage in regular subroutines
This commit is contained in:
@@ -440,12 +440,13 @@ enum class RegisterOrPair {
|
||||
}
|
||||
|
||||
fun asScopedNameVirtualReg(type: DataType?): List<String> {
|
||||
require(this in Cx16VirtualRegisters)
|
||||
require(this in Cx16VirtualRegisters || this in CombinedLongRegisters)
|
||||
val suffix = when(type?.base) {
|
||||
BaseDataType.UBYTE, BaseDataType.BOOL -> "L"
|
||||
BaseDataType.BYTE -> "sL"
|
||||
BaseDataType.WORD -> "s"
|
||||
BaseDataType.UWORD, BaseDataType.POINTER, null -> ""
|
||||
BaseDataType.LONG -> "sl"
|
||||
else -> throw IllegalArgumentException("invalid register param type for cx16 virtual reg")
|
||||
}
|
||||
return listOf("cx16", name.lowercase()+suffix)
|
||||
|
||||
@@ -268,8 +268,8 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
|
||||
val reg = parameter.register
|
||||
if(reg!=null) {
|
||||
require(reg in Cx16VirtualRegisters) { "can only use R0-R15 'registers' here" }
|
||||
val varName = "cx16.${reg.name.lowercase()}"
|
||||
require(reg in Cx16VirtualRegisters || reg in CombinedLongRegisters) { "can only use R0-R15 'registers' here" }
|
||||
val varName = reg.asScopedNameVirtualReg(value.type).joinToString(".")
|
||||
asmgen.assignExpressionToVariable(value, varName, parameter.type)
|
||||
} else {
|
||||
val varName = asmgen.asmVariableName(sub.scopedName + "." + parameter.name)
|
||||
|
||||
@@ -924,7 +924,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
else
|
||||
argRegisters.add(FunctionCallArgs.ArgumentSpec(parameter.name, null, FunctionCallArgs.RegSpec(paramDt, tr.resultReg, null)))
|
||||
} else {
|
||||
require(parameter.register in Cx16VirtualRegisters) { "can only use R0-R15 'registers' here" }
|
||||
require(parameter.register in Cx16VirtualRegisters || parameter.register in CombinedLongRegisters) { "can only use R0-R15 'registers' here" }
|
||||
val regname = parameter.register!!.asScopedNameVirtualReg(parameter.type).joinToString(".")
|
||||
val assign = PtAssignment(fcall.position)
|
||||
val target = PtAssignTarget(false, fcall.position)
|
||||
|
||||
@@ -1934,7 +1934,7 @@ class IRCodeGen(
|
||||
result += IRSubroutine.IRParam(it.name, orig.dt)
|
||||
} else {
|
||||
val reg = it.register
|
||||
require(reg in Cx16VirtualRegisters) { "can only use R0-R15 'registers' here" }
|
||||
require(reg in Cx16VirtualRegisters || reg in CombinedLongRegisters) { "can only use R0-R15 'registers' here" }
|
||||
val regname = it.register!!.asScopedNameVirtualReg(it.type).joinToString(".")
|
||||
val targetVar = symbolTable.lookup(regname) as StMemVar
|
||||
result += IRSubroutine.IRParam(regname, targetVar.dt)
|
||||
|
||||
@@ -247,11 +247,15 @@ class VarConstantValueTypeAdjuster(
|
||||
dt.isLong -> {
|
||||
val value = functionCallExpr.args[0].constValue(program)?.number
|
||||
if(value!=null && value<0) {
|
||||
errors.err("expected unsigned or float numeric argument", functionCallExpr.args[0].position)
|
||||
errors.err("expected positive integer or float numeric argument", functionCallExpr.args[0].position)
|
||||
return noModifications
|
||||
}
|
||||
"sqrt__long"
|
||||
}
|
||||
dt.isSigned -> {
|
||||
errors.err("expected unsigned (positive) numeric argument", functionCallExpr.args[0].position)
|
||||
return noModifications
|
||||
}
|
||||
else -> {
|
||||
errors.err("expected numeric argument", functionCallExpr.args[0].position)
|
||||
return noModifications
|
||||
|
||||
@@ -584,12 +584,13 @@ internal class AstChecker(private val program: Program,
|
||||
// Instead, their reference (address) should be passed (as an UWORD).
|
||||
for(p in subroutine.parameters) {
|
||||
if (!subroutine.isAsmSubroutine && p.registerOrPair!=null) {
|
||||
if (p.registerOrPair !in Cx16VirtualRegisters) errors.err("can only use R0-R15 as register param for normal subroutines", p.position)
|
||||
if (p.registerOrPair !in Cx16VirtualRegisters && p.registerOrPair !in CombinedLongRegisters)
|
||||
errors.err("can only use R0-R15 as register param for normal subroutines", p.position)
|
||||
else {
|
||||
if(!compilerOptions.ignoreFootguns)
|
||||
errors.warn("\uD83D\uDCA3 footgun: reusing R0-R15 as parameters risks overwriting due to clobbering or no callstack", subroutine.position)
|
||||
if(!p.type.isWordOrByteOrBool && !p.type.isPointer) {
|
||||
errors.err("can only use register param when type is boolean, byte, word or pointer", p.position)
|
||||
if(!p.type.isInteger && !p.type.isBool && !p.type.isPointer) {
|
||||
errors.err("can only use register param when type is boolean, integer or pointer", p.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,8 +281,8 @@ class AstPreprocessor(val program: Program,
|
||||
registerParams
|
||||
.filter { it.name !in namesInSub && it.name !in existingAliases }
|
||||
.forEach {
|
||||
if (it.registerOrPair in Cx16VirtualRegisters) {
|
||||
if(it.type.isWordOrByteOrBool || it.type.isPointer) {
|
||||
if (it.registerOrPair in Cx16VirtualRegisters || it.registerOrPair in CombinedLongRegisters) {
|
||||
if(it.type.isInteger || it.type.isBool || it.type.isPointer) {
|
||||
val mappedParamVar = VarDecl.fromParameter(it)
|
||||
mods += IAstModification.InsertFirst(mappedParamVar, subroutine)
|
||||
} else {
|
||||
|
||||
@@ -337,6 +337,7 @@ main {
|
||||
sub start() {
|
||||
foo(42)
|
||||
bar(9999,55)
|
||||
bar2(9999999)
|
||||
}
|
||||
|
||||
sub foo(ubyte arg @R2) {
|
||||
@@ -346,14 +347,27 @@ main {
|
||||
sub bar(uword arg @R0, ubyte arg2 @R1) {
|
||||
arg += arg2
|
||||
}
|
||||
|
||||
sub bar2(long arg @R14R15) {
|
||||
arg++
|
||||
}
|
||||
}"""
|
||||
|
||||
val errors = ErrorReporterForTests(keepMessagesAfterReporting = true)
|
||||
compileText(C64Target(), false, src, outputDir, writeAssembly = false, errors = errors) shouldNotBe null
|
||||
compileText(C64Target(), false, src, outputDir, writeAssembly = true, errors = errors) shouldNotBe null
|
||||
errors.errors.size shouldBe 0
|
||||
errors.warnings.size shouldBe 2
|
||||
errors.warnings.size shouldBe 3
|
||||
errors.warnings[0] shouldContain "footgun"
|
||||
errors.warnings[1] shouldContain "footgun"
|
||||
errors.warnings[2] shouldContain "footgun"
|
||||
|
||||
errors.clear()
|
||||
compileText(VMTarget(), false, src, outputDir, writeAssembly = true, errors = errors) shouldNotBe null
|
||||
errors.errors.size shouldBe 0
|
||||
errors.warnings.size shouldBe 3
|
||||
errors.warnings[0] shouldContain "footgun"
|
||||
errors.warnings[1] shouldContain "footgun"
|
||||
errors.warnings[2] shouldContain "footgun"
|
||||
}
|
||||
|
||||
test("reg params R0-R15 cannot be used for invalid types") {
|
||||
|
||||
+1
-1
@@ -4,4 +4,4 @@ org.gradle.parallel=true
|
||||
org.gradle.daemon=true
|
||||
org.gradle.configuration-cache=false
|
||||
kotlin.code.style=official
|
||||
version=12.1.1
|
||||
version=12.2-SNAPSHOT
|
||||
|
||||
Reference in New Issue
Block a user