Skip to content

Reduce boilerplate in ForthOps.td and ForthToMemRef conversion pass #17

@tetsuo-cpp

Description

@tetsuo-cpp

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 convertRegionTypesinlineRegionBeforecreateBlockmergeBlocks 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions