Skip to content

Commit 7d487e3

Browse files
bors[bot]vext01
andauthored
88: Don't assume that there is a 1-1 mapping between LLVM an Yk IR instructions. r=ltratt a=vext01 Co-authored-by: Edd Barrett <[email protected]>
2 parents cdf6ef5 + 8b2bba4 commit 7d487e3

File tree

1 file changed

+70
-26
lines changed

1 file changed

+70
-26
lines changed

llvm/lib/YkIR/YkIRWriter.cpp

+70-26
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,36 @@ template <class C, class E> size_t getIndex(C *Container, E *FindElement) {
8383
return Idx;
8484
}
8585

86-
#define GENERIC_INST_SERIALISE(LLVM_INST, LLVM_INST_TYPE, YKIR_OPCODE) \
87-
if (isa<LLVM_INST_TYPE>(LLVM_INST)) { \
88-
serialiseInstGeneric(LLVM_INST, YKIR_OPCODE); \
89-
return; \
90-
}
86+
// A <BBIdx, InstrIdx> pair that Uniquely identifies an Yk IR instruction within
87+
// a function.
88+
using InstrLoc = std::tuple<size_t, size_t>;
89+
90+
// Maps an LLVM instruction that generates a value to the corresponding Yk IR
91+
// instruction.
92+
using ValueLoweringMap = map<Instruction *, InstrLoc>;
9193

