[fir][NFC] Move parser/printer/builder to cpp file

Move the parsers, printers and builders from the TableGen file
to the .cpp file. Remaining parsers, printers and builders will be
moved when we update the operations.

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: schweitz

Differential Revision: https://reviews.llvm.org/D110626

GitOrigin-RevId: 633f70f76ec66956282087dbaf0ab4086a9ffd4f
diff --git a/include/flang/Optimizer/Dialect/FIROps.td b/include/flang/Optimizer/Dialect/FIROps.td
index bbe8d9a..45c11e2 100644
--- a/include/flang/Optimizer/Dialect/FIROps.td
+++ b/include/flang/Optimizer/Dialect/FIROps.td
@@ -394,43 +394,11 @@
 
   let arguments = (ins Arg<AnyReferenceLike, "", [MemRead]>:$memref);
 
-  let builders = [OpBuilder<(ins "mlir::Value":$refVal),
-    [{
-      if (!refVal) {
-        mlir::emitError($_state.location, "LoadOp has null argument");
-        return;
-      }
-      auto eleTy = fir::dyn_cast_ptrEleTy(refVal.getType());
-      if (!eleTy) {
-        mlir::emitError($_state.location, "not a memory reference type");
-        return;
-      }
-      $_state.addOperands(refVal);
-      $_state.addTypes(eleTy);
-    }]
-  >];
+  let builders = [OpBuilder<(ins "mlir::Value":$refVal)>];
 
-  let parser = [{
-    mlir::Type type;
-    mlir::OpAsmParser::OperandType oper;
-    if (parser.parseOperand(oper) ||
-        parser.parseOptionalAttrDict(result.attributes) ||
-        parser.parseColonType(type) ||
-        parser.resolveOperand(oper, type, result.operands))
-       return mlir::failure();
-    mlir::Type eleTy;
-    if (getElementOf(eleTy, type) ||
-        parser.addTypeToList(eleTy, result.types))
-       return mlir::failure();
-    return mlir::success();
-  }];
+  let parser = "return parseLoadOp(parser, result);";
 
-  let printer = [{
-    p << ' ';
-    p.printOperand(memref());
-    p.printOptionalAttrDict((*this)->getAttrs(), {});
-    p << " : " << memref().getType();
-  }];
+  let printer = "::print(p, *this);";
 
   let extraClassDeclaration = [{
     static mlir::ParseResult getElementOf(mlir::Type &ele, mlir::Type ref);
@@ -878,60 +846,9 @@
 
   let parser = "return parseSelectCase(parser, result);";
 
-  let printer = [{
-    p << ' ';
-    p.printOperand(getSelector());
-    p << " : " << getSelector().getType() << " [";
-    auto cases = (*this)->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
-    auto count = getNumConditions();
-    for (decltype(count) i = 0; i != count; ++i) {
-      if (i)
-        p << ", ";
-      p << cases[i] << ", ";
-      if (!cases[i].isa<mlir::UnitAttr>()) {
-        auto caseArgs = *getCompareOperands(i);
-        p.printOperand(*caseArgs.begin());
-        p << ", ";
-        if (cases[i].isa<fir::ClosedIntervalAttr>()) {
-          p.printOperand(*(++caseArgs.begin()));
-          p << ", ";
-        }
-      }
-      printSuccessorAtIndex(p, i);
-    }
-    p << ']';
-    p.printOptionalAttrDict((*this)->getAttrs(), {getCasesAttr(), getCompareOffsetAttr(),
-        getTargetOffsetAttr(), getOperandSegmentSizeAttr()});
-  }];
+  let printer = "::print(p, *this);";
 
-  let verifier = [{
-    if (!(getSelector().getType().isa<mlir::IntegerType>() ||
-          getSelector().getType().isa<mlir::IndexType>() ||
-          getSelector().getType().isa<fir::IntegerType>() ||
-          getSelector().getType().isa<fir::LogicalType>() ||
-          getSelector().getType().isa<fir::CharacterType>()))
-      return emitOpError("must be an integer, character, or logical");
-    auto cases = (*this)->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
-    auto count = getNumDest();
-    if (count == 0)
-      return emitOpError("must have at least one successor");
-    if (getNumConditions() != count)
-      return emitOpError("number of conditions and successors don't match");
-    if (compareOffsetSize() != count)
-      return emitOpError("incorrect number of compare operand groups");
-    if (targetOffsetSize() != count)
-      return emitOpError("incorrect number of successor operand groups");
-    for (decltype(count) i = 0; i != count; ++i) {
-      auto &attr = cases[i];
-      if (!(attr.isa<fir::PointIntervalAttr>() ||
-            attr.isa<fir::LowerBoundAttr>() ||
-            attr.isa<fir::UpperBoundAttr>() ||
-            attr.isa<fir::ClosedIntervalAttr>() ||
-            attr.isa<mlir::UnitAttr>()))
-        return emitOpError("incorrect select case attribute type");
-    }
-    return mlir::success();
-  }];
+  let verifier = "return ::verify(*this);";
 
   let extraClassDeclaration = extraSwitchClassDeclaration#[{
     unsigned compareOffsetSize();
@@ -994,42 +911,9 @@
 
   let parser = "return parseSelectType(parser, result);";
 
-  let printer = [{
-    p << ' ';
-    p.printOperand(getSelector());
-    p << " : " << getSelector().getType() << " [";
-    auto cases = (*this)->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
-    auto count = getNumConditions();
-    for (decltype(count) i = 0; i != count; ++i) {
-      if (i)
-        p << ", ";
-      p << cases[i] << ", ";
-      printSuccessorAtIndex(p, i);
-    }
-    p << ']';
-    p.printOptionalAttrDict((*this)->getAttrs(), {getCasesAttr(), getCompareOffsetAttr(),
-        getTargetOffsetAttr(), getOperandSegmentSizeAttr()});
-  }];
+  let printer = "::print(p, *this);";
 
-  let verifier = [{
-    if (!(getSelector().getType().isa<fir::BoxType>()))
-      return emitOpError("must be a boxed type");
-    auto cases = (*this)->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
-    auto count = getNumDest();
-    if (count == 0)
-      return emitOpError("must have at least one successor");
-    if (getNumConditions() != count)
-      return emitOpError("number of conditions and successors don't match");
-    if (targetOffsetSize() != count)
-      return emitOpError("incorrect number of successor operand groups");
-    for (decltype(count) i = 0; i != count; ++i) {
-      auto &attr = cases[i];
-      if (!(attr.isa<fir::ExactTypeAttr>() || attr.isa<fir::SubclassAttr>() ||
-            attr.isa<mlir::UnitAttr>()))
-        return emitOpError("invalid type-case alternative");
-    }
-    return mlir::success();
-  }];
+  let verifier = "return ::verify(*this);";
 
   let extraClassDeclaration = extraSwitchClassDeclaration;
 }
@@ -1201,7 +1085,7 @@
     $box (`(` $shape^ `)`)? (`[` $slice^ `]`)? attr-dict `:` functional-type(operands, results)
   }];
 
-  let verifier = [{ return ::verify(*this); }];
+  let verifier = "return ::verify(*this);";
 }
 
 def fir_EmboxCharOp : fir_Op<"emboxchar", [NoSideEffect]> {
@@ -1234,12 +1118,7 @@
     $memref `,` $len attr-dict `:` functional-type(operands, results)
   }];
 
-  let verifier = [{
-    auto eleTy = elementTypeOf(memref().getType());
-    if (!eleTy.dyn_cast<CharacterType>())
-      return mlir::failure();
-    return mlir::success();
-  }];
+  let verifier = "return ::verify(*this);";
 }
 
 def fir_EmboxProcOp : fir_Op<"emboxproc", [NoSideEffect]> {
@@ -1271,64 +1150,11 @@
 
   let results = (outs fir_BoxProcType);
 
-  let parser = [{
-    mlir::SymbolRefAttr procRef;
-    if (parser.parseAttribute(procRef, "funcname", result.attributes))
-      return mlir::failure();
-    bool hasTuple = false;
-    mlir::OpAsmParser::OperandType tupleRef;
-    if (!parser.parseOptionalComma()) {
-      if (parser.parseOperand(tupleRef))
-        return mlir::failure();
-      hasTuple = true;
-    }
-    mlir::FunctionType type;
-    if (parser.parseColon() ||
-        parser.parseLParen() ||
-        parser.parseType(type))
-      return mlir::failure();
-    result.addAttribute("functype", mlir::TypeAttr::get(type));
-    if (hasTuple) {
-      mlir::Type tupleType;
-      if (parser.parseComma() ||
-          parser.parseType(tupleType) ||
-          parser.resolveOperand(tupleRef, tupleType, result.operands))
-        return mlir::failure();
-    }
-    mlir::Type boxType;
-    if (parser.parseRParen() ||
-        parser.parseArrow() ||
-        parser.parseType(boxType) ||
-        parser.addTypesToList(boxType, result.types))
-      return mlir::failure();
-    return mlir::success();
-  }];
+  let parser = "return parseEmboxProcOp(parser, result);";
 
-  let printer = [{
-    p << ' ' << (*this)->getAttr("funcname");
-    auto h = host();
-    if (h) {
-      p << ", ";
-      p.printOperand(h);
-    }
-    p << " : (" << (*this)->getAttr("functype");
-    if (h)
-      p << ", " << h.getType();
-    p << ") -> " << getType();
-  }];
+  let printer = "::print(p, *this);";
 
-  let verifier = [{
-    // host bindings (optional) must be a reference to a tuple
-    if (auto h = host()) {
-      if (auto r = h.getType().dyn_cast<ReferenceType>()) {
-        if (!r.getEleTy().dyn_cast<mlir::TupleType>())
-          return mlir::failure();
-      } else {
-        return mlir::failure();
-      }
-    }
-    return mlir::success();
-  }];
+  let verifier = "return ::verify(*this);";
 }
 
 def fir_UnboxOp : fir_SimpleOp<"unbox", [NoSideEffect]> {
@@ -1390,12 +1216,7 @@
     ```
   }];
 
-  let verifier = [{
-    if (auto eleTy = fir::dyn_cast_ptrEleTy(refTuple().getType()))
-      if (eleTy.isa<mlir::TupleType>())
-        return mlir::success();
-    return emitOpError("second output argument has bad type");
-  }];
+  let verifier = "return ::verify(*this);";
 
   let arguments = (ins fir_BoxProcType:$boxproc);
 
@@ -1705,7 +1526,7 @@
         attr-dict `:` functional-type(operands, results)
   }];
 
-  let verifier = [{ return ::verify(*this); }];
+  let verifier = "return ::verify(*this);";
 
   let extraClassDeclaration = [{
     std::vector<mlir::Value> getExtents();
@@ -1935,9 +1756,9 @@
 
   let results = (outs fir_ReferenceType);
 
-  let parser =  [{ return parseCoordinateCustom(parser, result); }];
-  let printer = [{ ::print(p, *this); }];
-  let verifier = [{ return ::verify(*this); }];
+  let parser =  "return parseCoordinateCustom(parser, result);";
+  let printer = "::print(p, *this);";
+  let verifier = "return ::verify(*this);";
 
   let builders = [
     OpBuilder<(ins "mlir::Type":$resultType,
@@ -2141,18 +1962,7 @@
     operands attr-dict `:` functional-type(operands, results)
   }];
 
-  let verifier = [{
-    auto size = pairs().size();
-    if (size < 2 || size > 16 * 2)
-      return emitOpError("incorrect number of args");
-    if (size % 2 != 0)
-      return emitOpError("requires a multiple of 2 args");
-    auto shapeTy = getType().dyn_cast<fir::ShapeShiftType>();
-    assert(shapeTy && "must be a shape shift type");
-    if (shapeTy.getRank() * 2 != size)
-      return emitOpError("shape type rank mismatch");
-    return mlir::success();
-  }];
+  let verifier = "return ::verify(*this);";
 
   let extraClassDeclaration = [{
     // Logically unzip the origins from the extent values.
@@ -2199,14 +2009,7 @@
     operands attr-dict `:` functional-type(operands, results)
   }];
 
-  let verifier = [{
-    auto size = origins().size();
-    auto shiftTy = getType().dyn_cast<fir::ShiftType>();
-    assert(shiftTy && "must be a shift type");
-    if (shiftTy.getRank() != size)
-      return emitOpError("shift type rank mismatch");
-    return mlir::success();
-  }];
+  let verifier = "return ::verify(*this);";
 
   let extraClassDeclaration = [{
     std::vector<mlir::Value> getOrigins() {
@@ -2253,18 +2056,7 @@
     $triples (`path` $fields^)? attr-dict `:` functional-type(operands, results)
   }];
 
-  let verifier = [{
-    auto size = triples().size();
-    if (size < 3 || size > 16 * 3)
-      return emitOpError("incorrect number of args for triple");
-    if (size % 3 != 0)
-      return emitOpError("requires a multiple of 3 args");
-    auto sliceTy = getType().dyn_cast<fir::SliceType>();
-    assert(sliceTy && "must be a slice type");
-    if (sliceTy.getRank() * 3 != size)
-      return emitOpError("slice type rank mismatch");
-    return mlir::success();
-  }];
+  let verifier = "return ::verify(*this);";
 
   let extraClassDeclaration = [{
     unsigned getOutRank() { return getOutputRank(triples()); }
@@ -2363,29 +2155,9 @@
 
   let arguments = (ins StrAttr:$field_id, TypeAttr:$on_type);
 
-  let parser = [{
-    llvm::StringRef fieldName;
-    auto &builder = parser.getBuilder();
-    mlir::Type recty;
-    if (parser.parseOptionalKeyword(&fieldName) ||
-        parser.parseComma() ||
-        parser.parseType(recty))
-      return mlir::failure();
-    result.addAttribute(fieldAttrName(), builder.getStringAttr(fieldName));
-    if (!recty.dyn_cast<RecordType>())
-      return mlir::failure();
-    result.addAttribute(typeAttrName(), mlir::TypeAttr::get(recty));
-    mlir::Type lenType = fir::LenType::get(builder.getContext());
-    if (parser.addTypeToList(lenType, result.types))
-      return mlir::failure();
-    return mlir::success();
-  }];
+  let parser = "return parseLenParamIndexOp(parser, result);";
 
-  let printer = [{
-    p << ' '
-      << (*this)->getAttrOfType<mlir::StringAttr>(fieldAttrName()).getValue()
-      << ", " << (*this)->getAttr(typeAttrName());
-  }];
+  let printer = "::print(p, *this);";
 
   let builders = [OpBuilder<(ins "llvm::StringRef":$fieldName,
       "mlir::Type":$recTy),
@@ -2425,7 +2197,7 @@
 
   let assemblyFormat = "($results^ `:` type($results))? attr-dict";
 
-  let verifier = [{ return ::verify(*this); }];
+  let verifier = "return ::verify(*this);";
 }
 
 def FirRegionTerminator : SingleBlockImplicitTerminator<"ResultOp">;
@@ -2433,9 +2205,9 @@
 class region_Op<string mnemonic, list<OpTrait> traits = []> :
     fir_Op<mnemonic,
     !listconcat(traits, [FirRegionTerminator, RecursiveSideEffects])> {
-  let printer = [{ return ::print(p, *this); }];
-  let verifier = [{ return ::verify(*this); }];
-  let parser = [{ return ::parse$cppClass(parser, result); }];
+  let printer = "return ::print(p, *this);";
+  let verifier = "return ::verify(*this);";
+  let parser = "return ::parse$cppClass(parser, result);";
 }
 
 def fir_DoLoopOp : region_Op<"do_loop",
@@ -2757,41 +2529,9 @@
 
   let results = (outs Variadic<AnyType>);
 
-  let parser = [{
-    mlir::FunctionType calleeType;
-    llvm::SmallVector<mlir::OpAsmParser::OperandType, 4> operands;
-    auto calleeLoc = parser.getNameLoc();
-    llvm::StringRef calleeName;
-    if (failed(parser.parseOptionalKeyword(&calleeName))) {
-      mlir::StringAttr calleeAttr;
-      if (parser.parseAttribute(calleeAttr, "method", result.attributes))
-        return mlir::failure();
-    } else {
-      result.addAttribute(methodAttrName(result.name),
-          parser.getBuilder().getStringAttr(calleeName));
-    }
-    if (parser.parseOperandList(operands,
-                                mlir::OpAsmParser::Delimiter::Paren) ||
-        parser.parseOptionalAttrDict(result.attributes) ||
-        parser.parseColonType(calleeType) ||
-        parser.addTypesToList(calleeType.getResults(), result.types) ||
-        parser.resolveOperands(
-            operands, calleeType.getInputs(), calleeLoc, result.operands))
-      return mlir::failure();
-    return mlir::success();
-  }];
+  let parser = "return parseDispatchOp(parser, result);";
 
-  let printer = [{
-    p << ' ' << methodAttr() << '(';
-    p.printOperand(object());
-    if (!args().empty()) {
-      p << ", ";
-      p.printOperands(args());
-    }
-    p << ") : ";
-    p.printFunctionalType((*this)->getOperandTypes(),
-        (*this)->getResultTypes());
-  }];
+  let printer = "::print(p, *this);";
 
   let extraClassDeclaration = [{
     mlir::FunctionType getFunctionType();
@@ -2804,6 +2544,7 @@
     static constexpr llvm::StringRef passArgAttrName() {
       return "pass_arg_pos";
     }
+    static constexpr llvm::StringRef getMethodAttrName() { return "method"; }
     unsigned passArgPos();
   }];
 }
@@ -2912,39 +2653,11 @@
 
   let results = (outs fir_ComplexType);
 
-  let parser = [{
-    fir::RealAttr realp;
-    fir::RealAttr imagp;
-    mlir::Type type;
-    if (parser.parseLParen() ||
-        parser.parseAttribute(realp, realAttrName(), result.attributes) ||
-        parser.parseComma() ||
-        parser.parseAttribute(imagp, imagAttrName(), result.attributes) ||
-        parser.parseRParen() ||
-        parser.parseColonType(type) ||
-        parser.addTypesToList(type, result.types))
-      return mlir::failure();
-    return mlir::success();
-  }];
+  let parser = "return parseConstcOp(parser, result);";
 
-  let printer = [{
-    p << " (0x";
-    auto f1 = (*this)->getAttr(realAttrName()).cast<mlir::FloatAttr>();
-    auto i1 = f1.getValue().bitcastToAPInt();
-    p.getStream().write_hex(i1.getZExtValue());
-    p << ", 0x";
-    auto f2 = (*this)->getAttr(imagAttrName()).cast<mlir::FloatAttr>();
-    auto i2 = f2.getValue().bitcastToAPInt();
-    p.getStream().write_hex(i2.getZExtValue());
-    p << ") : ";
-    p.printType(getType());
-  }];
+  let printer = "::print(p, *this);";
 
-  let verifier = [{
-    if (!getType().isa<fir::ComplexType>())
-      return emitOpError("must be a !fir.complex type");
-    return mlir::success();
-  }];
+  let verifier = "return ::verify(*this);";
 
   let extraClassDeclaration = [{
     static constexpr llvm::StringRef realAttrName() { return "real"; }
@@ -3052,23 +2765,7 @@
 
   let hasFolder = 1;
 
-  let verifier = [{
-    auto inType = value().getType();
-    auto outType = getType();
-    if (inType == outType)
-      return mlir::success();
-    if ((isPointerCompatible(inType) && isPointerCompatible(outType)) ||
-        (isIntegerCompatible(inType) && isIntegerCompatible(outType)) ||
-        (isIntegerCompatible(inType) && isFloatCompatible(outType)) ||
-        (isFloatCompatible(inType) && isIntegerCompatible(outType)) ||
-        (isFloatCompatible(inType) && isFloatCompatible(outType)) ||
-        (isIntegerCompatible(inType) && isPointerCompatible(outType)) ||
-        (isPointerCompatible(inType) && isIntegerCompatible(outType)) ||
-        (inType.isa<fir::BoxType>() && outType.isa<fir::BoxType>()) ||
-        (fir::isa_complex(inType) && fir::isa_complex(outType)))
-      return mlir::success();
-    return emitOpError("invalid type conversion");
-  }];
+  let verifier = "return ::verify(*this);";
 
   let extraClassDeclaration = [{
     static bool isIntegerCompatible(mlir::Type ty);
@@ -3106,34 +2803,13 @@
 
   let arguments = (ins FortranTypeAttr:$in_type);
 
-  let parser = [{
-    mlir::Type intype;
-    if (parser.parseType(intype))
-      return mlir::failure();
-    result.addAttribute("in_type", mlir::TypeAttr::get(intype));
-    mlir::Type restype = TypeDescType::get(intype);
-    if (parser.addTypeToList(restype, result.types))
-      return mlir::failure();
-    return mlir::success();
-  }];
+  let parser = "return parseGenTypeDescOp(parser, result);";
 
-  let printer = [{
-    p << ' ' << (*this)->getAttr("in_type");
-    p.printOptionalAttrDict((*this)->getAttrs(), {"in_type"});
-  }];
+  let printer = "::print(p, *this);";
 
   let builders = [OpBuilder<(ins "mlir::TypeAttr":$inty)>];
 
-  let verifier = [{
-    mlir::Type resultTy = getType();
-    if (auto tdesc = resultTy.dyn_cast<TypeDescType>()) {
-      if (tdesc.getOfTy() != getInType())
-        return emitOpError("wrapped type mismatched");
-    } else {
-      return emitOpError("must be !fir.tdesc type");
-    }
-    return mlir::success();
-  }];
+  let verifier = "return ::verify(*this);";
 
   let extraClassDeclaration = [{
     mlir::Type getInType() {
@@ -3355,44 +3031,11 @@
     ```
   }];
 
