mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-07 07:29:49 +00:00
Implemented most of stack based parameter fetching inside procedures. #316
This commit is contained in:
parent
51d1e6f41f
commit
25742f1654
@ -35,7 +35,7 @@ public class CompileLog {
|
||||
/**
|
||||
* Should Memory usage be verbose
|
||||
*/
|
||||
private boolean verboseMemoryUsage = false;
|
||||
private boolean verboseSizeInfo = false;
|
||||
|
||||
/**
|
||||
* Should loop unrolling be verbose.
|
||||
@ -101,17 +101,17 @@ public class CompileLog {
|
||||
return log;
|
||||
}
|
||||
|
||||
public CompileLog verboseMemoryUsage() {
|
||||
setVerboseMemoryUsage(true);
|
||||
public CompileLog verboseSizeInfo() {
|
||||
setVerboseSizeInfo(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isVerboseMemoryUsage() {
|
||||
return verboseMemoryUsage;
|
||||
public boolean isVerboseSizeInfo() {
|
||||
return verboseSizeInfo;
|
||||
}
|
||||
|
||||
public void setVerboseMemoryUsage(boolean verboseMemoryUsage) {
|
||||
this.verboseMemoryUsage = verboseMemoryUsage;
|
||||
public void setVerboseSizeInfo(boolean verboseSizeInfo) {
|
||||
this.verboseSizeInfo = verboseSizeInfo;
|
||||
}
|
||||
|
||||
public CompileLog verboseSsaSourceCode() {
|
||||
|
@ -321,7 +321,7 @@ public class Compiler {
|
||||
|
||||
private void pass2Optimize() {
|
||||
|
||||
if(getLog().isVerboseMemoryUsage()) {
|
||||
if(getLog().isVerboseSizeInfo()) {
|
||||
getLog().append(program.getSizeInfo());
|
||||
}
|
||||
|
||||
@ -373,7 +373,7 @@ public class Compiler {
|
||||
|
||||
private void pass2InlineConstants() {
|
||||
|
||||
if(getLog().isVerboseMemoryUsage()) {
|
||||
if(getLog().isVerboseSizeInfo()) {
|
||||
getLog().append(program.getSizeInfo());
|
||||
}
|
||||
|
||||
@ -445,7 +445,7 @@ public class Compiler {
|
||||
|
||||
private void pass3Analysis() {
|
||||
|
||||
if(getLog().isVerboseMemoryUsage()) {
|
||||
if(getLog().isVerboseSizeInfo()) {
|
||||
getLog().append(program.getSizeInfo());
|
||||
}
|
||||
|
||||
@ -485,6 +485,10 @@ public class Compiler {
|
||||
new PassNBlockSequencePlanner(program).step();
|
||||
new Pass3AddNopBeforeCallOns(program).generate();
|
||||
new PassNStatementIndices(program).execute();
|
||||
|
||||
// Handle calling convention stack
|
||||
new PassNCallingConventionStack(program).execute();
|
||||
|
||||
program.clearCallGraph();
|
||||
program.clearStatementInfos();
|
||||
program.clearVariableReferenceInfos();
|
||||
@ -499,7 +503,7 @@ public class Compiler {
|
||||
|
||||
private void pass4RegisterAllocation() {
|
||||
|
||||
if(getLog().isVerboseMemoryUsage()) {
|
||||
if(getLog().isVerboseSizeInfo()) {
|
||||
getLog().append(program.getSizeInfo());
|
||||
}
|
||||
|
||||
@ -554,7 +558,7 @@ public class Compiler {
|
||||
} while(change);
|
||||
getLog().append(program.getRegisterPotentials().toString());
|
||||
|
||||
if(getLog().isVerboseMemoryUsage()) {
|
||||
if(getLog().isVerboseSizeInfo()) {
|
||||
getLog().append(program.getSizeInfo());
|
||||
}
|
||||
|
||||
|
@ -90,8 +90,8 @@ public class KickC implements Callable<Void> {
|
||||
@CommandLine.Option(names = {"-voptimize"}, description = "Verbosity Option. Control Flow Graph Optimization.")
|
||||
private boolean verboseSSAOptimize = false;
|
||||
|
||||
@CommandLine.Option(names = {"-vmemory"}, description = "Verbosity Option. Compiler Data Structure Sizes.")
|
||||
private boolean verboseMemory = false;
|
||||
@CommandLine.Option(names = {"-vsizeinfo"}, description = "Verbosity Option. Compiler Data Structure Size Information.")
|
||||
private boolean verboseSizeInfo = false;
|
||||
|
||||
@CommandLine.Option(names = {"-vnonoptimize"}, description = "Verbosity Option. Choices not to optimize.")
|
||||
private boolean verboseNonOptimization = false;
|
||||
@ -380,8 +380,8 @@ public class KickC implements Callable<Void> {
|
||||
compiler.getLog().setVerboseSSAOptimize(true);
|
||||
compiler.getLog().setSysOut(true);
|
||||
}
|
||||
if(verboseMemory) {
|
||||
compiler.getLog().setVerboseMemoryUsage(true);
|
||||
if(verboseSizeInfo) {
|
||||
compiler.getLog().setVerboseSizeInfo(true);
|
||||
compiler.getLog().setSysOut(true);
|
||||
}
|
||||
if(verboseNonOptimization) {
|
||||
|
@ -233,7 +233,6 @@ public class AsmFragmentInstanceSpecFactory {
|
||||
* @return The bound name of the value. If the value has already been bound the existing bound name is returned.
|
||||
*/
|
||||
public String bind(Value value, SymbolType castType) {
|
||||
|
||||
if(value instanceof CastValue) {
|
||||
CastValue cast = (CastValue) value;
|
||||
SymbolType toType = cast.getToType();
|
||||
@ -357,8 +356,11 @@ public class AsmFragmentInstanceSpecFactory {
|
||||
String name = "la" + nextLabelIdx++;
|
||||
bind(name, value);
|
||||
return name;
|
||||
} else if(value instanceof ParamStackValue) {
|
||||
// TODO: Handle different parameter types!
|
||||
return "_stackbyte_"+bind(((ParamStackValue) value).getStackOffset());
|
||||
}
|
||||
throw new RuntimeException("Binding of value type not supported " + value);
|
||||
throw new RuntimeException("Binding of value type not supported " + value.toString(program));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -775,6 +775,26 @@ public interface ProgramValue {
|
||||
|
||||
}
|
||||
|
||||
/** Value inside a parameter stack value . */
|
||||
class ProgramValueParamStackValue implements ProgramValue {
|
||||
private final ParamStackValue paramValue;
|
||||
|
||||
ProgramValueParamStackValue(ParamStackValue paramValue) {
|
||||
this.paramValue = paramValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value get() {
|
||||
return paramValue.getStackOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Value val) {
|
||||
paramValue.setStackOffset((ConstantRef) val);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pointer inside a pointer derefence value.
|
||||
*/
|
||||
|
@ -236,6 +236,8 @@ public class ProgramValueIterator {
|
||||
subValues.add(new ProgramValue.ProgramValueLValueIntermediateVariable((LvalueIntermediate) value));
|
||||
} else if(value instanceof ParamValue) {
|
||||
subValues.add(new ProgramValue.ProgramValueParamValue((ParamValue) value));
|
||||
} else if(value instanceof ParamStackValue) {
|
||||
subValues.add(new ProgramValue.ProgramValueParamStackValue((ParamStackValue) value));
|
||||
} else if(value == null ||
|
||||
value instanceof VariableRef ||
|
||||
value instanceof VariableVersion ||
|
||||
|
@ -116,6 +116,8 @@ public class SymbolTypeInference {
|
||||
return ((StructZero)rValue).getTypeStruct();
|
||||
} else if(rValue instanceof ParamValue) {
|
||||
return inferType(symbols, ((ParamValue) rValue).getParameter());
|
||||
} else if(rValue instanceof ParamStackValue) {
|
||||
return SymbolType.BYTE;
|
||||
} else if(rValue instanceof StructUnwoundPlaceholder) {
|
||||
return ((StructUnwoundPlaceholder) rValue).getTypeStruct();
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ public class SymbolTypeStruct implements SymbolType {
|
||||
} else {
|
||||
return memberType.getSizeBytes();
|
||||
}
|
||||
throw new InternalError("Memeber type not handled "+memberType);
|
||||
throw new InternalError("Member type not handled "+memberType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,28 @@
|
||||
package dk.camelot64.kickc.model.values;
|
||||
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
|
||||
/** The value passed into a function for a specific parameter using the stack. */
|
||||
public class ParamStackValue implements RValue {
|
||||
|
||||
/** The constant holding the stack offset of the parameter. */
|
||||
private ConstantRef stackOffset;
|
||||
|
||||
public ParamStackValue(ConstantRef stackOffset) {
|
||||
this.stackOffset = stackOffset;
|
||||
}
|
||||
|
||||
public ConstantRef getStackOffset() {
|
||||
return stackOffset;
|
||||
}
|
||||
|
||||
public void setStackOffset(ConstantRef stackOffset) {
|
||||
this.stackOffset = stackOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Program program) {
|
||||
return "paramstack("+stackOffset+")";
|
||||
}
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ import dk.camelot64.kickc.model.Program;
|
||||
public class ParamValue implements RValue {
|
||||
|
||||
/** The (unversioned) parameter variable. */
|
||||
VariableRef parameter;
|
||||
private VariableRef parameter;
|
||||
|
||||
public ParamValue(VariableRef parameter) {
|
||||
this.parameter = parameter;
|
||||
|
@ -0,0 +1,104 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.symbols.*;
|
||||
import dk.camelot64.kickc.model.types.SymbolType;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** Handle calling convention {@link Procedure.CallingConvension#STACK_CALL} by converting the making control flow graph and symbols calling convention specific. */
|
||||
public class PassNCallingConventionStack extends Pass2SsaOptimization {
|
||||
|
||||
public PassNCallingConventionStack(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
// Offset-constants for all stack-call parameters
|
||||
Map<VariableRef, ConstantRef> offsetConstants = new HashMap<>();
|
||||
|
||||
// Introduce STACK_OFFSET constants
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
if(Procedure.CallingConvension.STACK_CALL.equals(procedure.getCallingConvension())) {
|
||||
for(Variable parameter : procedure.getParameters()) {
|
||||
ConstantRef parameterOffsetConstant = getParameterOffsetConstant(procedure, parameter, getScope());
|
||||
offsetConstants.put(parameter.getRef(), parameterOffsetConstant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Add global STACK_BASE constant
|
||||
|
||||
if(offsetConstants.size() > 0) {
|
||||
// Convert ParamValue to ParamStackValue
|
||||
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {
|
||||
if(programValue.get() instanceof ParamValue) {
|
||||
// Convert ParamValues to calling-convention specific param-value
|
||||
ParamValue paramValue = (ParamValue) programValue.get();
|
||||
VariableRef parameterRef = paramValue.getParameter();
|
||||
if(offsetConstants.containsKey(parameterRef)) {
|
||||
ParamStackValue paramStackValue = new ParamStackValue(offsetConstants.get(parameterRef));
|
||||
programValue.set(paramStackValue);
|
||||
getLog().append("Calling convention " + Procedure.CallingConvension.STACK_CALL + " replacing " + paramValue.toString(getProgram()) + " with " + paramStackValue.toString(getProgram()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the constant variable containing the (byte) index of a parameter on the stack
|
||||
*
|
||||
* @param procedure The procedure
|
||||
* @param procedure The parameter
|
||||
* @param programScope The program scope (used for finding/adding the constant).
|
||||
* @return The constant variable
|
||||
*/
|
||||
public static ConstantRef getParameterOffsetConstant(Procedure procedure, Variable parameter, ProgramScope programScope) {
|
||||
String paramOffsetConstantName = getParameterOffsetConstantName(parameter.getName());
|
||||
ConstantVar paramOffsetConstant = procedure.getConstant(paramOffsetConstantName);
|
||||
if(paramOffsetConstant == null) {
|
||||
// Constant not found - create it
|
||||
long paramByteOffset = getParameterByteOffset(procedure, parameter, programScope);
|
||||
paramOffsetConstant = new ConstantVar(paramOffsetConstantName, procedure, SymbolType.BYTE, new ConstantInteger(paramByteOffset & 0xff, SymbolType.BYTE), Scope.SEGMENT_DATA_DEFAULT);
|
||||
procedure.add(paramOffsetConstant);
|
||||
}
|
||||
return paramOffsetConstant.getRef();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the constant variable containing the (byte) offset of a specific parameter on the stack
|
||||
*
|
||||
* @param parameterName The name of the struct member
|
||||
* @return The name of the constant
|
||||
*/
|
||||
private static String getParameterOffsetConstantName(String parameterName) {
|
||||
// TODO: Maybe use asmName?
|
||||
return "OFFSET_STACK_" + parameterName.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bytes that a parameter is offset on the stack
|
||||
*
|
||||
* @param parameter The parameter to find offset for
|
||||
* @return The byte offset of the start of the member data
|
||||
*/
|
||||
public static long getParameterByteOffset(Procedure procedure, Variable parameter, ProgramScope programScope) {
|
||||
long byteOffset = 0;
|
||||
for(Variable procedureParameter : procedure.getParameters()) {
|
||||
if(parameter.equals(procedureParameter)) {
|
||||
break;
|
||||
} else {
|
||||
// TODO: Consider hos passing a struct should handle inline arrays byteOffset += SymbolTypeStruct.getMemberSizeBytes(parameter.getType(), programScope);
|
||||
byteOffset += parameter.getType().getSizeBytes();
|
||||
}
|
||||
}
|
||||
return byteOffset;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user