mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-06-02 00:41:42 +00:00
Consolidate string constants per segment. If the same string is defined within 2 different segments, then this constant will be allocated in memory in the asm under each data segment.
This commit is contained in:
parent
adb93aa3a0
commit
84d2715e34
|
@ -11,7 +11,11 @@ import dk.camelot64.kickc.model.values.*;
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Compiler Pass finding and consolidating identical constant strings
|
||||
* Compiler Pass finding and consolidating identical constant strings.
|
||||
* The term "root" refers to the consolidated string that will actually result in a declaration
|
||||
* in the assembler. The children will point to this declared root.
|
||||
* The string consolidation will act for each data segment independently.
|
||||
* So a program with multiple data segments will have multiple string consolidated roots.
|
||||
*/
|
||||
public class Pass2ConstantStringConsolidation extends Pass2SsaOptimization {
|
||||
|
||||
|
@ -58,69 +62,83 @@ public class Pass2ConstantStringConsolidation extends Pass2SsaOptimization {
|
|||
*/
|
||||
private boolean handleDuplicateConstantString(List<Variable> constantVars, ConstantString constString) {
|
||||
boolean modified = false;
|
||||
// Look for a constant in the root scope - or check if they are all in the same scope
|
||||
Variable rootConstant = null;
|
||||
boolean isCommonScope = true;
|
||||
ScopeRef commonScope = null;
|
||||
String segmentData = null;
|
||||
Map<String, List<Variable>> segmentDataMap = new LinkedHashMap<>();
|
||||
for(Variable constantVar : constantVars) {
|
||||
ScopeRef constScope = constantVar.getScope().getRef();
|
||||
segmentData = constantVar.getDataSegment();
|
||||
if(constScope.equals(ScopeRef.ROOT)) {
|
||||
rootConstant = constantVar;
|
||||
break;
|
||||
}
|
||||
if(commonScope == null) {
|
||||
commonScope = constScope;
|
||||
} else {
|
||||
if(!commonScope.equals(constScope)) {
|
||||
// Found two different scopes
|
||||
isCommonScope = false;
|
||||
}
|
||||
String segmentData = constantVar.getDataSegment();
|
||||
if(segmentData!= null && !segmentDataMap.containsKey(segmentData)) {
|
||||
segmentDataMap.put(segmentData, new LinkedList<Variable>());
|
||||
}
|
||||
List<Variable> constantVarsSegmentData = segmentDataMap.get(segmentData);
|
||||
constantVarsSegmentData.add(constantVar);
|
||||
}
|
||||
for(String segmentData : segmentDataMap.keySet()) {
|
||||
List<Variable> constantVarsSegmentData = segmentDataMap.get(segmentData);
|
||||
// Look for a constant in the root scope - or check if they are all in the same scope
|
||||
boolean modifiedSegment = false;
|
||||
Variable rootConstant = null;
|
||||
boolean isCommonScope = true;
|
||||
ScopeRef commonScope = null;
|
||||
for(Variable constantVar : constantVarsSegmentData) {
|
||||
if (constantVar.getDataSegment().equals(segmentData)) {
|
||||
ScopeRef constScope = constantVar.getScope().getRef();
|
||||
if (constScope.equals(ScopeRef.ROOT)) {
|
||||
rootConstant = constantVar;
|
||||
break;
|
||||
}
|
||||
if (commonScope == null) {
|
||||
commonScope = constScope;
|
||||
} else {
|
||||
if (!commonScope.equals(constScope)) {
|
||||
// Found two different scopes
|
||||
isCommonScope = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(String keySegmentData : segmentDataMap.keySet()) {
|
||||
List<Variable> constantVarsSegmentData = segmentDataMap.get(keySegmentData);
|
||||
if (rootConstant == null) {
|
||||
if (isCommonScope) {
|
||||
// If all constants are in the same scope pick the first one as root
|
||||
rootConstant = constantVarsSegmentData.get(0);
|
||||
} else {
|
||||
// Create a new root - and roll around again
|
||||
ProgramScope rootScope = getProgramScope();
|
||||
String localName = keySegmentData + getRootName(constantVars);
|
||||
final long stringLength = constString.getStringLength();
|
||||
final ConstantInteger arraySize = new ConstantInteger(stringLength, stringLength < 256 ? SymbolType.BYTE : SymbolType.WORD);
|
||||
Variable newRootConstant = Variable.createConstant(localName, new SymbolTypePointer(SymbolType.BYTE, new ArraySpec(arraySize), false, false), rootScope, constString, segmentData);
|
||||
rootScope.add(newRootConstant);
|
||||
rootConstant = newRootConstant;
|
||||
if (rootConstant == null) {
|
||||
if (isCommonScope) {
|
||||
// If all constants are in the same scope pick the first one as root
|
||||
rootConstant = constantVarsSegmentData.get(0);
|
||||
} else {
|
||||
// Create a new root - and roll around again
|
||||
ProgramScope rootScope = getProgramScope();
|
||||
String localName = getRootName(constantVars, segmentData);
|
||||
final long stringLength = constString.getStringLength();
|
||||
final ConstantInteger arraySize = new ConstantInteger(stringLength, stringLength < 256 ? SymbolType.BYTE : SymbolType.WORD);
|
||||
Variable newRootConstant = Variable.createConstant(localName, new SymbolTypePointer(SymbolType.BYTE, new ArraySpec(arraySize), false, false), rootScope, constString, segmentData);
|
||||
rootScope.add(newRootConstant);
|
||||
rootConstant = newRootConstant;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Modify all other constants to be references to the root constant
|
||||
for (Variable constantVar : constantVars) {
|
||||
if (!constantVar.equals(rootConstant)) {
|
||||
constantVar.setInitValue(new ConstantRef(rootConstant));
|
||||
modified = true;
|
||||
if(constantVar.getDataSegment().equals(segmentData)) {
|
||||
if (!constantVar.equals(rootConstant)) {
|
||||
constantVar.setInitValue(new ConstantRef(rootConstant));
|
||||
modifiedSegment = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(modified) {
|
||||
getLog().append("Consolidated constant strings into " + rootConstant);
|
||||
if(modifiedSegment) {
|
||||
getLog().append("Consolidated constant strings into " + rootConstant);
|
||||
}
|
||||
modified |= modifiedSegment;
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
private String getRootName(List<Variable> constantVars) {
|
||||
private String getRootName(List<Variable> constantVars, String segmentData) {
|
||||
String constName = null;
|
||||
// Try all variables with non-intermediate names
|
||||
for(Variable constantVar : constantVars) {
|
||||
if(!constantVar.getRef().isIntermediate()) {
|
||||
String candidateName = constantVar.getLocalName();
|
||||
if(getProgramScope().getLocalSymbol(candidateName) == null) {
|
||||
if(constName == null || constName.length() > candidateName.length()) {
|
||||
constName = candidateName;
|
||||
if(constantVar.getDataSegment().equals(segmentData)) {
|
||||
if (!constantVar.getRef().isIntermediate()) {
|
||||
String candidateName = constantVar.getLocalName();
|
||||
if (getProgramScope().getLocalSymbol(candidateName) == null) {
|
||||
if (constName == null || constName.length() > candidateName.length()) {
|
||||
constName = candidateName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +149,7 @@ public class Pass2ConstantStringConsolidation extends Pass2SsaOptimization {
|
|||
// Try string_nn until an unused name is found
|
||||
int i = 0;
|
||||
do {
|
||||
String candidateName = "string_" + i;
|
||||
String candidateName = "string_" + i + "_" + segmentData;
|
||||
if(getProgramScope().getLocalSymbol(candidateName) == null) {
|
||||
return candidateName;
|
||||
}
|
||||
|
|
|
@ -4029,6 +4029,12 @@ public class TestProgramsFast extends TestPrograms {
|
|||
compileAndCompare("uninitialized.c");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testStringConstConsolidationRootSegments() throws IOException {
|
||||
compileAndCompare("string-const-consolidation-root-segments.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringConstConsolidationNoRoot() throws IOException {
|
||||
compileAndCompare("string-const-consolidation-noroot.c");
|
||||
|
|
Loading…
Reference in New Issue
Block a user