-  let parser = [{
-    // Parse the name as a symbol reference attribute.
-    SymbolRefAttr nameAttr;
-    if (parser.parseAttribute(nameAttr, mlir::SymbolTable::getSymbolAttrName(),
-                              result.attributes))
-      return failure();
+  let parser = "return parseDispatchTableOp(parser, result);";
 
-    // Convert the parsed name attr into a string attr.
-    result.attributes.set(mlir::SymbolTable::getSymbolAttrName(),
-      nameAttr.getRootReference());
+  let printer = "::print(p, *this);";
 
-    // Parse the optional table body.
-    mlir::Region *body = result.addRegion();
-    OptionalParseResult parseResult = parser.parseOptionalRegion(*body);
-    if (parseResult.hasValue() && failed(*parseResult))
-      return mlir::failure();
-
-    ensureTerminator(*body, parser.getBuilder(), result.location);
-    return mlir::success();
-  }];
-
-  let printer = [{
-    auto tableName = (*this)->getAttrOfType<StringAttr>(
-      mlir::SymbolTable::getSymbolAttrName()).getValue();
-    p << " @" << tableName;
-
-    Region &body = (*this)->getRegion(0);
-    if (!body.empty())
-      p.printRegion(body, /*printEntryBlockArgs=*/false,
-                          /*printBlockTerminators=*/false);
-  }];
-
-  let verifier = [{
-    for (auto &op : getBlock())
-      if (!(isa<fir::DTEntryOp>(op) || isa<fir::FirEndOp>(op)))
-        return emitOpError("dispatch table must contain dt_entry");
-    return mlir::success();
-  }];
+  let verifier = "return ::verify(*this);";
 
   let regions = (region SizedRegion<1>:$region);
 
