Expose custom asmprinter support to core operations and have them adopt it,

fixing the printing syntax for dim, constant, fadd, etc.

PiperOrigin-RevId: 205908627
This commit is contained in:
Chris Lattner 2018-07-24 16:07:22 -07:00 committed by jpienaar
parent f7f70ee691
commit b5cdf60477
8 changed files with 194 additions and 77 deletions

View File

@ -1,4 +1,4 @@
//===- OperationImpl.h - Implementation details of *Op classes --*- C++ -*-===//
//===- OpDefinition.h - Classes for defining concrete Op types --*- C++ -*-===//
//
// Copyright 2019 The MLIR Authors.
//
@ -15,22 +15,23 @@
// limitations under the License.
// =============================================================================
//
// This file implements helper classes for working with the "Op", most of which
// go into the mlir::OpImpl namespace since they are only used by code that is
// defining the op implementations, not by clients.
// This file implements helper classes for implementing the "Op" types. Most of
// this goes into the mlir::OpImpl namespace since they are only used by code
// that is defining the op implementations, not by clients.
//
// The purpose of these types are to allow light-weight implementation of
// concrete ops (like DimOp) with very little boilerplate.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_IR_OPERATIONIMPL_H
#define MLIR_IR_OPERATIONIMPL_H
#ifndef MLIR_IR_OPDEFINITION_H
#define MLIR_IR_OPDEFINITION_H
#include "mlir/IR/Operation.h"
namespace mlir {
class Type;
class OpAsmPrinter;
/// This pointer represents a notional "Operation*" but where the actual
/// storage of the pointer is maintained in the templated "OpType" class.
@ -108,7 +109,7 @@ protected:
const char *verify() const { return nullptr; }
// The fallback for the printer is to print it the longhand form.
void print(raw_ostream &os) const;
void print(OpAsmPrinter *p) const;
/// Mutability management is handled by the OpWrapper/OpConstWrapper classes,
/// so we can cast it away here.
@ -139,8 +140,8 @@ public:
/// This is the hook used by the AsmPrinter to emit this to the .mlir file.
/// Op implementations should provide a print method.
static void printAssembly(const Operation *op, raw_ostream &os) {
op->getAs<ConcreteType>()->print(os);
static void printAssembly(const Operation *op, OpAsmPrinter *p) {
op->getAs<ConcreteType>()->print(p);
}
/// This is the hook used by the Verifier to check out this instruction. It

View File

@ -0,0 +1,83 @@
//===- OpImplementation.h - Classes for implementing Op types ---*- C++ -*-===//
//
// Copyright 2019 The MLIR Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =============================================================================
//
// This classes used by the implementation details of Op types.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_IR_OPIMPLEMENTATION_H
#define MLIR_IR_OPIMPLEMENTATION_H
#include "mlir/IR/OpDefinition.h"
namespace mlir {
class AffineMap;
class AffineExpr;
/// This is a pure-virtual base class that exposes the asmprinter hooks
/// necessary to implement a custom print() method.
class OpAsmPrinter {
public:
OpAsmPrinter() {}
virtual ~OpAsmPrinter();
virtual raw_ostream &getStream() const = 0;
/// Print implementations for various things an operation contains.
virtual void printOperand(const SSAValue *value) = 0;
virtual void printType(const Type *type) = 0;
virtual void printAttribute(const Attribute *attr) = 0;
virtual void printAffineMap(const AffineMap *map) = 0;
virtual void printAffineExpr(const AffineExpr *expr) = 0;
/// Print the entire operation with the default verbose formatting.
virtual void printDefaultOp(const Operation *op) = 0;
private:
OpAsmPrinter(const OpAsmPrinter &) = delete;
void operator=(const OpAsmPrinter &) = delete;
};
// Make the implementations convenient to use.
inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const SSAValue &value) {
p.printOperand(&value);
return p;
}
inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const Type &type) {
p.printType(&type);
return p;
}
inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const Attribute &attr) {
p.printAttribute(&attr);
return p;
}
inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const AffineMap &map) {
p.printAffineMap(&map);
return p;
}
template <typename T>
inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const T &other) {
p.getStream() << other;
return p;
}
} // end namespace mlir
#endif

