cminus/submit/RegisterAllocator.java

154 lines
3.7 KiB
Java

/*
*/
package submit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*
*
*
*/
public final class RegisterAllocator {
// True if t is used
private final boolean[] t = new boolean[10];
private final boolean[] s = new boolean[8];
private final Set<String> used = new HashSet<>();
public RegisterAllocator() { clearAll(); }
public String getRegisterOrLoadIntoRegister(MIPSResult result,
StringBuilder code) {
if (result.getRegister() != null) {
return result.getRegister();
}
String reg = result.getAddress();
return this.loadIntoRegister(result, code, reg);
}
public String loadIntoRegister(MIPSResult result, StringBuilder code,
String register) {
return loadIntoRegisterWithOffset(result, code, register, 0);
}
public String loadIntoRegisterWithOffset(MIPSResult result,
StringBuilder code, String register,
int offset) {
code.append(
String.format("lw %s %d(%s)\n", register, offset, result.getAddress()));
return register;
}
public String getT() {
for (int i = 0; i < t.length; ++i) {
if (!t[i]) {
t[i] = true;
String str = "$t" + i;
used.add(str);
return str;
}
}
return null;
}
// public String getS() {
// for (int i = 0; i < s.length; ++i) {
// if (!s[i]) {
// s[i] = true;
// String str = "$s" + i;
// used.add(str);
// return str;
// }
// }
// return null;
// }
// Returns the number of bytes used to save the registers
public int saveRestore(StringBuilder code, int baseOffset, boolean s_or_t,
boolean save) {
boolean[] r = s;
String prefix = "$s";
if (!s_or_t) {
r = t;
prefix = "$t";
}
String instruction = "sw";
if (!save) {
instruction = "lw";
}
int offset = 0;
for (int i = 0; i < r.length; ++i) {
if (r[i]) {
offset -= 4;
String str = prefix + i;
code.append(instruction)
.append(" ")
.append(str)
.append(" ")
.append(offset - baseOffset)
.append("($sp)\n");
}
}
return -offset;
}
// public int saveS(StringBuilder code, int baseOffset) {
// return saveRestore(code, baseOffset, true, true);
// }
public int saveT(StringBuilder code, int baseOffset) {
return saveRestore(code, baseOffset, false, true);
}
// public int restoreS(StringBuilder code, int baseOffset) {
// return saveRestore(code, baseOffset, true, false);
// }
public int restoreT(StringBuilder code, int baseOffset) {
return saveRestore(code, baseOffset, false, false);
}
public List<String> getUsed() { return new ArrayList<>(used); }
/**
* Any time you call this method you should seriously consider adding a
* corresponding clear() call.
*
* @return
*/
public String getAny() {
// String availS = getS();
// if (availS != null) {
// return availS;
// }
String t = getT();
if (t == null) {
throw new RuntimeException("Out of registers");
}
return t;
}
public void clear(String reg) {
if (reg == null)
return;
if (reg.charAt(1) == 's') {
s[Integer.parseInt(reg.substring(2))] = false;
} else if (reg.charAt(1) == 't') {
t[Integer.parseInt(reg.substring(2))] = false;
} else {
throw new RuntimeException("Unexpected register in clear");
}
}
public void clearAll() {
Arrays.fill(t, false);
Arrays.fill(s, false);
}
}