@@ -3438,28 +3081,13 @@
 
   let arguments = (ins StrAttr:$method, SymbolRefAttr:$proc);
 
-  let parser = [{
-    llvm::StringRef methodName;
-    // allow `methodName` or `"methodName"`
-    if (failed(parser.parseOptionalKeyword(&methodName))) {
-      mlir::StringAttr methodAttr;
-      if (parser.parseAttribute(methodAttr, "method",
-                                result.attributes))
-        return mlir::failure();
-    } else {
-      result.addAttribute(methodAttrName(result.name),
-          parser.getBuilder().getStringAttr(methodName));
-    }
-    mlir::SymbolRefAttr calleeAttr;
-    if (parser.parseComma() ||
-        parser.parseAttribute(calleeAttr, "proc", result.attributes))
-      return mlir::failure();
-    return mlir::success();
-  }];
+  let parser = "return parseDTEntryOp(parser, result);";
 
-  let printer = [{
-    p << ' ' << methodAttr() << ", "
-      << procAttr();
+  let printer = "::print(p, *this);";
+
+  let extraClassDeclaration = [{
+    static constexpr llvm::StringRef getMethodAttrName() { return "method"; }
+    static constexpr llvm::StringRef getProcAttrName() { return "proc"; }
   }];
 }
 
diff --git a/lib/Optimizer/Dialect/FIROps.cpp b/lib/Optimizer/Dialect/FIROps.cpp
index 0f2a469..ab6fe7f 100644
--- a/lib/Optimizer/Dialect/FIROps.cpp
+++ b/lib/Optimizer/Dialect/FIROps.cpp
@@ -658,6 +658,50 @@
 }
 
 //===----------------------------------------------------------------------===//
