@@ -259,6 +259,16 @@ static std::string getVTableName(SymbolRefAttr className) {
259259 return className.getRootReference ().str () + " ::vtable" ;
260260}
261261
262+ static VTableOp findVTableOp (ModuleOp mod, SymbolRefAttr classSym) {
263+ auto vtableSym =
264+ SymbolRefAttr::get (classSym.getRootReference (),
265+ FlatSymbolRefAttr::get (mod.getContext (), " vtable" ));
266+ for (auto candidate : mod.getOps <VTableOp>())
267+ if (candidate.getSymNameAttr () == vtableSym)
268+ return candidate;
269+ return {};
270+ }
271+
262272static void
263273collectVTableEntries (VTableOp op,
264274 llvm::SmallDenseMap<StringRef, unsigned > &slots,
@@ -291,16 +301,7 @@ static FailureOr<ClassTypeCache::VTableInfo> getOrCreateVTableInfo(
291301 if (auto info = cache.getVTableInfo (classSym))
292302 return *info;
293303
294- auto vtableSym =
295- SymbolRefAttr::get (classSym.getRootReference (),
296- FlatSymbolRefAttr::get (mod.getContext (), " vtable" ));
297- VTableOp vtableOp;
298- for (auto candidate : mod.getOps <VTableOp>()) {
299- if (candidate.getSymNameAttr () == vtableSym) {
300- vtableOp = candidate;
301- break ;
302- }
303- }
304+ VTableOp vtableOp = findVTableOp (mod, classSym);
304305 if (!vtableOp)
305306 return failure ();
306307
@@ -1186,10 +1187,12 @@ struct ClassUpcastOpConversion : public OpConversionPattern<ClassUpcastOp> {
11861187
11871188// / moore.class.new lowering: heap-allocate storage for the class object.
11881189struct ClassNewOpConversion : public OpConversionPattern <ClassNewOp> {
1189- ClassNewOpConversion (TypeConverter &tc, MLIRContext *ctx,
1190- ClassTypeCache &cache, FunctionCache &funcCache)
1190+ ClassNewOpConversion (LLVMTypeConverter &tc, MLIRContext *ctx,
1191+ ClassTypeCache &cache, FunctionCache &funcCache,
1192+ SymbolTableCollection &symbolTables)
11911193 : OpConversionPattern<ClassNewOp>(tc, ctx), cache(cache),
1192- funcCache (funcCache) {}
1194+ funcCache (funcCache), symbolTables(symbolTables),
1195+ llvmTypeConverter (tc) {}
11931196
11941197 LogicalResult
11951198 matchAndRewrite (ClassNewOp op, OpAdaptor adaptor,
@@ -1242,10 +1245,31 @@ struct ClassNewOpConversion : public OpConversionPattern<ClassNewOp> {
12421245 rewriter, loc, i32Ty,
12431246 rewriter.getI32IntegerAttr (
12441247 cache.getStructInfo (sym)->typeInfoFieldIndex ));
1245- auto headerPtr =
1248+ auto headerBasePtr =
12461249 LLVM::GEPOp::create (rewriter, loc, ptrTy, structTy, call.getResult (0 ),
1247- ValueRange{headerIdx, typeInfoIdx});
1248- LLVM::StoreOp::create (rewriter, loc, typeInfoAddr, headerPtr);
1250+ ValueRange{headerIdx});
1251+ auto typeInfoPtr = LLVM::GEPOp::create (
1252+ rewriter, loc, ptrTy, cache.getStructInfo (sym)->headerTy , headerBasePtr,
1253+ ValueRange{headerIdx, typeInfoIdx});
1254+ LLVM::StoreOp::create (rewriter, loc, typeInfoAddr, typeInfoPtr);
1255+
1256+ if (findVTableOp (mod, sym)) {
1257+ auto vtableInfo = getOrCreateVTableInfo (
1258+ mod, sym, rewriter, llvmTypeConverter, symbolTables, cache);
1259+ if (failed (vtableInfo))
1260+ return op.emitError () << " Could not create vtable for " << sym;
1261+
1262+ auto vtableAddr =
1263+ LLVM::AddressOfOp::create (rewriter, loc, vtableInfo->global );
1264+ auto vtableIdx = LLVM::ConstantOp::create (
1265+ rewriter, loc, i32Ty,
1266+ rewriter.getI32IntegerAttr (
1267+ cache.getStructInfo (sym)->vtableFieldIndex ));
1268+ auto vtablePtr = LLVM::GEPOp::create (
1269+ rewriter, loc, ptrTy, cache.getStructInfo (sym)->headerTy ,
1270+ headerBasePtr, ValueRange{headerIdx, vtableIdx});
1271+ LLVM::StoreOp::create (rewriter, loc, vtableAddr, vtablePtr);
1272+ }
12491273
12501274 // Replace the new op with the malloc pointer (no cast needed with opaque
12511275 // ptrs).
@@ -1256,6 +1280,8 @@ struct ClassNewOpConversion : public OpConversionPattern<ClassNewOp> {
12561280private:
12571281 ClassTypeCache &cache; // shared, owned by the pass
12581282 FunctionCache &funcCache;
1283+ SymbolTableCollection &symbolTables;
1284+ LLVMTypeConverter &llvmTypeConverter;
12591285};
12601286
12611287struct ClassDeclOpConversion : public OpConversionPattern <ClassDeclOp> {
@@ -1302,6 +1328,73 @@ struct VTableOpConversion : public OpConversionPattern<VTableOp> {
13021328 LLVMTypeConverter &llvmTypeConverter;
13031329};
13041330
1331+ struct VTableLoadMethodOpConversion
1332+ : public OpConversionPattern<VTableLoadMethodOp> {
1333+ VTableLoadMethodOpConversion (LLVMTypeConverter &tc, MLIRContext *ctx,
1334+ ClassTypeCache &cache,
1335+ SymbolTableCollection &symbolTables)
1336+ : OpConversionPattern<VTableLoadMethodOp>(tc, ctx), cache(cache),
1337+ symbolTables (symbolTables), llvmTypeConverter(tc) {}
1338+
1339+ LogicalResult
1340+ matchAndRewrite (VTableLoadMethodOp op, OpAdaptor adaptor,
1341+ ConversionPatternRewriter &rewriter) const override {
1342+ auto objectTy = cast<ClassHandleType>(op.getObject ().getType ());
1343+ auto classSym = objectTy.getClassSym ();
1344+ auto methodName = op.getMethodSymAttr ().getLeafReference ();
1345+ if (!methodName)
1346+ return rewriter.notifyMatchFailure (op, " missing method symbol" );
1347+
1348+ auto mod = op->getParentOfType <ModuleOp>();
1349+ if (failed (resolveClassStructBody (mod, classSym, *typeConverter, cache)))
1350+ return op.emitError ()
1351+ << " Could not resolve class struct for " << classSym;
1352+
1353+ auto vtableInfo = getOrCreateVTableInfo (
1354+ mod, classSym, rewriter, llvmTypeConverter, symbolTables, cache);
1355+ if (failed (vtableInfo))
1356+ return op.emitError () << " Could not resolve vtable for " << classSym;
1357+
1358+ auto slotIt = vtableInfo->methodSlot .find (methodName.getValue ());
1359+ if (slotIt == vtableInfo->methodSlot .end ())
1360+ return op.emitError () << " No vtable slot for method " << methodName;
1361+
1362+ auto structTy = cache.getStructInfo (classSym)->classBody ;
1363+ auto ptrTy = LLVM::LLVMPointerType::get (rewriter.getContext ());
1364+ auto i32Ty = rewriter.getI32Type ();
1365+ auto zero = LLVM::ConstantOp::create (rewriter, op.getLoc (), i32Ty,
1366+ rewriter.getI32IntegerAttr (0 ));
1367+ auto vtableIdx = LLVM::ConstantOp::create (
1368+ rewriter, op.getLoc (), i32Ty,
1369+ rewriter.getI32IntegerAttr (
1370+ cache.getStructInfo (classSym)->vtableFieldIndex ));
1371+ auto slotIdx =
1372+ LLVM::ConstantOp::create (rewriter, op.getLoc (), i32Ty,
1373+ rewriter.getI32IntegerAttr (slotIt->second ));
1374+
1375+ auto headerBasePtr =
1376+ LLVM::GEPOp::create (rewriter, op.getLoc (), ptrTy, structTy,
1377+ adaptor.getObject (), ValueRange{zero});
1378+ auto vtablePtrPtr = LLVM::GEPOp::create (
1379+ rewriter, op.getLoc (), ptrTy, cache.getStructInfo (classSym)->headerTy ,
1380+ headerBasePtr, ValueRange{zero, vtableIdx});
1381+ auto vtablePtr =
1382+ LLVM::LoadOp::create (rewriter, op.getLoc (), ptrTy, vtablePtrPtr);
1383+ auto slotPtr =
1384+ LLVM::GEPOp::create (rewriter, op.getLoc (), ptrTy, vtableInfo->tableTy ,
1385+ vtablePtr, ValueRange{zero, slotIdx});
1386+ auto methodPtr =
1387+ LLVM::LoadOp::create (rewriter, op.getLoc (), ptrTy, slotPtr);
1388+ rewriter.replaceOp (op, methodPtr.getResult ());
1389+ return success ();
1390+ }
1391+
1392+ private:
1393+ ClassTypeCache &cache;
1394+ SymbolTableCollection &symbolTables;
1395+ LLVMTypeConverter &llvmTypeConverter;
1396+ };
1397+
13051398struct VariableOpConversion : public OpConversionPattern <VariableOp> {
13061399 using OpConversionPattern::OpConversionPattern;
13071400
@@ -3427,7 +3520,9 @@ static void populateOpConversion(ConversionPatternSet &patterns,
34273520 patterns.add <VTableOpConversion>(typeConverter, patterns.getContext (),
34283521 classCache, symbolTables);
34293522 patterns.add <ClassNewOpConversion>(typeConverter, patterns.getContext (),
3430- classCache, funcCache);
3523+ classCache, funcCache, symbolTables);
3524+ patterns.add <VTableLoadMethodOpConversion>(
3525+ typeConverter, patterns.getContext (), classCache, symbolTables);
34313526 patterns.add <ClassPropertyRefOpConversion>(typeConverter,
34323527 patterns.getContext (), classCache);
34333528
0 commit comments