94+
// The class responsible for serialising our IR into the interpreter binary.
95+
//
96+
// It walks over the LLVM IR, lowering each function, block, instruction, etc.
97+
// into a Yk IR equivalent.
98+
//
99+
// As it does this there are some invariants that must be maintained:
100+
//
101+
// - The current basic block index (BBIdx) is passed down the lowering process.
102+
// This must be incremented each time we finish a Yk IR basic block.
103+
//
104+
// - Similarly for instructions. Each time we finish a Yk IR instruction,
105+
// we must increment the current instruction index (InstIdx).
106+
//
107+
// - When we are done lowering an LLVM instruction that generates a value, we
108+
// must update the `VLMap` with an entry that maps the LLVM instruction to
109+
// the final Yk IR instruction in the lowering. If the LLVM instruction
110+
// doesn't generate a value, or the LLVM instruction lowered to exactly zero
111+
// Yk IR instructions, then there is no need to update the `VLMap`.
112+
//
113+
// These invariants are required so that when we encounter a local variable as
114+
// an operand to an LLVM instruction, we can quickly find the corresponding Yk
115+
// IR local variable.
92116
class YkIRWriter {
93117
private:
94118
Module &M;
@@ -139,18 +163,10 @@ class YkIRWriter {
139163
OutStreamer.emitSizeT(constantIndex(C));
140164
}
141165

142-
void serialiseLocalVariableOperand(Instruction *I) {
143-
// For now we assume that there is a one to one relationship between LLVM
144-
// instructions and Yk IR instructions, and that the instruction
145-
// (and block) indices are the same in both IRs.
146-
BasicBlock *ParentBlock = I->getParent();
147-
Function *ParentFunc = ParentBlock->getParent();
148-
149-
size_t BlockIdx = getIndex(ParentFunc, ParentBlock);
150-
size_t InstIdx = getIndex(ParentBlock, I);
151-
166+
void serialiseLocalVariableOperand(Instruction *I, ValueLoweringMap &VLMap) {
167+
auto [BBIdx, InstIdx] = VLMap.at(I);
152168
OutStreamer.emitInt8(OperandKind::LocalVariable);
153-
OutStreamer.emitSizeT(BlockIdx);
169+
OutStreamer.emitSizeT(BBIdx);
154170
OutStreamer.emitSizeT(InstIdx);
155171
}
156172

@@ -167,29 +183,45 @@ class YkIRWriter {
167183
serialiseString(toString(V));
168184
}
169185

170-
void serialiseOperand(Instruction *Parent, Value *V) {
186+
void serialiseOperand(Instruction *Parent, ValueLoweringMap &VLMap,
187+
Value *V) {
171188
if (llvm::Constant *C = dyn_cast<llvm::Constant>(V)) {
172189
serialiseConstantOperand(Parent, C);
173190
} else if (Instruction *I = dyn_cast<Instruction>(V)) {
174191
// If an instruction defines the operand, it's a local variable.
175-
serialiseLocalVariableOperand(I);
192+
serialiseLocalVariableOperand(I, VLMap);
176193
} else {
177194
serialiseUnimplementedOperand(V);
178195
}
179196
}
180197

181198
/// Does a naiave serialisation of an LLVM instruction by iterating over its
182199
/// operands and serialising them in turn.
183-
void serialiseInstGeneric(Instruction *I, OpCode Opc) {
200+
void serialiseInstGeneric(Instruction *I, ValueLoweringMap &VLMap,
201+
unsigned BBIdx, unsigned &InstIdx, OpCode Opc) {
184202
OutStreamer.emitSizeT(typeIndex(I->getType()));
185203
serialiseOpcode(Opc);
186204
OutStreamer.emitInt32(I->getNumOperands());
187205
for (Value *O : I->operands()) {
188-
serialiseOperand(I, O);
206+
serialiseOperand(I, VLMap, O);
207+
}
208+
if (!I->getType()->isVoidTy()) {
209+
VLMap[I] = {BBIdx, InstIdx};
189210
}
211+
InstIdx++;
212+
}
213+
214+
void serialiseInst(Instruction *I, ValueLoweringMap &VLMap, unsigned BBIdx,
215+
unsigned &InstIdx) {
216+
// Macro to help dispatch to generic lowering.
217+
//
218+
// Note that this is unhygenic so as to make the call-sites readable.
219+
#define GENERIC_INST_SERIALISE(LLVM_INST, LLVM_INST_TYPE, YKIR_OPCODE) \
220+
if (isa<LLVM_INST_TYPE>(LLVM_INST)) { \
221+
serialiseInstGeneric(LLVM_INST, VLMap, BBIdx, InstIdx, YKIR_OPCODE); \
222+
return; \
190223
}
191224

192-
void serialiseInst(Instruction *I) {
193225
GENERIC_INST_SERIALISE(I, LoadInst, Load)
194226
GENERIC_INST_SERIALISE(I, StoreInst, Store)
195227
GENERIC_INST_SERIALISE(I, AllocaInst, Alloca)
@@ -202,27 +234,37 @@ class YkIRWriter {
202234

203235
// GENERIC_INST_SERIALISE does an early return upon a match, so if we get
204236
// here then the instruction wasn't handled.
205-
serialiseUnimplementedInstruction(I);
237+
serialiseUnimplementedInstruction(I, VLMap, BBIdx, InstIdx);
206238
}
207239

208240
// An unimplemented instruction is lowered to an instruction with one
209241
// unimplemented operand containing the textual LLVM IR we couldn't handle.
210-
void serialiseUnimplementedInstruction(Instruction *I) {
242+
void serialiseUnimplementedInstruction(Instruction *I,
243+
ValueLoweringMap &VLMap,
244+
unsigned BBIdx, unsigned &InstIdx) {
211245
// opcode:
212246
serialiseOpcode(UnimplementedInstruction);
213247
// num_operands:
214248
OutStreamer.emitInt32(1);
215249
// problem instruction:
216250
serialiseUnimplementedOperand(I);
251+
252+
if (!I->getType()->isVoidTy()) {
253+
VLMap[I] = {BBIdx, InstIdx};
254+
}
255+
InstIdx++;
217256
}
218257

219-
void serialiseBlock(BasicBlock &BB) {
258+
void serialiseBlock(BasicBlock &BB, ValueLoweringMap &VLMap,
259+
unsigned &BBIdx) {
220260
// num_instrs:
221261
OutStreamer.emitSizeT(BB.size());
222262
// instrs:
263+
unsigned InstIdx = 0;
223264
for (Instruction &I : BB) {
224-
serialiseInst(&I);
265+
serialiseInst(&I, VLMap, BBIdx, InstIdx);
225266
}
267+
BBIdx++;
226268
}
227269

228270
void serialiseFunc(Function &F) {
@@ -231,8 +273,10 @@ class YkIRWriter {
231273
// num_blocks:
232274
OutStreamer.emitSizeT(F.size());
233275
// blocks:
276+
unsigned BBIdx = 0;
277+
ValueLoweringMap VLMap;
234278
for (BasicBlock &BB : F) {
235-
serialiseBlock(BB);
279+
serialiseBlock(BB, VLMap, BBIdx);
236280
}
237281
}
238282

0 commit comments

Comments
 (0)