+// ConstcOp
+//===----------------------------------------------------------------------===//
+
+static mlir::ParseResult parseConstcOp(mlir::OpAsmParser &parser,
+                                       mlir::OperationState &result) {
+  fir::RealAttr realp;
+  fir::RealAttr imagp;
+  mlir::Type type;
+  if (parser.parseLParen() ||
+      parser.parseAttribute(realp, fir::ConstcOp::realAttrName(),
+                            result.attributes) ||
+      parser.parseComma() ||
+      parser.parseAttribute(imagp, fir::ConstcOp::imagAttrName(),
+                            result.attributes) ||
+      parser.parseRParen() || parser.parseColonType(type) ||
+      parser.addTypesToList(type, result.types))
+    return mlir::failure();
+  return mlir::success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::ConstcOp &op) {
+  p << " (0x";
+  auto f1 = op.getOperation()
+                ->getAttr(fir::ConstcOp::realAttrName())
+                .cast<mlir::FloatAttr>();
+  auto i1 = f1.getValue().bitcastToAPInt();
+  p.getStream().write_hex(i1.getZExtValue());
+  p << ", 0x";
+  auto f2 = op.getOperation()
+                ->getAttr(fir::ConstcOp::imagAttrName())
+                .cast<mlir::FloatAttr>();
+  auto i2 = f2.getValue().bitcastToAPInt();
+  p.getStream().write_hex(i2.getZExtValue());
+  p << ") : ";
+  p.printType(op.getType());
+}
+
+static mlir::LogicalResult verify(fir::ConstcOp &op) {
+  if (!op.getType().isa<fir::ComplexType>())
+    return op.emitOpError("must be a !fir.complex type");
+  return mlir::success();
+}
+
+//===----------------------------------------------------------------------===//
 // ConvertOp
 //===----------------------------------------------------------------------===//
 
@@ -699,6 +743,24 @@
          ty.isa<mlir::FunctionType>() || ty.isa<fir::TypeDescType>();
 }
 
+static mlir::LogicalResult verify(fir::ConvertOp &op) {
+  auto inType = op.value().getType();
+  auto outType = op.getType();
+  if (inType == outType)
+    return mlir::success();
+  if ((op.isPointerCompatible(inType) && op.isPointerCompatible(outType)) ||
+      (op.isIntegerCompatible(inType) && op.isIntegerCompatible(outType)) ||
+      (op.isIntegerCompatible(inType) && op.isFloatCompatible(outType)) ||
+      (op.isFloatCompatible(inType) && op.isIntegerCompatible(outType)) ||
+      (op.isFloatCompatible(inType) && op.isFloatCompatible(outType)) ||
+      (op.isIntegerCompatible(inType) && op.isPointerCompatible(outType)) ||
+      (op.isPointerCompatible(inType) && op.isIntegerCompatible(outType)) ||
+      (inType.isa<fir::BoxType>() && outType.isa<fir::BoxType>()) ||
+      (fir::isa_complex(inType) && fir::isa_complex(outType)))
+    return mlir::success();
+  return op.emitOpError("invalid type conversion");
+}
+
 //===----------------------------------------------------------------------===//
 // CoordinateOp
 //===----------------------------------------------------------------------===//
@@ -769,6 +831,44 @@
                                  getResultTypes());
 }
 
+static mlir::ParseResult parseDispatchOp(mlir::OpAsmParser &parser,
+                                         mlir::OperationState &result) {
+  mlir::FunctionType calleeType;
+  llvm::SmallVector<mlir::OpAsmParser::OperandType> operands;
+  auto calleeLoc = parser.getNameLoc();
+  llvm::StringRef calleeName;
+  if (failed(parser.parseOptionalKeyword(&calleeName))) {
+    mlir::StringAttr calleeAttr;
+    if (parser.parseAttribute(calleeAttr, fir::DispatchOp::getMethodAttrName(),
+                              result.attributes))
+      return mlir::failure();
+  } else {
+    result.addAttribute(fir::DispatchOp::getMethodAttrName(),
+                        parser.getBuilder().getStringAttr(calleeName));
+  }
+  if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::Paren) ||
+      parser.parseOptionalAttrDict(result.attributes) ||
+      parser.parseColonType(calleeType) ||
+      parser.addTypesToList(calleeType.getResults(), result.types) ||
+      parser.resolveOperands(operands, calleeType.getInputs(), calleeLoc,
+                             result.operands))
+    return mlir::failure();
+  return mlir::success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::DispatchOp &op) {
+  p << ' ' << op.getOperation()->getAttr(fir::DispatchOp::getMethodAttrName())
+    << '(';
+  p.printOperand(op.object());
+  if (!op.args().empty()) {
+    p << ", ";
+    p.printOperands(op.args());
+  }
+  p << ") : ";
+  p.printFunctionalType(op.getOperation()->getOperandTypes(),
+                        op.getOperation()->getResultTypes());
+}
+
 //===----------------------------------------------------------------------===//
 // DispatchTableOp
 //===----------------------------------------------------------------------===//
@@ -779,6 +879,49 @@
   block.getOperations().insert(block.end(), op);
 }
 