View File

@ -27,6 +27,7 @@
namespace mlir {
class Operation;
class OpAsmPrinter;
class MLIRContextImpl;
class MLIRContext;
@ -49,7 +50,7 @@ public:
bool (&isClassFor)(const Operation *op);
/// This hook implements the AsmPrinter for this operation.
void (&printAssembly)(const Operation *op, raw_ostream &os);
void (&printAssembly)(const Operation *op, OpAsmPrinter *p);
/// This hook implements the verifier for this operation. It should return
/// an error message if a problem is detected or return null on success.
@ -59,7 +60,7 @@ public:
private:
AbstractOperation(StringRef name, bool (&isClassFor)(const Operation *op),
void (&printAssembly)(const Operation *op, raw_ostream &os),
void (&printAssembly)(const Operation *op, OpAsmPrinter *p),
const char *(&verifyInvariants)(const Operation *op))
: name(name), isClassFor(isClassFor), printAssembly(printAssembly),
verifyInvariants(verifyInvariants) {}

View File

@ -24,7 +24,7 @@
#define MLIR_IR_STANDARDOPS_H
#include "mlir/IR/Attributes.h"
#include "mlir/IR/OperationImpl.h"
#include "mlir/IR/OpDefinition.h"
namespace mlir {
class OperationSet;
@ -43,7 +43,7 @@ public:
static StringRef getOperationName() { return "addf"; }
const char *verify() const;
void print(raw_ostream &os) const;
void print(OpAsmPrinter *p) const;
private:
friend class Operation;
@ -109,7 +109,7 @@ public:
// Hooks to customize behavior of this op.
const char *verify() const;
void print(raw_ostream &os) const;
void print(OpAsmPrinter *p) const;
private:
friend class Operation;
@ -139,7 +139,7 @@ public:
// Hooks to customize behavior of this op.
const char *verify() const;
void print(raw_ostream &os) const;
void print(OpAsmPrinter *p) const;
private:
friend class Operation;

View File

@ -26,6 +26,7 @@
#include "mlir/IR/CFGFunction.h"
#include "mlir/IR/MLFunction.h"
#include "mlir/IR/Module.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/IR/OperationSet.h"
#include "mlir/IR/Statements.h"
#include "mlir/IR/Types.h"
@ -38,6 +39,8 @@ void Identifier::print(raw_ostream &os) const { os << str(); }
void Identifier::dump() const { print(llvm::errs()); }
OpAsmPrinter::~OpAsmPrinter() {}
//===----------------------------------------------------------------------===//
// ModuleState
//===----------------------------------------------------------------------===//
@ -176,15 +179,15 @@ public:
}
void print(const Module *module);
void print(const Attribute *attr) const;
void print(const Type *type) const;
void printAttribute(const Attribute *attr);
void printType(const Type *type);
void print(const Function *fn);
void print(const ExtFunction *fn);
void print(const CFGFunction *fn);
void print(const MLFunction *fn);
void print(const AffineMap *map);
void print(const AffineExpr *expr) const;
void printAffineMap(const AffineMap *map);
void printAffineExpr(const AffineExpr *expr);
protected:
raw_ostream &os;
@ -192,9 +195,9 @@ protected:
void printFunctionSignature(const Function *fn);
void printAffineMapId(int affineMapId) const;
void printAffineMapReference(const AffineMap *affineMap) const;
void printAffineMapReference(const AffineMap *affineMap);
void print(const AffineBinaryOpExpr *expr) const;
void printAffineBinaryOpExpr(const AffineBinaryOpExpr *expr);
};
} // end anonymous namespace
@ -215,7 +218,7 @@ void ModulePrinter::printAffineMapId(int affineMapId) const {
os << "#map" << affineMapId;
}
void ModulePrinter::printAffineMapReference(const AffineMap *affineMap) const {
void ModulePrinter::printAffineMapReference(const AffineMap *affineMap) {
int mapId = state.getAffineMapId(affineMap);
if (mapId >= 0) {
// Map will be printed at top of module so print reference to its id.
@ -237,7 +240,7 @@ void ModulePrinter::print(const Module *module) {
print(fn);
}
void ModulePrinter::print(const Attribute *attr) const {
void ModulePrinter::printAttribute(const Attribute *attr) {
switch (attr->getKind()) {
case Attribute::Kind::Bool:
os << (cast<BoolAttr>(attr)->getValue() ? "true" : "false");
@ -256,7 +259,7 @@ void ModulePrinter::print(const Attribute *attr) const {
case Attribute::Kind::Array: {
auto elts = cast<ArrayAttr>(attr)->getValue();
os << '[';
interleaveComma(elts, [&](Attribute *attr) { print(attr); });
interleaveComma(elts, [&](Attribute *attr) { printAttribute(attr); });
os << ']';
break;
}
@ -266,7 +269,7 @@ void ModulePrinter::print(const Attribute *attr) const {
}
}
void ModulePrinter::print(const Type *type) const {
void ModulePrinter::printType(const Type *type) {
switch (type->getKind()) {
case Type::Kind::AffineInt:
os << "affineint";
@ -356,7 +359,7 @@ void ModulePrinter::print(const Type *type) const {
// Affine expressions and maps
//===----------------------------------------------------------------------===//
void ModulePrinter::print(const AffineExpr *expr) const {
void ModulePrinter::printAffineExpr(const AffineExpr *expr) {
switch (expr->getKind()) {
case AffineExpr::Kind::SymbolId:
os << 's' << cast<AffineSymbolExpr>(expr)->getPosition();
@ -372,14 +375,14 @@ void ModulePrinter::print(const AffineExpr *expr) const {
case AffineExpr::Kind::FloorDiv:
case AffineExpr::Kind::CeilDiv:
case AffineExpr::Kind::Mod:
return print(cast<AffineBinaryOpExpr>(expr));
return printAffineBinaryOpExpr(cast<AffineBinaryOpExpr>(expr));
}
}
void ModulePrinter::print(const AffineBinaryOpExpr *expr) const {
void ModulePrinter::printAffineBinaryOpExpr(const AffineBinaryOpExpr *expr) {
if (expr->getKind() != AffineExpr::Kind::Add) {
os << '(';
print(expr->getLHS());
printAffineExpr(expr->getLHS());
switch (expr->getKind()) {
case AffineExpr::Kind::Mul:
os << " * ";
@ -397,14 +400,14 @@ void ModulePrinter::print(const AffineBinaryOpExpr *expr) const {
llvm_unreachable("unexpected affine binary op expression");
}
print(expr->getRHS());
printAffineExpr(expr->getRHS());
os << ')';
return;
}
// Print out special "pretty" forms for add.
os << '(';
print(expr->getLHS());
printAffineExpr(expr->getLHS());
// Pretty print addition to a product that has a negative operand as a
// subtraction.
@ -413,7 +416,7 @@ void ModulePrinter::print(const AffineBinaryOpExpr *expr) const {
if (auto *rrhs = dyn_cast<AffineConstantExpr>(rhs->getRHS())) {
if (rrhs->getValue() < 0) {
os << " - (";
print(rhs->getLHS());
printAffineExpr(rhs->getLHS());
os << " * " << -rrhs->getValue() << "))";
return;
}
@ -430,11 +433,11 @@ void ModulePrinter::print(const AffineBinaryOpExpr *expr) const {
}
os << " + ";
print(expr->getRHS());
printAffineExpr(expr->getRHS());
os << ')';
}
void ModulePrinter::print(const AffineMap *map) {
void ModulePrinter::printAffineMap(const AffineMap *map) {
// Dimension identifiers.
os << '(';
for (int i = 0; i < (int)map->getNumDims() - 1; i++)
@ -457,7 +460,8 @@ void ModulePrinter::print(const AffineMap *map) {
assert(!map->getResults().empty());
// Result affine expressions.
os << " -> (";
interleaveComma(map->getResults(), [&](AffineExpr *expr) { print(expr); });
interleaveComma(map->getResults(),
[&](AffineExpr *expr) { printAffineExpr(expr); });
os << ")";
if (!map->isBounded()) {
@ -466,7 +470,8 @@ void ModulePrinter::print(const AffineMap *map) {
// Print range sizes for bounded affine maps.
os << " size (";
interleaveComma(map->getRangeSizes(), [&](AffineExpr *expr) { print(expr); });
interleaveComma(map->getRangeSizes(),
[&](AffineExpr *expr) { printAffineExpr(expr); });
os << ")";
}
@ -478,7 +483,8 @@ void ModulePrinter::printFunctionSignature(const Function *fn) {
auto type = fn->getType();
os << "@" << fn->getName() << '(';
interleaveComma(type->getInputs(), [&](Type *eltType) { print(eltType); });
interleaveComma(type->getInputs(),
[&](Type *eltType) { printType(eltType); });
os << ')';
switch (type->getResults().size()) {
@ -486,11 +492,12 @@ void ModulePrinter::printFunctionSignature(const Function *fn) {
break;
case 1:
os << " -> ";
print(type->getResults()[0]);
printType(type->getResults()[0]);
break;
default:
os << " -> (";
interleaveComma(type->getResults(), [&](Type *eltType) { print(eltType); });
interleaveComma(type->getResults(),
[&](Type *eltType) { printType(eltType); });
os << ')';
break;
}
@ -504,13 +511,29 @@ void ModulePrinter::print(const ExtFunction *fn) {
namespace {
// FunctionState contains common functionality for printing
// FunctionPrinter contains common functionality for printing
// CFG and ML functions.
class FunctionState : public ModulePrinter {
class FunctionPrinter : public ModulePrinter, private OpAsmPrinter {
public:
FunctionState(const ModulePrinter &other) : ModulePrinter(other) {}
FunctionPrinter(const ModulePrinter &other) : ModulePrinter(other) {}
void printOperation(const Operation *op);
void printDefaultOp(const Operation *op);
// Implement OpAsmPrinter.
raw_ostream &getStream() const { return os; }
void printType(const Type *type) { ModulePrinter::printType(type); }
void printAttribute(const Attribute *attr) {
ModulePrinter::printAttribute(attr);
}
void printAffineMap(const AffineMap *map) {
return ModulePrinter::printAffineMap(map);
}
void printAffineExpr(const AffineExpr *expr) {
return ModulePrinter::printAffineExpr(expr);
}
void printOperand(const SSAValue *value) { printValueID(value); }
protected:
void numberValueID(const SSAValue *value) {
@ -551,7 +574,7 @@ private:
};
} // end anonymous namespace
void FunctionState::printOperation(const Operation *op) {
void FunctionPrinter::printOperation(const Operation *op) {
os << " ";
if (op->getNumResults()) {
@ -562,12 +585,15 @@ void FunctionState::printOperation(const Operation *op) {
// Check to see if this is a known operation. If so, use the registered
// custom printer hook.
if (auto opInfo = state.operationSet->lookup(op->getName().str())) {
opInfo->printAssembly(op, os);
opInfo->printAssembly(op, this);
return;
}
// Otherwise use the standard verbose printing approach.
printDefaultOp(op);
}
void FunctionPrinter::printDefaultOp(const Operation *op) {
// TODO: escape name if necessary.
os << "\"" << op->getName().str() << "\"(";
@ -580,7 +606,7 @@ void FunctionState::printOperation(const Operation *op) {
os << '{';
interleaveComma(attrs, [&](NamedAttribute attr) {
os << attr.first << ": ";
print(attr.second);
printAttribute(attr.second);
});
os << '}';
}
@ -588,15 +614,16 @@ void FunctionState::printOperation(const Operation *op) {
// Print the type signature of the operation.
os << " : (";
interleaveComma(op->getOperands(),
[&](const SSAValue *value) { print(value->getType()); });
[&](const SSAValue *value) { printType(value->getType()); });
os << ") -> ";
if (op->getNumResults() == 1) {
print(op->getResult(0)->getType());
printType(op->getResult(0)->getType());
} else {
os << '(';
interleaveComma(op->getResults(),
[&](const SSAValue *result) { print(result->getType()); });
interleaveComma(op->getResults(), [&](const SSAValue *result) {
printType(result->getType());
});
os << ')';
}
}
@ -606,7 +633,7 @@ void FunctionState::printOperation(const Operation *op) {
//===----------------------------------------------------------------------===//
namespace {
class CFGFunctionPrinter : public FunctionState {
class CFGFunctionPrinter : public FunctionPrinter {
public:
CFGFunctionPrinter(const CFGFunction *function, const ModulePrinter &other);
@ -637,7 +664,7 @@ private:
CFGFunctionPrinter::CFGFunctionPrinter(const CFGFunction *function,
const ModulePrinter &other)
: FunctionState(other), function(function) {
: FunctionPrinter(other), function(function) {
// Each basic block gets a unique ID per function.
unsigned blockID = 0;
for (auto &block : *function) {
@ -679,7 +706,7 @@ void CFGFunctionPrinter::print(const BasicBlock *block) {
interleaveComma(block->getArguments(), [&](const BBArgument *arg) {
printValueID(arg);
os << ": ";
ModulePrinter::print(arg->getType());
printType(arg->getType());
});
os << ')';
}
@ -722,7 +749,7 @@ void CFGFunctionPrinter::print(const BranchInst *inst) {
});
os << ") : ";
interleaveComma(inst->getInstOperands(), [&](const InstOperand &operand) {
ModulePrinter::print(operand.get()->getType());
printType(operand.get()->getType());
});
}
}
@ -738,7 +765,7 @@ void CFGFunctionPrinter::print(const CondBranchInst *inst) {
[&](const CFGValue *operand) { printValueID(operand); });
os << " : ";
interleaveComma(inst->getTrueOperands(), [&](const CFGValue *operand) {
ModulePrinter::print(operand->getType());
printType(operand->getType());
});
os << ")";
}
@ -750,7 +777,7 @@ void CFGFunctionPrinter::print(const CondBranchInst *inst) {
[&](const CFGValue *operand) { printValueID(operand); });
os << " : ";
interleaveComma(inst->getFalseOperands(), [&](const CFGValue *operand) {
ModulePrinter::print(operand->getType());
printType(operand->getType());
});
os << ")";
}
@ -766,7 +793,7 @@ void CFGFunctionPrinter::print(const ReturnInst *inst) {
[&](const CFGValue *operand) { printValueID(operand); });
os << " : ";
interleaveComma(inst->getOperands(), [&](const CFGValue *operand) {
ModulePrinter::print(operand->getType());
printType(operand->getType());
});
}
@ -779,7 +806,7 @@ void ModulePrinter::print(const CFGFunction *fn) {
//===----------------------------------------------------------------------===//
namespace {
class MLFunctionPrinter : public FunctionState {
class MLFunctionPrinter : public FunctionPrinter {
public:
MLFunctionPrinter(const MLFunction *function, const ModulePrinter &other);
@ -806,7 +833,7 @@ private:
MLFunctionPrinter::MLFunctionPrinter(const MLFunction *function,
const ModulePrinter &other)
: FunctionState(other), function(function), numSpaces(0) {}
: FunctionPrinter(other), function(function), numSpaces(0) {}
void MLFunctionPrinter::print() {
os << "mlfunc ";
@ -874,14 +901,14 @@ void ModulePrinter::print(const MLFunction *fn) {
void Attribute::print(raw_ostream &os) const {
ModuleState state(/*no context is known*/ nullptr);
ModulePrinter(os, state).print(this);
ModulePrinter(os, state).printAttribute(this);
}
void Attribute::dump() const { print(llvm::errs()); }
void Type::print(raw_ostream &os) const {
ModuleState state(getContext());
ModulePrinter(os, state).print(this);
ModulePrinter(os, state).printType(this);
}
void Type::dump() const { print(llvm::errs()); }
@ -898,12 +925,12 @@ void AffineExpr::dump() const {
void AffineExpr::print(raw_ostream &os) const {
ModuleState state(/*no context is known*/ nullptr);
ModulePrinter(os, state).print(this);
ModulePrinter(os, state).printAffineExpr(this);
}
void AffineMap::print(raw_ostream &os) const {
ModuleState state(/*no context is known*/ nullptr);
ModulePrinter(os, state).print(this);
ModulePrinter(os, state).printAffineMap(this);
}
void Instruction::print(raw_ostream &os) const {

View File

@ -16,15 +16,16 @@
// =============================================================================
#include "mlir/IR/OperationSet.h"
#include "mlir/IR/OperationImpl.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/OpImplementation.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/raw_ostream.h"
using namespace mlir;
using llvm::StringMap;
// The fallback for the printer is to print it the longhand form.
void OpImpl::BaseState::print(raw_ostream &os) const {
os << "FIXME: IMPLEMENT DEFAULT PRINTER";
void OpImpl::BaseState::print(OpAsmPrinter *p) const {
p->printDefaultOp(getOperation());
}
static StringMap<AbstractOperation> &getImpl(void *pImpl) {

View File

@ -17,14 +17,16 @@
#include "mlir/IR/StandardOps.h"
#include "mlir/IR/AffineMap.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/IR/OperationSet.h"
#include "mlir/IR/SSAValue.h"
#include "mlir/IR/Types.h"
#include "llvm/Support/raw_ostream.h"
using namespace mlir;
void AddFOp::print(raw_ostream &os) const {
os << "addf xx, yy : sometype";
void AddFOp::print(OpAsmPrinter *p) const {
*p << "addf " << *getOperand(0) << ", " << *getOperand(1) << " : "
<< *getType();
}
// Return an error message on failure.
@ -62,8 +64,9 @@ bool ConstantIntOp::isClassFor(const Operation *op) {
isa<IntegerType>(op->getResult(0)->getType());
}
void DimOp::print(raw_ostream &os) const {
os << "dim xxx, " << getIndex() << " : sometype";
void DimOp::print(OpAsmPrinter *p) const {
*p << "dim " << *getOperand() << ", " << getIndex() << " : "
<< *getOperand()->getType();
}
const char *DimOp::verify() const {
@ -90,9 +93,9 @@ const char *DimOp::verify() const {
return nullptr;
}
void AffineApplyOp::print(raw_ostream &os) const {
os << "affine_apply map: ";
getAffineMap()->print(os);
void AffineApplyOp::print(OpAsmPrinter *p) const {
// TODO: Print operands etc.
*p << "affine_apply map: " << *getAffineMap();
}
const char *AffineApplyOp::verify() const {

View File

@ -9,10 +9,10 @@ bb0(%a : f32):
// CHECK: %1 = "getTensor"() : () -> tensor<4x4x?xf32>
%t = "getTensor"() : () -> tensor<4x4x?xf32>
// CHECK: dim xxx, 2 : sometype
// CHECK: %2 = dim %1, 2 : tensor<4x4x?xf32>
%t2 = "dim"(%t){index: 2} : (tensor<4x4x?xf32>) -> affineint
// CHECK: addf xx, yy : sometype
// CHECK: %3 = addf %0, %0 : f32
%x = "addf"(%a, %a) : (f32,f32) -> (f32)
// CHECK: return
@ -25,15 +25,16 @@ bb42: // CHECK: bb0:
// CHECK: %0 = "getTensor"() : () -> tensor<4x4x?xf32>
%42 = "getTensor"() : () -> tensor<4x4x?xf32>
// CHECK: dim xxx, 2 : sometype
// CHECK: dim %0, 2 : tensor<4x4x?xf32>
%a = "dim"(%42){index: 2} : (tensor<4x4x?xf32>) -> affineint
// FIXME: Add support for fp attributes so this can use 'constant'.
%f = "FIXMEConst"(){value: 1} : () -> f32
// CHECK: addf xx, yy : sometype
// CHECK: %3 = addf %2, %2 : f32
"addf"(%f, %f) : (f32,f32) -> f32
// TODO: CHECK: FIXME: IMPLEMENT DEFAULT PRINTER
// CHECK: %4 = "constant"(){value: 42} : () -> i32
%x = "constant"(){value: 42} : () -> i32
return
}