static constexpr const char kBranchWeightAttrName[] = "branch_weights";
static constexpr const char kCallee[] = "callee";
static constexpr const char kClusterSize[] = "cluster_size";
+static constexpr const char kControl[] = "control";
static constexpr const char kDefaultValueAttrName[] = "default_value";
static constexpr const char kExecutionScopeAttrName[] = "execution_scope";
static constexpr const char kEqualSemanticsAttrName[] = "equal_semantics";
return success();
}
+/// Parses Function, Selection and Loop control attributes. If no control is
+/// specified, "None" is used as a default.
+template <typename EnumClass>
+static ParseResult
+parseControlAttribute(OpAsmParser &parser, OperationState &state,
+ StringRef attrName = spirv::attributeName<EnumClass>()) {
+ if (succeeded(parser.parseOptionalKeyword(kControl))) {
+ EnumClass control;
+ if (parser.parseLParen() || parseEnumKeywordAttr(control, parser, state) ||
+ parser.parseRParen())
+ return failure();
+ return success();
+ }
+ // Set control to "None" otherwise.
+ Builder builder = parser.getBuilder();
+ state.addAttribute(attrName, builder.getI32IntegerAttr(0));
+ return success();
+}
+
/// Parses optional memory access attributes attached to a memory access
/// operand/pointer. Specifically, parses the following syntax:
/// (`[` memory-access `]`)?
}
static ParseResult parseLoopOp(OpAsmParser &parser, OperationState &state) {
- // TODO: support loop control properly
- Builder builder = parser.getBuilder();
- state.addAttribute("loop_control",
- builder.getI32IntegerAttr(
- static_cast<uint32_t>(spirv::LoopControl::None)));
-
+ if (parseControlAttribute<spirv::LoopControl>(parser, state))
+ return failure();
return parser.parseRegion(*state.addRegion(), /*arguments=*/{},
/*argTypes=*/{});
}
auto *op = loopOp.getOperation();
printer << spirv::LoopOp::getOperationName();
+ auto control = loopOp.loop_control();
+ if (control != spirv::LoopControl::None)
+ printer << " control(" << spirv::stringifyLoopControl(control) << ")";
printer.printRegion(op->getRegion(0), /*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/true);
}
static ParseResult parseSelectionOp(OpAsmParser &parser,
OperationState &state) {
- // TODO: support selection control properly
- Builder builder = parser.getBuilder();
- state.addAttribute("selection_control",
- builder.getI32IntegerAttr(
- static_cast<uint32_t>(spirv::SelectionControl::None)));
-
+ if (parseControlAttribute<spirv::SelectionControl>(parser, state))
+ return failure();
return parser.parseRegion(*state.addRegion(), /*arguments=*/{},
/*argTypes=*/{});
}
auto *op = selectionOp.getOperation();
printer << spirv::SelectionOp::getOperationName();
+ auto control = selectionOp.selection_control();
+ if (control != spirv::SelectionControl::None)
+ printer << " control(" << spirv::stringifySelectionControl(control) << ")";
printer.printRegion(op->getRegion(0), /*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/true);
}
Block *mergeBlock;
Block *continueBlock; // nullptr for spv.selection
Location loc;
-
- BlockMergeInfo(Location location)
- : mergeBlock(nullptr), continueBlock(nullptr), loc(location) {}
- BlockMergeInfo(Location location, Block *m, Block *c = nullptr)
- : mergeBlock(m), continueBlock(c), loc(location) {}
+ uint32_t control;
+
+ BlockMergeInfo(Location location, uint32_t control)
+ : mergeBlock(nullptr), continueBlock(nullptr), loc(location),
+ control(control) {}
+ BlockMergeInfo(Location location, uint32_t control, Block *m,
+ Block *c = nullptr)
+ : mergeBlock(m), continueBlock(c), loc(location), control(control) {}
};
/// A struct for containing OpLine instruction information.
"OpSelectionMerge must specify merge target and selection control");
}
- if (static_cast<uint32_t>(spirv::SelectionControl::None) != operands[1]) {
- return emitError(unknownLoc,
- "unimplmented OpSelectionMerge selection control: ")
- << operands[2];
- }
-
auto *mergeBlock = getOrCreateBlock(operands[0]);
auto loc = createFileLineColLoc(opBuilder);
+ auto selectionControl = operands[1];
- if (!blockMergeInfo.try_emplace(curBlock, loc, mergeBlock).second) {
+ if (!blockMergeInfo.try_emplace(curBlock, loc, selectionControl, mergeBlock)
+ .second) {
return emitError(
unknownLoc,
"a block cannot have more than one OpSelectionMerge instruction");
"continue target and loop control");
}
- if (static_cast<uint32_t>(spirv::LoopControl::None) != operands[2]) {
- return emitError(unknownLoc, "unimplmented OpLoopMerge loop control: ")
- << operands[2];
- }
-
auto *mergeBlock = getOrCreateBlock(operands[0]);
auto *continueBlock = getOrCreateBlock(operands[1]);
auto loc = createFileLineColLoc(opBuilder);
+ uint32_t loopControl = operands[2];
- if (!blockMergeInfo.try_emplace(curBlock, loc, mergeBlock, continueBlock)
+ if (!blockMergeInfo
+ .try_emplace(curBlock, loc, loopControl, mergeBlock, continueBlock)
.second) {
return emitError(
unknownLoc,
/// the `headerBlock` will be redirected to the `mergeBlock`.
/// This method will also update `mergeInfo` by remapping all blocks inside to
/// the newly cloned ones inside structured control flow op's regions.
- static LogicalResult structurize(Location loc, BlockMergeInfoMap &mergeInfo,
+ static LogicalResult structurize(Location loc, uint32_t control,
+ BlockMergeInfoMap &mergeInfo,
Block *headerBlock, Block *mergeBlock,
Block *continueBlock) {
- return ControlFlowStructurizer(loc, mergeInfo, headerBlock, mergeBlock,
- continueBlock)
+ return ControlFlowStructurizer(loc, control, mergeInfo, headerBlock,
+ mergeBlock, continueBlock)
.structurizeImpl();
}
private:
- ControlFlowStructurizer(Location loc, BlockMergeInfoMap &mergeInfo,
- Block *header, Block *merge, Block *cont)
- : location(loc), blockMergeInfo(mergeInfo), headerBlock(header),
- mergeBlock(merge), continueBlock(cont) {}
+ ControlFlowStructurizer(Location loc, uint32_t control,
+ BlockMergeInfoMap &mergeInfo, Block *header,
+ Block *merge, Block *cont)
+ : location(loc), control(control), blockMergeInfo(mergeInfo),
+ headerBlock(header), mergeBlock(merge), continueBlock(cont) {}
/// Creates a new spv.selection op at the beginning of the `mergeBlock`.
- spirv::SelectionOp createSelectionOp();
+ spirv::SelectionOp createSelectionOp(uint32_t selectionControl);
/// Creates a new spv.loop op at the beginning of the `mergeBlock`.
- spirv::LoopOp createLoopOp();
+ spirv::LoopOp createLoopOp(uint32_t loopControl);
/// Collects all blocks reachable from `headerBlock` except `mergeBlock`.
void collectBlocksInConstruct();
LogicalResult structurizeImpl();
Location location;
+ uint32_t control;
BlockMergeInfoMap &blockMergeInfo;
};
} // namespace
-spirv::SelectionOp ControlFlowStructurizer::createSelectionOp() {
+spirv::SelectionOp
+ControlFlowStructurizer::createSelectionOp(uint32_t selectionControl) {
// Create a builder and set the insertion point to the beginning of the
// merge block so that the newly created SelectionOp will be inserted there.
OpBuilder builder(&mergeBlock->front());
- auto control = builder.getI32IntegerAttr(
- static_cast<uint32_t>(spirv::SelectionControl::None));
+ auto control = builder.getI32IntegerAttr(selectionControl);
auto selectionOp = builder.create<spirv::SelectionOp>(location, control);
selectionOp.addMergeBlock();
return selectionOp;
}
-spirv::LoopOp ControlFlowStructurizer::createLoopOp() {
+spirv::LoopOp ControlFlowStructurizer::createLoopOp(uint32_t loopControl) {
// Create a builder and set the insertion point to the beginning of the
// merge block so that the newly created LoopOp will be inserted there.
OpBuilder builder(&mergeBlock->front());
- // TODO: handle loop control properly
- auto loopOp = builder.create<spirv::LoopOp>(location);
+ auto control = builder.getI32IntegerAttr(loopControl);
+ auto loopOp = builder.create<spirv::LoopOp>(location, control);
loopOp.addEntryAndMergeBlock();
return loopOp;
Operation *op = nullptr;
bool isLoop = continueBlock != nullptr;
if (isLoop) {
- if (auto loopOp = createLoopOp())
+ if (auto loopOp = createLoopOp(control))
op = loopOp.getOperation();
} else {
- if (auto selectionOp = createSelectionOp())
+ if (auto selectionOp = createSelectionOp(control))
op = selectionOp.getOperation();
}
if (!op)
// The iterator should be erased before adding a new entry into
// blockMergeInfo to avoid iterator invalidation.
blockMergeInfo.erase(it);
- blockMergeInfo.try_emplace(newHeader, loc, newMerge, newContinue);
+ blockMergeInfo.try_emplace(newHeader, loc, it->second.control, newMerge,
+ newContinue);
}
// The structured selection/loop's entry block does not have arguments.
// Erase this case before calling into structurizer, who will update
// blockMergeInfo.
blockMergeInfo.erase(blockMergeInfo.begin());
- if (failed(ControlFlowStructurizer::structurize(mergeInfo.loc,
- blockMergeInfo, headerBlock,
- mergeBlock, continueBlock)))
+ if (failed(ControlFlowStructurizer::structurize(
+ mergeInfo.loc, mergeInfo.control, blockMergeInfo, headerBlock,
+ mergeBlock, continueBlock)))
return failure();
}