net.sandius.rembulan.compiler.analysis.SlotAllocator Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2016 Miroslav Janíček
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sandius.rembulan.compiler.analysis;
import net.sandius.rembulan.compiler.IRFunc;
import net.sandius.rembulan.compiler.ir.*;
import net.sandius.rembulan.util.Check;
import java.util.*;
public class SlotAllocator {
private final IRFunc fn;
private final Map valSlots;
private final Map varSlots;
private IRNode currentNode;
public SlotAllocator(IRFunc fn) {
this.fn = Check.notNull(fn);
this.valSlots = new HashMap<>();
this.varSlots = new HashMap<>();
}
public static SlotAllocInfo allocateSlots(IRFunc fn) {
SlotAllocator allocator = new SlotAllocator(fn);
return allocator.process();
}
private IRNode node() {
if (currentNode == null) {
throw new IllegalStateException("Current node is null");
}
return currentNode;
}
private boolean hasSlot(Var v) {
return varSlots.get(Check.notNull(v)) != null;
}
private boolean hasSlot(AbstractVal v) {
return valSlots.get(Check.notNull(v)) != null;
}
private int slotOf(Var v) {
Check.notNull(v);
Integer idx = varSlots.get(v);
if (idx == null) {
throw new NoSuchElementException("Slot not defined for variable " + v);
}
else {
return idx;
}
}
private int slotOf(AbstractVal v) {
Check.notNull(v);
Integer idx = valSlots.get(v);
if (idx == null) {
throw new NoSuchElementException("Slot not defined for value " + v);
}
else {
return idx;
}
}
private BitSet occupiedSlots(LivenessInfo liveness, IRNode node) {
BitSet occupied = new BitSet();
LivenessInfo.Entry e = liveness.entry(node);
for (Var v : e.inVar()) {
int idx = slotOf(v);
if (occupied.get(idx)) {
throw new IllegalStateException("Slot " + idx + " already occupied");
}
if (e.outVar().contains(v)) {
occupied.set(slotOf(v));
}
}
for (AbstractVal v : e.inVal()) {
int idx = slotOf(v);
if (occupied.get(idx)) {
throw new IllegalStateException("Slot " + idx + " already occupied");
}
if (e.outVal().contains(v)) {
occupied.set(slotOf(v));
}
}
return occupied;
}
private int findFreeSlot(LivenessInfo liveness, IRNode node) {
BitSet occupied = occupiedSlots(liveness, node);
int idx = 0;
while (occupied.get(idx)) {
idx++;
}
assert (!occupied.get(idx));
return idx;
}
private void assignParamSlots(List params) {
int idx = 0;
for (Var v : params) {
varSlots.put(v, idx++);
}
}
private void assignSlot(Var v, LivenessInfo liveness, IRNode node) {
if (hasSlot(v)) {
throw new IllegalStateException("Slot already assigned for variable " + v);
}
varSlots.put(v, findFreeSlot(liveness, node));
}
private void assignSlot(AbstractVal v, LivenessInfo liveness, IRNode node) {
if (hasSlot(v)) {
throw new IllegalStateException("Slot already assigned for value " + v);
}
valSlots.put(v, findFreeSlot(liveness, node));
}
public SlotAllocInfo process() {
LivenessInfo liveness = LivenessAnalyser.computeLiveness(fn);
Set