+static mlir::ParseResult parseDispatchTableOp(mlir::OpAsmParser &parser,
+                                              mlir::OperationState &result) {
+  // Parse the name as a symbol reference attribute.
+  SymbolRefAttr nameAttr;
+  if (parser.parseAttribute(nameAttr, mlir::SymbolTable::getSymbolAttrName(),
+                            result.attributes))
+    return failure();
+
+  // Convert the parsed name attr into a string attr.
+  result.attributes.set(mlir::SymbolTable::getSymbolAttrName(),
+                        nameAttr.getRootReference());
+
+  // Parse the optional table body.
+  mlir::Region *body = result.addRegion();
+  OptionalParseResult parseResult = parser.parseOptionalRegion(*body);
+  if (parseResult.hasValue() && failed(*parseResult))
+    return mlir::failure();
+
+  fir::DispatchTableOp::ensureTerminator(*body, parser.getBuilder(),
+                                         result.location);
+  return mlir::success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::DispatchTableOp &op) {
+  auto tableName =
+      op.getOperation()
+          ->getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName())
+          .getValue();
+  p << " @" << tableName;
+
+  Region &body = op.getOperation()->getRegion(0);
+  if (!body.empty())
+    p.printRegion(body, /*printEntryBlockArgs=*/false,
+                  /*printBlockTerminators=*/false);
+}
+
+static mlir::LogicalResult verify(fir::DispatchTableOp &op) {
+  for (auto &op : op.getBlock())
+    if (!(isa<fir::DTEntryOp>(op) || isa<fir::FirEndOp>(op)))
+      return op.emitOpError("dispatch table must contain dt_entry");
+  return mlir::success();
+}
+
 //===----------------------------------------------------------------------===//
 // EmboxOp
 //===----------------------------------------------------------------------===//
@@ -814,6 +957,76 @@
 }
 
 //===----------------------------------------------------------------------===//
+// EmboxCharOp
+//===----------------------------------------------------------------------===//
+
+static mlir::LogicalResult verify(fir::EmboxCharOp &op) {
+  auto eleTy = fir::dyn_cast_ptrEleTy(op.memref().getType());
+  if (!eleTy.dyn_cast_or_null<CharacterType>())
+    return mlir::failure();
+  return mlir::success();
+}
+
+//===----------------------------------------------------------------------===//
+// EmboxProcOp
+//===----------------------------------------------------------------------===//
+
+static mlir::ParseResult parseEmboxProcOp(mlir::OpAsmParser &parser,
+                                          mlir::OperationState &result) {
+  mlir::SymbolRefAttr procRef;
+  if (parser.parseAttribute(procRef, "funcname", result.attributes))
+    return mlir::failure();
+  bool hasTuple = false;
+  mlir::OpAsmParser::OperandType tupleRef;
+  if (!parser.parseOptionalComma()) {
+    if (parser.parseOperand(tupleRef))
+      return mlir::failure();
+    hasTuple = true;
+  }
+  mlir::FunctionType type;
+  if (parser.parseColon() || parser.parseLParen() || parser.parseType(type))
+    return mlir::failure();
+  result.addAttribute("functype", mlir::TypeAttr::get(type));
+  if (hasTuple) {
+    mlir::Type tupleType;
+    if (parser.parseComma() || parser.parseType(tupleType) ||
+        parser.resolveOperand(tupleRef, tupleType, result.operands))
+      return mlir::failure();
+  }
+  mlir::Type boxType;
+  if (parser.parseRParen() || parser.parseArrow() ||
+      parser.parseType(boxType) || parser.addTypesToList(boxType, result.types))
+    return mlir::failure();
+  return mlir::success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::EmboxProcOp &op) {
+  p << ' ' << op.getOperation()->getAttr("funcname");
+  auto h = op.host();
+  if (h) {
+    p << ", ";
+    p.printOperand(h);
+  }
+  p << " : (" << op.getOperation()->getAttr("functype");
+  if (h)
+    p << ", " << h.getType();
+  p << ") -> " << op.getType();
+}
+
+static mlir::LogicalResult verify(fir::EmboxProcOp &op) {
+  // host bindings (optional) must be a reference to a tuple
+  if (auto h = op.host()) {
+    if (auto r = h.getType().dyn_cast<ReferenceType>()) {
+      if (!r.getEleTy().dyn_cast<mlir::TupleType>())
+        return mlir::failure();
+    } else {
+      return mlir::failure();
+    }
+  }
+  return mlir::success();
+}
+
+//===----------------------------------------------------------------------===//
 // GenTypeDescOp
 //===----------------------------------------------------------------------===//
 
@@ -823,6 +1036,34 @@
   result.addTypes(TypeDescType::get(inty.getValue()));
 }
 
+static mlir::ParseResult parseGenTypeDescOp(mlir::OpAsmParser &parser,
+                                            mlir::OperationState &result) {
+  mlir::Type intype;
+  if (parser.parseType(intype))
+    return mlir::failure();
+  result.addAttribute("in_type", mlir::TypeAttr::get(intype));
+  mlir::Type restype = TypeDescType::get(intype);
+  if (parser.addTypeToList(restype, result.types))
+    return mlir::failure();
+  return mlir::success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::GenTypeDescOp &op) {
+  p << ' ' << op.getOperation()->getAttr("in_type");
+  p.printOptionalAttrDict(op.getOperation()->getAttrs(), {"in_type"});
+}
+
+static mlir::LogicalResult verify(fir::GenTypeDescOp &op) {
+  mlir::Type resultTy = op.getType();
+  if (auto tdesc = resultTy.dyn_cast<TypeDescType>()) {
+    if (tdesc.getOfTy() != op.getInType())
+      return op.emitOpError("wrapped type mismatched");
+  } else {
+    return op.emitOpError("must be !fir.tdesc type");
+  }
+  return mlir::success();
+}
+
 //===----------------------------------------------------------------------===//
 // GlobalOp
 //===----------------------------------------------------------------------===//
@@ -1323,9 +1564,57 @@
 }
 
 //===----------------------------------------------------------------------===//
