@@ -60,7 +60,7 @@ struct ClassTypeCache {
6060 // / Record/overwrite the field path to a single property for a class.
6161 void setFieldPath (StringRef propertyName, ArrayRef<unsigned > path) {
6262 this ->propertyPath [propertyName] =
63- llvm:: SmallVector<unsigned , 2 >(path.begin (), path.end ());
63+ SmallVector<unsigned , 2 >(path.begin (), path.end ());
6464 }
6565
6666 // / Lookup the full GEP path for a (class, field).
@@ -94,6 +94,24 @@ struct ClassTypeCache {
9494 DenseMap<Attribute, ClassStructInfo> classToStructMap;
9595};
9696
97+ // / Ensure we have `declare i8* @malloc(i64)` (opaque ptr prints as !llvm.ptr).
98+ static LLVM::LLVMFuncOp getOrCreateMalloc (ModuleOp mod, OpBuilder &b) {
99+ if (auto f = mod.lookupSymbol <LLVM::LLVMFuncOp>(" malloc" ))
100+ return f;
101+
102+ OpBuilder::InsertionGuard g (b);
103+ b.setInsertionPointToStart (mod.getBody ());
104+
105+ auto i64Ty = IntegerType::get (mod.getContext (), 64 );
106+ auto ptrTy = LLVM::LLVMPointerType::get (mod.getContext ()); // opaque pointer
107+ auto fnTy = LLVM::LLVMFunctionType::get (ptrTy, {i64Ty}, false );
108+
109+ auto fn = LLVM::LLVMFuncOp::create (b, mod.getLoc (), " malloc" , fnTy);
110+ // Link this in from somewhere else.
111+ fn.setLinkage (LLVM::Linkage::External);
112+ return fn;
113+ }
114+
97115// / Helper function to create an opaque LLVM Struct Type which corresponds
98116// / to the sym
99117static LLVM::LLVMStructType getOrCreateOpaqueStruct (MLIRContext *ctx,
@@ -120,21 +138,30 @@ static LogicalResult resolveClassStructBody(ClassDeclOp op,
120138
121139 if (auto baseClass = op.getBaseAttr ()) {
122140
123- // Process base class' struct layout first
124- auto baseClassStruct = cache.getStructInfo (baseClass);
125- if (!baseClassStruct)
126- return op.emitOpError () << " Base class " << baseClass << " of "
127- << classSym << " has not been converted." ;
128-
129- structBodyMembers.push_back (baseClassStruct->classBody );
130- derivedStartIdx = 1 ;
131-
132- // Inherit base field paths with a leading 0.
133- for (auto &kv : baseClassStruct->propertyPath ) {
134- SmallVector<unsigned , 2 > path;
135- path.push_back (0 ); // into base subobject
136- path.append (kv.second .begin (), kv.second .end ());
137- structBody.setFieldPath (kv.first , path);
141+ ModuleOp mod = op->getParentOfType <ModuleOp>();
142+ // It's possible the base class does not resolve since it materialzes
143+ // no methods or properties. In that case we can simply ignore inheritance.
144+ if (auto *opSym = mod.lookupSymbol (baseClass)) {
145+ auto classDeclOp = dyn_cast<ClassDeclOp>(opSym);
146+ if (!classDeclOp)
147+ return op.emitError () << " Found symbol corresponding to " << baseClass
148+ << " but it wasn't a classdeclop!" ;
149+
150+ if (failed (resolveClassStructBody (classDeclOp, typeConverter, cache)))
151+ return failure ();
152+
153+ // Process base class' struct layout first
154+ auto baseClassStruct = cache.getStructInfo (baseClass);
155+ structBodyMembers.push_back (baseClassStruct->classBody );
156+ derivedStartIdx = 1 ;
157+
158+ // Inherit base field paths with a leading 0.
159+ for (auto &kv : baseClassStruct->propertyPath ) {
160+ SmallVector<unsigned , 2 > path;
161+ path.push_back (0 ); // into base subobject
162+ path.append (kv.second .begin (), kv.second .end ());
163+ structBody.setFieldPath (kv.first , path);
164+ }
138165 }
139166 }
140167
@@ -171,6 +198,14 @@ static LogicalResult resolveClassStructBody(ClassDeclOp op,
171198 return success ();
172199}
173200
201+ // / Convenience overload that looks up ClassDeclOp
202+ static LogicalResult resolveClassStructBody (ModuleOp mod, SymbolRefAttr op,
203+ TypeConverter const &typeConverter,
204+ ClassTypeCache &cache) {
205+ auto classDeclOp = cast<ClassDeclOp>(*mod.lookupSymbol (op));
206+ return resolveClassStructBody (classDeclOp, typeConverter, cache);
207+ }
208+
174209// / Returns the passed value if the integer width is already correct.
175210// / Zero-extends if it is too narrow.
176211// / Truncates if the integer is too wide and the truncated part is zero, if it
@@ -678,6 +713,52 @@ static Value createZeroValue(Type type, Location loc,
678713 return rewriter.createOrFold <hw::BitcastOp>(loc, type, constZero);
679714}
680715
716+ // / moore.class.new lowering: heap-allocate storage for the class object.
717+ struct ClassNewOpConversion : public OpConversionPattern <ClassNewOp> {
718+ ClassNewOpConversion (TypeConverter &tc, MLIRContext *ctx,
719+ ClassTypeCache &cache)
720+ : OpConversionPattern<ClassNewOp>(tc, ctx), cache(cache) {}
721+
722+ LogicalResult
723+ matchAndRewrite (ClassNewOp op, OpAdaptor adaptor,
724+ ConversionPatternRewriter &rewriter) const override {
725+ Location loc = op.getLoc ();
726+ MLIRContext *ctx = rewriter.getContext ();
727+
728+ auto handleTy = cast<ClassHandleType>(op.getResult ().getType ());
729+ auto sym = handleTy.getClassSym ();
730+
731+ ModuleOp mod = op->getParentOfType <ModuleOp>();
732+
733+ if (failed (resolveClassStructBody (mod, sym, *typeConverter, cache)))
734+ return op.emitError () << " Could not resolve class struct for " << sym;
735+
736+ auto structTy = cache.getStructInfo (sym)->classBody ;
737+
738+ DataLayout dl (mod);
739+ // DataLayout::getTypeSize gives a byte count for LLVM types.
740+ uint64_t byteSize = dl.getTypeSize (structTy);
741+ auto i64Ty = IntegerType::get (ctx, 64 );
742+ auto cSize = LLVM::ConstantOp::create (rewriter, loc, i64Ty,
743+ rewriter.getI64IntegerAttr (byteSize));
744+
745+ // Get or declare malloc and call it.
746+ auto mallocFn = getOrCreateMalloc (mod, rewriter);
747+ auto ptrTy = LLVM::LLVMPointerType::get (ctx); // opaque pointer result
748+ auto call =
749+ LLVM::CallOp::create (rewriter, loc, TypeRange{ptrTy},
750+ SymbolRefAttr::get (mallocFn), ValueRange{cSize});
751+
752+ // Replace the new op with the malloc pointer (no cast needed with opaque
753+ // ptrs).
754+ rewriter.replaceOp (op, call.getResult ());
755+ return success ();
756+ }
757+
758+ private:
759+ ClassTypeCache &cache; // shared, owned by the pass
760+ };
761+
681762struct ClassDeclOpConversion : public OpConversionPattern <ClassDeclOp> {
682763 ClassDeclOpConversion (TypeConverter &tc, MLIRContext *ctx,
683764 ClassTypeCache &cache)
@@ -686,9 +767,9 @@ struct ClassDeclOpConversion : public OpConversionPattern<ClassDeclOp> {
686767 LogicalResult
687768 matchAndRewrite (ClassDeclOp op, OpAdaptor,
688769 ConversionPatternRewriter &rewriter) const override {
770+
689771 if (failed (resolveClassStructBody (op, *typeConverter, cache)))
690772 return failure ();
691-
692773 // The declaration itself is a no-op
693774 rewriter.eraseOp (op);
694775 return success ();
@@ -2077,7 +2158,8 @@ static void populateOpConversion(ConversionPatternSet &patterns,
20772158
20782159 patterns.add <ClassDeclOpConversion>(typeConverter, patterns.getContext (),
20792160 classCache);
2080-
2161+ patterns.add <ClassNewOpConversion>(typeConverter, patterns.getContext (),
2162+ classCache);
20812163 // clang-format off
20822164 patterns.add <
20832165 // Patterns of declaration operations.
0 commit comments