[spirv] Make confugration deduction return state consistent (#12561)
We have some kernel confugration deduction function (e.g., for
reduction) returning `failure()` on failing to find a configuration, and
the rest returning `success()`. This is inconsistent and confusing.
Additionally, for the latter we rely on `getLoweringConfig()` as a
separate call to check whether a configuration is indeed set. This won't
actually work anymore with transform dialect, where we will embed the
configuration in the schedule.
So this commit switches all into returning `failure()` meaning unable to
find a configuration.
This is a preliminary step towards enabling transform dialect in SPIR-V
CodeGen.
diff --git a/compiler/src/iree/compiler/Codegen/SPIRV/AMDConfig.cpp b/compiler/src/iree/compiler/Codegen/SPIRV/AMDConfig.cpp
index 4346284..ba6fe02 100644
--- a/compiler/src/iree/compiler/Codegen/SPIRV/AMDConfig.cpp
+++ b/compiler/src/iree/compiler/Codegen/SPIRV/AMDConfig.cpp
@@ -37,12 +37,11 @@
static LogicalResult setAMDMatmulConfig(linalg::LinalgOp op,
const spirv::TargetEnv &targetEnv) {
- if (failed(setCooperativeMatrixConfig(
+ if (succeeded(setCooperativeMatrixConfig(
targetEnv, op, AMDNumSubgroupsPerWorkgroup, AMDNumMNTilesPerSubgroup,
AMDCoopMatrixSoftwarePipelineDepth,
AMDCoopMatrixSoftwarePipelineStoreStage)))
- return failure();
- if (getLoweringConfig(op)) return success();
+ return success();
spirv::ResourceLimitsAttr limits = targetEnv.getResourceLimits();
const int subgroupSize = limits.getSubgroupSize();
@@ -98,7 +97,7 @@
int bestTilingFactor = hasPaddedInput ? 16 : 32;
return setConvOpConfig(op, subgroupSize, bestTilingFactor);
})
- .Default([](Operation *) { return success(); });
+ .Default([](Operation *) { return failure(); });
}
} // namespace detail
diff --git a/compiler/src/iree/compiler/Codegen/SPIRV/AdrenoConfig.cpp b/compiler/src/iree/compiler/Codegen/SPIRV/AdrenoConfig.cpp
index afc293b..81967b4 100644
--- a/compiler/src/iree/compiler/Codegen/SPIRV/AdrenoConfig.cpp
+++ b/compiler/src/iree/compiler/Codegen/SPIRV/AdrenoConfig.cpp
@@ -61,7 +61,7 @@
return setConvOpConfig(op, subgroupSize,
/*bestTilingFactor=*/16);
})
- .Default([](Operation *) { return success(); });
+ .Default([](Operation *) { return failure(); });
}
} // namespace detail
diff --git a/compiler/src/iree/compiler/Codegen/SPIRV/AppleConfig.cpp b/compiler/src/iree/compiler/Codegen/SPIRV/AppleConfig.cpp
index f3943ee..2a0fe40 100644
--- a/compiler/src/iree/compiler/Codegen/SPIRV/AppleConfig.cpp
+++ b/compiler/src/iree/compiler/Codegen/SPIRV/AppleConfig.cpp
@@ -61,7 +61,7 @@
return setConvOpConfig(op, subgroupSize,
/*bestTilingFactor=*/16);
})
- .Default([](Operation *) { return success(); });
+ .Default([](Operation *) { return failure(); });
}
} // namespace detail
diff --git a/compiler/src/iree/compiler/Codegen/SPIRV/KernelConfig.cpp b/compiler/src/iree/compiler/Codegen/SPIRV/KernelConfig.cpp
index 0dc9aae..d38107c 100644
--- a/compiler/src/iree/compiler/Codegen/SPIRV/KernelConfig.cpp
+++ b/compiler/src/iree/compiler/Codegen/SPIRV/KernelConfig.cpp
@@ -167,7 +167,7 @@
const bool isNCHW = isa<linalg::Conv2DNchwFchwOp>(*linalgOp);
const bool isNHWC = isa<linalg::Conv2DNhwcHwcfOp>(*linalgOp) ||
isa<linalg::DepthwiseConv2DNhwcHwcOp>(*linalgOp);
- if (!isNCHW & !isNHWC) return success();
+ if (!isNCHW & !isNHWC) return failure();
const int icIndex = isNHWC ? 3 : 1;
const int ohIndex = isNHWC ? 1 : 2;
@@ -176,7 +176,7 @@
if (ShapedType::isDynamic(inputShape[icIndex]) ||
llvm::any_of(outputShape.drop_front(), ShapedType::isDynamic)) {
- return success();
+ return failure();
}
const int64_t ic = inputShape[icIndex], oc = outputShape[ocIndex];
@@ -184,7 +184,7 @@
// The conversion pipeline requires the input channel dimension to be some
// multipler of four, or less than four.
- if (!(ic % 4 == 0 || ic < 4)) return success();
+ if (!(ic % 4 == 0 || ic < 4)) return failure();
// The core idea is to distribute the convolution dimensions to the workgroup
// Z/Y/X dimensions, with each thread in a workgroup handling multiple vector
@@ -208,14 +208,14 @@
!tileConvOneDim(oc, /*isInnerMostDim=*/false, residualThreads,
residualTilingFactor, workgroupSize[2],
workgroupTileSizes[1])) {
- return success();
+ return failure();
}
} else {
// OC -> x
if (!tileConvOneDim(oc, /*isInnerMostDim=*/true, residualThreads,
residualTilingFactor, workgroupSize[0],
workgroupTileSizes[3]))
- return success();
+ return failure();
// Deduce the configruation for the OW and OH dimension. Try to make them
// even if possible given we typically have images with the same height
@@ -234,7 +234,7 @@
!tileConvOneDim(oh, /*isInnerMostDim=*/false, residualThreads,
residualTilingFactor, workgroupSize[2],
workgroupTileSizes[1])) {
- return success();
+ return failure();
}
}
}
@@ -256,7 +256,7 @@
} else if (isa<linalg::DepthwiseConv2DNhwcHwcOp>(linalgOp)) {
tileSizes.push_back({0, 0, 0, 0, 1, 1}); // (N, OH, OW, C, FH, FW)
} else {
- return success();
+ return failure();
}
// Tile along OH by size 1 to enable downsizing 2-D convolution to 1-D.
SmallVector<int64_t> windowTileSizes(4, 0);
@@ -543,19 +543,19 @@
auto rhsType = rhs->get().getType().cast<ShapedType>();
auto elementBits =
static_cast<int>(lhsType.getElementType().getIntOrFloatBitWidth());
- if (!llvm::is_contained({8, 16, 32}, elementBits)) return success();
+ if (!llvm::is_contained({8, 16, 32}, elementBits)) return failure();
ArrayRef<int64_t> lhsShape = lhsType.getShape();
ArrayRef<int64_t> rhsShape = rhsType.getShape();
- if (llvm::any_of(lhsShape, ShapedType::isDynamic)) return success();
- if (llvm::any_of(rhsShape, ShapedType::isDynamic)) return success();
+ if (llvm::any_of(lhsShape, ShapedType::isDynamic)) return failure();
+ if (llvm::any_of(rhsShape, ShapedType::isDynamic)) return failure();
assert(llvm::is_contained({2u, 3u}, op.getNumParallelLoops()));
int lastParallelDim = -1;
const auto [bIndex, mIndex, nIndex, kIndex] =
getMatmulBMNKIndex(op, &lastParallelDim);
- if (mIndex < 0 || nIndex < 0 || kIndex < 0) return success();
+ if (mIndex < 0 || nIndex < 0 || kIndex < 0) return failure();
const bool isBM = bIndex >= 0;
SmallVector<int64_t, 4> loopRanges = op.getStaticLoopRanges();
@@ -608,7 +608,7 @@
residualTilingFactor, workgroupSize[1],
workgroupTileSizes[mIndex]) ||
!tileMatmulK(dimK, residualTilingFactor, reductionTileSizes[kIndex])) {
- return success();
+ return failure();
}
LLVM_DEBUG({
llvm::dbgs() << "workgroup tile size before promotion = (";
@@ -801,10 +801,10 @@
// This configuration is only for cooperative matrix.
if (!targetEnv.allows(spirv::Capability::CooperativeMatrixNV) ||
!targetEnv.allows(spirv::Extension::SPV_NV_cooperative_matrix)) {
- return success();
+ return failure();
}
- if (op.hasDynamicShape()) return success();
+ if (op.hasDynamicShape()) return failure();
Value lhs = op.getDpsInputOperand(0)->get();
Value rhs = op.getDpsInputOperand(1)->get();
@@ -813,7 +813,7 @@
int lastParallelDim = -1;
const auto [bIndex, mIndex, nIndex, kIndex] =
getMatmulBMNKIndex(op, &lastParallelDim);
- if (mIndex < 0 || nIndex < 0 || kIndex < 0) return success();
+ if (mIndex < 0 || nIndex < 0 || kIndex < 0) return failure();
const bool isBM = bIndex >= 0;
SmallVector<int64_t, 4> loopRanges = op.getStaticLoopRanges();
@@ -841,7 +841,7 @@
limits, numSubgroupsPerWorkgroup, numMNTilesPerSubgroup,
getElementType(lhs), getElementType(rhs), getElementType(init), dimM,
dimN, dimK);
- if (!coopMatSize) return success();
+ if (!coopMatSize) return failure();
auto pipeline = IREE::Codegen::DispatchLoweringPassPipeline::
SPIRVCooperativeMatrixVectorize;
@@ -1331,33 +1331,33 @@
return setUserConfig(entryPointFn, rootOp, compilationInfo);
}
- LogicalResult result = success();
// First try to find a proper CodeGen configuration to tile and vectorize for
// the current target architecture.
switch (targetEnv.getVendorID()) {
case spirv::Vendor::AMD:
- result = detail::setAMDCodeGenConfig(targetEnv, rootOp);
+ if (succeeded(detail::setAMDCodeGenConfig(targetEnv, rootOp)))
+ return success();
break;
case spirv::Vendor::Apple:
- result = detail::setAppleCodeGenConfig(targetEnv, rootOp);
+ if (succeeded(detail::setAppleCodeGenConfig(targetEnv, rootOp)))
+ return success();
break;
case spirv::Vendor::ARM:
- result = detail::setMaliCodeGenConfig(targetEnv, rootOp);
+ if (succeeded(detail::setMaliCodeGenConfig(targetEnv, rootOp)))
+ return success();
break;
case spirv::Vendor::NVIDIA:
- result = detail::setNVIDIACodeGenConfig(targetEnv, rootOp);
+ if (succeeded(detail::setNVIDIACodeGenConfig(targetEnv, rootOp)))
+ return success();
break;
case spirv::Vendor::Qualcomm:
- result = detail::setAdrenoCodeGenConfig(targetEnv, rootOp);
+ if (succeeded(detail::setAdrenoCodeGenConfig(targetEnv, rootOp)))
+ return success();
break;
default:
break;
}
- if (failed(result)) return result;
- // Check whether there is actually a configuration found. If so, it's done.
- if (getLoweringConfig(rootOp)) return result;
-
// Otherwise fallback to use a default configuration that tiles and
// distributes/vectorizes.
spirv::ResourceLimitsAttr limits = targetEnv.getResourceLimits();
@@ -1376,8 +1376,7 @@
}
auto result =
detail::setMatmulOpConfig(limits, op, workgroupXY, threadMNK);
- if (failed(result)) return result;
- if (getLoweringConfig(op)) return result;
+ if (succeeded(result)) return success();
// If unsuccessful, try to tile and distribute.
return setDefaultOpConfig(limits, op);
@@ -1388,8 +1387,7 @@
// per subgroup for GPUs.
auto result = detail::setConvOpConfig(op, /*subgroupSize=*/32,
/*bestTilingFactor=*/32);
- if (failed(result)) return result;
- if (getLoweringConfig(op)) return result;
+ if (succeeded(result)) return success();
// If unsuccessful, try to tile and distribute.
return setDefaultOpConfig(limits, op);
@@ -1408,7 +1406,7 @@
if (op.getNumLoops() != op.getNumParallelLoops()) {
return setDefaultOpConfig(limits, op);
}
- return success();
+ return failure();
})
.Case<IREE::LinalgExt::FftOp>([limits](IREE::LinalgExt::FftOp op) {
return setFftOpConfig(limits, op);
@@ -1416,13 +1414,44 @@
.Case<IREE::LinalgExt::WinogradInputTransformOp,
IREE::LinalgExt::WinogradOutputTransformOp>(
[&](auto op) { return setWinogradOpConfig(limits, op); })
- .Default([](Operation *) { return success(); });
+ .Default([](Operation *) { return failure(); });
};
//===----------------------------------------------------------------------===//
// Entry Point
//===----------------------------------------------------------------------===//
+static LogicalResult setConfigForKernel(const spirv::TargetEnv &targetEnv,
+ IREE::HAL::ExecutableExportOp exportOp,
+ func::FuncOp funcOp) {
+ SmallVector<Operation *> computeOps;
+ if (failed(getComputeOps(funcOp, computeOps))) {
+ return funcOp.emitOpError("failed to get compute ops");
+ }
+
+ if (computeOps.empty()) {
+ // No compute operations found. Allow to pass through without a config.
+ return success();
+ }
+
+ // Try to find a configuration according to a matmul/convolution op and use
+ // it as the root op.
+ for (Operation *computeOp : computeOps) {
+ if (succeeded(setSPIRVOpConfig(targetEnv, funcOp, computeOp)))
+ return success();
+ }
+
+ Operation *computeOp = computeOps.back();
+ spirv::ResourceLimitsAttr limits = targetEnv.getResourceLimits();
+ // If there are still no root op, check for any linalg.generic op.
+ if (succeeded(setDefaultOpConfig(limits, computeOp))) return success();
+
+ // Check if the op configuration was set.
+ return computeOp->emitOpError(
+ "without known roots, the last compute operation in the tiled "
+ "loop body is expected to be set as root");
+}
+
LogicalResult initSPIRVLaunchConfig(ModuleOp module) {
llvm::StringMap<IREE::HAL::ExecutableExportOp> exportOps =
getAllEntryPoints(module);
@@ -1433,52 +1462,16 @@
"attribute");
}
spirv::TargetEnv targetEnv(targetEnvAttr);
- spirv::ResourceLimitsAttr limits = targetEnv.getResourceLimits();
for (auto funcOp : module.getOps<func::FuncOp>()) {
auto exportOp = exportOps.lookup(funcOp.getName());
if (!exportOp) continue;
- SmallVector<Operation *> computeOps;
- if (failed(getComputeOps(funcOp, computeOps))) {
- return funcOp.emitOpError("failed to get compute ops");
- }
-
- if (computeOps.empty()) {
- // No compute operations found. Allow to pass through without a config.
- continue;
- }
-
- Operation *rootOperation = nullptr;
- // Try to find a configuration according to a matmul/convolution op and use
- // it as the root op.
- for (Operation *computeOp : computeOps) {
- if (failed(setSPIRVOpConfig(targetEnv, funcOp, computeOp)))
- return failure();
-
- // Check if the op configuration was set.
- if (!getLoweringConfig(computeOp)) continue;
-
- rootOperation = computeOp;
- // Break after finding the first one--following ops may still use the same
- // attribute for other purposes.
- break;
- }
-
- if (!rootOperation) {
- // If there are still no root op, check for any linalg.generic op.
- Operation *computeOp = computeOps.back();
- if (failed(setDefaultOpConfig(limits, computeOp))) return failure();
-
- // Check if the op configuration was set.
- if (!getLoweringConfig(computeOp)) {
- return computeOp->emitOpError(
- "without known roots, the last compute operation in the tiled "
- "loop body is expected to be set as root");
- }
- rootOperation = computeOp;
+ if (failed(setConfigForKernel(targetEnv, exportOp, funcOp))) {
+ return failure();
}
}
+
return success();
}
diff --git a/compiler/src/iree/compiler/Codegen/SPIRV/KernelConfig.h b/compiler/src/iree/compiler/Codegen/SPIRV/KernelConfig.h
index 5992708..956b18b 100644
--- a/compiler/src/iree/compiler/Codegen/SPIRV/KernelConfig.h
+++ b/compiler/src/iree/compiler/Codegen/SPIRV/KernelConfig.h
@@ -78,9 +78,8 @@
/// `translation_info` attribute to the entry point containing `rootOp` and a
/// `lowering_config` attribute to `rootOp`.
///
-/// Returns success when either no configuration is found or a configuration is
-/// successfullly attached as attribute. Returns failure only when there is an
-/// issue attaching the attribute.
+/// Returns success when a configuration is successfullly attached as attribute.
+/// Returns failure otherwise.
LogicalResult setAdrenoCodeGenConfig(const spirv::TargetEnv &targetEnv,
Operation *rootOp);
diff --git a/compiler/src/iree/compiler/Codegen/SPIRV/MaliConfig.cpp b/compiler/src/iree/compiler/Codegen/SPIRV/MaliConfig.cpp
index eb88393..d3ad643 100644
--- a/compiler/src/iree/compiler/Codegen/SPIRV/MaliConfig.cpp
+++ b/compiler/src/iree/compiler/Codegen/SPIRV/MaliConfig.cpp
@@ -68,7 +68,7 @@
int bestTilingFactor = hasPaddedInput ? 8 : 16;
return setConvOpConfig(op, subgroupSize, bestTilingFactor);
})
- .Default([](Operation *) { return success(); });
+ .Default([](Operation *) { return failure(); });
}
} // namespace detail
diff --git a/compiler/src/iree/compiler/Codegen/SPIRV/NVIDIAConfig.cpp b/compiler/src/iree/compiler/Codegen/SPIRV/NVIDIAConfig.cpp
index 39eb3ee..5c58fe6 100644
--- a/compiler/src/iree/compiler/Codegen/SPIRV/NVIDIAConfig.cpp
+++ b/compiler/src/iree/compiler/Codegen/SPIRV/NVIDIAConfig.cpp
@@ -36,11 +36,10 @@
const spirv::TargetEnv &targetEnv) {
// First try to see if we can use tensor cores.
spirv::ResourceLimitsAttr limits = targetEnv.getResourceLimits();
- if (failed(setCooperativeMatrixConfig(targetEnv, op,
- NVIDIANumSubgroupsPerWorkgroup,
- NVIDIANumMNTilesPerSubgroup)))
- return failure();
- if (getLoweringConfig(op)) return success();
+ if (succeeded(setCooperativeMatrixConfig(targetEnv, op,
+ NVIDIANumSubgroupsPerWorkgroup,
+ NVIDIANumMNTilesPerSubgroup)))
+ return success();
const int subgroupSize = limits.getSubgroupSize();
const std::array<int64_t, 2> workgroupXY = {subgroupSize, 8};
@@ -95,7 +94,7 @@
return TypeSwitch<Operation *, LogicalResult>(rootOp)
.Case<linalg::BatchMatmulOp, linalg::MatmulOp>(
[&](auto op) { return setNVIDIAMatmulConfig(op, targetEnv); })
- .Default([](Operation *) { return success(); });
+ .Default([](Operation *) { return failure(); });
}
} // namespace detail