@@ -52,6 +52,7 @@ enum OpCode {
52
52
OpCodeBinOp,
53
53
OpCodeCast,
54
54
OpCodeSwitch,
55
+ OpCodePHI,
55
56
OpCodeUnimplemented = 255 , // YKFIXME: Will eventually be deleted.
56
57
};
57
58
@@ -174,6 +175,18 @@ class YkIRWriter {
174
175
vector<llvm::Constant *> Constants;
175
176
vector<llvm::GlobalVariable *> Globals;
176
177
178
+ // Instruction indices that need to be patched up later.
179
+ vector<tuple<Instruction *, MCSymbol *>> InstIdxPacthUps;
180
+
181
+ // Fill in instruction indices that had to be deferred.
182
+ void patchUpInstIdxs (ValueLoweringMap &VLMap) {
183
+ MCContext &MCtxt = OutStreamer.getContext ();
184
+ for (auto &[Inst, Sym] : InstIdxPacthUps) {
185
+ auto [_, InstIdx] = VLMap.at (Inst);
186
+ OutStreamer.emitAssignment (Sym, MCConstantExpr::create (InstIdx, MCtxt));
187
+ }
188
+ }
189
+
177
190
// Return the index of the LLVM type `Ty`, inserting a new entry if
178
191
// necessary.
179
192
size_t typeIndex (llvm::Type *Ty) {
@@ -244,11 +257,33 @@ class YkIRWriter {
244
257
}
245
258
246
259
void serialiseLocalVariableOperand (Instruction *I, ValueLoweringMap &VLMap) {
247
- auto [BBIdx, InstIdx] = VLMap.at (I);
248
260
serialiseOperandKind (OperandKindLocal);
249
261
OutStreamer.emitSizeT (getIndex (&M, I->getFunction ()));
250
- OutStreamer.emitSizeT (BBIdx);
251
- OutStreamer.emitSizeT (InstIdx);
262
+
263
+ if (VLMap.count (I) == 1 ) {
264
+ auto [BBIdx, InstIdx] = VLMap.at (I);
265
+ OutStreamer.emitSizeT (BBIdx);
266
+ OutStreamer.emitSizeT (InstIdx);
267
+ } else {
268
+ // It's a local variable generated by an instruction that we haven't
269
+ // serialised yet. This can happen in loop bodies where a PHI node merges
270
+ // in a variable from the end of the loop body.
271
+ //
272
+ // To work around this, we emit a dummy instruction index
273
+ // and patch it up later once it becomes known.
274
+ //
275
+ // The basic block index can be immediately known, since the indices are
276
+ // the same in the LLVM IR and our AOT IR.
277
+ //
278
+ // FIXME: In light of the above, there's no need to store basic block
279
+ // indices in the VLMap?
280
+ OutStreamer.emitSizeT (getIndex (I->getFunction (), I->getParent ()));
281
+
282
+ MCContext &MCtxt = OutStreamer.getContext ();
283
+ MCSymbol *PatchUpSym = MCtxt.createTempSymbol ();
284
+ OutStreamer.emitSymbolValue (PatchUpSym, sizeof (size_t ));
285
+ InstIdxPacthUps.push_back ({I, PatchUpSym});
286
+ }
252
287
}
253
288
254
289
void serialiseFunctionOperand (llvm::Function *F) {
@@ -690,6 +725,26 @@ class YkIRWriter {
690
725
InstIdx++;
691
726
}
692
727
728
+ void serialisePhiInst (PHINode *I, ValueLoweringMap &VLMap, unsigned BBIdx,
729
+ unsigned &InstIdx) {
730
+ // opcode:
731
+ serialiseOpcode (OpCodePHI);
732
+ // num_incoming:
733
+ size_t NumIncoming = I->getNumIncomingValues ();
734
+ OutStreamer.emitSizeT (NumIncoming);
735
+ // incoming_bbs:
736
+ for (size_t J = 0 ; J < NumIncoming; J++) {
737
+ serialiseBlockLabel (I->getIncomingBlock (J));
738
+ }
739
+ // incoming_vals:
740
+ for (size_t J = 0 ; J < NumIncoming; J++) {
741
+ serialiseOperand (I, VLMap, I->getIncomingValue (J));
742
+ }
743
+
744
+ VLMap[I] = {BBIdx, InstIdx};
745
+ InstIdx++;
746
+ }
747
+
693
748
void serialiseInst (Instruction *I, ValueLoweringMap &VLMap, unsigned BBIdx,
694
749
unsigned &InstIdx) {
695
750
// Macro to make the dispatch below easier to read/sort.
@@ -707,6 +762,7 @@ class YkIRWriter {
707
762
INST_SERIALISE (I, ICmpInst, serialiseICmpInst);
708
763
INST_SERIALISE (I, InsertValueInst, serialiseInsertValueInst);
709
764
INST_SERIALISE (I, LoadInst, serialiseLoadInst);
765
+ INST_SERIALISE (I, PHINode, serialisePhiInst);
710
766
INST_SERIALISE (I, ReturnInst, serialiseReturnInst);
711
767
INST_SERIALISE (I, SExtInst, serialiseSExtInst);
712
768
INST_SERIALISE (I, StoreInst, serialiseStoreInst);
@@ -798,6 +854,11 @@ class YkIRWriter {
798
854
for (BasicBlock &BB : F) {
799
855
serialiseBlock (BB, VLMap, BBIdx);
800
856
}
857
+
858
+ patchUpInstIdxs (VLMap);
859
+ // FIXME: it'd be better to make a new patchup struct for each function and
860
+ // just let it fall out of scope when done. Lots of plumbing...
861
+ InstIdxPacthUps.clear ();
801
862
}
802
863
803
864
void serialiseFunctionType (FunctionType *Ty) {
0 commit comments