+// LenParamIndexOp
+//===----------------------------------------------------------------------===//
+
+static mlir::ParseResult parseLenParamIndexOp(mlir::OpAsmParser &parser,
+                                              mlir::OperationState &result) {
+  llvm::StringRef fieldName;
+  auto &builder = parser.getBuilder();
+  mlir::Type recty;
+  if (parser.parseOptionalKeyword(&fieldName) || parser.parseComma() ||
+      parser.parseType(recty))
+    return mlir::failure();
+  result.addAttribute(fir::LenParamIndexOp::fieldAttrName(),
+                      builder.getStringAttr(fieldName));
+  if (!recty.dyn_cast<RecordType>())
+    return mlir::failure();
+  result.addAttribute(fir::LenParamIndexOp::typeAttrName(),
+                      mlir::TypeAttr::get(recty));
+  mlir::Type lenType = fir::LenType::get(builder.getContext());
+  if (parser.addTypeToList(lenType, result.types))
+    return mlir::failure();
+  return mlir::success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::LenParamIndexOp &op) {
+  p << ' '
+    << op.getOperation()
+           ->getAttrOfType<mlir::StringAttr>(
+               fir::LenParamIndexOp::fieldAttrName())
+           .getValue()
+    << ", " << op.getOperation()->getAttr(fir::LenParamIndexOp::typeAttrName());
+}
+
+//===----------------------------------------------------------------------===//
 // LoadOp
 //===----------------------------------------------------------------------===//
 
+void fir::LoadOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
+                        mlir::Value refVal) {
+  if (!refVal) {
+    mlir::emitError(result.location, "LoadOp has null argument");
+    return;
+  }
+  auto eleTy = fir::dyn_cast_ptrEleTy(refVal.getType());
+  if (!eleTy) {
+    mlir::emitError(result.location, "not a memory reference type");
+    return;
+  }
+  result.addOperands(refVal);
+  result.addTypes(eleTy);
+}
+
 /// Get the element type of a reference like type; otherwise null
 static mlir::Type elementTypeOf(mlir::Type ref) {
   return llvm::TypeSwitch<mlir::Type, mlir::Type>(ref)
@@ -1340,6 +1629,29 @@
   return mlir::failure();
 }
 
+static mlir::ParseResult parseLoadOp(mlir::OpAsmParser &parser,
+                                     mlir::OperationState &result) {
+  mlir::Type type;
+  mlir::OpAsmParser::OperandType oper;
+  if (parser.parseOperand(oper) ||
+      parser.parseOptionalAttrDict(result.attributes) ||
+      parser.parseColonType(type) ||
+      parser.resolveOperand(oper, type, result.operands))
+    return mlir::failure();
+  mlir::Type eleTy;
+  if (fir::LoadOp::getElementOf(eleTy, type) ||
+      parser.addTypeToList(eleTy, result.types))
+    return mlir::failure();
+  return mlir::success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::LoadOp &op) {
+  p << ' ';
+  p.printOperand(op.memref());
+  p.printOptionalAttrDict(op.getOperation()->getAttrs(), {});
+  p << " : " << op.memref().getType();
+}
+
 //===----------------------------------------------------------------------===//
 // DoLoopOp
 //===----------------------------------------------------------------------===//
@@ -1560,6 +1872,36 @@
 }
 
 //===----------------------------------------------------------------------===//
+// DTEntryOp
+//===----------------------------------------------------------------------===//
+
+static mlir::ParseResult parseDTEntryOp(mlir::OpAsmParser &parser,
+                                        mlir::OperationState &result) {
+  llvm::StringRef methodName;
+  // allow `methodName` or `"methodName"`
+  if (failed(parser.parseOptionalKeyword(&methodName))) {
+    mlir::StringAttr methodAttr;
+    if (parser.parseAttribute(methodAttr, fir::DTEntryOp::getMethodAttrName(),
+                              result.attributes))
+      return mlir::failure();
+  } else {
+    result.addAttribute(fir::DTEntryOp::getMethodAttrName(),
+                        parser.getBuilder().getStringAttr(methodName));
+  }
+  mlir::SymbolRefAttr calleeAttr;
+  if (parser.parseComma() ||
+      parser.parseAttribute(calleeAttr, fir::DTEntryOp::getProcAttrName(),
+                            result.attributes))
+    return mlir::failure();
+  return mlir::success();
+}
+
+static void print(mlir::OpAsmPrinter &p, fir::DTEntryOp &op) {
+  p << ' ' << op.getOperation()->getAttr(fir::DTEntryOp::getMethodAttrName())
+    << ", " << op.getOperation()->getAttr(fir::DTEntryOp::getProcAttrName());
+}
+
+//===----------------------------------------------------------------------===//
 // ReboxOp
 //===----------------------------------------------------------------------===//
 
@@ -1896,6 +2238,36 @@
   return mlir::success();
 }
 
+static void print(mlir::OpAsmPrinter &p, fir::SelectCaseOp &op) {
+  p << ' ';
+  p.printOperand(op.getSelector());
+  p << " : " << op.getSelector().getType() << " [";
+  auto cases = op.getOperation()
+                   ->getAttrOfType<mlir::ArrayAttr>(op.getCasesAttr())
+                   .getValue();
+  auto count = op.getNumConditions();
+  for (decltype(count) i = 0; i != count; ++i) {
+    if (i)
+      p << ", ";
+    p << cases[i] << ", ";
+    if (!cases[i].isa<mlir::UnitAttr>()) {
+      auto caseArgs = *op.getCompareOperands(i);
+      p.printOperand(*caseArgs.begin());
+      p << ", ";
+      if (cases[i].isa<fir::ClosedIntervalAttr>()) {
+        p.printOperand(*(++caseArgs.begin()));
+        p << ", ";
+      }
+    }
+    op.printSuccessorAtIndex(p, i);
+  }
+  p << ']';
+  p.printOptionalAttrDict(op.getOperation()->getAttrs(),
+                          {op.getCasesAttr(), getCompareOffsetAttr(),
+                           getTargetOffsetAttr(),
+                           op.getOperandSegmentSizeAttr()});
+}
+
 unsigned fir::SelectCaseOp::compareOffsetSize() {
   return denseElementsSize((*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
       getCompareOffsetAttr()));
@@ -1984,6 +2356,35 @@
         destOperands, attributes);
 }
 
