forked from OSchip/llvm-project
[mlir] Add an assertion on creating an Operation with null result types
Null types are commonly used as an error marker. Catch them in the constructor of Operation if they are present in the result type list, as otherwise this could lead to further surprising behavior when querying op result types. Fix AsyncToLLVM and StandardToLLVM that were using null types when constructing operations. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D91770
This commit is contained in:
parent
6c1c308c0e
commit
9bb5bff570
|
@ -223,7 +223,7 @@ static void addResumeFunction(ModuleOp module) {
|
||||||
auto *block = resumeOp.addEntryBlock();
|
auto *block = resumeOp.addEntryBlock();
|
||||||
OpBuilder blockBuilder = OpBuilder::atBlockEnd(block);
|
OpBuilder blockBuilder = OpBuilder::atBlockEnd(block);
|
||||||
|
|
||||||
blockBuilder.create<LLVM::CallOp>(loc, Type(),
|
blockBuilder.create<LLVM::CallOp>(loc, TypeRange(),
|
||||||
blockBuilder.getSymbolRefAttr(kCoroResume),
|
blockBuilder.getSymbolRefAttr(kCoroResume),
|
||||||
resumeOp.getArgument(0));
|
resumeOp.getArgument(0));
|
||||||
|
|
||||||
|
@ -343,7 +343,8 @@ static CoroMachinery setupCoroMachinery(FuncOp func) {
|
||||||
ValueRange({coroId.getResult(0), coroHdl.getResult(0)}));
|
ValueRange({coroId.getResult(0), coroHdl.getResult(0)}));
|
||||||
|
|
||||||
// Free the memory.
|
// Free the memory.
|
||||||
builder.create<LLVM::CallOp>(loc, Type(), builder.getSymbolRefAttr(kFree),
|
builder.create<LLVM::CallOp>(loc, TypeRange(),
|
||||||
|
builder.getSymbolRefAttr(kFree),
|
||||||
ValueRange(coroMem.getResult(0)));
|
ValueRange(coroMem.getResult(0)));
|
||||||
// Branch into the suspend block.
|
// Branch into the suspend block.
|
||||||
builder.create<BranchOp>(loc, suspendBlock);
|
builder.create<BranchOp>(loc, suspendBlock);
|
||||||
|
@ -503,7 +504,7 @@ outlineExecuteOp(SymbolTable &symbolTable, ExecuteOp execute) {
|
||||||
|
|
||||||
// Call async runtime API to execute a coroutine in the managed thread.
|
// Call async runtime API to execute a coroutine in the managed thread.
|
||||||
SmallVector<Value, 2> executeArgs = {coro.coroHandle, resumePtr.res()};
|
SmallVector<Value, 2> executeArgs = {coro.coroHandle, resumePtr.res()};
|
||||||
builder.create<CallOp>(loc, Type(), kExecute, executeArgs);
|
builder.create<CallOp>(loc, TypeRange(), kExecute, executeArgs);
|
||||||
|
|
||||||
// Split the entry block before the terminator.
|
// Split the entry block before the terminator.
|
||||||
Block *resume = addSuspensionPoint(coro, coroSave.getResult(0),
|
Block *resume = addSuspensionPoint(coro, coroSave.getResult(0),
|
||||||
|
@ -524,7 +525,7 @@ outlineExecuteOp(SymbolTable &symbolTable, ExecuteOp execute) {
|
||||||
// to async runtime to emplace the result token.
|
// to async runtime to emplace the result token.
|
||||||
for (Operation &op : execute.body().getOps()) {
|
for (Operation &op : execute.body().getOps()) {
|
||||||
if (isa<async::YieldOp>(op)) {
|
if (isa<async::YieldOp>(op)) {
|
||||||
builder.create<CallOp>(loc, kEmplaceToken, Type(), coro.asyncToken);
|
builder.create<CallOp>(loc, kEmplaceToken, TypeRange(), coro.asyncToken);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
builder.clone(op, valueMapping);
|
builder.clone(op, valueMapping);
|
||||||
|
@ -671,7 +672,7 @@ public:
|
||||||
// Inside regular function we convert await operation to the blocking
|
// Inside regular function we convert await operation to the blocking
|
||||||
// async API await function call.
|
// async API await function call.
|
||||||
if (!isInCoroutine)
|
if (!isInCoroutine)
|
||||||
rewriter.create<CallOp>(loc, Type(), blockingAwaitFuncName,
|
rewriter.create<CallOp>(loc, TypeRange(), blockingAwaitFuncName,
|
||||||
ValueRange(op->getOperand(0)));
|
ValueRange(op->getOperand(0)));
|
||||||
|
|
||||||
// Inside the coroutine we convert await operation into coroutine suspension
|
// Inside the coroutine we convert await operation into coroutine suspension
|
||||||
|
@ -696,7 +697,7 @@ public:
|
||||||
// the async await argument becomes ready.
|
// the async await argument becomes ready.
|
||||||
SmallVector<Value, 3> awaitAndExecuteArgs = {
|
SmallVector<Value, 3> awaitAndExecuteArgs = {
|
||||||
await.getOperand(), coro.coroHandle, resumePtr.res()};
|
await.getOperand(), coro.coroHandle, resumePtr.res()};
|
||||||
builder.create<CallOp>(loc, Type(), coroAwaitFuncName,
|
builder.create<CallOp>(loc, TypeRange(), coroAwaitFuncName,
|
||||||
awaitAndExecuteArgs);
|
awaitAndExecuteArgs);
|
||||||
|
|
||||||
// Split the entry block before the await operation.
|
// Split the entry block before the await operation.
|
||||||
|
|
|
@ -2290,7 +2290,7 @@ struct CallOpInterfaceLowering : public ConvertOpToLLVMPattern<CallOpType> {
|
||||||
auto callOp = cast<CallOpType>(op);
|
auto callOp = cast<CallOpType>(op);
|
||||||
|
|
||||||
// Pack the result types into a struct.
|
// Pack the result types into a struct.
|
||||||
Type packedResult;
|
Type packedResult = nullptr;
|
||||||
unsigned numResults = callOp.getNumResults();
|
unsigned numResults = callOp.getNumResults();
|
||||||
auto resultTypes = llvm::to_vector<4>(callOp.getResultTypes());
|
auto resultTypes = llvm::to_vector<4>(callOp.getResultTypes());
|
||||||
|
|
||||||
|
@ -2302,8 +2302,9 @@ struct CallOpInterfaceLowering : public ConvertOpToLLVMPattern<CallOpType> {
|
||||||
|
|
||||||
auto promoted = this->typeConverter.promoteOperands(
|
auto promoted = this->typeConverter.promoteOperands(
|
||||||
op->getLoc(), /*opOperands=*/op->getOperands(), operands, rewriter);
|
op->getLoc(), /*opOperands=*/op->getOperands(), operands, rewriter);
|
||||||
auto newOp = rewriter.create<LLVM::CallOp>(op->getLoc(), packedResult,
|
auto newOp = rewriter.create<LLVM::CallOp>(
|
||||||
promoted, op->getAttrs());
|
op->getLoc(), packedResult ? TypeRange(packedResult) : TypeRange(),
|
||||||
|
promoted, op->getAttrs());
|
||||||
|
|
||||||
SmallVector<Value, 4> results;
|
SmallVector<Value, 4> results;
|
||||||
if (numResults < 2) {
|
if (numResults < 2) {
|
||||||
|
|
|
@ -167,6 +167,8 @@ Operation::Operation(Location location, OperationName name,
|
||||||
: location(location), numSuccs(numSuccessors), numRegions(numRegions),
|
: location(location), numSuccs(numSuccessors), numRegions(numRegions),
|
||||||
hasOperandStorage(hasOperandStorage), hasSingleResult(false), name(name),
|
hasOperandStorage(hasOperandStorage), hasSingleResult(false), name(name),
|
||||||
attrs(attributes) {
|
attrs(attributes) {
|
||||||
|
assert(llvm::all_of(resultTypes, [](Type t) { return t; }) &&
|
||||||
|
"unexpected null result type");
|
||||||
if (!resultTypes.empty()) {
|
if (!resultTypes.empty()) {
|
||||||
// If there is a single result it is stored in-place, otherwise use a tuple.
|
// If there is a single result it is stored in-place, otherwise use a tuple.
|
||||||
hasSingleResult = resultTypes.size() == 1;
|
hasSingleResult = resultTypes.size() == 1;
|
||||||
|
|
|
@ -14,7 +14,10 @@ using namespace mlir;
|
||||||
// TypeRange
|
// TypeRange
|
||||||
|
|
||||||
TypeRange::TypeRange(ArrayRef<Type> types)
|
TypeRange::TypeRange(ArrayRef<Type> types)
|
||||||
: TypeRange(types.data(), types.size()) {}
|
: TypeRange(types.data(), types.size()) {
|
||||||
|
assert(llvm::all_of(types, [](Type t) { return t; }) &&
|
||||||
|
"attempting to construct a TypeRange with null types");
|
||||||
|
}
|
||||||
TypeRange::TypeRange(OperandRange values)
|
TypeRange::TypeRange(OperandRange values)
|
||||||
: TypeRange(values.begin().getBase(), values.size()) {}
|
: TypeRange(values.begin().getBase(), values.size()) {}
|
||||||
TypeRange::TypeRange(ResultRange values)
|
TypeRange::TypeRange(ResultRange values)
|
||||||
|
|
|
@ -203,3 +203,13 @@ func @get_gv3_memref() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This should not trigger an assertion by creating an LLVM::CallOp with a
|
||||||
|
// nullptr result type.
|
||||||
|
|
||||||
|
// CHECK-LABEL: @call_zero_result_func
|
||||||
|
func @call_zero_result_func() {
|
||||||
|
// CHECK: call @zero_result_func
|
||||||
|
call @zero_result_func() : () -> ()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func private @zero_result_func()
|
||||||
|
|
Loading…
Reference in New Issue