@@ -97,6 +97,23 @@ struct ClassTypeCache {
9797 llvm::DenseMap<mlir::Attribute, ClassStructInfo> classToStructMap;
9898};
9999
100+ // / Ensure we have `declare i8* @malloc(i64)` (opaque ptr prints as !llvm.ptr).
101+ static LLVM::LLVMFuncOp getOrCreateMalloc (ModuleOp mod, OpBuilder &b) {
102+ if (auto f = mod.lookupSymbol <LLVM::LLVMFuncOp>(" malloc" ))
103+ return f;
104+
105+ OpBuilder::InsertionGuard g (b);
106+ b.setInsertionPointToStart (mod.getBody ());
107+
108+ auto i64Ty = IntegerType::get (mod.getContext (), 64 );
109+ auto ptrTy = LLVM::LLVMPointerType::get (mod.getContext ()); // opaque pointer
110+ auto fnTy = LLVM::LLVMFunctionType::get (ptrTy, {i64Ty}, /* isVarArg=*/ false );
111+
112+ auto fn = LLVM::LLVMFuncOp::create (b, mod.getLoc (), " malloc" , fnTy);
113+ fn.setLinkage (LLVM::Linkage::External);
114+ return fn;
115+ }
116+
100117// / Helper function to create an LLVM-friendly name from a class name symbol
101118// / Classname is expected to be in a H1::H2::H3::@C format.
102119static std::string mangleClassName (SymbolRefAttr className) {
@@ -147,12 +164,13 @@ static LogicalResult resolveClassStructBody(circt::moore::ClassDeclOp op,
147164
148165 if (auto baseClass = op.getBaseAttr ()) {
149166
167+ ModuleOp mod = op->getParentOfType <ModuleOp>();
168+ auto classDeclOp = cast<moore::ClassDeclOp>(*mod.lookupSymbol (baseClass));
169+ if (failed (resolveClassStructBody (classDeclOp, typeConverter, cache)))
170+ op.emitError () << " Failed to convert base class " << baseClass;
171+
150172 // Process base class' struct layout first
151173 auto baseClassStruct = cache.getStructInfo (baseClass);
152- if (!baseClassStruct)
153- return op.emitOpError () << " Base class " << baseClass << " of "
154- << classSym << " has not been converted." ;
155-
156174 structBodyMembers.push_back (baseClassStruct->classBody );
157175 derivedStartIdx = 1 ;
158176
@@ -198,6 +216,14 @@ static LogicalResult resolveClassStructBody(circt::moore::ClassDeclOp op,
198216 return success ();
199217}
200218
219+ // / Convenience overload if
220+ static LogicalResult resolveClassStructBody (ModuleOp mod, SymbolRefAttr op,
221+ TypeConverter const &typeConverter,
222+ ClassTypeCache &cache) {
223+ auto classDeclOp = cast<moore::ClassDeclOp>(*mod.lookupSymbol (op));
224+ return resolveClassStructBody (classDeclOp, typeConverter, cache);
225+ }
226+
201227// / Returns the passed value if the integer width is already correct.
202228// / Zero-extends if it is too narrow.
203229// / Truncates if the integer is too wide and the truncated part is zero, if it
@@ -705,6 +731,52 @@ static Value createZeroValue(Type type, Location loc,
705731 return rewriter.createOrFold <hw::BitcastOp>(loc, type, constZero);
706732}
707733
734+ // / moore.class.new lowering: heap-allocate storage for the class object.
735+ struct ClassNewOpConversion : public OpConversionPattern <ClassNewOp> {
736+ ClassNewOpConversion (TypeConverter &tc, MLIRContext *ctx,
737+ ClassTypeCache &cache)
738+ : OpConversionPattern<ClassNewOp>(tc, ctx), cache(cache) {}
739+
740+ LogicalResult
741+ matchAndRewrite (ClassNewOp op, OpAdaptor adaptor,
742+ ConversionPatternRewriter &rewriter) const override {
743+ Location loc = op.getLoc ();
744+ MLIRContext *ctx = rewriter.getContext ();
745+
746+ auto handleTy = cast<ClassHandleType>(op.getResult ().getType ());
747+ auto sym = handleTy.getClassSym ();
748+
749+ ModuleOp mod = op->getParentOfType <ModuleOp>();
750+
751+ if (failed (resolveClassStructBody (mod, sym, *typeConverter, cache)))
752+ return op.emitError () << " Could not resolve class struct for " << sym;
753+
754+ auto structTy = cache.getStructInfo (sym)->classBody ;
755+
756+ DataLayout dl (mod);
757+ // DataLayout::getTypeSize gives a byte count for LLVM types.
758+ uint64_t byteSize = dl.getTypeSize (structTy);
759+ auto i64Ty = IntegerType::get (ctx, 64 );
760+ auto cSize = LLVM::ConstantOp::create (rewriter, loc, i64Ty,
761+ rewriter.getI64IntegerAttr (byteSize));
762+
763+ // Get or declare malloc and call it.
764+ auto mallocFn = getOrCreateMalloc (mod, rewriter);
765+ auto ptrTy = LLVM::LLVMPointerType::get (ctx); // opaque pointer result
766+ auto call =
767+ LLVM::CallOp::create (rewriter, loc, TypeRange{ptrTy},
768+ SymbolRefAttr::get (mallocFn), ValueRange{cSize});
769+
770+ // Replace the new op with the malloc pointer (no cast needed with opaque
771+ // ptrs).
772+ rewriter.replaceOp (op, call.getResult ());
773+ return success ();
774+ }
775+
776+ private:
777+ ClassTypeCache &cache; // shared, owned by the pass
778+ };
779+
708780struct ClassDeclOpConversion : public OpConversionPattern <ClassDeclOp> {
709781 ClassDeclOpConversion (TypeConverter &tc, MLIRContext *ctx,
710782 ClassTypeCache &cache)
@@ -713,9 +785,9 @@ struct ClassDeclOpConversion : public OpConversionPattern<ClassDeclOp> {
713785 LogicalResult
714786 matchAndRewrite (ClassDeclOp op, OpAdaptor,
715787 ConversionPatternRewriter &rewriter) const override {
788+
716789 if (failed (resolveClassStructBody (op, *typeConverter, cache)))
717790 return failure ();
718-
719791 // The declaration itself is a no-op
720792 rewriter.eraseOp (op);
721793 return success ();
@@ -2104,7 +2176,8 @@ static void populateOpConversion(ConversionPatternSet &patterns,
21042176
21052177 patterns.add <ClassDeclOpConversion>(typeConverter, patterns.getContext (),
21062178 classCache);
2107-
2179+ patterns.add <ClassNewOpConversion>(typeConverter, patterns.getContext (),
2180+ classCache);
21082181 // clang-format off
21092182 patterns.add <
21102183 // Patterns of declaration operations.
0 commit comments