+static mlir::LogicalResult verify(fir::SelectCaseOp &op) {
+  if (!(op.getSelector().getType().isa<mlir::IntegerType>() ||
+        op.getSelector().getType().isa<mlir::IndexType>() ||
+        op.getSelector().getType().isa<fir::IntegerType>() ||
+        op.getSelector().getType().isa<fir::LogicalType>() ||
+        op.getSelector().getType().isa<fir::CharacterType>()))
+    return op.emitOpError("must be an integer, character, or logical");
+  auto cases = op.getOperation()
+                   ->getAttrOfType<mlir::ArrayAttr>(op.getCasesAttr())
+                   .getValue();
+  auto count = op.getNumDest();
+  if (count == 0)
+    return op.emitOpError("must have at least one successor");
+  if (op.getNumConditions() != count)
+    return op.emitOpError("number of conditions and successors don't match");
+  if (op.compareOffsetSize() != count)
+    return op.emitOpError("incorrect number of compare operand groups");
+  if (op.targetOffsetSize() != count)
+    return op.emitOpError("incorrect number of successor operand groups");
+  for (decltype(count) i = 0; i != count; ++i) {
+    auto &attr = cases[i];
+    if (!(attr.isa<fir::PointIntervalAttr>() ||
+          attr.isa<fir::LowerBoundAttr>() || attr.isa<fir::UpperBoundAttr>() ||
+          attr.isa<fir::ClosedIntervalAttr>() || attr.isa<mlir::UnitAttr>()))
+      return op.emitOpError("incorrect select case attribute type");
+  }
+  return mlir::success();
+}
+
 //===----------------------------------------------------------------------===//
 // SelectRankOp
 //===----------------------------------------------------------------------===//
@@ -2099,6 +2500,79 @@
       getTargetOffsetAttr()));
 }
 
+static void print(mlir::OpAsmPrinter &p, fir::SelectTypeOp &op) {
+  p << ' ';
+  p.printOperand(op.getSelector());
+  p << " : " << op.getSelector().getType() << " [";
+  auto cases = op.getOperation()
+                   ->getAttrOfType<mlir::ArrayAttr>(op.getCasesAttr())
+                   .getValue();
+  auto count = op.getNumConditions();
+  for (decltype(count) i = 0; i != count; ++i) {
+    if (i)
+      p << ", ";
+    p << cases[i] << ", ";
+    op.printSuccessorAtIndex(p, i);
+  }
+  p << ']';
+  p.printOptionalAttrDict(op.getOperation()->getAttrs(),
+                          {op.getCasesAttr(), getCompareOffsetAttr(),
+                           getTargetOffsetAttr(),
+                           fir::SelectTypeOp::getOperandSegmentSizeAttr()});
+}
+
+static mlir::LogicalResult verify(fir::SelectTypeOp &op) {
+  if (!(op.getSelector().getType().isa<fir::BoxType>()))
+    return op.emitOpError("must be a boxed type");
+  auto cases = op.getOperation()
+                   ->getAttrOfType<mlir::ArrayAttr>(op.getCasesAttr())
+                   .getValue();
+  auto count = op.getNumDest();
+  if (count == 0)
+    return op.emitOpError("must have at least one successor");
+  if (op.getNumConditions() != count)
+    return op.emitOpError("number of conditions and successors don't match");
+  if (op.targetOffsetSize() != count)
+    return op.emitOpError("incorrect number of successor operand groups");
+  for (decltype(count) i = 0; i != count; ++i) {
+    auto &attr = cases[i];
+    if (!(attr.isa<fir::ExactTypeAttr>() || attr.isa<fir::SubclassAttr>() ||
+          attr.isa<mlir::UnitAttr>()))
+      return op.emitOpError("invalid type-case alternative");
+  }
+  return mlir::success();
+}
+
+//===----------------------------------------------------------------------===//
+// ShapeShiftOp
+//===----------------------------------------------------------------------===//
+
+static mlir::LogicalResult verify(fir::ShapeShiftOp &op) {
+  auto size = op.pairs().size();
+  if (size < 2 || size > 16 * 2)
+    return op.emitOpError("incorrect number of args");
+  if (size % 2 != 0)
+    return op.emitOpError("requires a multiple of 2 args");
+  auto shapeTy = op.getType().dyn_cast<fir::ShapeShiftType>();
+  assert(shapeTy && "must be a shape shift type");
+  if (shapeTy.getRank() * 2 != size)
+    return op.emitOpError("shape type rank mismatch");
+  return mlir::success();
+}
+
+//===----------------------------------------------------------------------===//
+// ShiftOp
+//===----------------------------------------------------------------------===//
+
+static mlir::LogicalResult verify(fir::ShiftOp &op) {
+  auto size = op.origins().size();
+  auto shiftTy = op.getType().dyn_cast<fir::ShiftType>();
+  assert(shiftTy && "must be a shift type");
+  if (shiftTy.getRank() != size)
+    return op.emitOpError("shift type rank mismatch");
+  return mlir::success();
+}
+
 //===----------------------------------------------------------------------===//
 // SliceOp
 //===----------------------------------------------------------------------===//
@@ -2118,6 +2592,19 @@
   return rank;
 }
 
+static mlir::LogicalResult verify(fir::SliceOp &op) {
+  auto size = op.triples().size();
+  if (size < 3 || size > 16 * 3)
+    return op.emitOpError("incorrect number of args for triple");
+  if (size % 3 != 0)
+    return op.emitOpError("requires a multiple of 3 args");
+  auto sliceTy = op.getType().dyn_cast<fir::SliceType>();
+  assert(sliceTy && "must be a slice type");
+  if (sliceTy.getRank() * 3 != size)
+    return op.emitOpError("slice type rank mismatch");
+  return mlir::success();
+}
+
 //===----------------------------------------------------------------------===//
 // StoreOp
 //===----------------------------------------------------------------------===//
@@ -2257,6 +2744,17 @@
 }
 
 //===----------------------------------------------------------------------===//
+// UnboxProcOp
+//===----------------------------------------------------------------------===//
+
+static mlir::LogicalResult verify(fir::UnboxProcOp &op) {
+  if (auto eleTy = fir::dyn_cast_ptrEleTy(op.refTuple().getType()))
+    if (eleTy.isa<mlir::TupleType>())
+      return mlir::success();
+  return op.emitOpError("second output argument has bad type");
+}
+
+//===----------------------------------------------------------------------===//
 // IfOp
 //===----------------------------------------------------------------------===//