BlockArguments gained the ability to have locations attached a while ago, but they
have always been optional. This goes against the core tenant of MLIR where location
information is a requirement, so this commit updates the API to require locations.
Fixes #53279
Differential Revision: https://reviews.llvm.org/D117633
case FixupTy::Codes::ArgumentAsLoad: {
// Argument was pass-by-value, but is now pass-by-reference and
// possibly with a different element type.
- auto newArg =
- func.front().insertArgument(fixup.index, newInTys[fixup.index]);
+ auto newArg = func.front().insertArgument(fixup.index,
+ newInTys[fixup.index], loc);
rewriter->setInsertionPointToStart(&func.front());
auto oldArgTy = ReferenceType::get(oldArgTys[fixup.index - offset]);
auto cast = rewriter->create<ConvertOp>(loc, oldArgTy, newArg);
case FixupTy::Codes::ArgumentType: {
// Argument is pass-by-value, but its type has likely been modified to
// suit the target ABI convention.
- auto newArg =
- func.front().insertArgument(fixup.index, newInTys[fixup.index]);
+ auto newArg = func.front().insertArgument(fixup.index,
+ newInTys[fixup.index], loc);
rewriter->setInsertionPointToStart(&func.front());
auto mem =
rewriter->create<fir::AllocaOp>(loc, newInTys[fixup.index]);
case FixupTy::Codes::CharPair: {
// The FIR boxchar argument has been split into a pair of distinct
// arguments that are in juxtaposition to each other.
- auto newArg =
- func.front().insertArgument(fixup.index, newInTys[fixup.index]);
+ auto newArg = func.front().insertArgument(fixup.index,
+ newInTys[fixup.index], loc);
if (fixup.second == 1) {
rewriter->setInsertionPointToStart(&func.front());
auto boxTy = oldArgTys[fixup.index - offset - fixup.second];
case FixupTy::Codes::ReturnAsStore: {
// The value being returned is now being returned in memory (callee
// stack space) through a hidden reference argument.
- auto newArg =
- func.front().insertArgument(fixup.index, newInTys[fixup.index]);
+ auto newArg = func.front().insertArgument(fixup.index,
+ newInTys[fixup.index], loc);
offset++;
func.walk([&](mlir::ReturnOp ret) {
rewriter->setInsertionPoint(ret);
case FixupTy::Codes::Split: {
// The FIR argument has been split into a pair of distinct arguments
// that are in juxtaposition to each other. (For COMPLEX value.)
- auto newArg =
- func.front().insertArgument(fixup.index, newInTys[fixup.index]);
+ auto newArg = func.front().insertArgument(fixup.index,
+ newInTys[fixup.index], loc);
if (fixup.second == 1) {
rewriter->setInsertionPointToStart(&func.front());
auto cplxTy = oldArgTys[fixup.index - offset - fixup.second];
// The first part of the pair appears in the original argument
// position. The second part of the pair is appended after all the
// original arguments. (Boxchar arguments.)
- auto newBufArg =
- func.front().insertArgument(fixup.index, newInTys[fixup.index]);
- auto newLenArg = func.front().addArgument(trailingTys[fixup.second]);
+ auto newBufArg = func.front().insertArgument(
+ fixup.index, newInTys[fixup.index], loc);
+ auto newLenArg =
+ func.front().addArgument(trailingTys[fixup.second], loc);
auto boxTy = oldArgTys[fixup.index - offset];
rewriter->setInsertionPointToStart(&func.front());
auto box =
result.addTypes(v.getType());
mlir::Region *bodyRegion = result.addRegion();
bodyRegion->push_back(new Block{});
- bodyRegion->front().addArgument(builder.getIndexType());
- bodyRegion->front().addArgument(iterate.getType());
- bodyRegion->front().addArguments(iterArgs.getTypes());
+ bodyRegion->front().addArgument(builder.getIndexType(), result.location);
+ bodyRegion->front().addArgument(iterate.getType(), result.location);
+ bodyRegion->front().addArguments(
+ iterArgs.getTypes(),
+ SmallVector<Location>(iterArgs.size(), result.location));
result.addAttributes(attributes);
}
bodyRegion->push_back(new Block{});
if (iterArgs.empty() && !finalCountValue)
DoLoopOp::ensureTerminator(*bodyRegion, builder, result.location);
- bodyRegion->front().addArgument(builder.getIndexType());
- bodyRegion->front().addArguments(iterArgs.getTypes());
+ bodyRegion->front().addArgument(builder.getIndexType(), result.location);
+ bodyRegion->front().addArguments(
+ iterArgs.getTypes(),
+ SmallVector<Location>(iterArgs.size(), result.location));
if (unordered)
result.addAttribute(unorderedAttrName(result.name), builder.getUnitAttr());
result.addAttributes(attributes);
mlir::OpBuilder rewriter(context);
auto resultType = funcTy.getResult(0);
auto argTy = getResultArgumentType(resultType, options);
- options.newArg = func.front().insertArgument(zero, argTy);
+ options.newArg = func.front().insertArgument(zero, argTy, loc);
if (mustEmboxResult(resultType, options)) {
auto bufferType = fir::ReferenceType::get(resultType);
rewriter.setInsertionPointToStart(&func.front());
// conditional block since it already has the induction variable and
// loop-carried values as arguments.
auto *conditionalBlock = &loop.region().front();
- conditionalBlock->addArgument(rewriter.getIndexType());
+ conditionalBlock->addArgument(rewriter.getIndexType(), loc);
auto *firstBlock =
rewriter.splitBlock(conditionalBlock, conditionalBlock->begin());
auto *lastBlock = &loop.region().back();
/// Creates a new empty block with the given argument types and transfers
/// ownership to the caller.
MLIR_CAPI_EXPORTED MlirBlock mlirBlockCreate(intptr_t nArgs,
- MlirType const *args);
+ MlirType const *args,
+ MlirLocation const *locs);
/// Takes a block owned by the caller and destroys it.
MLIR_CAPI_EXPORTED void mlirBlockDestroy(MlirBlock block);
/// Appends an argument of the specified type to the block. Returns the newly
/// added argument.
MLIR_CAPI_EXPORTED MlirValue mlirBlockAddArgument(MlirBlock block,
- MlirType type);
+ MlirType type,
+ MlirLocation loc);
/// Returns `pos`-th argument of the block.
MLIR_CAPI_EXPORTED MlirValue mlirBlockGetArgument(MlirBlock block,
/// Adds a new block argument that corresponds to buffers located in
/// workgroup memory.
- BlockArgument addWorkgroupAttribution(Type type);
+ BlockArgument addWorkgroupAttribution(Type type, Location loc);
/// Returns the number of buffers located in the private memory.
unsigned getNumPrivateAttributions() {
/// Adds a new block argument that corresponds to buffers located in
/// private memory.
- BlockArgument addPrivateAttribution(Type type);
+ BlockArgument addPrivateAttribution(Type type, Location loc);
/// Returns the name of the attribute containing the number of buffers
/// located in the workgroup memory.
getOperation()->insertOperands(getNumControlOperands() + numInputs,
operand);
- getBody()->insertArgument(numLoops + numInputs, operand.getType());
+ getBody()->insertArgument(numLoops + numInputs, operand.getType(),
+ getLoc());
getOperation()->setAttr(
TiledLoopOp::getOperandSegmentSizeAttr(),
builder.getI32VectorAttr(
getOperation()->insertOperands(
getNumControlOperands() + numInputs + numOutputs, operand);
getBody()->insertArgument(numLoops + numInputs + numOutputs,
- operand.getType());
+ operand.getType(), getLoc());
getOperation()->setAttr(
TiledLoopOp::getOperandSegmentSizeAttr(),
builder.getI32VectorAttr(
bool args_empty() { return arguments.empty(); }
/// Add one value to the argument list.
- BlockArgument addArgument(Type type, Optional<Location> loc = {});
+ BlockArgument addArgument(Type type, Location loc);
/// Insert one value to the position in the argument list indicated by the
/// given iterator. The existing arguments are shifted. The block is expected
/// not to have predecessors.
- BlockArgument insertArgument(args_iterator it, Type type,
- Optional<Location> loc = {});
+ BlockArgument insertArgument(args_iterator it, Type type, Location loc);
/// Add one argument to the argument list for each type specified in the list.
+ /// `locs` is required to have the same number of elements as `types`.
iterator_range<args_iterator> addArguments(TypeRange types,
- ArrayRef<Location> locs = {});
+ ArrayRef<Location> locs);
/// Add one value to the argument list at the specified position.
- BlockArgument insertArgument(unsigned index, Type type,
- Optional<Location> loc = {});
+ BlockArgument insertArgument(unsigned index, Type type, Location loc);
/// Erase the argument at 'index' and remove it from the argument list.
void eraseArgument(unsigned index);
/// Add new block with 'argTypes' arguments and set the insertion point to the
/// end of it. The block is inserted at the provided insertion point of
- /// 'parent'.
+ /// 'parent'. `locs` contains the locations of the inserted arguments, and
+ /// should match the size of `argTypes`.
Block *createBlock(Region *parent, Region::iterator insertPt = {},
TypeRange argTypes = llvm::None,
- ArrayRef<Location> locs = {});
+ ArrayRef<Location> locs = llvm::None);
/// Add new block with 'argTypes' arguments and set the insertion point to the
- /// end of it. The block is placed before 'insertBefore'.
+ /// end of it. The block is placed before 'insertBefore'. `locs` contains the
+ /// locations of the inserted arguments, and should match the size of
+ /// `argTypes`.
Block *createBlock(Block *insertBefore, TypeRange argTypes = llvm::None,
- ArrayRef<Location> locs = {});
+ ArrayRef<Location> locs = llvm::None);
//===--------------------------------------------------------------------===//
// Operation Creation
OpAsmParser &parser, bool allowAttributes, bool allowVariadic,
SmallVectorImpl<OpAsmParser::OperandType> &argNames,
SmallVectorImpl<Type> &argTypes, SmallVectorImpl<NamedAttrList> &argAttrs,
- SmallVectorImpl<Optional<Location>> &argLocations, bool &isVariadic);
+ SmallVectorImpl<Location> &argLocations, bool &isVariadic);
/// Parses a function signature using `parser`. The `allowVariadic` argument
/// indicates whether functions with variadic arguments are supported. The
SmallVectorImpl<OpAsmParser::OperandType> &argNames,
SmallVectorImpl<Type> &argTypes,
SmallVectorImpl<NamedAttrList> &argAttrs,
- SmallVectorImpl<Optional<Location>> &argLocations,
+ SmallVectorImpl<Location> &argLocations,
bool &isVariadic, SmallVectorImpl<Type> &resultTypes,
SmallVectorImpl<NamedAttrList> &resultAttrs);
void insertFunctionArguments(Operation *op, ArrayRef<unsigned> argIndices,
TypeRange argTypes,
ArrayRef<DictionaryAttr> argAttrs,
- ArrayRef<Optional<Location>> argLocs,
+ ArrayRef<Location> argLocs,
unsigned originalNumArgs, Type newType);
/// Insert the specified results and update the function type attribute.
assert(empty() && "function already has an entry block");
Block *entry = new Block();
push_back(entry);
- entry->addArguments($_op.getArgumentTypes());
+
+ // FIXME: Allow for passing in locations for these arguments instead of using
+ // the operations location.
+ ArrayRef<Type> inputTypes = $_op.getArgumentTypes();
+ SmallVector<Location> locations(inputTypes.size(),
+ $_op.getOperation()->getLoc());
+ entry->addArguments(inputTypes, locations);
return entry;
}
/// Insert a single argument of type `argType` with attributes `argAttrs` and
/// location `argLoc` at `argIndex`.
void insertArgument(unsigned argIndex, Type argType, DictionaryAttr argAttrs,
- Optional<Location> argLoc = {}) {
+ Location argLoc) {
insertArguments({argIndex}, {argType}, {argAttrs}, {argLoc});
}
/// appear in the same order that they were listed here.
void insertArguments(ArrayRef<unsigned> argIndices, TypeRange argTypes,
ArrayRef<DictionaryAttr> argAttrs,
- ArrayRef<Optional<Location>> argLocs) {
+ ArrayRef<Location> argLocs) {
unsigned originalNumArgs = $_op.getNumArguments();
Type newType = $_op.getTypeWithArgsAndResults(
argIndices, argTypes, /*resultIndices=*/{}, /*resultTypes=*/{});
/// Parses a region. Any parsed blocks are appended to 'region' and must be
/// moved to the op regions after the op is created. The first block of the
/// region takes 'arguments' of types 'argTypes'. If `argLocations` is
- /// non-empty it contains an optional location to be attached to each
- /// argument. If 'enableNameShadowing' is set to true, the argument names are
- /// allowed to shadow the names of other existing SSA values defined above the
- /// region scope. 'enableNameShadowing' can only be set to true for regions
- /// attached to operations that are 'IsolatedFromAbove'.
- virtual ParseResult
- parseRegion(Region ®ion, ArrayRef<OperandType> arguments = {},
- ArrayRef<Type> argTypes = {},
- ArrayRef<Optional<Location>> argLocations = {},
- bool enableNameShadowing = false) = 0;
+ /// non-empty it contains a location to be attached to each argument. If
+ /// 'enableNameShadowing' is set to true, the argument names are allowed to
+ /// shadow the names of other existing SSA values defined above the region
+ /// scope. 'enableNameShadowing' can only be set to true for regions attached
+ /// to operations that are 'IsolatedFromAbove'.
+ virtual ParseResult parseRegion(Region ®ion,
+ ArrayRef<OperandType> arguments = {},
+ ArrayRef<Type> argTypes = {},
+ ArrayRef<Location> argLocations = {},
+ bool enableNameShadowing = false) = 0;
/// Parses a region if present.
virtual OptionalParseResult
parseOptionalRegion(Region ®ion, ArrayRef<OperandType> arguments = {},
ArrayRef<Type> argTypes = {},
- ArrayRef<Optional<Location>> argLocations = {},
+ ArrayRef<Location> argLocations = {},
bool enableNameShadowing = false) = 0;
/// Parses a region if present. If the region is present, a new region is
return empty() ? BlockArgListType() : front().getArguments();
}
+ /// Returns the argument types of the first block within the region.
ValueTypeRange<BlockArgListType> getArgumentTypes();
using args_iterator = BlockArgListType::iterator;
bool args_empty() { return getArguments().empty(); }
/// Add one value to the argument list.
- BlockArgument addArgument(Type type) { return front().addArgument(type); }
+ BlockArgument addArgument(Type type, Location loc) {
+ return front().addArgument(type, loc);
+ }
/// Insert one value to the position in the argument list indicated by the
/// given iterator. The existing arguments are shifted. The block is expected
/// not to have predecessors.
- BlockArgument insertArgument(args_iterator it, Type type) {
- return front().insertArgument(it, type);
+ BlockArgument insertArgument(args_iterator it, Type type, Location loc) {
+ return front().insertArgument(it, type, loc);
}
/// Add one argument to the argument list for each type specified in the list.
- iterator_range<args_iterator> addArguments(TypeRange types);
+ /// `locs` contains the locations for each of the new arguments, and must be
+ /// of equal size to `types`.
+ iterator_range<args_iterator> addArguments(TypeRange types,
+ ArrayRef<Location> locs);
/// Add one value to the argument list at the specified position.
- BlockArgument insertArgument(unsigned index, Type type) {
- return front().insertArgument(index, type);
+ BlockArgument insertArgument(unsigned index, Type type, Location loc) {
+ return front().insertArgument(index, type, loc);
}
/// Erase the argument at 'index' and remove it from the argument list.
PyBlock appendBlock(const py::args &pyArgTypes) {
operation->checkValid();
llvm::SmallVector<MlirType, 4> argTypes;
+ llvm::SmallVector<MlirLocation, 4> argLocs;
argTypes.reserve(pyArgTypes.size());
+ argLocs.reserve(pyArgTypes.size());
for (auto &pyArg : pyArgTypes) {
argTypes.push_back(pyArg.cast<PyType &>());
+ // TODO: Pass in a proper location here.
+ argLocs.push_back(
+ mlirLocationUnknownGet(mlirTypeGetContext(argTypes.back())));
}
- MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
+ MlirBlock block =
+ mlirBlockCreate(argTypes.size(), argTypes.data(), argLocs.data());
mlirRegionAppendOwnedBlock(region, block);
return PyBlock(operation, block);
}
[](PyRegion &parent, py::list pyArgTypes) {
parent.checkValid();
llvm::SmallVector<MlirType, 4> argTypes;
+ llvm::SmallVector<MlirLocation, 4> argLocs;
argTypes.reserve(pyArgTypes.size());
+ argLocs.reserve(pyArgTypes.size());
for (auto &pyArg : pyArgTypes) {
argTypes.push_back(pyArg.cast<PyType &>());
+ // TODO: Pass in a proper location here.
+ argLocs.push_back(
+ mlirLocationUnknownGet(mlirTypeGetContext(argTypes.back())));
}
- MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
+ MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data(),
+ argLocs.data());
mlirRegionInsertOwnedBlock(parent, 0, block);
return PyBlock(parent.getParentOperation(), block);
},
[](PyBlock &self, py::args pyArgTypes) {
self.checkValid();
llvm::SmallVector<MlirType, 4> argTypes;
+ llvm::SmallVector<MlirLocation, 4> argLocs;
argTypes.reserve(pyArgTypes.size());
+ argLocs.reserve(pyArgTypes.size());
for (auto &pyArg : pyArgTypes) {
argTypes.push_back(pyArg.cast<PyType &>());
+ // TODO: Pass in a proper location here.
+ argLocs.push_back(
+ mlirLocationUnknownGet(mlirTypeGetContext(argTypes.back())));
}
- MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
+ MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data(),
+ argLocs.data());
MlirRegion region = mlirBlockGetParentRegion(self.get());
mlirRegionInsertOwnedBlockBefore(region, self.get(), block);
return PyBlock(self.getParentOperation(), block);
[](PyBlock &self, py::args pyArgTypes) {
self.checkValid();
llvm::SmallVector<MlirType, 4> argTypes;
+ llvm::SmallVector<MlirLocation, 4> argLocs;
argTypes.reserve(pyArgTypes.size());
+ argLocs.reserve(pyArgTypes.size());
for (auto &pyArg : pyArgTypes) {
argTypes.push_back(pyArg.cast<PyType &>());
- }
- MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
+ // TODO: Pass in a proper location here.
+ argLocs.push_back(
+ mlirLocationUnknownGet(mlirTypeGetContext(argTypes.back())));
+ }
+ MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data(),
+ argLocs.data());
MlirRegion region = mlirBlockGetParentRegion(self.get());
mlirRegionInsertOwnedBlockAfter(region, self.get(), block);
return PyBlock(self.getParentOperation(), block);
"Expected Linalg op with 0 blocks");
SmallVector<Type, 8> argTypes;
- for (OpOperand *opOperand : linalgOp.getInputAndOutputOperands())
+ SmallVector<Location, 8> argLocs;
+ for (OpOperand *opOperand : linalgOp.getInputAndOutputOperands()) {
argTypes.push_back(getElementTypeOrSelf(opOperand->get().getType()));
+ argLocs.push_back(opOperand->get().getLoc());
+ }
ImplicitLocOpBuilder b(op->getLoc(), op->getContext());
Region ®ion = op->getRegion(0);
- Block *body = b.createBlock(®ion, /*insertPt=*/{}, argTypes);
+ Block *body = b.createBlock(®ion, /*insertPt=*/{}, argTypes, argLocs);
b.setInsertionPointToStart(body);
fun(b, *body);
}
// Block API.
//===----------------------------------------------------------------------===//
-MlirBlock mlirBlockCreate(intptr_t nArgs, MlirType const *args) {
+MlirBlock mlirBlockCreate(intptr_t nArgs, MlirType const *args,
+ MlirLocation const *locs) {
Block *b = new Block;
for (intptr_t i = 0; i < nArgs; ++i)
- b->addArgument(unwrap(args[i]));
+ b->addArgument(unwrap(args[i]), unwrap(locs[i]));
return wrap(b);
}
return static_cast<intptr_t>(unwrap(block)->getNumArguments());
}
-MlirValue mlirBlockAddArgument(MlirBlock block, MlirType type) {
- return wrap(unwrap(block)->addArgument(unwrap(type)));
+MlirValue mlirBlockAddArgument(MlirBlock block, MlirType type,
+ MlirLocation loc) {
+ return wrap(unwrap(block)->addArgument(unwrap(type), unwrap(loc)));
}
MlirValue mlirBlockGetArgument(MlirBlock block, intptr_t pos) {
if (allocaScopeOp.getNumResults() == 0) {
continueBlock = remainingOpsBlock;
} else {
- continueBlock = rewriter.createBlock(remainingOpsBlock,
- allocaScopeOp.getResultTypes());
+ continueBlock = rewriter.createBlock(
+ remainingOpsBlock, allocaScopeOp.getResultTypes(),
+ SmallVector<Location>(allocaScopeOp->getNumResults(),
+ allocaScopeOp.getLoc()));
rewriter.create<LLVM::BrOp>(loc, ValueRange(), remainingOpsBlock);
}
Block::iterator remainingOpsIt = std::next(rewriter.getInsertionPoint());
Block *condBlock = rewriter.createBlock(initBlock->getParent(), {},
- {indexType, indexType});
+ {indexType, indexType}, {loc, loc});
// Move the remaining initBlock ops to condBlock.
Block *remainingBlock = rewriter.splitBlock(initBlock, remainingOpsIt);
Position *inputPos = valueToPosition.lookup(oldValue);
assert(inputPos && "expected value to be a pattern input");
usedMatchValues.push_back(inputPos);
- return newValue = rewriterFunc.front().addArgument(oldValue.getType());
+ return newValue = rewriterFunc.front().addArgument(oldValue.getType(),
+ oldValue.getLoc());
};
// If this is a custom rewriter, simply dispatch to the registered rewrite
Type type = reduce.getOperand().getType();
builder.createBlock(&decl.initializerRegion(), decl.initializerRegion().end(),
- {type});
+ {type}, {reduce.getOperand().getLoc()});
builder.setInsertionPointToEnd(&decl.initializerRegion().back());
Value init =
builder.create<LLVM::ConstantOp>(reduce.getLoc(), type, initValue);
OpBuilder::InsertionGuard guard(builder);
Type type = reduce.getOperand().getType();
Type ptrType = LLVM::LLVMPointerType::get(type);
+ Location reduceOperandLoc = reduce.getOperand().getLoc();
builder.createBlock(&decl.atomicReductionRegion(),
- decl.atomicReductionRegion().end(), {ptrType, ptrType});
+ decl.atomicReductionRegion().end(), {ptrType, ptrType},
+ {reduceOperandLoc, reduceOperandLoc});
Block *atomicBlock = &decl.atomicReductionRegion().back();
builder.setInsertionPointToEnd(atomicBlock);
Value loaded = builder.create<LLVM::LoadOp>(reduce.getLoc(),
loopOp.body().getBlocks().insert(getBlockIt(loopOp.body(), 1), header);
// Create the new induction variable to use.
+ Value adapLowerBound = adaptor.getLowerBound();
BlockArgument newIndVar =
- header->addArgument(adaptor.getLowerBound().getType());
+ header->addArgument(adapLowerBound.getType(), adapLowerBound.getLoc());
for (Value arg : adaptor.getInitArgs())
- header->addArgument(arg.getType());
+ header->addArgument(arg.getType(), arg.getLoc());
Block *body = forOp.getBody();
// Apply signature conversion to the body of the forOp. It has a single block,
continueBlock = remainingOpsBlock;
} else {
continueBlock =
- rewriter.createBlock(remainingOpsBlock, ifOp.getResultTypes());
+ rewriter.createBlock(remainingOpsBlock, ifOp.getResultTypes(),
+ SmallVector<Location>(ifOp.getNumResults(), loc));
rewriter.create<BranchOp>(loc, remainingOpsBlock);
}
rewriter.inlineRegionBefore(region, remainingOpsBlock);
SmallVector<Value> vals;
- for (auto arg : remainingOpsBlock->addArguments(op->getResultTypes())) {
+ SmallVector<Location> argLocs(op.getNumResults(), op->getLoc());
+ for (auto arg :
+ remainingOpsBlock->addArguments(op->getResultTypes(), argLocs))
vals.push_back(arg);
- }
rewriter.replaceOp(op, vals);
return success();
}
// Split the block into initial, loop, and ending parts.
auto *initBlock = rewriter.getInsertionBlock();
- auto *loopBlock =
- rewriter.createBlock(initBlock->getParent(),
- std::next(Region::iterator(initBlock)), valueType);
+ auto *loopBlock = rewriter.createBlock(
+ initBlock->getParent(), std::next(Region::iterator(initBlock)),
+ valueType, loc);
auto *endBlock = rewriter.createBlock(
loopBlock->getParent(), std::next(Region::iterator(loopBlock)));
SmallVector<Value> operands = {args[0], leadingZeros, zero};
SmallVector<Type> types = {elementTy, elementTy, elementTy};
+ SmallVector<Location> locations = {loc, loc, loc};
auto whileOp = rewriter.create<scf::WhileOp>(loc, types, operands);
- Block *before = rewriter.createBlock(&whileOp.getBefore(), {}, types);
- Block *after = rewriter.createBlock(&whileOp.getAfter(), {}, types);
+ Block *before =
+ rewriter.createBlock(&whileOp.getBefore(), {}, types, locations);
+ Block *after =
+ rewriter.createBlock(&whileOp.getAfter(), {}, types, locations);
// The conditional block of the while loop.
{
OpBuilder::InsertionGuard regionGuard(rewriter);
rewriter.createBlock(&genericOp.region(), genericOp.region().end(),
- TypeRange({resultElementTy}));
+ TypeRange({resultElementTy}), loc);
Value batch = rewriter.create<linalg::IndexOp>(loc, 0);
Value y = rewriter.create<linalg::IndexOp>(loc, 1);
Value x = rewriter.create<linalg::IndexOp>(loc, 2);
{
OpBuilder::InsertionGuard regionGuard(rewriter);
- Block *block =
- rewriter.createBlock(&genericOp.region(), genericOp.region().end(),
- TypeRange({inputElementTy, resultElementTy}));
+ Block *block = rewriter.createBlock(
+ &genericOp.region(), genericOp.region().end(),
+ TypeRange({inputElementTy, resultElementTy}), {loc, loc});
auto inputValue = block->getArgument(0);
rewriter.setInsertionPointToStart(block);
newLoop.getLoopBody().getBlocks().splice(
newLoop.getLoopBody().getBlocks().begin(),
loop.getLoopBody().getBlocks());
- for (auto operand : newIterOperands)
- newLoop.getBody()->addArgument(operand.getType());
+ for (Value operand : newIterOperands)
+ newLoop.getBody()->addArgument(operand.getType(), operand.getLoc());
for (auto it : llvm::zip(loop.getResults(), newLoop.getResults().take_front(
loop.getNumResults())))
Region *bodyRegion = result.addRegion();
bodyRegion->push_back(new Block);
Block &bodyBlock = bodyRegion->front();
- Value inductionVar = bodyBlock.addArgument(builder.getIndexType());
+ Value inductionVar =
+ bodyBlock.addArgument(builder.getIndexType(), result.location);
for (Value val : iterArgs)
- bodyBlock.addArgument(val.getType());
+ bodyBlock.addArgument(val.getType(), val.getLoc());
// Create the default terminator if the builder is not provided and if the
// iteration arguments are not provided. Otherwise, leave this to the caller
// Take the body of the original parent loop.
newLoop.getLoopBody().takeBody(loop.getLoopBody());
for (Value val : newIterArgs)
- newLoop.getLoopBody().addArgument(val.getType());
+ newLoop.getLoopBody().addArgument(val.getType(), val.getLoc());
// Update yield operation with new values to be added.
if (!newYieldedValues.empty()) {
auto *body = new Block();
// Add all the block arguments.
for (unsigned i = 0, e = steps.size(); i < e; ++i)
- body->addArgument(IndexType::get(builder.getContext()));
+ body->addArgument(IndexType::get(builder.getContext()), result.location);
bodyRegion->push_back(body);
if (resultTypes.empty())
ensureTerminator(*bodyRegion, builder, result.location);
for (Value operand : operands) {
auto valueType = operand.getType().dyn_cast<ValueType>();
bodyBlock.addArgument(valueType ? valueType.getValueType()
- : operand.getType());
+ : operand.getType(),
+ operand.getLoc());
}
// Create the default terminator if the builder is not provided and if the
rewriter.getListener()->notifyOperationInserted(func);
// Create function entry block.
- Block *block = b.createBlock(&func.getBody(), func.begin(), type.getInputs());
+ Block *block =
+ b.createBlock(&func.getBody(), func.begin(), type.getInputs(),
+ SmallVector<Location>(type.getNumInputs(), op.getLoc()));
b.setInsertionPointToEnd(block);
ParallelComputeFunctionArgs args = {op.getNumLoops(), func.getArguments()};
rewriter.getListener()->notifyOperationInserted(func);
// Create function entry block.
- Block *block = b.createBlock(&func.getBody(), func.begin(), type.getInputs());
+ Block *block = b.createBlock(&func.getBody(), func.begin(), type.getInputs(),
+ SmallVector<Location>(type.getNumInputs(), loc));
b.setInsertionPointToEnd(block);
Type indexTy = b.getIndexType();
// Create a work splitting while loop for the [blockStart, blockEnd) range.
SmallVector<Type> types = {indexTy, indexTy};
SmallVector<Value> operands = {blockStart, blockEnd};
+ SmallVector<Location> locations = {loc, loc};
// Create a recursive dispatch loop.
scf::WhileOp whileOp = b.create<scf::WhileOp>(types, operands);
- Block *before = b.createBlock(&whileOp.getBefore(), {}, types);
- Block *after = b.createBlock(&whileOp.getAfter(), {}, types);
+ Block *before = b.createBlock(&whileOp.getBefore(), {}, types, locations);
+ Block *after = b.createBlock(&whileOp.getAfter(), {}, types, locations);
// Setup dispatch loop condition block: decide if we need to go into the
// `after` block and launch one more async dispatch.
// the rest have the same types as the data operands.
Region *kernelRegion = result.addRegion();
Block *body = new Block();
- body->addArguments(
- std::vector<Type>(kNumConfigRegionAttributes, builder.getIndexType()));
+ for (unsigned i = 0; i < kNumConfigRegionAttributes; ++i)
+ body->addArgument(builder.getIndexType(), result.location);
kernelRegion->push_back(body);
}
if (parser.parseOptionalKeyword("args"))
return success();
SmallVector<NamedAttrList> argAttrs;
- SmallVector<Optional<Location>> argLocations;
+ SmallVector<Location> argLocations;
bool isVariadic = false;
return function_interface_impl::parseFunctionArgumentList(
parser, /*allowAttributes=*/false,
/// Adds a new block argument that corresponds to buffers located in
/// workgroup memory.
-BlockArgument GPUFuncOp::addWorkgroupAttribution(Type type) {
+BlockArgument GPUFuncOp::addWorkgroupAttribution(Type type, Location loc) {
auto attrName = getNumWorkgroupAttributionsAttrName();
auto attr = (*this)->getAttrOfType<IntegerAttr>(attrName);
(*this)->setAttr(attrName,
IntegerAttr::get(attr.getType(), attr.getValue() + 1));
return getBody().insertArgument(getType().getNumInputs() + attr.getInt(),
- type);
+ type, loc);
}
/// Adds a new block argument that corresponds to buffers located in
/// private memory.
-BlockArgument GPUFuncOp::addPrivateAttribution(Type type) {
+BlockArgument GPUFuncOp::addPrivateAttribution(Type type, Location loc) {
// Buffers on the private memory always come after buffers on the workgroup
// memory.
- return getBody().addArgument(type);
+ return getBody().addArgument(type, loc);
}
void GPUFuncOp::build(OpBuilder &builder, OperationState &result,
result.addAttributes(attrs);
Region *body = result.addRegion();
Block *entryBlock = new Block;
- entryBlock->addArguments(type.getInputs());
- entryBlock->addArguments(workgroupAttributions);
- entryBlock->addArguments(privateAttributions);
+
+ // TODO: Allow passing in proper locations here.
+ for (Type type : type.getInputs())
+ entryBlock->addArgument(type, result.location);
+ for (Type type : workgroupAttributions)
+ entryBlock->addArgument(type, result.location);
+ for (Type type : privateAttributions)
+ entryBlock->addArgument(type, result.location);
body->getBlocks().push_back(entryBlock);
}
SmallVector<NamedAttrList> resultAttrs;
SmallVector<Type> argTypes;
SmallVector<Type> resultTypes;
- SmallVector<Optional<Location>> argLocations;
+ SmallVector<Location> argLocations;
bool isVariadic;
// Parse the function name.
/// Adds type to funcOp's workgroup attributions.
Value createWorkgroupBuffer() {
+ // TODO: Pick a proper location for the attribution.
int workgroupMemoryAddressSpace =
gpu::GPUDialect::getWorkgroupAddressSpace();
auto bufferType = MemRefType::get({kSubgroupSize}, valueType, AffineMap{},
workgroupMemoryAddressSpace);
- return funcOp.addWorkgroupAttribution(bufferType);
+ return funcOp.addWorkgroupAttribution(bufferType, rewriter.getUnknownLoc());
}
/// Returns an accumulator factory using either the op attribute or the body
// Return accumulator result.
rewriter.setInsertionPointToStart(split);
- return split->addArgument(lhs.getType());
+ return split->addArgument(lhs.getType(), lhs.getLoc());
});
}
assert(thenOperands.size() == elseOperands.size());
rewriter.setInsertionPointToStart(continueBlock);
for (auto operand : thenOperands)
- continueBlock->addArgument(operand.getType());
+ continueBlock->addArgument(operand.getType(), operand.getLoc());
}
/// Shortcut for createIf with empty else block and no block operands.
executeOp.operandsMutable().append(asyncTokens);
SmallVector<Type, 1> tokenTypes(
asyncTokens.size(), builder.getType<gpu::AsyncTokenType>());
- copy(executeOp.getBody()->addArguments(tokenTypes),
+ SmallVector<Location, 1> tokenLocs(asyncTokens.size(),
+ executeOp.getLoc());
+ copy(executeOp.getBody()->addArguments(tokenTypes, tokenLocs),
std::back_inserter(tokens));
});
int workgroupMemoryAddressSpace = gpu::GPUDialect::getWorkgroupAddressSpace();
auto bufferType = MemRefType::get(type.getShape(), type.getElementType(), {},
workgroupMemoryAddressSpace);
-
- Value attribution = op.addWorkgroupAttribution(bufferType);
+ Value attribution = op.addWorkgroupAttribution(bufferType, value.getLoc());
// Replace the uses first since only the original uses are currently present.
// Then insert the copies.
auto *entry = new Block;
push_back(entry);
+ // FIXME: Allow passing in proper locations for the entry arguments.
LLVMFunctionType type = getType();
for (unsigned i = 0, e = type.getNumParams(); i < e; ++i)
- entry->addArgument(type.getParamType(i));
+ entry->addArgument(type.getParamType(i), getLoc());
return entry;
}
SmallVector<NamedAttrList> resultAttrs;
SmallVector<Type> argTypes;
SmallVector<Type> resultTypes;
- SmallVector<Optional<Location>> argLocations;
+ SmallVector<Location> argLocations;
bool isVariadic;
auto signatureLocation = parser.getCurrentLocation();
for (int position : llvm::drop_begin(successor.second, 1)) {
Block *dummyBlock = builder.createBlock(bb.getParent());
terminator->setSuccessor(dummyBlock, position);
- dummyBlock->addArguments(successor.first->getArgumentTypes());
+ for (BlockArgument arg : successor.first->getArguments())
+ dummyBlock->addArgument(arg.getType(), arg.getLoc());
builder.create<LLVM::BrOp>(terminator->getLoc(),
dummyBlock->getArguments(), successor.first);
}
auto tensorType = bbArg.getType().dyn_cast<TensorType>();
// Non-tensor types are just forwarded.
if (!tensorType) {
- frontBlock.addArgument(bbArg.getType());
+ frontBlock.addArgument(bbArg.getType(), bbArg.getLoc());
bbArg.replaceAllUsesWith(frontBlock.getArguments().back());
frontBlock.eraseArgument(0);
continue;
// Get the buffer type from the bufferized function type.
Type memrefType = bufferizedFuncType.getInput(idx);
- Value memref = frontBlock.addArgument(memrefType);
+ Value memref = frontBlock.addArgument(memrefType, bbArg.getLoc());
OpBuilder b(funcOp->getContext());
b.setInsertionPointToStart(&frontBlock);
// Replace all uses of bbArg through a ToMemRefOp by a memref::CastOp.
auto castOp = operand.get().getDefiningOp<memref::CastOp>();
if (castOp && memref::CastOp::canFoldIntoConsumerOp(castOp)) {
operand.set(castOp.getOperand());
- BlockArgument newBbArg =
- body->insertArgument(bbArgIndex, castOp.getOperand().getType());
+ BlockArgument newBbArg = body->insertArgument(
+ bbArgIndex, castOp.getOperand().getType(), op.getLoc());
BlockArgument oldBbArg = body->getArgument(newBbArg.getArgNumber() + 1);
// Insert memref.cast back to the original type.
return;
SmallVector<Type, 4> blockArgTypes;
- for (ValueRange container : {inputs, outputs})
- for (Value v : container)
+ SmallVector<Location, 4> blockArgLocs;
+ for (ValueRange container : {inputs, outputs}) {
+ for (Value v : container) {
blockArgTypes.push_back(getElementTypeOrSelf(v));
+ blockArgLocs.push_back(v.getLoc());
+ }
+ }
OpBuilder::InsertionGuard guard(builder);
auto ®ion = *result.regions.front();
- Block *bodyBlock = builder.createBlock(®ion, region.end(), blockArgTypes);
+ Block *bodyBlock =
+ builder.createBlock(®ion, region.end(), blockArgTypes, blockArgLocs);
bodyBuild(builder, result.location, bodyBlock->getArguments());
}
auto padTensorOp =
builder.create<linalg::PadTensorOp>(loc, type, source, low, high, nofold);
int rank = padTensorOp.getResultType().getRank();
- SmallVector<Type, 4> blockArgTypes;
- blockArgTypes.assign(rank, builder.getIndexType());
+ SmallVector<Type, 4> blockArgTypes(rank, builder.getIndexType());
+ SmallVector<Location, 4> blockArgLocs(rank, loc);
auto ®ion = padTensorOp.region();
// `builder.createBlock` changes the insertion point within the block. Create
// a guard to reset the insertion point of the builder after it is destroyed.
OpBuilder::InsertionGuard guard(builder);
- builder.createBlock(®ion, region.end(), blockArgTypes);
+ builder.createBlock(®ion, region.end(), blockArgTypes, blockArgLocs);
builder.create<linalg::YieldOp>(loc, pad);
return padTensorOp;
}
OpBuilder::InsertionGuard guard(builder);
unsigned numIVs = steps.size();
SmallVector<Type, 8> argTypes(numIVs, builder.getIndexType());
- for (Type type : TypeRange(inputs))
- argTypes.push_back(type);
- for (Type type : TypeRange(outputs))
- argTypes.push_back(type);
+ SmallVector<Location, 8> argLocs(numIVs, result.location);
+ for (Value input : inputs) {
+ argTypes.push_back(input.getType());
+ argLocs.push_back(input.getLoc());
+ }
+ for (Value output : outputs) {
+ argTypes.push_back(output.getType());
+ argLocs.push_back(output.getLoc());
+ }
Region *bodyRegion = result.addRegion();
- Block *bodyBlock = builder.createBlock(bodyRegion, {}, argTypes);
+ Block *bodyBlock = builder.createBlock(bodyRegion, {}, argTypes, argLocs);
if (bodyBuilderFn) {
builder.setInsertionPointToStart(bodyBlock);
// TODO: atm all operands go through getElementTypeOrSelf,
// reconsider when we have evidence we need to.
SmallVector<Type, 8> argTypes;
- for (auto containers : {inputTypes, outputTypes})
- for (auto t : containers)
+ SmallVector<Location, 8> argLocs;
+ for (auto containers : {inputTypes, outputTypes}) {
+ for (auto t : containers) {
argTypes.push_back(getElementTypeOrSelf(t));
+ // TODO: Pass in a proper location here.
+ argLocs.push_back(opBuilder.getUnknownLoc());
+ }
+ }
+
// RAII.
OpBuilder::InsertionGuard guard(opBuilder);
- Block *body = opBuilder.createBlock(®ion, /*insertPt=*/{}, argTypes);
+ Block *body =
+ opBuilder.createBlock(®ion, /*insertPt=*/{}, argTypes, argLocs);
unsigned actual = body->getNumArguments();
unsigned expected = NamedStructuredOpType::getNumRegionArgs();
if (expected != actual) {
// 3. Consumer input operands up to consumerIdx (exclusive).
for (BlockArgument bbArg : consumerBlock.getArguments().take_front(
consumerOpOperand->getOperandNumber())) // input assumption.
- mapper.map(bbArg, fusedBlock->addArgument(bbArg.getType()));
+ mapper.map(bbArg, fusedBlock->addArgument(bbArg.getType(), bbArg.getLoc()));
// Replacing consumerIdx requires getting the cloned, yielded, value from
// the (cloned) producer block. This happens in step 9.
// 4. Splice in producer's input operands.
for (BlockArgument bbArg :
producerBlock.getArguments().take_front(producer.getNumInputs()))
- mapper.map(bbArg, fusedBlock->addArgument(bbArg.getType()));
+ mapper.map(bbArg, fusedBlock->addArgument(bbArg.getType(), bbArg.getLoc()));
// 4.b. Producer output operand/map that is fused needs to be mapped to the
// producer bbArg if it is an "initTensor" (i.e. its value is actually read).
.drop_front(producer.getNumInputs())
// TODO: bbArg index of
.front();
- mapper.map(bbArg, fusedBlock->addArgument(bbArg.getType()));
+ mapper.map(bbArg, fusedBlock->addArgument(bbArg.getType(), bbArg.getLoc()));
}
// 5. Remaining consumer's input operands (drop past index `consumerIdx`).
for (BlockArgument bbArg :
consumerBlock.getArguments()
.take_front(consumer.getNumInputs())
.drop_front(consumerOpOperand->getOperandNumber() + 1))
- mapper.map(bbArg, fusedBlock->addArgument(bbArg.getType()));
+ mapper.map(bbArg, fusedBlock->addArgument(bbArg.getType(), bbArg.getLoc()));
// 6. All of consumer's output operands.
for (BlockArgument bbArg :
consumerBlock.getArguments().take_back(consumer.getNumOutputs()))
- mapper.map(bbArg, fusedBlock->addArgument(bbArg.getType()));
+ mapper.map(bbArg, fusedBlock->addArgument(bbArg.getType(), bbArg.getLoc()));
// 7. All of producer's output operands except the one fused.
// TODO: allow fusion of multi-result producers.
assert(producer->getNumResults() == 1 && "expected single result producer");
OpBuilder::InsertionGuard guard(builder);
unsigned numIVs = steps.size();
SmallVector<Type, 8> argTypes(numIVs, steps.getType().front());
- builder.createBlock(bodyRegion, {}, argTypes);
+ SmallVector<Location, 8> argLocs(numIVs, result.location);
+ builder.createBlock(bodyRegion, {}, argTypes, argLocs);
}
}
build(builder, state, range, successor);
if (initLoop) {
// Create the block and the loop variable.
+ // FIXME: Allow passing in a proper location for the loop variable.
auto rangeType = range.getType().cast<pdl::RangeType>();
state.regions.front()->emplaceBlock();
- state.regions.front()->addArgument(rangeType.getElementType());
+ state.regions.front()->addArgument(rangeType.getElementType(),
+ state.location);
}
}
SmallVector<Value> blockArgs;
for (auto res : op.getResults())
- blockArgs.push_back(postBlock->addArgument(res.getType()));
+ blockArgs.push_back(postBlock->addArgument(res.getType(), res.getLoc()));
rewriter.replaceOp(op, blockArgs);
return success();
Region *bodyRegion = result.addRegion();
bodyRegion->push_back(new Block);
Block &bodyBlock = bodyRegion->front();
- bodyBlock.addArgument(builder.getIndexType());
+ bodyBlock.addArgument(builder.getIndexType(), result.location);
for (Value v : iterArgs)
- bodyBlock.addArgument(v.getType());
+ bodyBlock.addArgument(v.getType(), v.getLoc());
// Create the default terminator if the builder is not provided and if the
// iteration arguments are not provided. Otherwise, leave this to the caller
OpBuilder::InsertionGuard guard(builder);
unsigned numIVs = steps.size();
SmallVector<Type, 8> argTypes(numIVs, builder.getIndexType());
+ SmallVector<Location, 8> argLocs(numIVs, result.location);
Region *bodyRegion = result.addRegion();
- Block *bodyBlock = builder.createBlock(bodyRegion, {}, argTypes);
+ Block *bodyBlock = builder.createBlock(bodyRegion, {}, argTypes, argLocs);
if (bodyBuilderFn) {
builder.setInsertionPointToStart(bodyBlock);
OpBuilder::InsertionGuard guard(builder);
Region *bodyRegion = result.addRegion();
- Block *body = builder.createBlock(bodyRegion, {}, ArrayRef<Type>{type, type});
+ Block *body = builder.createBlock(bodyRegion, {}, ArrayRef<Type>{type, type},
+ {result.location, result.location});
if (bodyBuilderFn)
bodyBuilderFn(builder, result.location, body->getArgument(0),
body->getArgument(1));
SmallVector<unsigned> newResultsIndices;
SmallVector<Type> newResultTypes;
SmallVector<Value> newTermArgs;
+ SmallVector<Location> newArgLocs;
bool needUpdate = false;
for (const auto &it :
llvm::enumerate(llvm::zip(op.getResults(), afterArgs, termArgs))) {
newResultsIndices.emplace_back(i);
newTermArgs.emplace_back(termArg);
newResultTypes.emplace_back(result.getType());
+ newArgLocs.emplace_back(result.getLoc());
}
}
rewriter.create<WhileOp>(op.getLoc(), newResultTypes, op.getInits());
Block &newAfterBlock = *rewriter.createBlock(
- &newWhile.getAfter(), /*insertPt*/ {}, newResultTypes);
+ &newWhile.getAfter(), /*insertPt*/ {}, newResultTypes, newArgLocs);
// Build new results list and new after block args (unused entries will be
// null).
PatternRewriter &rewriter) const override {
// Generate type signature for the loop-carried values. The induction
// variable is placed first, followed by the forOp.iterArgs.
- SmallVector<Type, 8> lcvTypes;
+ SmallVector<Type> lcvTypes;
+ SmallVector<Location> lcvLocs;
lcvTypes.push_back(forOp.getInductionVar().getType());
- llvm::transform(forOp.getInitArgs(), std::back_inserter(lcvTypes),
- [&](auto v) { return v.getType(); });
+ lcvLocs.push_back(forOp.getInductionVar().getLoc());
+ for (Value value : forOp.getInitArgs()) {
+ lcvTypes.push_back(value.getType());
+ lcvLocs.push_back(value.getLoc());
+ }
// Build scf.WhileOp
SmallVector<Value> initArgs;
// 'before' region contains the loop condition and forwarding of iteration
// arguments to the 'after' region.
auto *beforeBlock = rewriter.createBlock(
- &whileOp.getBefore(), whileOp.getBefore().begin(), lcvTypes, {});
+ &whileOp.getBefore(), whileOp.getBefore().begin(), lcvTypes, lcvLocs);
rewriter.setInsertionPointToStart(&whileOp.getBefore().front());
auto cmpOp = rewriter.create<arith::CmpIOp>(
whileOp.getLoc(), arith::CmpIPredicate::slt,
// region. The return type of the execRegionOp does not contain the
// iv - yields in the source for-loop contain only iterArgs.
auto *afterBlock = rewriter.createBlock(
- &whileOp.getAfter(), whileOp.getAfter().begin(), lcvTypes, {});
+ &whileOp.getAfter(), whileOp.getAfter().begin(), lcvTypes, lcvLocs);
// Add induction variable incrementation
rewriter.setInsertionPointToEnd(afterBlock);
ValueRange outlinedValues(captures.getArrayRef());
SmallVector<Type> outlinedFuncArgTypes;
+ SmallVector<Location> outlinedFuncArgLocs;
// Region's arguments are exactly the first block's arguments as per
// Region::getArguments().
// Func's arguments are cat(regions's arguments, captures arguments).
- llvm::append_range(outlinedFuncArgTypes, region.getArgumentTypes());
- llvm::append_range(outlinedFuncArgTypes, outlinedValues.getTypes());
+ for (BlockArgument arg : region.getArguments()) {
+ outlinedFuncArgTypes.push_back(arg.getType());
+ outlinedFuncArgLocs.push_back(arg.getLoc());
+ }
+ for (Value value : outlinedValues) {
+ outlinedFuncArgTypes.push_back(value.getType());
+ outlinedFuncArgLocs.push_back(value.getLoc());
+ }
FunctionType outlinedFuncType =
FunctionType::get(rewriter.getContext(), outlinedFuncArgTypes,
originalTerminator->getOperandTypes());
// terminator(call_results).
Block *newBlock = rewriter.createBlock(
®ion, region.begin(),
- TypeRange{outlinedFuncArgTypes}.take_front(numOriginalBlockArguments));
+ TypeRange{outlinedFuncArgTypes}.take_front(numOriginalBlockArguments),
+ ArrayRef<Location>(outlinedFuncArgLocs)
+ .take_front(numOriginalBlockArguments));
{
OpBuilder::InsertionGuard g(rewriter);
rewriter.setInsertionPointToEnd(newBlock);
SmallVector<NamedAttrList> resultAttrs;
SmallVector<Type> argTypes;
SmallVector<Type> resultTypes;
- SmallVector<Optional<Location>> argLocations;
+ SmallVector<Location> argLocations;
auto &builder = parser.getBuilder();
// Parse the name as a symbol.
Region *bodyRegion = result.addRegion();
bodyRegion->push_back(new Block);
Block &bodyBlock = bodyRegion->front();
- bodyBlock.addArgument(builder.getIndexType());
+ bodyBlock.addArgument(builder.getIndexType(), result.location);
Type elementType;
if (auto tensorType = shape.getType().dyn_cast<TensorType>())
elementType = tensorType.getElementType();
else
elementType = SizeType::get(builder.getContext());
- bodyBlock.addArgument(elementType);
+ bodyBlock.addArgument(elementType, shape.getLoc());
- for (Type initValType : initVals.getTypes()) {
- bodyBlock.addArgument(initValType);
- result.addTypes(initValType);
+ for (Value initVal : initVals) {
+ bodyBlock.addArgument(initVal.getType(), initVal.getLoc());
+ result.addTypes(initVal.getType());
}
}
assert(types.size() == operands.size());
Location loc = op.getLoc();
scf::WhileOp whileOp = rewriter.create<scf::WhileOp>(loc, types, operands);
- Block *before = rewriter.createBlock(&whileOp.getBefore(), {}, types);
- Block *after = rewriter.createBlock(&whileOp.getAfter(), {}, types);
+
+ SmallVector<Location> locs(types.size(), loc);
+ Block *before = rewriter.createBlock(&whileOp.getBefore(), {}, types, locs);
+ Block *after = rewriter.createBlock(&whileOp.getAfter(), {}, types, locs);
// Build the "before" region, which effectively consists
// of a conjunction of "i < upper" tests on all induction.
Region *bodyRegion = result.addRegion();
bodyRegion->push_back(new Block());
- bodyRegion->addArgument(elementType);
+ bodyRegion->addArgument(elementType, memref.getLoc());
}
}
Region *bodyRegion = result.regions.front().get();
auto rank = resultTy.cast<RankedTensorType>().getRank();
SmallVector<Type, 2> argumentTypes(rank, b.getIndexType());
+ SmallVector<Location, 2> argumentLocs(rank, result.location);
Block *bodyBlock =
- b.createBlock(bodyRegion, bodyRegion->end(), argumentTypes);
+ b.createBlock(bodyRegion, bodyRegion->end(), argumentTypes, argumentLocs);
bodyBuilder(b, result.location, bodyBlock->getArguments());
}
return ValueTypeRange<BlockArgListType>(getArguments());
}
-BlockArgument Block::addArgument(Type type, Optional<Location> loc) {
- // TODO: Require locations for BlockArguments.
- if (!loc.hasValue()) {
- // Use the location of the parent operation if the block is attached.
- if (Operation *parentOp = getParentOp())
- loc = parentOp->getLoc();
- else
- loc = UnknownLoc::get(type.getContext());
- }
-
- BlockArgument arg = BlockArgument::create(type, this, arguments.size(), *loc);
+BlockArgument Block::addArgument(Type type, Location loc) {
+ BlockArgument arg = BlockArgument::create(type, this, arguments.size(), loc);
arguments.push_back(arg);
return arg;
}
/// Add one argument to the argument list for each type specified in the list.
auto Block::addArguments(TypeRange types, ArrayRef<Location> locs)
-> iterator_range<args_iterator> {
- // TODO: Require locations for BlockArguments.
- assert((locs.empty() || types.size() == locs.size()) &&
+ assert(types.size() == locs.size() &&
"incorrect number of block argument locations");
size_t initialSize = arguments.size();
-
arguments.reserve(initialSize + types.size());
- // TODO: Require locations for BlockArguments.
- if (locs.empty()) {
- for (auto type : types)
- addArgument(type);
- } else {
- for (auto typeAndLoc : llvm::zip(types, locs))
- addArgument(std::get<0>(typeAndLoc), std::get<1>(typeAndLoc));
- }
+ for (auto typeAndLoc : llvm::zip(types, locs))
+ addArgument(std::get<0>(typeAndLoc), std::get<1>(typeAndLoc));
return {arguments.data() + initialSize, arguments.data() + arguments.size()};
}
-BlockArgument Block::insertArgument(unsigned index, Type type,
- Optional<Location> loc) {
- // TODO: Require locations for BlockArguments.
- if (!loc.hasValue()) {
- // Use the location of the parent operation if the block is attached.
- if (Operation *parentOp = getParentOp())
- loc = parentOp->getLoc();
- else
- loc = UnknownLoc::get(type.getContext());
- }
+BlockArgument Block::insertArgument(unsigned index, Type type, Location loc) {
+ assert(index <= arguments.size() && "invalid insertion index");
- auto arg = BlockArgument::create(type, this, index, *loc);
- assert(index <= arguments.size());
+ auto arg = BlockArgument::create(type, this, index, loc);
arguments.insert(arguments.begin() + index, arg);
// Update the cached position for all the arguments after the newly inserted
// one.
/// Insert one value to the given position of the argument list. The existing
/// arguments are shifted. The block is expected not to have predecessors.
-BlockArgument Block::insertArgument(args_iterator it, Type type,
- Optional<Location> loc) {
+BlockArgument Block::insertArgument(args_iterator it, Type type, Location loc) {
assert(llvm::empty(getPredecessors()) &&
"cannot insert arguments to blocks with predecessors");
return insertArgument(it->getArgNumber(), type, loc);
return op;
}
-/// Add new block with 'argTypes' arguments and set the insertion point to the
-/// end of it. The block is inserted at the provided insertion point of
-/// 'parent'.
Block *OpBuilder::createBlock(Region *parent, Region::iterator insertPt,
TypeRange argTypes, ArrayRef<Location> locs) {
assert(parent && "expected valid parent region");
+ assert(argTypes.size() == locs.size() && "argument location mismatch");
if (insertPt == Region::iterator())
insertPt = parent->end();
OpAsmParser &parser, bool allowAttributes, bool allowVariadic,
SmallVectorImpl<OpAsmParser::OperandType> &argNames,
SmallVectorImpl<Type> &argTypes, SmallVectorImpl<NamedAttrList> &argAttrs,
- SmallVectorImpl<Optional<Location>> &argLocations, bool &isVariadic) {
+ SmallVectorImpl<Location> &argLocations, bool &isVariadic) {
if (parser.parseLParen())
return failure();
if (!argument.name.empty() &&
parser.parseOptionalLocationSpecifier(explicitLoc))
return failure();
- argLocations.push_back(explicitLoc);
+ if (!explicitLoc)
+ explicitLoc = parser.getEncodedSourceLoc(loc);
+ argLocations.push_back(*explicitLoc);
return success();
};
OpAsmParser &parser, bool allowVariadic,
SmallVectorImpl<OpAsmParser::OperandType> &argNames,
SmallVectorImpl<Type> &argTypes, SmallVectorImpl<NamedAttrList> &argAttrs,
- SmallVectorImpl<Optional<Location>> &argLocations, bool &isVariadic,
+ SmallVectorImpl<Location> &argLocations, bool &isVariadic,
SmallVectorImpl<Type> &resultTypes,
SmallVectorImpl<NamedAttrList> &resultAttrs) {
bool allowArgAttrs = true;
SmallVector<NamedAttrList> resultAttrs;
SmallVector<Type> argTypes;
SmallVector<Type> resultTypes;
- SmallVector<Optional<Location>> argLocations;
+ SmallVector<Location> argLocations;
auto &builder = parser.getBuilder();
// Parse visibility.
llvm::SMLoc loc = parser.getCurrentLocation();
OptionalParseResult parseResult = parser.parseOptionalRegion(
*body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes,
- entryArgs.empty() ? ArrayRef<Optional<Location>>() : argLocations,
+ entryArgs.empty() ? ArrayRef<Location>() : argLocations,
/*enableNameShadowing=*/false);
if (parseResult.hasValue()) {
if (failed(*parseResult))
void mlir::function_interface_impl::insertFunctionArguments(
Operation *op, ArrayRef<unsigned> argIndices, TypeRange argTypes,
- ArrayRef<DictionaryAttr> argAttrs, ArrayRef<Optional<Location>> argLocs,
+ ArrayRef<DictionaryAttr> argAttrs, ArrayRef<Location> argLocs,
unsigned originalNumArgs, Type newType) {
assert(argIndices.size() == argTypes.size());
assert(argIndices.size() == argAttrs.size() || argAttrs.empty());
- assert(argIndices.size() == argLocs.size() || argLocs.empty());
+ assert(argIndices.size() == argLocs.size());
if (argIndices.empty())
return;
// Update the function type and any entry block arguments.
op->setAttr(getTypeAttrName(), TypeAttr::get(newType));
for (unsigned i = 0, e = argIndices.size(); i < e; ++i)
- entry.insertArgument(argIndices[i] + i, argTypes[i],
- argLocs.empty() ? Optional<Location>{} : argLocs[i]);
+ entry.insertArgument(argIndices[i] + i, argTypes[i], argLocs[i]);
}
void mlir::function_interface_impl::insertFunctionResults(
return container->getLoc();
}
-/// Return a range containing the types of the arguments for this region.
auto Region::getArgumentTypes() -> ValueTypeRange<BlockArgListType> {
return ValueTypeRange<BlockArgListType>(getArguments());
}
-/// Add one argument to the argument list for each type specified in the list.
-iterator_range<Region::args_iterator> Region::addArguments(TypeRange types) {
- return front().addArguments(types);
+iterator_range<Region::args_iterator>
+Region::addArguments(TypeRange types, ArrayRef<Location> locs) {
+ return front().addArguments(types, locs);
}
Region *Region::getParentRegion() {
/// region is isolated from those above.
ParseResult parseRegion(Region ®ion,
ArrayRef<std::pair<SSAUseInfo, Type>> entryArguments,
- ArrayRef<Optional<Location>> argLocations = {},
+ ArrayRef<Location> argLocations,
bool isIsolatedNameScope = false);
/// Parse a region body into 'region'.
ParseResult
parseRegionBody(Region ®ion, llvm::SMLoc startLoc,
ArrayRef<std::pair<SSAUseInfo, Type>> entryArguments,
- ArrayRef<Optional<Location>> argLocations,
- bool isIsolatedNameScope);
+ ArrayRef<Location> argLocations, bool isIsolatedNameScope);
//===--------------------------------------------------------------------===//
// Block Parsing
do {
// Create temporary regions with the top level region as parent.
result.regions.emplace_back(new Region(topLevelOp));
- if (parseRegion(*result.regions.back(), /*entryArguments=*/{}))
+ if (parseRegion(*result.regions.back(), /*entryArguments=*/{},
+ /*argLocations=*/{}))
return failure();
} while (consumeIf(Token::comma));
if (parseToken(Token::r_paren, "expected ')' to end region list"))
/// effectively defines the SSA values of `arguments` and assigns their type.
ParseResult parseRegion(Region ®ion, ArrayRef<OperandType> arguments,
ArrayRef<Type> argTypes,
- ArrayRef<Optional<Location>> argLocations,
+ ArrayRef<Location> argLocations,
bool enableNameShadowing) override {
assert(arguments.size() == argTypes.size() &&
"mismatching number of arguments and types");
}
/// Parses a region if present.
- OptionalParseResult
- parseOptionalRegion(Region ®ion, ArrayRef<OperandType> arguments,
- ArrayRef<Type> argTypes,
- ArrayRef<Optional<Location>> argLocations,
- bool enableNameShadowing) override {
+ OptionalParseResult parseOptionalRegion(Region ®ion,
+ ArrayRef<OperandType> arguments,
+ ArrayRef<Type> argTypes,
+ ArrayRef<Location> argLocations,
+ bool enableNameShadowing) override {
if (parser.getToken().isNot(Token::l_brace))
return llvm::None;
return parseRegion(region, arguments, argTypes, argLocations,
ParseResult OperationParser::parseRegion(
Region ®ion,
ArrayRef<std::pair<OperationParser::SSAUseInfo, Type>> entryArguments,
- ArrayRef<Optional<Location>> argLocations, bool isIsolatedNameScope) {
+ ArrayRef<Location> argLocations, bool isIsolatedNameScope) {
// Parse the '{'.
Token lBraceTok = getToken();
if (parseToken(Token::l_brace, "expected '{' to begin a region"))
ParseResult OperationParser::parseRegionBody(
Region ®ion, llvm::SMLoc startLoc,
ArrayRef<std::pair<OperationParser::SSAUseInfo, Type>> entryArguments,
- ArrayRef<Optional<Location>> argLocations, bool isIsolatedNameScope) {
+ ArrayRef<Location> argLocations, bool isIsolatedNameScope) {
assert(argLocations.empty() || argLocations.size() == entryArguments.size());
auto currentPt = opBuilder.saveInsertionPoint();
.attachNote(getEncodedSourceLocation(*defLoc))
<< "previously referenced here";
}
- Location loc =
- (!argLocations.empty() && argLocations[argIndex])
- ? *argLocations[argIndex]
- : getEncodedSourceLocation(placeholderArgPair.first.loc);
- BlockArgument arg = block->addArgument(placeholderArgPair.second, loc);
+ BlockArgument arg = block->addArgument(
+ placeholderArgPair.second,
+ argLocations.empty()
+ ? getEncodedSourceLocation(placeholderArgPair.first.loc)
+ : argLocations[argIndex]);
// Add a definition of this arg to the assembly state if provided.
if (state.asmState)
Type type = processType(inst->getType());
if (!type)
return failure();
- v = b.getInsertionBlock()->addArgument(type);
+ v = b.getInsertionBlock()->addArgument(
+ type, processDebugLoc(inst->getDebugLoc(), inst));
return success();
}
case llvm::Instruction::Call: {
currentEntryBlock = blockList[0];
// Add function arguments to the entry block.
- for (const auto &kv : llvm::enumerate(f->args()))
- instMap[&kv.value()] =
- blockList[0]->addArgument(functionType.getParamType(kv.index()));
+ for (const auto &kv : llvm::enumerate(f->args())) {
+ instMap[&kv.value()] = blockList[0]->addArgument(
+ functionType.getParamType(kv.index()), fop.getLoc());
+ }
for (auto bbs : llvm::zip(*f, blockList)) {
if (failed(processBasicBlock(&std::get<0>(bbs), std::get<1>(bbs))))
// Create a block argument for this OpPhi instruction.
Type blockArgType = getType(operands[0]);
- BlockArgument blockArg = curBlock->addArgument(blockArgType);
+ BlockArgument blockArg = curBlock->addArgument(blockArgType, unknownLoc);
valueMap[operands[1]] = blockArg;
LLVM_DEBUG(logger.startLine()
<< "[phi] created block argument " << blockArg
<< " from block " << block << "\n");
if (!isFnEntryBlock(block)) {
for (BlockArgument blockArg : block->getArguments()) {
- auto newArg = newBlock->addArgument(blockArg.getType());
+ auto newArg =
+ newBlock->addArgument(blockArg.getType(), blockArg.getLoc());
mapper.map(blockArg, newArg);
LLVM_DEBUG(logger.startLine() << "[cf] remapped block argument "
<< blockArg << " to " << newArg << "\n");
// The loop header block may have block arguments. Since now we place the
// loop op inside the old merge block, we need to make sure the old merge
// block has the same block argument list.
- for (BlockArgument blockArg : headerBlock->getArguments()) {
- mergeBlock->addArgument(blockArg.getType());
- }
+ for (BlockArgument blockArg : headerBlock->getArguments())
+ mergeBlock->addArgument(blockArg.getType(), blockArg.getLoc());
// If the loop header block has block arguments, make sure the spv.Branch op
// matches.
// Add the new arguments to the entry block if the function is not external.
if (func.isExternal())
return;
- auto newArgs = func.front().addArguments(erasedResultTypes);
- appendedEntryArgs.append(newArgs.begin(), newArgs.end());
+ Location loc = func.getLoc();
+ for (Type type : erasedResultTypes)
+ appendedEntryArgs.push_back(func.front().addArgument(type, loc));
}
// Updates all ReturnOps in the scope of the given FuncOp by either keeping them
OpBuilder b(funcOp);
FunctionType functionType = funcOp.getType();
+ SmallVector<Location> functionArgLocs(llvm::map_range(
+ funcOp.getArguments(), [](BlockArgument arg) { return arg.getLoc(); }));
SmallVector<Type, 8> inputTypes;
// Walk over each argument of a function to perform memref normalization (if
for (unsigned argIndex :
}
// Insert a new temporary argument with the new memref type.
- BlockArgument newMemRef =
- funcOp.front().insertArgument(argIndex, newMemRefType);
+ BlockArgument newMemRef = funcOp.front().insertArgument(
+ argIndex, newMemRefType, functionArgLocs[argIndex]);
BlockArgument oldMemRef = funcOp.getArgument(argIndex + 1);
AffineMap layoutMap = memrefType.getLayout().getAffineMap();
// Replace all uses of the old memref.
Block *newBlock = block->splitBlock(block->begin());
block->replaceAllUsesWith(newBlock);
- SmallVector<Value, 4> newArgRange(newBlock->addArguments(convertedTypes));
+ // FIXME: We should map the new arguments to proper locations.
+ SmallVector<Location> newLocs(convertedTypes.size(),
+ rewriter.getUnknownLoc());
+ SmallVector<Value, 4> newArgRange(
+ newBlock->addArguments(convertedTypes, newLocs));
ArrayRef<Value> newArgs(newArgRange);
// Remap each of the original arguments as determined by the signature
// Otherwise, there were multiple blocks inlined. Add arguments to the post
// insertion block to represent the results to replace.
for (const auto &resultToRepl : llvm::enumerate(resultsToReplace)) {
- resultToRepl.value().replaceAllUsesWith(postInsertBlock->addArgument(
- regionResultTypes[resultToRepl.index()]));
+ resultToRepl.value().replaceAllUsesWith(
+ postInsertBlock->addArgument(regionResultTypes[resultToRepl.index()],
+ resultToRepl.value().getLoc()));
}
/// Handle the terminators for each of the new blocks.
newArguments[i][it.index()] = operand.get();
// Update the operand and insert an argument if this is the leader.
- if (i == 0)
- operand.set(leaderBlock->addArgument(operand.get().getType()));
+ if (i == 0) {
+ Value operandVal = operand.get();
+ operand.set(leaderBlock->addArgument(operandVal.getType(),
+ operandVal.getLoc()));
+ }
}
}
// Update the predecessors for each of the blocks.
MlirType memrefType =
mlirTypeParseGet(ctx, mlirStringRefCreateFromCString("memref<?xf32>"));
MlirType funcBodyArgTypes[] = {memrefType, memrefType};
+ MlirLocation funcBodyArgLocs[] = {location, location};
MlirRegion funcBodyRegion = mlirRegionCreate();
- MlirBlock funcBody = mlirBlockCreate(
- sizeof(funcBodyArgTypes) / sizeof(MlirType), funcBodyArgTypes);
+ MlirBlock funcBody =
+ mlirBlockCreate(sizeof(funcBodyArgTypes) / sizeof(MlirType),
+ funcBodyArgTypes, funcBodyArgLocs);
mlirRegionAppendOwnedBlock(funcBodyRegion, funcBody);
MlirAttribute funcTypeAttr = mlirAttributeParseGet(
mlirBlockAppendOwnedOperation(funcBody, dim);
MlirRegion loopBodyRegion = mlirRegionCreate();
- MlirBlock loopBody = mlirBlockCreate(0, NULL);
- mlirBlockAddArgument(loopBody, indexType);
+ MlirBlock loopBody = mlirBlockCreate(0, NULL, NULL);
+ mlirBlockAddArgument(loopBody, indexType, location);
mlirRegionAppendOwnedBlock(loopBodyRegion, loopBody);
MlirAttribute indexOneLiteral =
MlirType i2 = mlirIntegerTypeGet(ctx, 2);
MlirType i3 = mlirIntegerTypeGet(ctx, 3);
MlirType i4 = mlirIntegerTypeGet(ctx, 4);
- MlirBlock block1 = mlirBlockCreate(1, &i1);
- MlirBlock block2 = mlirBlockCreate(1, &i2);
- MlirBlock block3 = mlirBlockCreate(1, &i3);
- MlirBlock block4 = mlirBlockCreate(1, &i4);
+ MlirBlock block1 = mlirBlockCreate(1, &i1, &loc);
+ MlirBlock block2 = mlirBlockCreate(1, &i2, &loc);
+ MlirBlock block3 = mlirBlockCreate(1, &i3, &loc);
+ MlirBlock block4 = mlirBlockCreate(1, &i4, &loc);
// Insert blocks so as to obtain the 1-2-3-4 order,
mlirRegionInsertOwnedBlockBefore(region, nullBlock, block3);
mlirRegionInsertOwnedBlockBefore(region, block3, block2);
MlirOperationState opState =
mlirOperationStateGet(mlirStringRefCreateFromCString("invalid.op"), loc);
MlirRegion region = mlirRegionCreate();
- MlirBlock block = mlirBlockCreate(0, NULL);
+ MlirBlock block = mlirBlockCreate(0, NULL, NULL);
mlirRegionAppendOwnedBlock(region, block);
mlirOperationStateAddOwnedRegions(&opState, 1, ®ion);
MlirOperation op = mlirOperationCreate(&opState);
newRegion.addRegion();
auto *regionOp = rewriter.createOperation(newRegion);
auto *entryBlock = rewriter.createBlock(®ionOp->getRegion(0));
- entryBlock->addArgument(rewriter.getIntegerType(64));
+ entryBlock->addArgument(rewriter.getIntegerType(64),
+ rewriter.getUnknownLoc());
// Add an explicitly illegal operation to ensure the conversion fails.
rewriter.create<ILLegalOpF>(op->getLoc(), rewriter.getIntegerType(32));
PatternRewriter &rewriter) const final {
Region ®ion = *op->getParentRegion();
Type i32Type = rewriter.getIntegerType(32);
- rewriter.createBlock(®ion, region.end(), {i32Type, i32Type});
- rewriter.create<TerminatorOp>(op->getLoc());
+ Location loc = op->getLoc();
+ rewriter.createBlock(®ion, region.end(), {i32Type, i32Type}, {loc, loc});
+ rewriter.create<TerminatorOp>(loc);
rewriter.replaceOp(op, {});
return success();
}
PatternRewriter &rewriter) const final {
Region ®ion = *op->getParentRegion();
Type i32Type = rewriter.getIntegerType(32);
- rewriter.createBlock(®ion, region.end(), {i32Type, i32Type});
+ Location loc = op->getLoc();
+ rewriter.createBlock(®ion, region.end(), {i32Type, i32Type}, {loc, loc});
// Create an illegal op to ensure the conversion fails.
- rewriter.create<ILLegalOpF>(op->getLoc(), i32Type);
- rewriter.create<TerminatorOp>(op->getLoc());
+ rewriter.create<ILLegalOpF>(loc, i32Type);
+ rewriter.create<TerminatorOp>(loc);
rewriter.replaceOp(op, {});
return success();
}
void runOnOperation() override {
auto module = getOperation();
+ UnknownLoc unknownLoc = UnknownLoc::get(module.getContext());
for (FuncOp func : module.getOps<FuncOp>()) {
auto inserts = func->getAttrOfType<ArrayAttr>("test.insert_args");
if (!inserts || inserts.empty())
SmallVector<unsigned, 4> indicesToInsert;
SmallVector<Type, 4> typesToInsert;
SmallVector<DictionaryAttr, 4> attrsToInsert;
- SmallVector<Optional<Location>, 4> locsToInsert;
+ SmallVector<Location, 4> locsToInsert;
for (auto insert : inserts.getAsRange<ArrayAttr>()) {
indicesToInsert.push_back(
insert[0].cast<IntegerAttr>().getValue().getZExtValue());
attrsToInsert.push_back(insert.size() > 2
? insert[2].cast<DictionaryAttr>()
: DictionaryAttr::get(&getContext()));
- locsToInsert.push_back(
- insert.size() > 3
- ? Optional<Location>(insert[3].cast<LocationAttr>())
- : Optional<Location>{});
+ locsToInsert.push_back(insert.size() > 3
+ ? Location(insert[3].cast<LocationAttr>())
+ : unknownLoc);
}
func->removeAttr("test.insert_args");
func.insertArguments(indicesToInsert, typesToInsert, attrsToInsert,