@@ -100,6 +100,23 @@ struct ClassTypeCache {
100100 llvm::DenseMap<mlir::Attribute, ClassStructInfo> classToStructMap;
101101};
102102
103+ // / Ensure we have `declare i8* @malloc(i64)` (opaque ptr prints as !llvm.ptr).
104+ static LLVM::LLVMFuncOp getOrCreateMalloc (ModuleOp mod, OpBuilder &b) {
105+ if (auto f = mod.lookupSymbol <LLVM::LLVMFuncOp>(" malloc" ))
106+ return f;
107+
108+ OpBuilder::InsertionGuard g (b);
109+ b.setInsertionPointToStart (mod.getBody ());
110+
111+ auto i64Ty = IntegerType::get (mod.getContext (), 64 );
112+ auto ptrTy = LLVM::LLVMPointerType::get (mod.getContext ()); // opaque pointer
113+ auto fnTy = LLVM::LLVMFunctionType::get (ptrTy, {i64Ty}, /* isVarArg=*/ false );
114+
115+ auto fn = LLVM::LLVMFuncOp::create (b, mod.getLoc (), " malloc" , fnTy);
116+ fn.setLinkage (LLVM::Linkage::External);
117+ return fn;
118+ }
119+
103120// / Helper function to create an LLVM-friendly name from a class name symbol
104121// / Classname is expected to be in a H1::H2::H3::@C format.
105122static std::string mangleClassName (SymbolRefAttr className) {
@@ -150,12 +167,13 @@ static LogicalResult resolveClassStructBody(circt::moore::ClassDeclOp op,
150167
151168 if (auto baseClass = op.getBaseAttr ()) {
152169
170+ ModuleOp mod = op->getParentOfType <ModuleOp>();
171+ auto classDeclOp = cast<moore::ClassDeclOp>(*mod.lookupSymbol (baseClass));
172+ if (failed (resolveClassStructBody (classDeclOp, typeConverter, cache)))
173+ op.emitError () << " Failed to convert base class " << baseClass;
174+
153175 // Process base class' struct layout first
154176 auto baseClassStruct = cache.getStructInfo (baseClass);
155- if (!baseClassStruct || !baseClassStruct->isFinalized )
156- return op.emitOpError () << " Base class " << baseClass << " of "
157- << classSym << " has not been converted." ;
158-
159177 structBodyMembers.push_back (baseClassStruct->classBody );
160178 derivedStartIdx = 1 ;
161179
@@ -200,6 +218,14 @@ static LogicalResult resolveClassStructBody(circt::moore::ClassDeclOp op,
200218 return success ();
201219}
202220
221+ // / Convenience overload if
222+ static LogicalResult resolveClassStructBody (ModuleOp mod, SymbolRefAttr op,
223+ TypeConverter const &typeConverter,
224+ ClassTypeCache &cache) {
225+ auto classDeclOp = cast<moore::ClassDeclOp>(*mod.lookupSymbol (op));
226+ return resolveClassStructBody (classDeclOp, typeConverter, cache);
227+ }
228+
203229// / Returns the passed value if the integer width is already correct.
204230// / Zero-extends if it is too narrow.
205231// / Truncates if the integer is too wide and the truncated part is zero, if it
@@ -701,6 +727,52 @@ static Value createZeroValue(Type type, Location loc,
701727 return rewriter.createOrFold <hw::BitcastOp>(loc, type, constZero);
702728}
703729
730+ // / moore.class.new lowering: heap-allocate storage for the class object.
731+ struct ClassNewOpConversion : public OpConversionPattern <ClassNewOp> {
732+ ClassNewOpConversion (TypeConverter &tc, MLIRContext *ctx,
733+ ClassTypeCache &cache)
734+ : OpConversionPattern<ClassNewOp>(tc, ctx), cache(cache) {}
735+
736+ LogicalResult
737+ matchAndRewrite (ClassNewOp op, OpAdaptor adaptor,
738+ ConversionPatternRewriter &rewriter) const override {
739+ Location loc = op.getLoc ();
740+ MLIRContext *ctx = rewriter.getContext ();
741+
742+ auto handleTy = cast<ClassHandleType>(op.getResult ().getType ());
743+ auto sym = handleTy.getClassSym ();
744+
745+ ModuleOp mod = op->getParentOfType <ModuleOp>();
746+
747+ if (failed (resolveClassStructBody (mod, sym, *typeConverter, cache)))
748+ return op.emitError () << " Could not resolve class struct for " << sym;
749+
750+ auto structTy = cache.getStructInfo (sym)->classBody ;
751+
752+ DataLayout dl (mod);
753+ // DataLayout::getTypeSize gives a byte count for LLVM types.
754+ uint64_t byteSize = dl.getTypeSize (structTy);
755+ auto i64Ty = IntegerType::get (ctx, 64 );
756+ auto cSize = LLVM::ConstantOp::create (rewriter, loc, i64Ty,
757+ rewriter.getI64IntegerAttr (byteSize));
758+
759+ // Get or declare malloc and call it.
760+ auto mallocFn = getOrCreateMalloc (mod, rewriter);
761+ auto ptrTy = LLVM::LLVMPointerType::get (ctx); // opaque pointer result
762+ auto call =
763+ LLVM::CallOp::create (rewriter, loc, TypeRange{ptrTy},
764+ SymbolRefAttr::get (mallocFn), ValueRange{cSize});
765+
766+ // Replace the new op with the malloc pointer (no cast needed with opaque
767+ // ptrs).
768+ rewriter.replaceOp (op, call.getResult ());
769+ return success ();
770+ }
771+
772+ private:
773+ ClassTypeCache &cache; // shared, owned by the pass
774+ };
775+
704776struct ClassDeclOpConversion : public OpConversionPattern <ClassDeclOp> {
705777 ClassDeclOpConversion (TypeConverter &tc, MLIRContext *ctx,
706778 ClassTypeCache &cache)
@@ -709,9 +781,9 @@ struct ClassDeclOpConversion : public OpConversionPattern<ClassDeclOp> {
709781 LogicalResult
710782 matchAndRewrite (ClassDeclOp op, OpAdaptor,
711783 ConversionPatternRewriter &rewriter) const override {
784+
712785 if (failed (resolveClassStructBody (op, *typeConverter, cache)))
713786 return failure ();
714-
715787 // The declaration itself is a no-op
716788 rewriter.eraseOp (op);
717789 return success ();
@@ -2118,7 +2190,8 @@ static void populateOpConversion(ConversionPatternSet &patterns,
21182190
21192191 patterns.add <ClassDeclOpConversion>(typeConverter, patterns.getContext (),
21202192 classCache);
2121-
2193+ patterns.add <ClassNewOpConversion>(typeConverter, patterns.getContext (),
2194+ classCache);
21222195 // clang-format off
21232196 patterns.add <
21242197 // Patterns of declaration operations.
0 commit comments