| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,189 @@ | ||
| //===- Operation.h - MLIR PDLL ODS Operation --------------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef MLIR_TOOLS_PDLL_ODS_OPERATION_H_ | ||
| #define MLIR_TOOLS_PDLL_ODS_OPERATION_H_ | ||
|
|
||
| #include <string> | ||
|
|
||
| #include "mlir/Support/LLVM.h" | ||
| #include "llvm/ADT/ArrayRef.h" | ||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "llvm/ADT/StringRef.h" | ||
| #include "llvm/Support/SMLoc.h" | ||
|
|
||
| namespace mlir { | ||
| namespace pdll { | ||
| namespace ods { | ||
| class AttributeConstraint; | ||
| class TypeConstraint; | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // VariableLengthKind | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| enum VariableLengthKind { Single, Optional, Variadic }; | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Attribute | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| /// This class provides an ODS representation of a specific operation attribute. | ||
| /// This includes the name, optionality, and more. | ||
| class Attribute { | ||
| public: | ||
| /// Return the name of this operand. | ||
| StringRef getName() const { return name; } | ||
|
|
||
| /// Return true if this attribute is optional. | ||
| bool isOptional() const { return optional; } | ||
|
|
||
| /// Return the constraint of this attribute. | ||
| const AttributeConstraint &getConstraint() const { return constraint; } | ||
|
|
||
| private: | ||
| Attribute(StringRef name, bool optional, | ||
| const AttributeConstraint &constraint) | ||
| : name(name.str()), optional(optional), constraint(constraint) {} | ||
|
|
||
| /// The ODS name of the attribute. | ||
| std::string name; | ||
|
|
||
| /// A flag indicating if the attribute is optional. | ||
| bool optional; | ||
|
|
||
| /// The ODS constraint of this attribute. | ||
| const AttributeConstraint &constraint; | ||
|
|
||
| /// Allow access to the private constructor. | ||
| friend class Operation; | ||
| }; | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // OperandOrResult | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| /// This class provides an ODS representation of a specific operation operand or | ||
| /// result. This includes the name, variable length flags, and more. | ||
| class OperandOrResult { | ||
| public: | ||
| /// Return the name of this value. | ||
| StringRef getName() const { return name; } | ||
|
|
||
| /// Returns true if this value is variadic (Note this is false if the value is | ||
| /// Optional). | ||
| bool isVariadic() const { | ||
| return variableLengthKind == VariableLengthKind::Variadic; | ||
| } | ||
|
|
||
| /// Returns the variable length kind of this value. | ||
| VariableLengthKind getVariableLengthKind() const { | ||
| return variableLengthKind; | ||
| } | ||
|
|
||
| /// Return the constraint of this value. | ||
| const TypeConstraint &getConstraint() const { return constraint; } | ||
|
|
||
| private: | ||
| OperandOrResult(StringRef name, VariableLengthKind variableLengthKind, | ||
| const TypeConstraint &constraint) | ||
| : name(name.str()), variableLengthKind(variableLengthKind), | ||
| constraint(constraint) {} | ||
|
|
||
| /// The ODS name of this value. | ||
| std::string name; | ||
|
|
||
| /// The variable length kind of this value. | ||
| VariableLengthKind variableLengthKind; | ||
|
|
||
| /// The ODS constraint of this value. | ||
| const TypeConstraint &constraint; | ||
|
|
||
| /// Allow access to the private constructor. | ||
| friend class Operation; | ||
| }; | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Operation | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| /// This class provides an ODS representation of a specific operation. This | ||
| /// includes all of the information necessary for use by the PDL frontend for | ||
| /// generating code for a pattern rewrite. | ||
| class Operation { | ||
| public: | ||
| /// Return the source location of this operation. | ||
| SMRange getLoc() const { return location; } | ||
|
|
||
| /// Append an attribute to this operation. | ||
| void appendAttribute(StringRef name, bool optional, | ||
| const AttributeConstraint &constraint) { | ||
| attributes.emplace_back(Attribute(name, optional, constraint)); | ||
| } | ||
|
|
||
| /// Append an operand to this operation. | ||
| void appendOperand(StringRef name, VariableLengthKind variableLengthKind, | ||
| const TypeConstraint &constraint) { | ||
| operands.emplace_back( | ||
| OperandOrResult(name, variableLengthKind, constraint)); | ||
| } | ||
|
|
||
| /// Append a result to this operation. | ||
| void appendResult(StringRef name, VariableLengthKind variableLengthKind, | ||
| const TypeConstraint &constraint) { | ||
| results.emplace_back(OperandOrResult(name, variableLengthKind, constraint)); | ||
| } | ||
|
|
||
| /// Returns the name of the operation. | ||
| StringRef getName() const { return name; } | ||
|
|
||
| /// Returns the summary of the operation. | ||
| StringRef getSummary() const { return summary; } | ||
|
|
||
| /// Returns the description of the operation. | ||
| StringRef getDescription() const { return description; } | ||
|
|
||
| /// Returns the attributes of this operation. | ||
| ArrayRef<Attribute> getAttributes() const { return attributes; } | ||
|
|
||
| /// Returns the operands of this operation. | ||
| ArrayRef<OperandOrResult> getOperands() const { return operands; } | ||
|
|
||
| /// Returns the results of this operation. | ||
| ArrayRef<OperandOrResult> getResults() const { return results; } | ||
|
|
||
| private: | ||
| Operation(StringRef name, StringRef summary, StringRef desc, SMLoc loc); | ||
|
|
||
| /// The name of the operation. | ||
| std::string name; | ||
|
|
||
| /// The documentation of the operation. | ||
| std::string summary; | ||
| std::string description; | ||
|
|
||
| /// The source location of this operation. | ||
| SMRange location; | ||
|
|
||
| /// The operands of the operation. | ||
| SmallVector<OperandOrResult> operands; | ||
|
|
||
| /// The results of the operation. | ||
| SmallVector<OperandOrResult> results; | ||
|
|
||
| /// The attributes of the operation. | ||
| SmallVector<Attribute> attributes; | ||
|
|
||
| /// Allow access to the private constructor. | ||
| friend class Dialect; | ||
| }; | ||
| } // namespace ods | ||
| } // namespace pdll | ||
| } // namespace mlir | ||
|
|
||
| #endif // MLIR_TOOLS_PDLL_ODS_OPERATION_H_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,5 +6,6 @@ add_mlir_library(MLIRPDLLAST | |
| Types.cpp | ||
|
|
||
| LINK_LIBS PUBLIC | ||
| MLIRPDLLODS | ||
| MLIRSupport | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| add_subdirectory(AST) | ||
| add_subdirectory(CodeGen) | ||
| add_subdirectory(ODS) | ||
| add_subdirectory(Parser) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| add_mlir_library(MLIRPDLLODS | ||
| Context.cpp | ||
| Dialect.cpp | ||
| Operation.cpp | ||
|
|
||
| LINK_LIBS PUBLIC | ||
| MLIRSupport | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| //===- Context.cpp --------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "mlir/Tools/PDLL/ODS/Context.h" | ||
| #include "mlir/Tools/PDLL/ODS/Constraint.h" | ||
| #include "mlir/Tools/PDLL/ODS/Dialect.h" | ||
| #include "mlir/Tools/PDLL/ODS/Operation.h" | ||
| #include "llvm/Support/ScopedPrinter.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
|
|
||
| using namespace mlir; | ||
| using namespace mlir::pdll::ods; | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Context | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| Context::Context() = default; | ||
| Context::~Context() = default; | ||
|
|
||
| const AttributeConstraint & | ||
| Context::insertAttributeConstraint(StringRef name, StringRef summary, | ||
| StringRef cppClass) { | ||
| std::unique_ptr<AttributeConstraint> &constraint = attributeConstraints[name]; | ||
| if (!constraint) { | ||
| constraint.reset(new AttributeConstraint(name, summary, cppClass)); | ||
| } else { | ||
| assert(constraint->getCppClass() == cppClass && | ||
| constraint->getSummary() == summary && | ||
| "constraint with the same name was already registered with a " | ||
| "different class"); | ||
| } | ||
| return *constraint; | ||
| } | ||
|
|
||
| const TypeConstraint &Context::insertTypeConstraint(StringRef name, | ||
| StringRef summary, | ||
| StringRef cppClass) { | ||
| std::unique_ptr<TypeConstraint> &constraint = typeConstraints[name]; | ||
| if (!constraint) | ||
| constraint.reset(new TypeConstraint(name, summary, cppClass)); | ||
| return *constraint; | ||
| } | ||
|
|
||
| Dialect &Context::insertDialect(StringRef name) { | ||
| std::unique_ptr<Dialect> &dialect = dialects[name]; | ||
| if (!dialect) | ||
| dialect.reset(new Dialect(name)); | ||
| return *dialect; | ||
| } | ||
|
|
||
| const Dialect *Context::lookupDialect(StringRef name) const { | ||
| auto it = dialects.find(name); | ||
| return it == dialects.end() ? nullptr : &*it->second; | ||
| } | ||
|
|
||
| std::pair<Operation *, bool> Context::insertOperation(StringRef name, | ||
| StringRef summary, | ||
| StringRef desc, | ||
| SMLoc loc) { | ||
| std::pair<StringRef, StringRef> dialectAndName = name.split('.'); | ||
| return insertDialect(dialectAndName.first) | ||
| .insertOperation(name, summary, desc, loc); | ||
| } | ||
|
|
||
| const Operation *Context::lookupOperation(StringRef name) const { | ||
| std::pair<StringRef, StringRef> dialectAndName = name.split('.'); | ||
| if (const Dialect *dialect = lookupDialect(dialectAndName.first)) | ||
| return dialect->lookupOperation(name); | ||
| return nullptr; | ||
| } | ||
|
|
||
| template <typename T> | ||
| SmallVector<T *> sortMapByName(const llvm::StringMap<std::unique_ptr<T>> &map) { | ||
| SmallVector<T *> storage; | ||
| for (auto &entry : map) | ||
| storage.push_back(entry.second.get()); | ||
| llvm::sort(storage, [](const auto &lhs, const auto &rhs) { | ||
| return lhs->getName() < rhs->getName(); | ||
| }); | ||
| return storage; | ||
| } | ||
|
|
||
| void Context::print(raw_ostream &os) const { | ||
| auto printVariableLengthCst = [&](StringRef cst, VariableLengthKind kind) { | ||
| switch (kind) { | ||
| case VariableLengthKind::Optional: | ||
| os << "Optional<" << cst << ">"; | ||
| break; | ||
| case VariableLengthKind::Single: | ||
| os << cst; | ||
| break; | ||
| case VariableLengthKind::Variadic: | ||
| os << "Variadic<" << cst << ">"; | ||
| break; | ||
| } | ||
| }; | ||
|
|
||
| llvm::ScopedPrinter printer(os); | ||
| llvm::DictScope odsScope(printer, "ODSContext"); | ||
| for (const Dialect *dialect : sortMapByName(dialects)) { | ||
| printer.startLine() << "Dialect `" << dialect->getName() << "` {\n"; | ||
| printer.indent(); | ||
|
|
||
| for (const Operation *op : sortMapByName(dialect->getOperations())) { | ||
| printer.startLine() << "Operation `" << op->getName() << "` {\n"; | ||
| printer.indent(); | ||
|
|
||
| // Attributes. | ||
| ArrayRef<Attribute> attributes = op->getAttributes(); | ||
| if (!attributes.empty()) { | ||
| printer.startLine() << "Attributes { "; | ||
| llvm::interleaveComma(attributes, os, [&](const Attribute &attr) { | ||
| os << attr.getName() << " : "; | ||
|
|
||
| auto kind = attr.isOptional() ? VariableLengthKind::Optional | ||
| : VariableLengthKind::Single; | ||
| printVariableLengthCst(attr.getConstraint().getName(), kind); | ||
| }); | ||
| os << " }\n"; | ||
| } | ||
|
|
||
| // Operands. | ||
| ArrayRef<OperandOrResult> operands = op->getOperands(); | ||
| if (!operands.empty()) { | ||
| printer.startLine() << "Operands { "; | ||
| llvm::interleaveComma( | ||
| operands, os, [&](const OperandOrResult &operand) { | ||
| os << operand.getName() << " : "; | ||
| printVariableLengthCst(operand.getConstraint().getName(), | ||
| operand.getVariableLengthKind()); | ||
| }); | ||
| os << " }\n"; | ||
| } | ||
|
|
||
| // Results. | ||
| ArrayRef<OperandOrResult> results = op->getResults(); | ||
| if (!results.empty()) { | ||
| printer.startLine() << "Results { "; | ||
| llvm::interleaveComma(results, os, [&](const OperandOrResult &result) { | ||
| os << result.getName() << " : "; | ||
| printVariableLengthCst(result.getConstraint().getName(), | ||
| result.getVariableLengthKind()); | ||
| }); | ||
| os << " }\n"; | ||
| } | ||
|
|
||
| printer.objectEnd(); | ||
| } | ||
| printer.objectEnd(); | ||
| } | ||
| for (const AttributeConstraint *cst : sortMapByName(attributeConstraints)) { | ||
| printer.startLine() << "AttributeConstraint `" << cst->getName() << "` {\n"; | ||
| printer.indent(); | ||
|
|
||
| printer.startLine() << "Summary: " << cst->getSummary() << "\n"; | ||
| printer.startLine() << "CppClass: " << cst->getCppClass() << "\n"; | ||
| printer.objectEnd(); | ||
| } | ||
| for (const TypeConstraint *cst : sortMapByName(typeConstraints)) { | ||
| printer.startLine() << "TypeConstraint `" << cst->getName() << "` {\n"; | ||
| printer.indent(); | ||
|
|
||
| printer.startLine() << "Summary: " << cst->getSummary() << "\n"; | ||
| printer.startLine() << "CppClass: " << cst->getCppClass() << "\n"; | ||
| printer.objectEnd(); | ||
| } | ||
| printer.objectEnd(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| //===- Dialect.cpp --------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "mlir/Tools/PDLL/ODS/Dialect.h" | ||
| #include "mlir/Tools/PDLL/ODS/Constraint.h" | ||
| #include "mlir/Tools/PDLL/ODS/Operation.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
|
|
||
| using namespace mlir; | ||
| using namespace mlir::pdll::ods; | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Dialect | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| Dialect::Dialect(StringRef name) : name(name.str()) {} | ||
| Dialect::~Dialect() = default; | ||
|
|
||
| std::pair<Operation *, bool> Dialect::insertOperation(StringRef name, | ||
| StringRef summary, | ||
| StringRef desc, | ||
| llvm::SMLoc loc) { | ||
| std::unique_ptr<Operation> &operation = operations[name]; | ||
| if (operation) | ||
| return std::make_pair(&*operation, /*wasInserted*/ false); | ||
|
|
||
| operation.reset(new Operation(name, summary, desc, loc)); | ||
| return std::make_pair(&*operation, /*wasInserted*/ true); | ||
| } | ||
|
|
||
| Operation *Dialect::lookupOperation(StringRef name) const { | ||
| auto it = operations.find(name); | ||
| return it != operations.end() ? it->second.get() : nullptr; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| //===- Operation.cpp ------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "mlir/Tools/PDLL/ODS/Operation.h" | ||
| #include "mlir/Support/IndentedOstream.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
|
|
||
| using namespace mlir; | ||
| using namespace mlir::pdll::ods; | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Operation | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| Operation::Operation(StringRef name, StringRef summary, StringRef desc, | ||
| llvm::SMLoc loc) | ||
| : name(name.str()), summary(summary.str()), | ||
| location(loc, llvm::SMLoc::getFromPointer(loc.getPointer() + 1)) { | ||
| llvm::raw_string_ostream descOS(description); | ||
| raw_indented_ostream(descOS).printReindented(desc.rtrim(" \t")); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,14 @@ | ||
| set(LLVM_LINK_COMPONENTS | ||
| Support | ||
| TableGen | ||
| ) | ||
|
|
||
| add_mlir_library(MLIRPDLLParser | ||
| Lexer.cpp | ||
| Parser.cpp | ||
|
|
||
| LINK_LIBS PUBLIC | ||
| MLIRPDLLAST | ||
| MLIRSupport | ||
| MLIRTableGen | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| include "mlir/IR/OpBase.td" | ||
|
|
||
| def Test_Dialect : Dialect { | ||
| let name = "test"; | ||
| } | ||
|
|
||
| def OpWithResults : Op<Test_Dialect, "with_results"> { | ||
| let results = (outs I64:$result, Variadic<I64>:$var_result); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,5 +19,5 @@ | |
|
|
||
| // ----- | ||
|
|
||
| // CHECK: expected include filename to end with `.pdll` or `.td` | ||
| #include "unknown_file.foo" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| include "mlir/IR/OpBase.td" | ||
|
|
||
| def TestAttrInterface : AttrInterface<"TestAttrInterface">; | ||
| def TestOpInterface : OpInterface<"TestOpInterface">; | ||
| def TestTypeInterface : TypeInterface<"TestTypeInterface">; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| include "include/interfaces.td" | ||
|
|
||
| def Test_Dialect : Dialect { | ||
| let name = "test"; | ||
| } | ||
|
|
||
| def OpAllEmpty : Op<Test_Dialect, "all_empty">; | ||
|
|
||
| def OpAllSingle : Op<Test_Dialect, "all_single"> { | ||
| let arguments = (ins I64:$operand, I64Attr:$attr); | ||
| let results = (outs I64:$result); | ||
| } | ||
|
|
||
| def OpAllOptional : Op<Test_Dialect, "all_optional"> { | ||
| let arguments = (ins Optional<I64>:$operand, OptionalAttr<I64Attr>:$attr); | ||
| let results = (outs Optional<I64>:$result); | ||
| } | ||
|
|
||
| def OpAllVariadic : Op<Test_Dialect, "all_variadic"> { | ||
| let arguments = (ins Variadic<I64>:$operands); | ||
| let results = (outs Variadic<I64>:$results); | ||
| } | ||
|
|
||
| def OpMultipleSingleResult : Op<Test_Dialect, "multiple_single_result"> { | ||
| let results = (outs I64:$result, I64:$result2); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| // RUN: mlir-pdll %s -I %S -I %S/../../../include -dump-ods 2>&1 | FileCheck %s | ||
|
|
||
| #include "include/ops.td" | ||
|
|
||
| // CHECK: Operation `test.all_empty` { | ||
| // CHECK-NEXT: } | ||
|
|
||
| // CHECK: Operation `test.all_optional` { | ||
| // CHECK-NEXT: Attributes { attr : Optional<I64Attr> } | ||
| // CHECK-NEXT: Operands { operand : Optional<I64> } | ||
| // CHECK-NEXT: Results { result : Optional<I64> } | ||
| // CHECK-NEXT: } | ||
|
|
||
| // CHECK: Operation `test.all_single` { | ||
| // CHECK-NEXT: Attributes { attr : I64Attr } | ||
| // CHECK-NEXT: Operands { operand : I64 } | ||
| // CHECK-NEXT: Results { result : I64 } | ||
| // CHECK-NEXT: } | ||
|
|
||
| // CHECK: Operation `test.all_variadic` { | ||
| // CHECK-NEXT: Operands { operands : Variadic<I64> } | ||
| // CHECK-NEXT: Results { results : Variadic<I64> } | ||
| // CHECK-NEXT: } | ||
|
|
||
| // CHECK: AttributeConstraint `I64Attr` { | ||
| // CHECK-NEXT: Summary: 64-bit signless integer attribute | ||
| // CHECK-NEXT: CppClass: ::mlir::IntegerAttr | ||
| // CHECK-NEXT: } | ||
|
|
||
| // CHECK: TypeConstraint `I64` { | ||
| // CHECK-NEXT: Summary: 64-bit signless integer | ||
| // CHECK-NEXT: CppClass: ::mlir::IntegerType | ||
| // CHECK-NEXT: } | ||
|
|
||
| // CHECK: UserConstraintDecl {{.*}} Name<TestAttrInterface> ResultType<Tuple<>> Code<llvm::isa<::TestAttrInterface>(self)> | ||
| // CHECK: `Inputs` | ||
| // CHECK: `-VariableDecl {{.*}} Name<self> Type<Attr> | ||
| // CHECK: `Constraints` | ||
| // CHECK: `-AttrConstraintDecl | ||
|
|
||
| // CHECK: UserConstraintDecl {{.*}} Name<TestOpInterface> ResultType<Tuple<>> Code<llvm::isa<::TestOpInterface>(self)> | ||
| // CHECK: `Inputs` | ||
| // CHECK: `-VariableDecl {{.*}} Name<self> Type<Op> | ||
| // CHECK: `Constraints` | ||
| // CHECK: `-OpConstraintDecl | ||
| // CHECK: `-OpNameDecl | ||
|
|
||
| // CHECK: UserConstraintDecl {{.*}} Name<TestTypeInterface> ResultType<Tuple<>> Code<llvm::isa<::TestTypeInterface>(self)> | ||
| // CHECK: `Inputs` | ||
| // CHECK: `-VariableDecl {{.*}} Name<self> Type<Type> | ||
| // CHECK: `Constraints` | ||
| // CHECK: `-TypeConstraintDecl {{.*}} |