1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-02-07 20:31:32 +00:00

Fixed exception when using a return value from a VOID function. Added proper error message when printf() is missing parameters referenced in the format string.

This commit is contained in:
jespergravgaard 2020-05-03 13:59:48 +02:00
parent dbbde914c7
commit f7f9ef4a6c
6 changed files with 116 additions and 6 deletions

View File

@ -322,6 +322,7 @@ public class Compiler {
getLog().append(program.getProcedureModifiedVars().toString(program));
}
new Pass1CallVoidReturns(program).execute();
new Pass1CallStack(program).execute();
new Pass1CallPhiParameters(program).execute();
//getLog().append("PROCEDURE PARAMETERS");

View File

@ -0,0 +1,65 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.VariableReferenceInfos;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.ProcedureRef;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.Collection;
/** Remove temporary variables assigned any void return value */
public class Pass1CallVoidReturns extends Pass2SsaOptimization {
public Pass1CallVoidReturns(Program program) {
super(program);
}
@Override
public boolean step() {
new PassNStatementIndices(getProgram()).execute();
getProgram().clearVariableReferenceInfos();
VariableReferenceInfos referenceInfos = getProgram().getVariableReferenceInfos();
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
for(Statement statement : block.getStatements()) {
if(statement instanceof StatementCall) {
final ProcedureRef procedureRef = ((StatementCall) statement).getProcedure();
final Procedure procedure = getScope().getProcedure(procedureRef);
if(SymbolType.VOID.equals(procedure.getReturnType())) {
// Found a call to a VOID returning procedure
final LValue lValue = ((StatementCall) statement).getlValue();
if(lValue instanceof VariableRef) {
VariableRef tmpVar = (VariableRef) lValue;
final Collection<Integer> usages = referenceInfos.getVarUseStatements(tmpVar);
if(usages.size() > 0) {
final Integer usageIdx = usages.iterator().next();
final Statement usage = getProgram().getStatementInfos().getStatement(usageIdx);
throw new CompileError("Error! Function " + procedure.getLocalName() + " does not return a value! ", usage);
} else {
// Delete the temporary variable
final Variable var = getScope().getVar(tmpVar);
var.getScope().remove(var);
// And remove the lValue
((StatementCall) statement).setlValue(null);
if(getLog().isVerbosePass1CreateSsa())
getLog().append("Removing LValue from call to function returning void");
}
}
}
}
}
}
getProgram().clearStatementIndices();
getProgram().clearVariableReferenceInfos();
return false;
}
}

View File

@ -62,7 +62,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
if(statement instanceof StatementCall && ((StatementCall) statement).getProcedureName().equals(INTRINSIC_PRINTF_NAME)) {
StatementCall printfCall = (StatementCall) statement;
final List<RValue> parameters = printfCall.getParameters();
final RValue formatParameter = parameters.get(0);
final RValue formatParameter = getParameterValue(parameters, 0, printfCall);
if(!(formatParameter instanceof ConstantValue))
throw new CompileError("Error! Only constant printf() format parameter supported!", statement);
final ConstantLiteral formatLiteral = ((ConstantValue) formatParameter).calculateLiteral(getProgram().getScope());
@ -138,7 +138,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
new ConstantInteger(width, SymbolType.BYTE),
new ConstantInteger(leftJustify, SymbolType.BYTE)
));
addPrintfCall(PRINTF_STRING, Arrays.asList(parameters.get(paramIdx), format_string_struct), stmtIt, printfCall);
addPrintfCall(PRINTF_STRING, Arrays.asList(getParameterValue(parameters, paramIdx, printfCall), format_string_struct), stmtIt, printfCall);
paramIdx++;
} else if("diuxXo".contains(typeField)) {
// A formatted integer
@ -174,7 +174,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
if(lengthField == null) {
// Check if the parameter type is 8-bit or 32-bit
RValue paramValue = parameters.get(paramIdx);
RValue paramValue = getParameterValue(parameters, paramIdx, printfCall);
SymbolType paramType = SymbolTypeInference.inferType(getScope(), paramValue);
if(SymbolType.BYTE.equals(paramType) || SymbolType.SBYTE.equals(paramType)) {
// Integer (8bit)
@ -214,11 +214,11 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
new ConstantInteger(upperCase, SymbolType.BYTE),
radix
));
addPrintfCall(printf_number_procedure, Arrays.asList(parameters.get(paramIdx), format_number_struct), stmtIt, printfCall);
addPrintfCall(printf_number_procedure, Arrays.asList(getParameterValue(parameters, paramIdx, printfCall), format_number_struct), stmtIt, printfCall);
paramIdx++;
} else if(typeField.equals("c")) {
// Print char
addPrintfCall(PRINTF_CHAR, Arrays.asList(parameters.get(paramIdx)), stmtIt, printfCall);
addPrintfCall(PRINTF_CHAR, Arrays.asList(getParameterValue(parameters, paramIdx, printfCall)), stmtIt, printfCall);
paramIdx++;
} else if(typeField.equals("p")) {
// Print a pointer
@ -231,7 +231,7 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
new ConstantInteger(upperCase, SymbolType.BYTE),
getScope().getLocalConstant(HEXADECIMAL).getRef()
));
addPrintfCall(PRINTF_UINT, Arrays.asList(new CastValue(SymbolType.WORD, parameters.get(paramIdx)), format_number_struct), stmtIt, printfCall);
addPrintfCall(PRINTF_UINT, Arrays.asList(new CastValue(SymbolType.WORD, getParameterValue(parameters, paramIdx, printfCall)), format_number_struct), stmtIt, printfCall);
paramIdx++;
}
}
@ -245,6 +245,21 @@ public class Pass1PrintfIntrinsicRewrite extends Pass2SsaOptimization {
return false;
}
/**
* Get a specific parameter value.
* @param parameters The list of parameters
* @param paramIdx The index of the parameter to get
* @param printfCall The printf call statement used for errors
* @return The parameter value.
*
* @throws CompileError if the parameter is not present
*/
private RValue getParameterValue(List<RValue> parameters, int paramIdx, StatementCall printfCall) {
if(parameters.size()<=paramIdx)
throw new CompileError("Error! printf missing parameter with index "+paramIdx, printfCall);
return parameters.get(paramIdx);
}
/**
* Adds a call to a PRINTF sub-function.
*

View File

@ -57,6 +57,11 @@ public class TestPrograms {
compileAndCompare("multiply-1.c");
}
@Test
public void testDoubleCallProblem() throws IOException, URISyntaxException {
assertError("double-call-problem.c", "Error! Function clrscr does not return a value! ");
}
@Test
public void testStructPointerToMember2() throws IOException, URISyntaxException {
compileAndCompare("struct-pointer-to-member-2.c");
@ -97,6 +102,11 @@ public class TestPrograms {
compileAndCompare("toupper-1.c");
}
@Test
public void testPrintfError6() throws IOException, URISyntaxException {
assertError("printf-error-6.c", "Error! printf missing parameter with index 1");
}
@Test
public void testPrintfError5() throws IOException, URISyntaxException {
assertError("printf-error-5.c", "Error! printf() format parameter must be a string!");

View File

@ -0,0 +1,10 @@
// Demonstrates problem with a double call not being detected as a type error
void main() {
clrscr()();
}
void clrscr(void) {
char * const SCREEN = 0x0400;
SCREEN[0] = '@';
}

View File

@ -0,0 +1,9 @@
// Tests printf function call rewriting
// To few parameters
#include <printf.h>
void main() {
printf("%d");
}