-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
There is significant repetition across the op definitions in ForthOps.td and the conversion patterns in ForthToMemRef.cpp. Adding a new op currently requires copy-pasting ~30 lines of tablegen and ~30 lines of C++ boilerplate that are nearly identical to existing ops.
Repetition in ForthOps.td
~38 out of ~45 ops share the exact same structure:
def Forth_FooOp : Forth_Op<"foo", [Pure]> {
let summary = "...";
let description = [{ ... }];
let arguments = (ins Forth_StackType:$input_stack);
let results = (outs Forth_StackType:$output_stack);
let assemblyFormat = [{
$input_stack attr-dict `:` type($input_stack) `->` type($output_stack)
}];
}
Only the op name, summary, and description differ. The exceptions with truly unique signatures are StackOp (no input), LiteralOp (extra I64Attr), ParamRefOp (extra StrAttr), and IntrinsicOp (non-stack signature).
A shared tablegen class could collapse these to 3-4 lines each.
Repetition in ForthToMemRef.cpp
1. Per-pattern boilerplate (~15 patterns)
Every conversion pattern repeats: constructor taking TypeConverter + MLIRContext, the OneToNOpAdaptor typedef, and the 4-line prologue to extract memref/stackPtr from the adaptor.
2. "Push value onto stack" idiom (~15 sites)
Value one = rewriter.create<arith::ConstantIndexOp>(loc, 1);
Value newSP = rewriter.create<arith::AddIOp>(loc, stackPtr, one);
rewriter.create<memref::StoreOp>(loc, value, memref, newSP);
rewriter.replaceOpWithMultiple(op, {{memref, newSP}});Appears in: LiteralOp, OverOp, ParamRefOp, LoopIndexOp, GlobalIdOp, and all 12 IntrinsicOpConversion instantiations.
3. "Pop top N values" idiom (~10 sites)
Value b = rewriter.create<memref::LoadOp>(loc, memref, stackPtr);
Value one = rewriter.create<arith::ConstantIndexOp>(loc, 1);
Value spMinus1 = rewriter.create<arith::SubIOp>(loc, stackPtr, one);
Value a = rewriter.create<memref::LoadOp>(loc, memref, spMinus1);Appears in: SwapOp, OverOp, RotOp, TuckOp, BinaryArithOpConversion, BinaryCmpOpConversion, StoreOp.
4. Region conversion boilerplate (4 ops, 5 regions)
The convertRegionTypes → inlineRegionBefore → createBlock → mergeBlocks sequence is duplicated across IfOp, BeginUntilOp, BeginWhileRepeatOp, and DoLoopOp.
5. GPU intrinsic registration (12 lines)
12 near-identical patterns.add<IntrinsicOpConversion<...>>(typeConverter, context, "name") calls that differ only in the template argument and string name.
Summary
| Area | What's repeated | Count |
|---|---|---|
.td op definitions |
Identical (ins stack) → (outs stack) + assemblyFormat |
~38 ops |
.cpp constructor/adaptor boilerplate |
Constructor + typedef + memref/SP extraction | ~15 patterns |
.cpp push-value-onto-stack |
SP++, store, replace | ~15 sites |
.cpp pop-N-values |
Load + SP decrement | ~10 sites |
.cpp region conversion |
convertRegionTypes + inline + mergeBlocks | 4 ops, 5 regions |
.cpp intrinsic registration |
patterns.add<IntrinsicOpConversion<T>>(…, name) |
12 lines |