1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-03 07:29:37 +00:00

- Fixed a clobber test issue with alive variables that are in libraries (as parameters) and do not need a clobber test, as the library tested full clobber issues. The issue was fixed by not generating memory, zp or register usage for procedure parameters imported from .asm libraries.

This commit is contained in:
Sven Van de Velde 2023-12-16 19:12:57 +01:00
parent fa678aac3d
commit d75d96473c
5 changed files with 89 additions and 23 deletions

View File

@ -96,9 +96,10 @@ public class AsmLibrary extends AsmLine {
* @param param The variable to describe
* @param scope The scope (procedure)
* @param signature The signature to append to
* @param isStackCall true if the signature is for stack call.
* @return The version of the variable chosen
*/
Variable generateSignatureVar(Variable param, Scope scope, StringBuilder signature) {
Variable generateSignatureVar(Variable param, Scope scope, StringBuilder signature, boolean isStackCall) {
if (param == null) return param;
if (param.isKindPhiMaster()) {
List<Variable> versions = new ArrayList<>(scope.getVersions(param));
@ -114,21 +115,23 @@ public class AsmLibrary extends AsmLine {
return param;
}
Registers.Register allocation = param.getAllocation();
if (allocation instanceof Registers.RegisterZpMem) {
Registers.RegisterZpMem registerZp = (Registers.RegisterZpMem) allocation;
signature.append("__zp(").append(AsmFormat.getAsmNumber(registerZp.getZp())).append(") ");
} else if (allocation instanceof Registers.RegisterMainMem) {
Registers.RegisterMainMem registerMainMem = (Registers.RegisterMainMem) allocation;
signature.append("__mem(").append(registerMainMem.getAddress() == null ? "" : AsmFormat.getAsmNumber(registerMainMem.getAddress())).append(") ");
} else if (allocation instanceof Registers.RegisterAByte) {
signature.append("__register(A) ");
} else if (allocation instanceof Registers.RegisterXByte) {
signature.append("__register(X) ");
} else if (allocation instanceof Registers.RegisterYByte) {
signature.append("__register(Y) ");
} else if (allocation instanceof Registers.RegisterZByte) {
signature.append("__register(Z) ");
if(!isStackCall) {
Registers.Register allocation = param.getAllocation();
if (allocation instanceof Registers.RegisterZpMem) {
Registers.RegisterZpMem registerZp = (Registers.RegisterZpMem) allocation;
signature.append("__zp(").append(AsmFormat.getAsmNumber(registerZp.getZp())).append(") ");
} else if (allocation instanceof Registers.RegisterMainMem) {
Registers.RegisterMainMem registerMainMem = (Registers.RegisterMainMem) allocation;
signature.append("__mem(").append(registerMainMem.getAddress() == null ? "" : AsmFormat.getAsmNumber(registerMainMem.getAddress())).append(") ");
} else if (allocation instanceof Registers.RegisterAByte) {
signature.append("__register(A) ");
} else if (allocation instanceof Registers.RegisterXByte) {
signature.append("__register(X) ");
} else if (allocation instanceof Registers.RegisterYByte) {
signature.append("__register(Y) ");
} else if (allocation instanceof Registers.RegisterZByte) {
signature.append("__register(Z) ");
}
}
return param;
}
@ -139,13 +142,16 @@ public class AsmLibrary extends AsmLine {
* which can be __mem, __zp, __register for the procedure parameters and return value.
* Local variables, when allocated to __zp within the pre-compiled .asm library,
* are reserved using __zp_reserve directive.
* __stackcall procedures don't produce __mem, __zp, __register directives.
* @param procedure The procedure to generate the header for.
* @return A String with the generated function prototype.
*/
private String generateHeader(Procedure procedure) {
StringBuilder signature = new StringBuilder();
Procedure.CallingConvention callingConvention = procedure.getCallingConvention();
boolean isStackCall = callingConvention == Procedure.CallingConvention.STACK_CALL;
signature.append("extern ");
signature.append(procedure.getCallingConvention().getName()).append(" ");
signature.append(callingConvention.getName()).append(" ");
signature.append("__asm_import(\"").append(this.getName()).append("\") ");
// reserve used zero pages if any.
@ -161,13 +167,13 @@ public class AsmLibrary extends AsmLine {
}
signature.append(zp);
generateSignatureVar(procedure.getLocalVar("return"), procedure, signature);
generateSignatureVar(procedure.getLocalVar("return"), procedure, signature, isStackCall);
signature.append(procedure.getReturnType().toCDecl());
signature.append(" ").append(procedure.getLocalName()).append("(");
int i = 0;
for (Variable parameter : procedure.getParameters()) {
if (i++ > 0) signature.append(", ");
Variable param = generateSignatureVar(parameter, procedure, signature);
Variable param = generateSignatureVar(parameter, procedure, signature, isStackCall);
signature.append(param.getType().toCDecl(parameter.getLocalName()));
}
signature.append(");");

View File

@ -144,14 +144,14 @@ public class Pass4AssertNoCpuClobber extends Pass2Base {
}
// Non-assigned alive variables must not be clobbered
for(VariableRef aliveVar : aliveVars) {
Variable variable = getProgram().getSymbolInfos().getVariable(aliveVar);
for(VariableRef aliveVarRef : aliveVars) {
Variable variable = getProgram().getSymbolInfos().getVariable(aliveVarRef);
Registers.Register aliveVarRegister = variable.getAllocation();
if(aliveVarRegister.isMem()) {
// No need to check a zp-register - here we are only interested in CPU registers
continue;
}
if(assignedVars.contains(aliveVar)) {
if(assignedVars.contains(aliveVarRef)) {
// No need to register that is assigned by the statement - it will be clobbered
continue;
}
@ -160,7 +160,7 @@ public class Pass4AssertNoCpuClobber extends Pass2Base {
if(verbose) {
throw new CompileError(
"Error! Generated ASM has register clobber problem. " +
"Alive variable " + aliveVar + " register " + aliveVarRegister + " clobbered by the ASM generated by statement " + statement.toString(getProgram(), true),
"Alive variable " + aliveVarRef + " register " + aliveVarRegister + " clobbered by the ASM generated by statement " + statement.toString(getProgram(), true),
statement.getSource()
);
}

View File

@ -0,0 +1,32 @@
#pragma link("printf_lib.ld")
#pragma encoding(screencode_mixed)
#pragma var_model(mem)
#pragma asm_library
#pragma calling(__varcall)
#pragma asm_export(__printf_lib_start, conio_x16_init)
#pragma asm_export(clrscr)
#pragma asm_export(gotoxy)
#pragma asm_export(wherex, wherey)
#pragma asm_export(screensize, screensizex, screensizey, cputln )
#pragma asm_export(cputcxy, cputs, cputsxy, textcolor, bgcolor, bordercolor )
#pragma asm_export(kbhit, cursor, scroll )
#pragma asm_export(screenlayer1, screenlayer2)
#pragma asm_export(cpeekc, cpeekcxy)
#pragma asm_export(printf_str)
#pragma asm_export(printf_uint, printf_sint)
#pragma asm_export(printf_ulong, printf_slong)
#pragma asm_export(printf_uchar, printf_schar)
#pragma calling(__stackcall)
#pragma asm_export(cputc)
#pragma calling(__phicall)
#include <conio.h>
#include <printf.h>

View File

@ -0,0 +1,6 @@
#if __asm_import__
#else
.segmentdef Code [start=%P]
.segmentdef Data [startAfter="Code"]
#endif

View File

@ -0,0 +1,22 @@
#pragma encoding(screencode_mixed)
#include "printf_lib_asm.h"
#include <conio.h>
#include <printf.h>
#include <math.h>
void main() {
clrscr();
printf("embedded printf statements demonstration\n\n");
printf("char = %c\n", 'a');
printf("unsigned int = %u to %u\n", (unsigned int)0, (unsigned int)((1<<16)-1));
printf("signed int = %i to %i\n", (signed int)(-((1<<15))), (signed int)((1<<15)-1));
printf("unsigned long = %lu to %lu\n", (unsigned long)0, (unsigned long)1<<32-1);
printf("signed long = %li to %li\n", (signed long)-((1<<31)), (signed long)((1<<31)-1));
printf("unsigned char = %hhu to %hhu\n", (unsigned char)0, (unsigned char)((1<<8)-1));
printf("signed char = %hhi to %hhi\n", (signed char)-((1<<7)), (signed char)((1<<7)-1));
printf("pointer address = %p to %p", (char*)0, (char*)0xFFFF);
}