This is an automated email from the ASF dual-hosted git repository.
tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new 4a6c989175 [REFACTOR][S-TIR] Preserve schedule error payloads across
FFI bridges (#20351)
4a6c989175 is described below
commit 4a6c989175801a5f161f802e825f9e7137f9ad85
Author: Tianqi Chen <[email protected]>
AuthorDate: Tue Sep 15 19:15:27 2026 -0400
[REFACTOR][S-TIR] Preserve schedule error payloads across FFI bridges
(#20351)
Move scheduling diagnostic state into a registered object carried by
`ffi::Error` through `extra_context`, so the payload survives structural
FFI bridges.
Recover the payload directly or through a visit context, retain it on
rendered errors for outer scheduling handlers, and preserve the original
diagnostic when nested handlers encounter an already rendered error.
---
src/s_tir/analysis/oob_checker.cc | 2 +-
.../postproc/rewrite_parallel_vectorize_unroll.cc | 5 +-
src/s_tir/meta_schedule/utils.h | 10 +++-
src/s_tir/schedule/analysis/analysis.cc | 66 ++++++++++++----------
src/s_tir/schedule/analysis/reducer.cc | 9 +--
src/s_tir/schedule/concrete_schedule.cc | 60 ++++++++++++--------
src/s_tir/schedule/error.cc | 20 ++++++-
src/s_tir/schedule/error.h | 30 ++++++++--
src/s_tir/schedule/ir_comparator.cc | 5 +-
src/s_tir/schedule/primitive/block_annotate.cc | 16 +++---
src/s_tir/schedule/primitive/blockize_tensorize.cc | 8 ++-
src/s_tir/schedule/primitive/cache_read_write.cc | 40 ++++++-------
src/s_tir/schedule/primitive/compute_at.cc | 14 ++---
src/s_tir/schedule/primitive/compute_inline.cc | 36 ++++++------
src/s_tir/schedule/primitive/decompose_padding.cc | 9 +--
src/s_tir/schedule/primitive/for_kind.cc | 4 +-
src/s_tir/schedule/primitive/hide_buffer_access.cc | 8 +--
.../schedule/primitive/layout_transformation.cc | 40 +++++++------
.../schedule/primitive/loop_transformation.cc | 61 +++++++++++---------
src/s_tir/schedule/primitive/pad_einsum.cc | 20 +++----
src/s_tir/schedule/primitive/reduction.cc | 29 +++++-----
.../schedule/primitive/reorder_block_iter_var.cc | 5 +-
src/s_tir/schedule/primitive/rolling_buffer.cc | 17 +++---
src/s_tir/schedule/transform.cc | 5 +-
24 files changed, 303 insertions(+), 216 deletions(-)
diff --git a/src/s_tir/analysis/oob_checker.cc
b/src/s_tir/analysis/oob_checker.cc
index b193d0b1ba..127c1f5a47 100644
--- a/src/s_tir/analysis/oob_checker.cc
+++ b/src/s_tir/analysis/oob_checker.cc
@@ -40,7 +40,7 @@ struct OOBLocation {
arith::IntSet shape_bounds;
};
-class OOBError : public s_tir::ScheduleError {
+class OOBError : public s_tir::ScheduleErrorContextObj {
public:
OOBError(IRModule mod, std::vector<OOBLocation> locations) : mod_(mod),
locations_(locations) {}
ffi::String FastErrorString() const final { return "Out of bound memory
access"; }
diff --git
a/src/s_tir/meta_schedule/postproc/rewrite_parallel_vectorize_unroll.cc
b/src/s_tir/meta_schedule/postproc/rewrite_parallel_vectorize_unroll.cc
index fe12d71fef..19ebfb1a85 100644
--- a/src/s_tir/meta_schedule/postproc/rewrite_parallel_vectorize_unroll.cc
+++ b/src/s_tir/meta_schedule/postproc/rewrite_parallel_vectorize_unroll.cc
@@ -477,7 +477,10 @@ class RewriteParallelVectorizeUnrollNode : public
PostprocNode {
int max_step = parsed.unroll_explicit + parsed.unroll_implicit + 1;
s_tir::RewriteUnroll(sch, unroll_explicit, max_step, block_rv,
loop_rvs[0]);
}
- } catch (const s_tir::ScheduleError& e) {
+ } catch (const ffi::Error& e) {
+ if (s_tir::GetScheduleErrorContext(e) == nullptr) {
+ throw;
+ }
DLOG(WARNING) << "Failed to apply parallelization/vectorization: "
<< e.what();
return false;
}
diff --git a/src/s_tir/meta_schedule/utils.h b/src/s_tir/meta_schedule/utils.h
index bceab91110..b45dd2cd87 100644
--- a/src/s_tir/meta_schedule/utils.h
+++ b/src/s_tir/meta_schedule/utils.h
@@ -341,7 +341,10 @@ struct ThreadedTraceApply {
s_tir::ScheduleErrorRenderLevel::kNone);
trace->ApplyToSchedule(sch, /*remove_postproc=*/true);
sch->EnterPostproc();
- } catch (const s_tir::ScheduleError& e) {
+ } catch (const ffi::Error& e) {
+ if (s_tir::GetScheduleErrorContext(e) == nullptr) {
+ throw;
+ }
TVM_PY_LOG(WARNING, nullptr) << "Trace replay failed with ScheduleError:
" << e.what();
this->trace_fail_counter_++;
return std::nullopt;
@@ -358,7 +361,10 @@ struct ThreadedTraceApply {
if (!item.postproc->Apply(sch)) {
success = false;
}
- } catch (const s_tir::ScheduleError& e) {
+ } catch (const ffi::Error& e) {
+ if (s_tir::GetScheduleErrorContext(e) == nullptr) {
+ throw;
+ }
DLOG(WARNING) << "Postproc #" << i << " failed with ScheduleError: "
<< e.what();
success = false;
} catch (const std::exception& e) {
diff --git a/src/s_tir/schedule/analysis/analysis.cc
b/src/s_tir/schedule/analysis/analysis.cc
index 8e715c83fd..00af05480c 100644
--- a/src/s_tir/schedule/analysis/analysis.cc
+++ b/src/s_tir/schedule/analysis/analysis.cc
@@ -64,7 +64,7 @@ const PrimFuncNode* GetRootPrimFunc(const IRModule& mod,
const StmtNode* root_bl
StmtSRef GetScopeRoot(const ScheduleState& self, const StmtSRef& sref,
bool require_stage_pipeline) {
- class RootBlockError : public ScheduleError {
+ class RootBlockError : public ScheduleErrorContextObj {
public:
explicit RootBlockError(IRModule mod) : mod_(mod) {}
IRModule mod() const final { return mod_; }
@@ -78,7 +78,7 @@ StmtSRef GetScopeRoot(const ScheduleState& self, const
StmtSRef& sref,
IRModule mod_;
};
- class NotStagePipelineError : public ScheduleError {
+ class NotStagePipelineError : public ScheduleErrorContextObj {
public:
explicit NotStagePipelineError(IRModule mod, SBlock block) : mod_(mod),
block_(block) {}
IRModule mod() const final { return mod_; }
@@ -113,7 +113,7 @@ Definition of a scope that is a stage pipeline:
}
}
if (p == nullptr) {
- throw RootBlockError(self->mod);
+ throw MakeScheduleError<RootBlockError>(self->mod);
}
}
// Step 2. Handle `require_stage_pipeline`
@@ -121,7 +121,7 @@ Definition of a scope that is a stage pipeline:
bool stage_pipeline = self->GetSBlockInfo(scope_root_sref).stage_pipeline;
if (stage_pipeline == false) {
const SBlockNode* block = TVM_SREF_TO_SBLOCK(scope_root_sref);
- throw NotStagePipelineError(self->mod, ffi::GetRef<SBlock>(block));
+ throw MakeScheduleError<NotStagePipelineError>(self->mod,
ffi::GetRef<SBlock>(block));
}
}
return scope_root_sref;
@@ -282,7 +282,7 @@ bool IsCompleteBlock(const ScheduleState& self, const
StmtSRef& block_sref,
void CheckCompleteBlock(const ScheduleState& self, const StmtSRef& block_sref,
const StmtSRef& scope_root_sref) {
- class IncompleteBlockError : public ScheduleError {
+ class IncompleteBlockError : public ScheduleErrorContextObj {
public:
explicit IncompleteBlockError(IRModule mod, SBlock block, int
violated_cond)
: mod_(std::move(mod)), block_(std::move(block)),
violated_cond_(violated_cond) {}
@@ -303,7 +303,8 @@ void CheckCompleteBlock(const ScheduleState& self, const
StmtSRef& block_sref,
int error_code = CheckCompleteBlockErrorCode(self, block_sref,
scope_root_sref);
if (error_code != 0) {
const SBlockNode* block = TVM_SREF_TO_SBLOCK(block_sref);
- throw IncompleteBlockError(self->mod, ffi::GetRef<SBlock>(block),
error_code);
+ throw MakeScheduleError<IncompleteBlockError>(self->mod,
ffi::GetRef<SBlock>(block),
+ error_code);
}
}
@@ -356,7 +357,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
void CheckReductionBlock(const ScheduleState& self, const StmtSRef& block_sref,
const StmtSRef& scope_root_sref) {
- class NotReductionBlockError : public ScheduleError {
+ class NotReductionBlockError : public ScheduleErrorContextObj {
public:
explicit NotReductionBlockError(IRModule mod, SBlock block, int
violated_cond)
: mod_(std::move(mod)), block_(std::move(block)),
violated_cond_(violated_cond) {}
@@ -377,13 +378,14 @@ void CheckReductionBlock(const ScheduleState& self, const
StmtSRef& block_sref,
int error_code = CheckReductionBlockErrorCode(self, block_sref,
scope_root_sref);
if (error_code != 0) {
const SBlockNode* block = TVM_SREF_TO_SBLOCK(block_sref);
- throw NotReductionBlockError(self->mod, ffi::GetRef<SBlock>(block),
error_code);
+ throw MakeScheduleError<NotReductionBlockError>(self->mod,
ffi::GetRef<SBlock>(block),
+ error_code);
}
}
void CheckCompleteOrReductionBlock(const ScheduleState& self, const StmtSRef&
block_sref,
const StmtSRef& scope_root_sref) {
- class NotCompleteOrReductionBlockError : public ScheduleError {
+ class NotCompleteOrReductionBlockError : public ScheduleErrorContextObj {
public:
explicit NotCompleteOrReductionBlockError(IRModule mod, SBlock block,
int complete_block_error_code,
@@ -424,12 +426,12 @@ void CheckCompleteOrReductionBlock(const ScheduleState&
self, const StmtSRef& bl
return;
}
const SBlockNode* block = TVM_SREF_TO_SBLOCK(block_sref);
- throw NotCompleteOrReductionBlockError(self->mod, ffi::GetRef<SBlock>(block),
- complete_block_error_code,
reduction_block_error_code);
+ throw MakeScheduleError<NotCompleteOrReductionBlockError>(
+ self->mod, ffi::GetRef<SBlock>(block), complete_block_error_code,
reduction_block_error_code);
}
void CheckSubtreeCompactDataflow(const ScheduleState& self, const StmtSRef&
subtree_root) {
- class NotCompactDataFlowError : public ScheduleError {
+ class NotCompactDataFlowError : public ScheduleErrorContextObj {
public:
explicit NotCompactDataFlowError(IRModule mod, Stmt subtree_root, SBlock
violate_block,
int local_complete_block_code, int
local_reduction_block_code)
@@ -477,9 +479,9 @@ void CheckSubtreeCompactDataflow(const ScheduleState& self,
const StmtSRef& subt
local_reduction_block_code = CheckReductionBlockErrorCode(self,
block_sref, subtree_root);
if (local_complete_block_code != 0 && local_reduction_block_code != 0) {
const SBlockNode* block = TVM_SREF_TO_SBLOCK(block_sref);
- throw NotCompactDataFlowError(self->mod,
ffi::GetRef<Stmt>(subtree_root->stmt),
- ffi::GetRef<SBlock>(block),
local_complete_block_code,
- local_reduction_block_code);
+ throw MakeScheduleError<NotCompactDataFlowError>(
+ self->mod, ffi::GetRef<Stmt>(subtree_root->stmt),
ffi::GetRef<SBlock>(block),
+ local_complete_block_code, local_reduction_block_code);
}
}
}
@@ -503,7 +505,7 @@ bool IsOutputBlock(const ScheduleState& self, const
StmtSRef& block_sref,
void CheckNotOutputBlock(const ScheduleState& self, const StmtSRef& block_sref,
const StmtSRef& scope_root_sref) {
- class OutputBlockError : public ScheduleError {
+ class OutputBlockError : public ScheduleErrorContextObj {
public:
explicit OutputBlockError(IRModule mod, SBlock block) : mod_(mod),
block_(block) {}
ffi::String FastErrorString() const final {
@@ -518,7 +520,7 @@ void CheckNotOutputBlock(const ScheduleState& self, const
StmtSRef& block_sref,
};
if (IsOutputBlock(self, block_sref, scope_root_sref)) {
const SBlockNode* block = TVM_SREF_TO_SBLOCK(block_sref);
- throw OutputBlockError(self->mod, ffi::GetRef<SBlock>(block));
+ throw MakeScheduleError<OutputBlockError>(self->mod,
ffi::GetRef<SBlock>(block));
}
}
@@ -589,7 +591,7 @@ bool IsAffineBinding(const SBlockRealize& realize, const
ffi::Map<Var, Range>& l
void CheckPartialAffineBinding(const ScheduleState& self, SBlock block,
const ffi::Optional<StmtSRef>& high_exclusive) {
- class NotAffineBindingError : public ScheduleError {
+ class NotAffineBindingError : public ScheduleErrorContextObj {
public:
explicit NotAffineBindingError(IRModule mod, SBlock block,
ffi::Optional<StmtSRef> high_exclusive)
@@ -639,7 +641,7 @@ void CheckPartialAffineBinding(const ScheduleState& self,
SBlock block,
return;
}
}
- throw NotAffineBindingError(self->mod, std::move(block), high_exclusive);
+ throw MakeScheduleError<NotAffineBindingError>(self->mod, std::move(block),
high_exclusive);
}
void CheckAffineBinding(const ScheduleState& self, SBlock block) {
@@ -647,7 +649,7 @@ void CheckAffineBinding(const ScheduleState& self, SBlock
block) {
}
void CheckBlockHasTrivialBinding(const ScheduleState& self, const StmtSRef&
block_sref) {
- class NotTrivialBindingError : public ScheduleError {
+ class NotTrivialBindingError : public ScheduleErrorContextObj {
public:
explicit NotTrivialBindingError(IRModule mod, SBlock block)
: mod_(std::move(mod)), block_(std::move(block)) {}
@@ -671,7 +673,8 @@ void CheckBlockHasTrivialBinding(const ScheduleState& self,
const StmtSRef& bloc
};
if (!IsTrivialBinding(self, block_sref)) {
- throw NotTrivialBindingError(self->mod,
ffi::GetRef<SBlock>(block_sref->StmtAs<SBlockNode>()));
+ throw MakeScheduleError<NotTrivialBindingError>(
+ self->mod, ffi::GetRef<SBlock>(block_sref->StmtAs<SBlockNode>()));
}
}
@@ -756,7 +759,7 @@ bool GetVarsTouchedByBlockIters(const SBlockRealize&
block_realize,
void CheckLoopStartsWithZero(const ScheduleState& self, const StmtSRef&
loop_sref,
arith::AnalyzerObj* analyzer) {
- class LoopNotStartWithZeroError : public ScheduleError {
+ class LoopNotStartWithZeroError : public ScheduleErrorContextObj {
public:
explicit LoopNotStartWithZeroError(IRModule mod, For loop)
: mod_(mod), loop_(std::move(loop)) {}
@@ -777,7 +780,7 @@ void CheckLoopStartsWithZero(const ScheduleState& self,
const StmtSRef& loop_sre
};
const ForNode* loop = TVM_SREF_TO_FOR(loop_sref);
if (!analyzer->CanProve(loop->min == 0)) {
- throw LoopNotStartWithZeroError(self->mod, ffi::GetRef<For>(loop));
+ throw MakeScheduleError<LoopNotStartWithZeroError>(self->mod,
ffi::GetRef<For>(loop));
}
}
@@ -823,7 +826,7 @@ ffi::Array<SBlockRealize>
GetChildBlockRealizeOnSRefTree(const StmtSRef& parent_
SBlockRealize CheckGetSingleChildBlockRealizeOnSRefTree(const ScheduleState&
self,
const StmtSRef&
parent_sref) {
- class NonSingleChildBlockError : public ScheduleError {
+ class NonSingleChildBlockError : public ScheduleErrorContextObj {
public:
explicit NonSingleChildBlockError(IRModule mod, const StmtSRef& sref)
: mod_(std::move(mod)), stmt_(ffi::GetRef<Stmt>(sref->stmt)) {
@@ -852,7 +855,7 @@ SBlockRealize
CheckGetSingleChildBlockRealizeOnSRefTree(const ScheduleState& sel
ffi::Array<SBlockRealize> child_block_realize =
GetChildBlockRealizeOnSRefTree(parent_sref);
if (child_block_realize.size() != 1) {
- throw NonSingleChildBlockError(self->mod, parent_sref);
+ throw MakeScheduleError<NonSingleChildBlockError>(self->mod, parent_sref);
}
return child_block_realize[0];
}
@@ -1117,7 +1120,7 @@ ProducerConsumerSplit ProducerConsumerSplit::Find(
const ffi::Array<StmtSRef>& producer_block_srefs,
const ffi::Array<StmtSRef>& consumer_block_srefs,
std::unordered_map<const SBlockNode*, const SBlockRealizeNode*>*
block2realize) {
- class InsertionPointNotFoundError : public ScheduleError {
+ class InsertionPointNotFoundError : public ScheduleErrorContextObj {
public:
explicit InsertionPointNotFoundError(IRModule mod, int
last_producer_position,
int first_consumer_position)
@@ -1202,7 +1205,8 @@ ProducerConsumerSplit ProducerConsumerSplit::Find(
}
}
if (last_producer_position >= first_consumer_position) {
- throw InsertionPointNotFoundError(self->mod, last_producer_position,
first_consumer_position);
+ throw MakeScheduleError<InsertionPointNotFoundError>(self->mod,
last_producer_position,
+
first_consumer_position);
}
return ProducerConsumerSplit{last_producer_position, //
first_consumer_position, //
@@ -1214,7 +1218,7 @@ ProducerConsumerSplit ProducerConsumerSplit::Find(
BufferRegion GetNthAccessBufferRegion(const ScheduleState& self, const SBlock&
block, int n,
BufferIndexType index_type) {
- class BufferIndexOutOfRangeError : public ScheduleError {
+ class BufferIndexOutOfRangeError : public ScheduleErrorContextObj {
public:
explicit BufferIndexOutOfRangeError(IRModule mod, SBlock block, int
buffer_index,
BufferIndexType index_type)
@@ -1262,7 +1266,7 @@ BufferRegion GetNthAccessBufferRegion(const
ScheduleState& self, const SBlock& b
index_type == BufferIndexType::kWrite ? block->writes : block->reads;
if (n < 0 || static_cast<int>(access_region.size()) <= n) {
- throw BufferIndexOutOfRangeError(self->mod, block, n, index_type);
+ throw MakeScheduleError<BufferIndexOutOfRangeError>(self->mod, block, n,
index_type);
}
return access_region[n];
}
@@ -1455,7 +1459,7 @@ AnalyzeReadWritePattern(const BufferRegion& read_region,
const BufferRegion& wri
/******** Storage Scope ********/
void CheckStorageScope(const ScheduleState& self, ffi::String storage_scope) {
- class InvalidStorageScopeError : public ScheduleError {
+ class InvalidStorageScopeError : public ScheduleErrorContextObj {
public:
explicit InvalidStorageScopeError(IRModule mod, ffi::String storage_scope)
: mod_(std::move(mod)), storage_scope_(std::move(storage_scope)) {}
@@ -1479,7 +1483,7 @@ void CheckStorageScope(const ScheduleState& self,
ffi::String storage_scope) {
try {
runtime::StorageScope::Create(std::string(storage_scope));
} catch (...) {
- throw InvalidStorageScopeError(self->mod, std::move(storage_scope));
+ throw MakeScheduleError<InvalidStorageScopeError>(self->mod,
std::move(storage_scope));
}
}
diff --git a/src/s_tir/schedule/analysis/reducer.cc
b/src/s_tir/schedule/analysis/reducer.cc
index bff5bec91e..cf54f1976d 100644
--- a/src/s_tir/schedule/analysis/reducer.cc
+++ b/src/s_tir/schedule/analysis/reducer.cc
@@ -315,7 +315,7 @@ static const char*
kRFactorCrossThreadReductionApplicableBlockDef =
void ErrorRFactorCrossThreadReductionNotApplicable(const
ffi::Optional<ScheduleState>& self,
SBlock block, int
violated_cond) {
- class RFactorNotApplicableError : public ScheduleError {
+ class RFactorNotApplicableError : public ScheduleErrorContextObj {
public:
explicit RFactorNotApplicableError(IRModule mod, SBlock block, int
violated_cond)
: mod_(std::move(mod)), block_(std::move(block)),
violated_cond_(violated_cond) {}
@@ -342,7 +342,8 @@ void ErrorRFactorCrossThreadReductionNotApplicable(const
ffi::Optional<ScheduleS
};
if (self.has_value()) {
- throw RFactorNotApplicableError(self.value()->mod, std::move(block),
violated_cond);
+ throw MakeScheduleError<RFactorNotApplicableError>(self.value()->mod,
std::move(block),
+ violated_cond);
} else {
TVM_FFI_THROW(ValueError) << "Cross-thread reduction cannot be applied to
the block "
<< block->name_hint << " because the block
violates the condition #"
@@ -603,7 +604,7 @@ bool ReductionIterNotIndexOutputBuffer(const SBlock& block)
{
return result.has_value() ? result.value()->value.cast<bool>() : true;
}
-class NoMatchedReducerError : public ScheduleError {
+class NoMatchedReducerError : public ScheduleErrorContextObj {
public:
explicit NoMatchedReducerError(IRModule mod, ffi::Array<PrimExpr> identities,
ffi::Array<BufferStore> combiners)
@@ -641,7 +642,7 @@ std::tuple<te::CommReducer, ffi::Array<PrimExpr>,
ffi::Array<PrimExpr>> GetReduc
FromIdentityCombiner(identities, combiners, &reducer, &combiner_lhs,
&combiner_rhs);
if (!matched) {
if (self.has_value()) {
- throw NoMatchedReducerError(self.value()->mod, identities, combiners);
+ throw MakeScheduleError<NoMatchedReducerError>(self.value()->mod,
identities, combiners);
} else {
TVM_FFI_THROW(ValueError)
<< "No matched reducer for the identity and the combiner of the "
diff --git a/src/s_tir/schedule/concrete_schedule.cc
b/src/s_tir/schedule/concrete_schedule.cc
index f407ed2bed..4feb99b1e6 100644
--- a/src/s_tir/schedule/concrete_schedule.cc
+++ b/src/s_tir/schedule/concrete_schedule.cc
@@ -209,22 +209,32 @@ Schedule ConcreteScheduleNode::Copy() {
/*! \brief Macro that guards the beginning of each invocation of TensorIR
schedule primitive */
#define TVM_TIR_SCHEDULE_BEGIN() try {
+/*! \brief Keep the payload on rendered errors for outer scheduling error
handlers. */
+#define TVM_TIR_SCHEDULE_THROW(error)
\
+ ffi::details::ErrorBuilder(
\
+ "ScheduleError", TVMFFIBacktrace(__FILE__, __LINE__, TVM_FFI_FUNC_SIG,
0), \
+ TVM_FFI_ALWAYS_LOG_BEFORE_THROW, std::nullopt, (error).extra_context())
\
+ .stream()
/*!
* \brief Macro that pairs with `TVM_TIR_SCHEDULE_BEGIN`, handling potential
errors and error
- * message rendering
+ * message rendering. Already rendered errors retain their original diagnostic.
* \param level An ScheduleErrorRenderLevel enum, level of error rendering
* \sa ScheduleErrorRenderLevel
*/
-#define TVM_TIR_SCHEDULE_END(primitive, level) \
- } \
- catch (const ScheduleError& error) { \
- if ((level) == ScheduleErrorRenderLevel::kDetail) { \
- TVM_FFI_THROW(ScheduleError) << error.RenderReport(primitive); \
- } else if ((level) == ScheduleErrorRenderLevel::kFast) { \
- TVM_FFI_THROW(ScheduleError) << error.FastErrorString(); \
- } else if ((level) == ScheduleErrorRenderLevel::kNone) { \
- TVM_FFI_THROW(ScheduleError) << "(not rendered)"; \
- } \
+#define TVM_TIR_SCHEDULE_END(primitive, level) \
+ } \
+ catch (const ffi::Error& error) { \
+ const auto* context = GetScheduleErrorContext(error); \
+ if (context == nullptr || !error.message().empty()) { \
+ throw; \
+ } \
+ if ((level) == ScheduleErrorRenderLevel::kDetail) { \
+ TVM_TIR_SCHEDULE_THROW(error) << context->RenderReport(primitive); \
+ } else if ((level) == ScheduleErrorRenderLevel::kFast) { \
+ TVM_TIR_SCHEDULE_THROW(error) << context->FastErrorString(); \
+ } else if ((level) == ScheduleErrorRenderLevel::kNone) { \
+ TVM_TIR_SCHEDULE_THROW(error) << "(not rendered)"; \
+ } \
}
/******** Schedule: Schedule: Sampling ********/
@@ -281,7 +291,7 @@ LoopRV ConcreteScheduleNode::SampleComputeLocation(const
SBlockRV& block_rv,
SBlockRV ConcreteScheduleNode::GetSBlock(const ffi::String& name,
const ffi::Optional<ffi::String>&
func_name) {
- class NotSingleResult : public ScheduleError {
+ class NotSingleResult : public ScheduleErrorContextObj {
public:
explicit NotSingleResult(ffi::String name, IRModule mod, const
ffi::Array<StmtSRef>& blocks)
: name_(name), mod_(mod), blocks_{} {
@@ -331,7 +341,7 @@ SBlockRV ConcreteScheduleNode::GetSBlock(const ffi::String&
name,
ffi::Array<StmtSRef> blocks = s_tir::GetSBlocks(this->state_, name, gv);
if (blocks.size() != 1) {
TVM_TIR_SCHEDULE_BEGIN();
- throw NotSingleResult(name, this->state_->mod, blocks);
+ throw MakeScheduleError<NotSingleResult>(name, this->state_->mod, blocks);
TVM_TIR_SCHEDULE_END("get-block", this->error_render_level_);
}
return CreateRV<SBlockRV>(blocks[0]);
@@ -404,7 +414,7 @@ LoopRV ConcreteScheduleNode::Fuse(const ffi::Array<LoopRV>&
loop_rvs, bool prese
return CreateRV<LoopRV>(result);
}
-class NotSingleInferFactorError : public ScheduleError {
+class NotSingleInferFactorError : public ScheduleErrorContextObj {
public:
explicit NotSingleInferFactorError(IRModule mod) : mod_(mod) {}
@@ -422,7 +432,7 @@ class NotSingleInferFactorError : public ScheduleError {
IRModule mod_;
};
-class WrongFactorError : public ScheduleError {
+class WrongFactorError : public ScheduleErrorContextObj {
public:
explicit WrongFactorError(IRModule mod, For loop, bool product)
: mod_(mod), loop_(std::move(loop)), product_(product) {}
@@ -450,7 +460,7 @@ class WrongFactorError : public ScheduleError {
bool product_;
};
-class NonPositiveFactorError : public ScheduleError {
+class NonPositiveFactorError : public ScheduleErrorContextObj {
public:
explicit NonPositiveFactorError(IRModule mod, int64_t factor, size_t idx)
: mod_(std::move(mod)), factor_(factor), idx_(idx) {}
@@ -491,13 +501,14 @@ ffi::Array<LoopRV> ConcreteScheduleNode::Split(const
LoopRV& loop_rv,
if (!factor_rvs[i].has_value()) {
factors.push_back(IntImm::Int32(-1));
if (infer_index != -1) {
- throw NotSingleInferFactorError(state_->mod);
+ throw MakeScheduleError<NotSingleInferFactorError>(state_->mod);
}
infer_index = i;
} else {
PrimExpr factor = this->Get(factor_rvs[i].value());
if (is_const_int(factor) && !is_positive_const(factor)) {
- throw NonPositiveFactorError(state_->mod,
factor.as<IntImmNode>()->value, i);
+ throw MakeScheduleError<NonPositiveFactorError>(state_->mod,
factor.as<IntImmNode>()->value,
+ i);
}
if (factor.ty().bits() > loop->extent.ty().bits()) {
factor = cast(loop->extent.ty(), factor);
@@ -510,7 +521,7 @@ ffi::Array<LoopRV> ConcreteScheduleNode::Split(const
LoopRV& loop_rv,
factors.Set(infer_index,
this->analyzer_->Simplify(floordiv(loop->extent + tot_length -
1, tot_length)));
} else if (!this->analyzer_->CanProve(tot_length >= loop->extent)) {
- throw WrongFactorError(state_->mod, ffi::GetRef<For>(loop), true);
+ throw MakeScheduleError<WrongFactorError>(state_->mod,
ffi::GetRef<For>(loop), true);
}
results = s_tir::Split(state_, loop_sref, factors, preserve_unit_iters,
disable_predication);
TVM_TIR_SCHEDULE_END("split", this->error_render_level_);
@@ -521,7 +532,7 @@ ffi::Array<LoopRV> ConcreteScheduleNode::Split(const
LoopRV& loop_rv,
ffi::Array<LoopRV> ConcreteScheduleNode::LoopPartition(
const LoopRV& loop_rv, const ffi::Array<ffi::Optional<ExprRV>>& factor_rvs,
bool preserve_unit_iters) {
- class SymbolicShapeError : public ScheduleError {
+ class SymbolicShapeError : public ScheduleErrorContextObj {
public:
explicit SymbolicShapeError(IRModule mod, For loop) : mod_(mod),
loop_(std::move(loop)) {}
@@ -551,20 +562,21 @@ ffi::Array<LoopRV> ConcreteScheduleNode::LoopPartition(
ffi::Array<StmtSRef> results;
TVM_TIR_SCHEDULE_BEGIN();
if (!is_const_number(loop->min) || !is_const_number(loop->extent)) {
- throw SymbolicShapeError(state_->mod, ffi::GetRef<For>(loop));
+ throw MakeScheduleError<SymbolicShapeError>(state_->mod,
ffi::GetRef<For>(loop));
}
// infer factor if needed and check validity of factors
for (size_t i = 0; i < factor_rvs.size(); i++) {
if (!factor_rvs[i].has_value()) {
factors.push_back(IntImm::Int32(-1));
if (infer_index != -1) {
- throw NotSingleInferFactorError(state_->mod);
+ throw MakeScheduleError<NotSingleInferFactorError>(state_->mod);
}
infer_index = i;
} else {
PrimExpr factor = this->Get(factor_rvs[i].value());
if (is_const_int(factor) && !is_positive_const(factor)) {
- throw NonPositiveFactorError(state_->mod,
factor.as<IntImmNode>()->value, i);
+ throw MakeScheduleError<NonPositiveFactorError>(state_->mod,
factor.as<IntImmNode>()->value,
+ i);
}
if (factor.ty().bits() > loop->extent.ty().bits()) {
factor = cast(loop->extent.ty(), factor);
@@ -574,7 +586,7 @@ ffi::Array<LoopRV> ConcreteScheduleNode::LoopPartition(
}
}
if (this->analyzer_->CanProve(tot_length >= loop->extent)) {
- throw WrongFactorError(state_->mod, ffi::GetRef<For>(loop), false);
+ throw MakeScheduleError<WrongFactorError>(state_->mod,
ffi::GetRef<For>(loop), false);
}
if (infer_index != -1) {
// if there is a 'None' in the factor list, 'None' becomes the difference
between the extent and
diff --git a/src/s_tir/schedule/error.cc b/src/s_tir/schedule/error.cc
index 09a1a323a3..bce875a2a3 100644
--- a/src/s_tir/schedule/error.cc
+++ b/src/s_tir/schedule/error.cc
@@ -16,6 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
+#include <tvm/ffi/extra/visit_error_context.h>
+#include <tvm/ffi/reflection/registry.h>
#include <tvm/script/printer/printer.h>
#include "./utils.h"
@@ -25,7 +27,21 @@ namespace s_tir {
using namespace tvm::prim;
using namespace tvm::tirx;
-ffi::String ScheduleError::RenderReport(const ffi::String& primitive) const {
+const ScheduleErrorContextObj* GetScheduleErrorContext(const ffi::Error&
error) {
+ if (auto context = error.extra_context()) {
+ if (const auto* payload = context->as<ScheduleErrorContextObj>()) {
+ return payload;
+ }
+ if (const auto* visit_context = context->as<ffi::VisitErrorContextObj>()) {
+ if (visit_context->prev_error_context) {
+ return
visit_context->prev_error_context.value().as<ScheduleErrorContextObj>();
+ }
+ }
+ }
+ return nullptr;
+}
+
+ffi::String ScheduleErrorContextObj::RenderReport(const ffi::String&
primitive) const {
IRModule mod = this->mod();
std::ostringstream os;
@@ -57,5 +73,7 @@ ffi::String ScheduleError::RenderReport(const ffi::String&
primitive) const {
return os.str();
}
+TVM_FFI_STATIC_INIT_BLOCK() {
ffi::reflection::ObjectDef<ScheduleErrorContextObj>(); }
+
} // namespace s_tir
} // namespace tvm
diff --git a/src/s_tir/schedule/error.h b/src/s_tir/schedule/error.h
index 0062edcffb..ca00fa7c9d 100644
--- a/src/s_tir/schedule/error.h
+++ b/src/s_tir/schedule/error.h
@@ -20,10 +20,12 @@
#define TVM_S_TIR_SCHEDULE_ERROR_H_
#include <tvm/ffi/error.h>
+#include <tvm/ffi/memory.h>
#include <tvm/ir/prim/expr.h>
#include <tvm/s_tir/schedule/state.h>
#include <string>
+#include <type_traits>
#include <utility>
namespace tvm {
@@ -31,11 +33,10 @@ namespace s_tir {
using namespace tvm::prim;
using namespace tvm::tirx;
-/*! \brief Error that happens during TensorIR scheduling */
-class ScheduleError : public tvm::ffi::Error {
+/*! \brief Diagnostic payload for an error that happens during TensorIR
scheduling. */
+class ScheduleErrorContextObj : public ffi::Object {
public:
- /*! \brief Base constructor */
- ScheduleError() : tvm::ffi::Error("ScheduleError", "",
TVMFFIBacktrace(nullptr, 0, nullptr, 0)) {}
+ virtual ~ScheduleErrorContextObj() = default;
/*! \brief The error occurred in this IRModule */
virtual IRModule mod() const = 0;
/*! \brief The locations of interest that we want to point out */
@@ -57,9 +58,28 @@ class ScheduleError : public tvm::ffi::Error {
virtual ffi::String FastErrorString() const = 0;
/*! \brief Render the ScheduleError with the template provided by
`DetailRenderTemplate` */
ffi::String RenderReport(const ffi::String& primitive) const;
+
+ static constexpr TVMFFISEqHashKind _type_s_eq_hash_kind =
kTVMFFISEqHashKindUnsupported;
+ TVM_FFI_DECLARE_OBJECT_INFO("s_tir.ScheduleErrorContext",
ScheduleErrorContextObj, ffi::Object);
};
-class LoopPositionError : public ScheduleError {
+/*! \brief Create a plain FFI error carrying a lazily rendered scheduling
diagnostic. */
+template <typename Context, typename... Args>
+ffi::Error MakeScheduleError(Args&&... args) {
+ static_assert(std::is_base_of_v<ScheduleErrorContextObj, Context>);
+ const TVMFFIByteArray* backtrace = TVMFFIBacktrace(nullptr, 0, nullptr, 0);
+ return ffi::Error("ScheduleError", "", std::string(backtrace->data,
backtrace->size),
+ std::nullopt,
+
ffi::ObjectRef(ffi::make_object<Context>(std::forward<Args>(args)...)));
+}
+
+/*!
+ * \brief Get the scheduling payload, directly or behind one visit-context
wrapper.
+ * \return The payload owned by error, or nullptr if the error has no
scheduling payload.
+ */
+const ScheduleErrorContextObj* GetScheduleErrorContext(const ffi::Error&
error);
+
+class LoopPositionError : public ScheduleErrorContextObj {
public:
explicit LoopPositionError(IRModule mod, For loop, SBlock block, const
std::string& primitive)
: mod_(std::move(mod)),
diff --git a/src/s_tir/schedule/ir_comparator.cc
b/src/s_tir/schedule/ir_comparator.cc
index 2f7621d111..3d742e59a6 100644
--- a/src/s_tir/schedule/ir_comparator.cc
+++ b/src/s_tir/schedule/ir_comparator.cc
@@ -47,7 +47,7 @@ using namespace tvm::tirx;
/******** Tensorize Comparator ********/
-class TensorIntrinMismatchError : public ScheduleError {
+class TensorIntrinMismatchError : public ScheduleErrorContextObj {
public:
explicit TensorIntrinMismatchError(IRModule lhs_mod, Stmt lhs_stmt, Stmt
rhs_stmt,
std::vector<std::string> error_messages)
@@ -89,7 +89,8 @@ bool TensorizeComparator::VisitStmt(const Stmt& n, const
Stmt& other) {
bool equal = n.same_as(other) ||
((n->type_index() == other->type_index()) &&
StmtComparator::VisitStmt(n, other));
if (!equal && assert_mode_ && (n->IsInstance<ForNode>() ||
n->IsInstance<SBlockNode>())) {
- throw TensorIntrinMismatchError(lhs_mod_, n, other,
std::move(error_messages_));
+ throw MakeScheduleError<TensorIntrinMismatchError>(lhs_mod_, n, other,
+
std::move(error_messages_));
}
return equal;
}
diff --git a/src/s_tir/schedule/primitive/block_annotate.cc
b/src/s_tir/schedule/primitive/block_annotate.cc
index 34fa04e1af..1a937a1809 100644
--- a/src/s_tir/schedule/primitive/block_annotate.cc
+++ b/src/s_tir/schedule/primitive/block_annotate.cc
@@ -29,7 +29,7 @@ namespace s_tir {
using namespace tvm::prim;
using namespace tvm::tirx;
-class StorageAlignAxisOutOfRangeError : public ScheduleError {
+class StorageAlignAxisOutOfRangeError : public ScheduleErrorContextObj {
public:
explicit StorageAlignAxisOutOfRangeError(IRModule mod, BufferVar buffer, int
axis)
: mod_(std::move(mod)), buffer_(std::move(buffer)), axis_(axis) {}
@@ -56,7 +56,7 @@ class StorageAlignAxisOutOfRangeError : public ScheduleError {
static int CheckAndUpdate(const IRModule& mod, const BufferVar& buffer, int
axis) {
int ndim = static_cast<int>(buffer->shape.size());
if (axis < -ndim || axis >= ndim) {
- throw StorageAlignAxisOutOfRangeError(mod, buffer, axis);
+ throw MakeScheduleError<StorageAlignAxisOutOfRangeError>(mod, buffer,
axis);
}
// If axis is negative, convert it to a non-negative one.
if (axis < 0) {
@@ -71,7 +71,7 @@ class StorageAlignAxisOutOfRangeError : public ScheduleError {
int axis_;
};
-class NonAllocatedBufferError : public ScheduleError {
+class NonAllocatedBufferError : public ScheduleErrorContextObj {
public:
explicit NonAllocatedBufferError(IRModule mod, BufferVar buffer) :
mod_(mod), buffer_(buffer) {}
@@ -92,7 +92,7 @@ class NonAllocatedBufferError : public ScheduleError {
const BufferVar& buffer) {
auto [defining_site_sref, is_alloc] = GetBufferDefiningSite(block_sref,
buffer);
if (!defining_site_sref.has_value() || !is_alloc) {
- throw NonAllocatedBufferError(mod, buffer);
+ throw MakeScheduleError<NonAllocatedBufferError>(mod, buffer);
}
return defining_site_sref.value();
@@ -106,7 +106,7 @@ class NonAllocatedBufferError : public ScheduleError {
BufferVar buffer_;
};
-class StorageAlignInvalidFactorError : public ScheduleError {
+class StorageAlignInvalidFactorError : public ScheduleErrorContextObj {
public:
explicit StorageAlignInvalidFactorError(IRModule mod, int factor)
: mod_(std::move(mod)), factor_(factor) {}
@@ -126,7 +126,7 @@ class StorageAlignInvalidFactorError : public ScheduleError
{
static void Check(const IRModule& mod, int factor) {
if (factor <= 0) {
- throw StorageAlignInvalidFactorError(mod, factor);
+ throw MakeScheduleError<StorageAlignInvalidFactorError>(mod, factor);
}
}
@@ -138,7 +138,7 @@ class StorageAlignInvalidFactorError : public ScheduleError
{
int factor_;
};
-class StorageAlignInvalidAnnotationError : public ScheduleError {
+class StorageAlignInvalidAnnotationError : public ScheduleErrorContextObj {
public:
explicit StorageAlignInvalidAnnotationError(IRModule mod, SBlock block)
: mod_(std::move(mod)), block_(std::move(block)) {}
@@ -162,7 +162,7 @@ class StorageAlignInvalidAnnotationError : public
ScheduleError {
auto it = block->annotations.find(s_tir::attr::buffer_dim_align);
if (it != block->annotations.end()) {
if (!IsValidAnnotation(block, (*it).second)) {
- throw StorageAlignInvalidAnnotationError(mod, block);
+ throw MakeScheduleError<StorageAlignInvalidAnnotationError>(mod,
block);
}
return (*it).second.as_or_throw<StorageAlignAnnotation>();
}
diff --git a/src/s_tir/schedule/primitive/blockize_tensorize.cc
b/src/s_tir/schedule/primitive/blockize_tensorize.cc
index c12baa5862..8d6475bf56 100644
--- a/src/s_tir/schedule/primitive/blockize_tensorize.cc
+++ b/src/s_tir/schedule/primitive/blockize_tensorize.cc
@@ -47,7 +47,7 @@ T DeepCopy(const T& stmt) {
* \brief ScheduleError that the bindings of the inner block are not divisible
by the subspace
* represented by the outer loops.
*/
-class SubspaceNotDivisibleError : public ScheduleError {
+class SubspaceNotDivisibleError : public ScheduleErrorContextObj {
public:
explicit SubspaceNotDivisibleError(IRModule mod, For scope_loop, SBlock
inner_block)
: mod_(std::move(mod)),
@@ -523,7 +523,8 @@ SBlockRealize BlockizeImpl(const ScheduleState& self, const
StmtSRef& loop_sref,
ffi::Array<ffi::Array<arith::IterMark>> division =
SubspaceDivide(block_realize, block_sref, loop_sref, &loops, analyzer,
preserve_unit_iters);
if (division.empty()) {
- throw SubspaceNotDivisibleError(self->mod, ffi::GetRef<For>(loops.back()),
block);
+ throw MakeScheduleError<SubspaceNotDivisibleError>(self->mod,
ffi::GetRef<For>(loops.back()),
+ block);
}
PrimExpr outer_predicate = division.back()[0]->extent;
PrimExpr inner_predicate = division.back()[1]->extent;
@@ -614,7 +615,8 @@ SBlockRealize BlockizeBlocks(const ScheduleState& self,
const ffi::Array<StmtSRe
ffi::Array<ffi::Array<arith::IterMark>> division = SubspaceDivide(
block_realize, block_sref, lca, &loops, analyzer.get(),
preserve_unit_iters, true);
if (division.empty()) {
- throw SubspaceNotDivisibleError(self->mod,
ffi::GetRef<For>(loops.back()), block);
+ throw MakeScheduleError<SubspaceNotDivisibleError>(self->mod,
ffi::GetRef<For>(loops.back()),
+ block);
}
outer_predicate = division.back()[0]->extent;
PrimExpr inner_predicate = division.back()[1]->extent;
diff --git a/src/s_tir/schedule/primitive/cache_read_write.cc
b/src/s_tir/schedule/primitive/cache_read_write.cc
index 4eee15145f..198e01fbe8 100644
--- a/src/s_tir/schedule/primitive/cache_read_write.cc
+++ b/src/s_tir/schedule/primitive/cache_read_write.cc
@@ -34,7 +34,7 @@ using namespace tvm::tirx;
/******** Error Classes ********/
-class NotSingleWriteBlock : public ScheduleError {
+class NotSingleWriteBlock : public ScheduleErrorContextObj {
public:
explicit NotSingleWriteBlock(IRModule mod, BufferVar buffer,
ffi::Array<StmtSRef> write_blocks)
: mod_(std::move(mod)), buffer_(std::move(buffer)) {
@@ -117,7 +117,7 @@ struct ReindexCacheStageInfo : CacheStageInfo {
/* \brief The schedule error that accessed buffer region is not a single point
for
* reindex_cache_read/write. */
-class NotSinglePointAccess : public ScheduleError {
+class NotSinglePointAccess : public ScheduleErrorContextObj {
public:
explicit NotSinglePointAccess(IRModule mod, SBlock block, BufferRegion
cache_region,
bool is_cache_read)
@@ -522,7 +522,7 @@ ffi::Optional<StmtSRef> GetOnlyWriteBlock(ScheduleState
self, const StmtSRef& sc
const ffi::Array<StmtSRef>& block_srefs = it->second;
TVM_FFI_ICHECK(!block_srefs.empty());
if (block_srefs.size() > 1) {
- throw NotSingleWriteBlock(self->mod, buffer, block_srefs);
+ throw MakeScheduleError<NotSingleWriteBlock>(self->mod, buffer,
block_srefs);
}
return block_srefs[0];
}
@@ -1492,7 +1492,7 @@ BufferVar CreateReindexBuffer(const BufferVar& buffer,
const ffi::Array<IterVar>
/*!
* \brief The schedule error that the target is not a leaf block.
*/
-class NotLeafBlockError : public ScheduleError {
+class NotLeafBlockError : public ScheduleErrorContextObj {
public:
NotLeafBlockError(IRModule mod, SBlock block) : mod_(std::move(mod)),
block_(std::move(block)) {}
ffi::String FastErrorString() const final {
@@ -1510,7 +1510,7 @@ class NotLeafBlockError : public ScheduleError {
};
/*! \brief The schedule error that the buffer access is invalid for reindex. */
-class InvalidBufferAccessError : public ScheduleError {
+class InvalidBufferAccessError : public ScheduleErrorContextObj {
public:
enum class ErrorKind {
kNoAccess, // buffer access not found
@@ -1557,8 +1557,8 @@ class ReIndexCollector : public StmtExprVisitor {
ReIndexCollector collector(mod, buffer, block);
collector(block->body);
if (!collector.buffer_access_indices_.has_value()) {
- throw InvalidBufferAccessError(mod, buffer, block,
-
InvalidBufferAccessError::ErrorKind::kNoAccess);
+ throw MakeScheduleError<InvalidBufferAccessError>(
+ mod, buffer, block, InvalidBufferAccessError::ErrorKind::kNoAccess);
}
return collector.buffer_access_indices_.value();
}
@@ -1576,7 +1576,7 @@ class ReIndexCollector : public StmtExprVisitor {
void VisitStmt_(const SBlockNode* block) final {
// no sub-blocks under this block
- throw NotLeafBlockError(mod_, block_);
+ throw MakeScheduleError<NotLeafBlockError>(mod_, block_);
}
void VisitStmt_(const BufferStoreNode* store) final {
@@ -1593,15 +1593,15 @@ class ReIndexCollector : public StmtExprVisitor {
} else if (!std::equal(buffer_access_indices_.value().begin(),
buffer_access_indices_.value().end(),
indices.begin(), indices.end(),
ExprDeepEqual())) {
- throw InvalidBufferAccessError(mod_, buffer_, block_,
-
InvalidBufferAccessError::ErrorKind::kNonUniqueAccess);
+ throw MakeScheduleError<InvalidBufferAccessError>(
+ mod_, buffer_, block_,
InvalidBufferAccessError::ErrorKind::kNonUniqueAccess);
}
}
void VisitExpr_(const VarNode* var) final {
if (var == buffer_.get()) {
- throw InvalidBufferAccessError(mod_, buffer_, block_,
-
InvalidBufferAccessError::ErrorKind::kOpaqueAccess);
+ throw MakeScheduleError<InvalidBufferAccessError>(
+ mod_, buffer_, block_,
InvalidBufferAccessError::ErrorKind::kOpaqueAccess);
}
}
/*! \brief The IR module */
@@ -1720,7 +1720,7 @@ class ReIndexRewriter : public StmtExprMutator {
};
void CheckRegionCover(const ScheduleState& self, StmtSRef scope_root,
BufferVar read_buffer) {
- class NotRegionCoverError : public ScheduleError {
+ class NotRegionCoverError : public ScheduleErrorContextObj {
public:
explicit NotRegionCoverError(IRModule mod, SBlock block) : mod_(mod),
block_(block) {}
IRModule mod() const final { return mod_; }
@@ -1743,7 +1743,7 @@ The region cover property require to hold for every of
its child blocks
if (region->buffer.same_as(read_buffer)) {
if (!self->block_info.at(child_block_sref).region_cover) {
const SBlockNode* block = TVM_SREF_TO_SBLOCK(scope_root);
- throw NotRegionCoverError(self->mod, ffi::GetRef<SBlock>(block));
+ throw MakeScheduleError<NotRegionCoverError>(self->mod,
ffi::GetRef<SBlock>(block));
}
}
}
@@ -1968,7 +1968,7 @@ ffi::Array<StmtSRef> GetLoopsUnderScope(const StmtSRef&
block_sref, const StmtSR
* \brief The schedule error that block iter vars appears in old buffer and new
* allocated cache buffer does not match.
*/
-class ReindexCacheReadWriteNotMatchError : public ScheduleError {
+class ReindexCacheReadWriteNotMatchError : public ScheduleErrorContextObj {
public:
ReindexCacheReadWriteNotMatchError(IRModule mod, SBlock block, Var var,
ffi::Array<PrimExpr> old_indices,
@@ -2054,8 +2054,8 @@ void CollectReindexCacheStageInfoAndCreateBuffer(
bool appears_in_new =
collector_new.use_count_.count(block_iter_var->var.get());
bool appears_in_old =
collector_old.use_count_.count(block_iter_var->var.get());
if (appears_in_new != appears_in_old) {
- throw ReindexCacheReadWriteNotMatchError(mod, block,
block_iter_var->var, old_indices,
- new_indices, is_cache_read,
appears_in_old);
+ throw MakeScheduleError<ReindexCacheReadWriteNotMatchError>(
+ mod, block, block_iter_var->var, old_indices, new_indices,
is_cache_read, appears_in_old);
}
if (appears_in_new) {
info->block_iter_vars.push_back(block_iter_var);
@@ -2099,7 +2099,7 @@ void CheckSinglePoint(ScheduleState self, const SBlock&
block, const BufferRegio
}
}
if (!single_point) {
- throw NotSinglePointAccess(self->mod, block, cache_region, is_cache_read);
+ throw MakeScheduleError<NotSinglePointAccess>(self->mod, block,
cache_region, is_cache_read);
}
}
@@ -2243,7 +2243,7 @@ StmtSRef ReindexCacheWrite(ScheduleState self, const
StmtSRef& block_sref, int w
}
/*! \brief The schedule error that the target block doesn't both read&write
target buffer. */
-class NotReadWriteError : public ScheduleError {
+class NotReadWriteError : public ScheduleErrorContextObj {
public:
NotReadWriteError(IRModule mod, SBlock block, BufferVar buffer)
: mod_(std::move(mod)), block_(std::move(block)),
buffer_(std::move(buffer)) {}
@@ -2285,7 +2285,7 @@ ffi::Array<StmtSRef> CacheInplace(ScheduleState self,
const StmtSRef& block_sref
ffi::Optional<BufferRegion> read_region =
GetBufferRegionFromBuffer(rw_block->reads, buffer);
ffi::Optional<BufferRegion> write_region =
GetBufferRegionFromBuffer(rw_block->writes, buffer);
if (!read_region.has_value() || !write_region.has_value()) {
- throw NotReadWriteError(self->mod, ffi::GetRef<SBlock>(rw_block), buffer);
+ throw MakeScheduleError<NotReadWriteError>(self->mod,
ffi::GetRef<SBlock>(rw_block), buffer);
}
ffi::Array<StmtSRef> results_block_sref;
diff --git a/src/s_tir/schedule/primitive/compute_at.cc
b/src/s_tir/schedule/primitive/compute_at.cc
index ca1d8d114f..d69e08bbb1 100644
--- a/src/s_tir/schedule/primitive/compute_at.cc
+++ b/src/s_tir/schedule/primitive/compute_at.cc
@@ -35,7 +35,7 @@ using support::NDIntSet;
* \tparam is_consumer Indicates if all the required blocks are consumers or
producers
*/
template <bool is_consumer>
-class NotAllRequiredBlocksAreVisitedError : public ScheduleError {
+class NotAllRequiredBlocksAreVisitedError : public ScheduleErrorContextObj {
public:
explicit NotAllRequiredBlocksAreVisitedError(IRModule mod, int
num_not_visited,
const ffi::Array<StmtSRef>&
required)
@@ -80,7 +80,7 @@ class NotAllRequiredBlocksAreVisitedError : public
ScheduleError {
* \brief An error raised when the given block is not in the same block scope
as the given loop,
* or the given loop is the ancestor of the given block.
*/
-class NotInSameScopeError : public ScheduleError {
+class NotInSameScopeError : public ScheduleErrorContextObj {
public:
static void CheckAndBindLoopDomain(const ScheduleState& self, const
StmtSRef& block_sref,
const StmtSRef& loop_sref, const
StmtSRef& scope_root_sref,
@@ -89,14 +89,14 @@ class NotInSameScopeError : public ScheduleError {
if (const ForNode* loop = p->StmtAs<ForNode>()) {
analyzer->Bind(loop->loop_var, Range::FromMinExtent(loop->min,
loop->extent));
} else if (p != scope_root_sref.get()) {
- throw NotInSameScopeError(self->mod, block_sref, loop_sref);
+ throw MakeScheduleError<NotInSameScopeError>(self->mod, block_sref,
loop_sref);
} else {
break;
}
}
for (const StmtSRefNode* p = block_sref->parent; p !=
scope_root_sref.get(); p = p->parent) {
if (p == loop_sref.get()) {
- throw NotInSameScopeError(self->mod, block_sref, loop_sref);
+ throw MakeScheduleError<NotInSameScopeError>(self->mod, block_sref,
loop_sref);
}
}
}
@@ -112,12 +112,12 @@ class NotInSameScopeError : public ScheduleError {
IRModule mod() const final { return mod_; }
ffi::Array<ffi::ObjectRef> LocationsOfInterest() const final { return
{block_, loop_}; }
- private:
explicit NotInSameScopeError(IRModule mod, const StmtSRef& block_sref, const
StmtSRef& loop_sref)
: mod_(mod),
block_(ffi::GetRef<SBlock>(block_sref->StmtAs<SBlockNode>())),
loop_(ffi::GetRef<For>(loop_sref->StmtAs<ForNode>())) {}
+ private:
IRModule mod_;
SBlock block_;
For loop_;
@@ -153,7 +153,7 @@ int FindInsertionPoint(
if (require_all_producers_visited) {
int num_producers = producer_srefs.size();
if (split.n_producers_visited < num_producers) {
- throw NotAllRequiredBlocksAreVisitedError<false>(
+ throw MakeScheduleError<NotAllRequiredBlocksAreVisitedError<false>>(
self->mod, num_producers - split.n_producers_visited,
producer_srefs);
}
}
@@ -161,7 +161,7 @@ int FindInsertionPoint(
if (require_all_consumers_visited) {
int num_consumers = consumer_srefs.size();
if (split.n_consumers_visited < num_consumers) {
- throw NotAllRequiredBlocksAreVisitedError<true>(
+ throw MakeScheduleError<NotAllRequiredBlocksAreVisitedError<true>>(
self->mod, num_consumers - split.n_consumers_visited,
consumer_srefs);
}
}
diff --git a/src/s_tir/schedule/primitive/compute_inline.cc
b/src/s_tir/schedule/primitive/compute_inline.cc
index 72fd161430..ae339cf471 100644
--- a/src/s_tir/schedule/primitive/compute_inline.cc
+++ b/src/s_tir/schedule/primitive/compute_inline.cc
@@ -38,7 +38,7 @@ and there should be no variables other than the index
variables), and f is a bij
mapping and there should not be predicates in the inlined block. The iter
domains of the inlined
block should be covered by the producer block.)";
-class HasInitBlock : public ScheduleError {
+class HasInitBlock : public ScheduleErrorContextObj {
public:
explicit HasInitBlock(IRModule mod, SBlock block) : mod_(mod), block_(block)
{}
@@ -55,7 +55,7 @@ class HasInitBlock : public ScheduleError {
static void Check(const IRModule& mod, const SBlock& block) {
if (block->init.has_value()) {
- throw HasInitBlock(mod, block);
+ throw MakeScheduleError<HasInitBlock>(mod, block);
}
}
@@ -64,7 +64,7 @@ class HasInitBlock : public ScheduleError {
SBlock block_;
};
-class NotSingleReadWriteBuffer : public ScheduleError {
+class NotSingleReadWriteBuffer : public ScheduleErrorContextObj {
public:
explicit NotSingleReadWriteBuffer(IRModule mod, bool is_read, SBlock block)
: mod_(mod), is_read_(is_read), block_(std::move(block)) {}
@@ -106,26 +106,26 @@ class NotSingleReadWriteBuffer : public ScheduleError {
}
if (buffer_writers.count(BufferVar(ffi::GetRef<Var>(buffer))) > 0) {
if (read_buffer != nullptr) {
- throw NotSingleReadWriteBuffer(self->mod, true, block);
+ throw MakeScheduleError<NotSingleReadWriteBuffer>(self->mod, true,
block);
}
read_buffer = buffer;
}
}
if (read_buffer == nullptr) {
- throw NotSingleReadWriteBuffer(self->mod, true, block);
+ throw MakeScheduleError<NotSingleReadWriteBuffer>(self->mod, true,
block);
}
return BufferVar(ffi::GetRef<Var>(read_buffer));
}
static BufferVar GetSingleWrite(const ScheduleState& self, const SBlock&
block) {
if (block->writes.size() != 1) {
- throw NotSingleReadWriteBuffer(self->mod, false, block);
+ throw MakeScheduleError<NotSingleReadWriteBuffer>(self->mod, false,
block);
}
return block->writes[0]->buffer;
}
};
-class BodyAnalysisError : public ScheduleError {
+class BodyAnalysisError : public ScheduleErrorContextObj {
public:
explicit BodyAnalysisError(bool is_reverse, IRModule mod, SBlock block)
: is_reverse_(is_reverse), mod_(mod), block_(std::move(block)) {}
@@ -147,7 +147,7 @@ class BodyAnalysisError : public ScheduleError {
SBlock block_;
};
-class NonSingleProducerError : public ScheduleError {
+class NonSingleProducerError : public ScheduleErrorContextObj {
public:
explicit NonSingleProducerError(IRModule mod, SBlock block)
: mod_(mod), block_(std::move(block)) {}
@@ -220,7 +220,8 @@ class NonSingleProducerError : public ScheduleError {
// Check if the producer block is a complete block
StmtSRef producer_block_sref = self_->stmt2ref.at(node);
if (!IsCompleteBlock(self_, producer_block_sref,
scope_root_sref_)) {
- throw NonSingleProducerError(self_->mod,
ffi::GetRef<SBlock>(node));
+ throw MakeScheduleError<NonSingleProducerError>(self_->mod,
+
ffi::GetRef<SBlock>(node));
}
producer_across_scope_.back().push_back(ffi::GetRef<SBlock>(node));
break;
@@ -235,13 +236,14 @@ class NonSingleProducerError : public ScheduleError {
std::vector<SBlock> producer_across_scope = ProducerFinder::GetProducer(
self, scope_root_sref, consumer_buffer,
ffi::GetRef<SBlock>(scope_block));
if (producer_across_scope.size() != 1) {
- throw NonSingleProducerError(self->mod,
ffi::GetRef<SBlock>(consumer_block));
+ throw MakeScheduleError<NonSingleProducerError>(self->mod,
+
ffi::GetRef<SBlock>(consumer_block));
}
return self->stmt2ref.at(producer_across_scope[0].get());
}
};
-class OpaqueAccessError : public ScheduleError {
+class OpaqueAccessError : public ScheduleErrorContextObj {
public:
explicit OpaqueAccessError(IRModule mod, StmtSRef scope_root_sref)
: mod_(mod), scope_root_(nullptr) {
@@ -266,7 +268,7 @@ class OpaqueAccessError : public ScheduleError {
SBlock scope_root_;
};
-class ProducerHasNonTrivialPredicateError : public ScheduleError {
+class ProducerHasNonTrivialPredicateError : public ScheduleErrorContextObj {
public:
explicit ProducerHasNonTrivialPredicateError(IRModule mod, SBlockRealize
producer,
PrimExpr new_predicate)
@@ -924,7 +926,7 @@ void ComputeInlineImpl(ScheduleState self, const StmtSRef&
producer_block_sref,
// Step 3. Analyze the block body
ComputeInliner inliner(inlined_buffer, producer_block, scope_root_sref);
if (!inliner.BodyPatternAllowInline(producer_block)) {
- throw BodyAnalysisError(false, self->mod, producer_block);
+ throw MakeScheduleError<BodyAnalysisError>(false, self->mod,
producer_block);
}
// Step 4. Create a plan that removes the leaf block to be inlined
LeafBlockRemovalPlan(self, producer_block_sref, &inliner.src_stmt,
&inliner.tgt_stmt);
@@ -932,7 +934,7 @@ void ComputeInlineImpl(ScheduleState self, const StmtSRef&
producer_block_sref,
// and update other blocks who read from the removed block
Stmt tgt_stmt = inliner(ffi::GetRef<Stmt>(scope_root_sref->stmt));
if (inliner.has_opaque_access) {
- throw OpaqueAccessError(self->mod, scope_root_sref);
+ throw MakeScheduleError<OpaqueAccessError>(self->mod, scope_root_sref);
}
// Step 6. Do the real mutation on the AST and the sref tree in the schedule
state
if (check_only) {
@@ -976,7 +978,7 @@ void ReverseComputeInlineImpl(ScheduleState self, const
StmtSRef& consumer_block
ReverseComputeInliner inliner(inlined_buffer,
producer_block_sref->StmtAs<SBlockNode>(),
consumer_block_realize, scope_root_sref,
self->mod);
if (!inliner.BodyPatternAllowInline(consumer_block_realize)) {
- throw BodyAnalysisError(true, self->mod, consumer_block);
+ throw MakeScheduleError<BodyAnalysisError>(true, self->mod,
consumer_block);
}
// Step 5. Create a plan that removes the leaf block to be inlined
LeafBlockRemovalPlan(self, consumer_block_sref, &inliner.src_stmt,
&inliner.tgt_stmt);
@@ -984,7 +986,7 @@ void ReverseComputeInlineImpl(ScheduleState self, const
StmtSRef& consumer_block
// and update other blocks who read from the removed block
Stmt tgt_stmt = inliner(ffi::GetRef<Stmt>(scope_root_sref->stmt));
if (inliner.has_opaque_access) {
- throw OpaqueAccessError(self->mod, scope_root_sref);
+ throw MakeScheduleError<OpaqueAccessError>(self->mod, scope_root_sref);
}
// Step 7. Do the real mutation on the AST and the sref tree in the schedule
state
if (check_only) {
@@ -1736,7 +1738,7 @@ void FuseReductionEpilogueImpl(ScheduleState self, const
StmtSRef& reduction_blo
ReductionEpilogueFuser fuser(reduction_buffer, _reduction_block,
epilogue_block_realize,
scope_root_sref);
if (!fuser.BodyPatternAllowFusion(epilogue_block_realize)) {
- throw BodyAnalysisError(true, self->mod, epilogue_block);
+ throw MakeScheduleError<BodyAnalysisError>(true, self->mod,
epilogue_block);
}
if (check_only) {
diff --git a/src/s_tir/schedule/primitive/decompose_padding.cc
b/src/s_tir/schedule/primitive/decompose_padding.cc
index c9ebd17444..c40ee24acc 100644
--- a/src/s_tir/schedule/primitive/decompose_padding.cc
+++ b/src/s_tir/schedule/primitive/decompose_padding.cc
@@ -40,7 +40,7 @@ struct PaddingSBlockInfo {
PrimExpr pad_value;
};
-class PaddingPatternMatchError : public ScheduleError {
+class PaddingPatternMatchError : public ScheduleErrorContextObj {
public:
PaddingPatternMatchError(IRModule mod, SBlock block, const std::string&
error_msg)
: mod_(std::move(mod)), block_(std::move(block)), error_msg_(error_msg)
{}
@@ -76,7 +76,8 @@ class PaddingInfoAnalyzer {
arith::AnalyzerObj*
analyzer) {
PaddingInfoAnalyzer padding_analyzer(analyzer);
if (!padding_analyzer.MatchPadding(realize, dom_map)) {
- throw PaddingPatternMatchError(mod, realize->block,
padding_analyzer.error_msg_);
+ throw MakeScheduleError<PaddingPatternMatchError>(mod, realize->block,
+
padding_analyzer.error_msg_);
}
return padding_analyzer.info_;
}
@@ -480,8 +481,8 @@ StmtSRef DecomposePaddingImpl(ScheduleState self, const
StmtSRef& block_sref,
}
TVM_FFI_ICHECK(in_bound_filling_pos.defined());
if (!found_const_filling_pos) {
- throw LoopPositionError(self->mod, const_filling_pos,
ffi::GetRef<SBlock>(block),
- "decompose_padding");
+ throw MakeScheduleError<LoopPositionError>(self->mod, const_filling_pos,
+ ffi::GetRef<SBlock>(block),
"decompose_padding");
}
// Check 3. match padding pattern and return padding operation info.
diff --git a/src/s_tir/schedule/primitive/for_kind.cc
b/src/s_tir/schedule/primitive/for_kind.cc
index 58e19d8496..28cb9194b2 100644
--- a/src/s_tir/schedule/primitive/for_kind.cc
+++ b/src/s_tir/schedule/primitive/for_kind.cc
@@ -26,7 +26,7 @@ namespace s_tir {
using namespace tvm::prim;
using namespace tvm::tirx;
-class WrongBlockIterTypeError : public ScheduleError {
+class WrongBlockIterTypeError : public ScheduleErrorContextObj {
public:
explicit WrongBlockIterTypeError(IRModule mod, ForKind for_kind, Var
loop_var, SBlock block)
: mod_(std::move(mod)), loop_var_(std::move(loop_var)),
block_(std::move(block)) {
@@ -112,7 +112,7 @@ void CheckLoopParallelizableInBlock(const ScheduleState&
self, ForKind for_kind,
IterVarType iter_type = iter_var->iter_type;
if (!(iter_type == kDataPar ||
(iter_type == kCommReduce && thread_scope.rank == 1 &&
thread_scope.dim_index != -1))) {
- throw WrongBlockIterTypeError(self->mod, for_kind, loop_var, block);
+ throw MakeScheduleError<WrongBlockIterTypeError>(self->mod, for_kind,
loop_var, block);
}
}
}
diff --git a/src/s_tir/schedule/primitive/hide_buffer_access.cc
b/src/s_tir/schedule/primitive/hide_buffer_access.cc
index 0065afe169..fce9329dbd 100644
--- a/src/s_tir/schedule/primitive/hide_buffer_access.cc
+++ b/src/s_tir/schedule/primitive/hide_buffer_access.cc
@@ -31,7 +31,7 @@ using namespace tvm::tirx;
/******** Error Classes ********/
namespace {
-class BufTypeError : public ScheduleError {
+class BufTypeError : public ScheduleErrorContextObj {
public:
explicit BufTypeError(IRModule mod, const ffi::String& buf_type)
: mod_(std::move(mod)), buf_type_(buf_type) {}
@@ -54,7 +54,7 @@ class BufTypeError : public ScheduleError {
ffi::String buf_type_;
};
-class InvalidIndexError : public ScheduleError {
+class InvalidIndexError : public ScheduleErrorContextObj {
public:
explicit InvalidIndexError(IRModule mod, int num_access_regions, int buf_idx)
: mod_(std::move(mod)), num_access_regions_(num_access_regions),
buf_idx_(buf_idx) {}
@@ -99,7 +99,7 @@ void UnsafeHideBufferAccess(ScheduleState self, const
StmtSRef& block_sref,
} else if (buf_type == "write") {
num_access_regions = block->writes.size();
} else {
- throw BufTypeError(self->mod, buf_type);
+ throw MakeScheduleError<BufTypeError>(self->mod, buf_type);
}
std::set<int> buf_indices;
@@ -108,7 +108,7 @@ void UnsafeHideBufferAccess(ScheduleState self, const
StmtSRef& block_sref,
if (buf_idx_val >= 0 && buf_idx_val < num_access_regions) {
buf_indices.insert(buf_idx_val);
} else {
- throw InvalidIndexError(self->mod, num_access_regions, buf_idx_val);
+ throw MakeScheduleError<InvalidIndexError>(self->mod,
num_access_regions, buf_idx_val);
}
}
diff --git a/src/s_tir/schedule/primitive/layout_transformation.cc
b/src/s_tir/schedule/primitive/layout_transformation.cc
index 6e09125efe..0a6c231cc9 100644
--- a/src/s_tir/schedule/primitive/layout_transformation.cc
+++ b/src/s_tir/schedule/primitive/layout_transformation.cc
@@ -978,7 +978,7 @@ class TransformLayoutRewriter : private
tirx::IRMutatorWithAnalyzer {
arith::Analyzer index_simplifier_;
};
-class BufferIsSubregionError : public ScheduleError {
+class BufferIsSubregionError : public ScheduleErrorContextObj {
public:
explicit BufferIsSubregionError(IRModule mod, BufferVar buffer) : mod_(mod),
buffer_(buffer) {}
@@ -1003,7 +1003,7 @@ class BufferIsSubregionError : public ScheduleError {
BufferVar buffer_;
};
-class TransformationPaddingIndexMapError : public ScheduleError {
+class TransformationPaddingIndexMapError : public ScheduleErrorContextObj {
public:
TransformationPaddingIndexMapError(IRModule mod, IndexMap pad_value)
: mod_(mod), pad_value_(pad_value) {}
@@ -1030,7 +1030,7 @@ class TransformationPaddingIndexMapError : public
ScheduleError {
IndexMap pad_value_;
};
-class TransformationPaddingTypeError : public ScheduleError {
+class TransformationPaddingTypeError : public ScheduleErrorContextObj {
public:
TransformationPaddingTypeError(IRModule mod, BufferVar buffer, IndexMap
pad_value)
: mod_(mod), buffer_(buffer), pad_value_(pad_value) {
@@ -1062,7 +1062,7 @@ class TransformationPaddingTypeError : public
ScheduleError {
DLDataType pad_value_dtype_;
};
-class TransformationPaddingExpressionError : public ScheduleError {
+class TransformationPaddingExpressionError : public ScheduleErrorContextObj {
public:
static void Check(IRModule mod, BufferVar buffer, IndexMap pad_value) {
Visitor visitor(buffer);
@@ -1070,8 +1070,8 @@ class TransformationPaddingExpressionError : public
ScheduleError {
<< "Internal error: Should be caught by ScheduleError checks prior to
this point";
visitor(pad_value->final_indices[0]);
if (visitor.illegal_load) {
- throw TransformationPaddingExpressionError(mod, buffer, pad_value,
- visitor.illegal_load.value());
+ throw MakeScheduleError<TransformationPaddingExpressionError>(mod,
buffer, pad_value,
+
visitor.illegal_load.value());
}
}
@@ -1090,10 +1090,12 @@ class TransformationPaddingExpressionError : public
ScheduleError {
ffi::Optional<TensorLoad> illegal_load;
};
+ public:
TransformationPaddingExpressionError(IRModule mod, BufferVar buffer,
IndexMap pad_value,
TensorLoad illegal_load)
: mod_(mod), buffer_(buffer), pad_value_(pad_value),
illegal_load_(illegal_load) {}
+ private:
ffi::String FastErrorString() const final {
std::ostringstream ss;
ss << "ScheduleError: Pad value may not contain load from "
@@ -1118,7 +1120,7 @@ class TransformationPaddingExpressionError : public
ScheduleError {
TensorLoad illegal_load_;
};
-class TransformationIntroducesPaddingError : public ScheduleError {
+class TransformationIntroducesPaddingError : public ScheduleErrorContextObj {
public:
TransformationIntroducesPaddingError(IRModule mod, BufferVar buffer,
IndexMap index_map,
PrimExpr padding_predicate)
@@ -1220,14 +1222,15 @@ void TransformLayout(ScheduleState self, const
StmtSRef& block_sref, int buffer_
auto [defining_site_sref, is_alloc] = GetBufferDefiningSite(block_sref,
old_buffer);
if (defining_site_sref.has_value() && !is_alloc) {
- throw BufferIsSubregionError(self->mod, old_buffer);
+ throw MakeScheduleError<BufferIsSubregionError>(self->mod, old_buffer);
}
if (pad_value) {
if (pad_value.value()->final_indices.size() != 1) {
- throw TransformationPaddingIndexMapError(self->mod, pad_value.value());
+ throw MakeScheduleError<TransformationPaddingIndexMapError>(self->mod,
pad_value.value());
}
if (pad_value.value()->final_indices[0].ty() != old_buffer->dtype) {
- throw TransformationPaddingTypeError(self->mod, old_buffer,
pad_value.value());
+ throw MakeScheduleError<TransformationPaddingTypeError>(self->mod,
old_buffer,
+
pad_value.value());
}
TransformationPaddingExpressionError::Check(self->mod, old_buffer,
pad_value.value());
@@ -1252,7 +1255,8 @@ void TransformLayout(ScheduleState self, const StmtSRef&
block_sref, int buffer_
bool has_padding = !is_zero(padding_predicate);
if (has_padding && !pad_value.has_value()) {
- throw TransformationIntroducesPaddingError(self->mod, old_buffer,
index_map, padding_predicate);
+ throw MakeScheduleError<TransformationIntroducesPaddingError>(self->mod,
old_buffer, index_map,
+
padding_predicate);
}
// Step 2: Infer the shape of the new buffer
@@ -1325,7 +1329,7 @@ IterVarType DetectNewBlockIterType(
return result;
}
-class NotBijectiveAffineIndexMapError : public ScheduleError {
+class NotBijectiveAffineIndexMapError : public ScheduleErrorContextObj {
public:
NotBijectiveAffineIndexMapError(IRModule mod, IndexMap index_map)
: mod_(std::move(mod)), index_map_(std::move(index_map)) {}
@@ -1348,11 +1352,11 @@ class NotBijectiveAffineIndexMapError : public
ScheduleError {
IndexMap index_map_;
};
-class IndexMapNotApplicableToBlockIterError : public ScheduleError {
+class IndexMapNotApplicableToBlockIterError : public ScheduleErrorContextObj {
public:
static void Check(const IRModule mod, const SBlock& block, const IndexMap&
index_map) {
if (index_map->initial_indices.size() != block->iter_vars.size()) {
- throw IndexMapNotApplicableToBlockIterError(mod, block, index_map);
+ throw MakeScheduleError<IndexMapNotApplicableToBlockIterError>(mod,
block, index_map);
}
}
explicit IndexMapNotApplicableToBlockIterError(IRModule mod, SBlock block,
IndexMap index_map)
@@ -1382,7 +1386,7 @@ class IndexMapNotApplicableToBlockIterError : public
ScheduleError {
IndexMap index_map_;
};
-class OpaqueNewIterTypeError : public ScheduleError {
+class OpaqueNewIterTypeError : public ScheduleErrorContextObj {
public:
explicit OpaqueNewIterTypeError(IRModule mod, SBlock block, PrimExpr
iter_value)
: mod_(std::move(mod)), block_(std::move(block)),
iter_value_(std::move(iter_value)) {}
@@ -1472,8 +1476,8 @@ void TransformBlockLayout(ScheduleState self, const
StmtSRef& block_sref,
iter_type = DetectNewBlockIterType(transformed_block_iters[i],
block_iter_type);
}
if (iter_type == kOpaque) {
- throw OpaqueNewIterTypeError(self->mod, ffi::GetRef<SBlock>(block_ptr),
- transformed_block_iters[i]);
+ throw MakeScheduleError<OpaqueNewIterTypeError>(self->mod,
ffi::GetRef<SBlock>(block_ptr),
+
transformed_block_iters[i]);
}
PrimType dtype = new_block_var->ty.as_or_throw<PrimType>();
new_block_iters.push_back(IterVar(
@@ -1494,7 +1498,7 @@ void TransformBlockLayout(ScheduleState self, const
StmtSRef& block_sref,
try {
inverse_index_map = index_map.Inverse(initial_ranges, analyzer);
} catch (...) {
- throw NotBijectiveAffineIndexMapError(self->mod, index_map);
+ throw MakeScheduleError<NotBijectiveAffineIndexMapError>(self->mod,
index_map);
}
// old block vars written in terms of new block vars
ffi::Array<PrimExpr> inversed_new_block_vars =
diff --git a/src/s_tir/schedule/primitive/loop_transformation.cc
b/src/s_tir/schedule/primitive/loop_transformation.cc
index 63ed21ac1f..91b03fde7f 100644
--- a/src/s_tir/schedule/primitive/loop_transformation.cc
+++ b/src/s_tir/schedule/primitive/loop_transformation.cc
@@ -149,7 +149,7 @@ class IterMapSimplifyBlockBinding : public StmtExprMutator {
bool preserve_unit_iters_;
};
-class BlockPropertyError : public ScheduleError {
+class BlockPropertyError : public ScheduleErrorContextObj {
public:
/*!
* \brief Check that all the blocks under the specific stmt have affine
bindings
@@ -169,7 +169,7 @@ class BlockPropertyError : public ScheduleError {
void VisitStmt_(const SBlockNode* op) final {
for (const IterVar& iter_var : op->iter_vars) {
if (iter_var->iter_type != kDataPar && iter_var->iter_type !=
kCommReduce) {
- throw BlockPropertyError(state_->mod, ffi::GetRef<SBlock>(op));
+ throw MakeScheduleError<BlockPropertyError>(state_->mod,
ffi::GetRef<SBlock>(op));
}
ffi::Optional<StmtSRef> high_exclusive = top_->parent
?
ffi::GetRef<StmtSRef>(top_->parent)
@@ -204,7 +204,7 @@ class BlockPropertyError : public ScheduleError {
SBlock block_;
};
-class HasAnnotationOrThreadBindingError : public ScheduleError {
+class HasAnnotationOrThreadBindingError : public ScheduleErrorContextObj {
public:
explicit HasAnnotationOrThreadBindingError(IRModule mod, For loop)
: mod_(mod), loop_(std::move(loop)) {}
@@ -225,7 +225,7 @@ class HasAnnotationOrThreadBindingError : public
ScheduleError {
For loop_;
};
-class OuterNotInnerParent : public ScheduleError {
+class OuterNotInnerParent : public ScheduleErrorContextObj {
public:
explicit OuterNotInnerParent(IRModule mod, For outer, For inner)
: mod_(mod), outer_(std::move(outer)), inner_(std::move(inner)) {}
@@ -247,7 +247,7 @@ class OuterNotInnerParent : public ScheduleError {
For inner_;
};
-class NotOnlyChildError : public ScheduleError {
+class NotOnlyChildError : public ScheduleErrorContextObj {
public:
explicit NotOnlyChildError(IRModule mod, For outer, For inner)
: mod_(mod), outer_(std::move(outer)), inner_(std::move(inner)) {}
@@ -269,7 +269,7 @@ class NotOnlyChildError : public ScheduleError {
For inner_;
};
-class NotSingleInferFactorError : public ScheduleError {
+class NotSingleInferFactorError : public ScheduleErrorContextObj {
public:
explicit NotSingleInferFactorError(IRModule mod) : mod_(mod) {}
@@ -287,7 +287,7 @@ class NotSingleInferFactorError : public ScheduleError {
IRModule mod_;
};
-class WrongFactorProductError : public ScheduleError {
+class WrongFactorProductError : public ScheduleErrorContextObj {
public:
explicit WrongFactorProductError(IRModule mod, For loop) : mod_(mod),
loop_(std::move(loop)) {}
@@ -307,7 +307,7 @@ class WrongFactorProductError : public ScheduleError {
For loop_;
};
-class LoopMultiAppearanceError : public ScheduleError {
+class LoopMultiAppearanceError : public ScheduleErrorContextObj {
public:
explicit LoopMultiAppearanceError(IRModule mod, For loop) : mod_(mod),
loop_(std::move(loop)) {}
@@ -326,7 +326,7 @@ class LoopMultiAppearanceError : public ScheduleError {
For loop_;
};
-class LoopsNotAChainError : public ScheduleError {
+class LoopsNotAChainError : public ScheduleErrorContextObj {
public:
enum class ProblemKind { kNotUnderAScope, kHaveNonSingleBranchStmt };
@@ -363,7 +363,7 @@ class LoopsNotAChainError : public ScheduleError {
ProblemKind kind_;
};
-class DependentLoopError : public ScheduleError {
+class DependentLoopError : public ScheduleErrorContextObj {
public:
enum class PrimitiveKind { kFuse, kReorder };
explicit DependentLoopError(IRModule mod, For loop, ffi::String inner_var,
PrimitiveKind kind)
@@ -406,7 +406,7 @@ ffi::Array<StmtSRef> Split(ScheduleState self, const
StmtSRef& loop_sref,
// Step 1. Check correctness
const ForNode* loop = TVM_SREF_TO_FOR(loop_sref);
if (!loop->annotations.empty() || loop->thread_binding.has_value()) {
- throw HasAnnotationOrThreadBindingError(self->mod, ffi::GetRef<For>(loop));
+ throw MakeScheduleError<HasAnnotationOrThreadBindingError>(self->mod,
ffi::GetRef<For>(loop));
}
// Currently, loops not starting with 0 are not supported
arith::Analyzer analyzer;
@@ -673,7 +673,7 @@ ffi::Array<StmtSRef> LoopPartition(ScheduleState self,
const StmtSRef& loop_sref
const ffi::Array<PrimExpr>& factors, bool
preserve_unit_iters) {
const ForNode* loop = TVM_SREF_TO_FOR(loop_sref);
if (!loop->annotations.empty() || loop->thread_binding.has_value()) {
- throw HasAnnotationOrThreadBindingError(self->mod, ffi::GetRef<For>(loop));
+ throw MakeScheduleError<HasAnnotationOrThreadBindingError>(self->mod,
ffi::GetRef<For>(loop));
}
arith::Analyzer analyzer;
@@ -867,7 +867,8 @@ StmtSRef Merge(ScheduleState self, const
ffi::Array<StmtSRef>& loop_srefs) {
for (auto p = sref.get(); p != lca.get(); p = p->parent) {
if (auto loop = p->StmtAs<ForNode>()) {
if (!loop->annotations.empty() || loop->thread_binding.has_value()) {
- throw HasAnnotationOrThreadBindingError(self->mod,
ffi::GetRef<For>(loop));
+ throw MakeScheduleError<HasAnnotationOrThreadBindingError>(self->mod,
+
ffi::GetRef<For>(loop));
}
CheckLoopStartsWithZero(self, ffi::GetRef<StmtSRef>(p),
analyzer.get());
nest_loop_i_loops.push_back(ffi::GetRef<For>(loop));
@@ -878,7 +879,7 @@ StmtSRef Merge(ScheduleState self, const
ffi::Array<StmtSRef>& loop_srefs) {
const ForNode* outer_loop = nullptr;
for (auto iter = nest_loop_i_loops.rbegin(); iter !=
nest_loop_i_loops.rend(); ++iter) {
if (outer_loop && !outer_loop->body.same_as(*iter)) {
- throw NotOnlyChildError(self->mod, ffi::GetRef<For>(outer_loop),
*iter);
+ throw MakeScheduleError<NotOnlyChildError>(self->mod,
ffi::GetRef<For>(outer_loop), *iter);
}
outer_loop = (*iter).get();
}
@@ -932,14 +933,16 @@ StmtSRef Fuse(ScheduleState self, const
ffi::Array<StmtSRef>& loop_srefs,
for (const StmtSRef& sref : loop_srefs) {
const ForNode* loop = TVM_SREF_TO_FOR(sref);
if (!loop->annotations.empty() || loop->thread_binding.has_value()) {
- throw HasAnnotationOrThreadBindingError(self->mod,
ffi::GetRef<For>(loop));
+ throw MakeScheduleError<HasAnnotationOrThreadBindingError>(self->mod,
ffi::GetRef<For>(loop));
}
if (outer_loop_sref.defined()) {
if (sref->parent != outer_loop_sref.get()) {
- throw OuterNotInnerParent(self->mod, ffi::GetRef<For>(outer_loop),
ffi::GetRef<For>(loop));
+ throw MakeScheduleError<OuterNotInnerParent>(self->mod,
ffi::GetRef<For>(outer_loop),
+ ffi::GetRef<For>(loop));
}
if (!outer_loop->body.same_as(ffi::GetRef<For>(loop))) {
- throw NotOnlyChildError(self->mod, ffi::GetRef<For>(outer_loop),
ffi::GetRef<For>(loop));
+ throw MakeScheduleError<NotOnlyChildError>(self->mod,
ffi::GetRef<For>(outer_loop),
+ ffi::GetRef<For>(loop));
}
}
outer_loop_sref = sref;
@@ -952,8 +955,8 @@ StmtSRef Fuse(ScheduleState self, const
ffi::Array<StmtSRef>& loop_srefs,
auto result = ffi::StructuralWalk<ffi::WalkOrder::kPreOrder>(loop->extent,
walkfn);
if (result.has_value()) {
Var used_var = result.value()->value.cast<Var>();
- throw DependentLoopError(self->mod, ffi::GetRef<For>(loop),
used_var->name,
- DependentLoopError::PrimitiveKind::kFuse);
+ throw MakeScheduleError<DependentLoopError>(self->mod,
ffi::GetRef<For>(loop), used_var->name,
+
DependentLoopError::PrimitiveKind::kFuse);
}
outer_loop_vars.insert(loop->loop_var.get());
loops.push_back(loop);
@@ -1024,7 +1027,7 @@ std::unordered_set<const StmtSRefNode*>
CollectLoopsIntoSet(
auto inserted = loop_srefs.insert(loop_sref.get());
if (!inserted.second) {
const ForNode* loop = TVM_SREF_TO_FOR(loop_sref);
- throw LoopMultiAppearanceError(self->mod, ffi::GetRef<For>(loop));
+ throw MakeScheduleError<LoopMultiAppearanceError>(self->mod,
ffi::GetRef<For>(loop));
}
}
return loop_srefs;
@@ -1052,8 +1055,8 @@ std::pair<const StmtSRefNode*, const StmtSRefNode*>
GetBoundaryOfReorderRange(
// Case 1. If `v` corresponds to a block, stop traversal.
if (v->stmt->IsInstance<SBlockNode>()) {
if (scope_block_visited) {
- throw LoopsNotAChainError(self->mod, std::nullopt,
-
LoopsNotAChainError::ProblemKind::kNotUnderAScope);
+ throw MakeScheduleError<LoopsNotAChainError>(
+ self->mod, std::nullopt,
LoopsNotAChainError::ProblemKind::kNotUnderAScope);
}
scope_block_visited = true;
break;
@@ -1062,8 +1065,9 @@ std::pair<const StmtSRefNode*, const StmtSRefNode*>
GetBoundaryOfReorderRange(
// `bottom`.
if (visited.count(v)) {
if (v != bottom) {
- throw LoopsNotAChainError(self->mod, ffi::GetRef<Stmt>(v->stmt),
-
LoopsNotAChainError::ProblemKind::kHaveNonSingleBranchStmt);
+ throw MakeScheduleError<LoopsNotAChainError>(
+ self->mod, ffi::GetRef<Stmt>(v->stmt),
+ LoopsNotAChainError::ProblemKind::kHaveNonSingleBranchStmt);
}
bottom = loop_sref;
break;
@@ -1099,8 +1103,9 @@ std::vector<const StmtSRefNode*>
GetLoopsInReorderRange(const ScheduleState& sel
const ForNode* inner = loop_sref->StmtAs<ForNode>();
TVM_FFI_ICHECK(outer != nullptr && inner != nullptr);
if (outer->body.get() != inner) {
- throw LoopsNotAChainError(self->mod, ffi::GetRef<For>(outer),
-
LoopsNotAChainError::ProblemKind::kHaveNonSingleBranchStmt);
+ throw MakeScheduleError<LoopsNotAChainError>(
+ self->mod, ffi::GetRef<For>(outer),
+ LoopsNotAChainError::ProblemKind::kHaveNonSingleBranchStmt);
}
chain.push_back(loop_sref);
loop_sref = parent_loop_sref;
@@ -1151,8 +1156,8 @@ For ConstructNewLoopChain(const ScheduleState& self,
std::vector<const StmtSRefN
}
if (result.has_value()) {
Var used_var = result.value()->value.cast<Var>();
- throw DependentLoopError(self->mod, ffi::GetRef<For>(copy),
used_var->name,
- DependentLoopError::PrimitiveKind::kReorder);
+ throw MakeScheduleError<DependentLoopError>(self->mod,
ffi::GetRef<For>(copy), used_var->name,
+
DependentLoopError::PrimitiveKind::kReorder);
}
inner_vars.insert(copy->loop_var.get());
new_loop = For(std::move(n));
diff --git a/src/s_tir/schedule/primitive/pad_einsum.cc
b/src/s_tir/schedule/primitive/pad_einsum.cc
index 6f08e80fb4..569f5fee8f 100644
--- a/src/s_tir/schedule/primitive/pad_einsum.cc
+++ b/src/s_tir/schedule/primitive/pad_einsum.cc
@@ -69,7 +69,7 @@ ffi::Optional<ffi::Array<Var>> CheckTrivialBufferAccess(const
BufferRegion& buff
}
/*! \brief The schedule error class when the padding size is invalid. */
-class InvalidPaddingError : public ScheduleError {
+class InvalidPaddingError : public ScheduleErrorContextObj {
public:
InvalidPaddingError(IRModule mod, SBlock block, ffi::Array<int64_t> padding)
: mod_(std::move(mod)), block_(std::move(block)),
padding_(std::move(padding)) {}
@@ -87,11 +87,11 @@ class InvalidPaddingError : public ScheduleError {
static void Check(const ScheduleState& self, const SBlock& block,
ffi::Array<int64_t> padding) {
if (padding.size() != block->iter_vars.size()) {
- throw InvalidPaddingError(self->mod, block, padding);
+ throw MakeScheduleError<InvalidPaddingError>(self->mod, block, padding);
}
for (int64_t pad : padding) {
if (pad <= 0) {
- throw InvalidPaddingError(self->mod, block, padding);
+ throw MakeScheduleError<InvalidPaddingError>(self->mod, block,
padding);
}
}
}
@@ -103,7 +103,7 @@ class InvalidPaddingError : public ScheduleError {
};
/*! \brief The schedule error class when the block body is not an Einsum
pattern. */
-class NonEinsumError : public ScheduleError {
+class NonEinsumError : public ScheduleErrorContextObj {
public:
explicit NonEinsumError(IRModule mod, SBlock block)
: mod_(std::move(mod)), block_(std::move(block)) {}
@@ -224,34 +224,34 @@ Einsum ExtractEinsum(const ScheduleState& self, const
SBlock& block) {
for (int i = 0; i < n_reads; ++i) {
const BufferVar& buffer = block->reads[i]->buffer;
if (buffer_used.count(buffer.get()) != 0) {
- throw NonEinsumError(self->mod, block);
+ throw MakeScheduleError<NonEinsumError>(self->mod, block);
}
buffer_used.insert(buffer.get());
if (ffi::Optional<ffi::Array<Var>> opt_indices =
CheckTrivialBufferAccess(block->reads[i])) {
result.input_buffers.push_back(buffer);
result.input_indices.Set(buffer, opt_indices.value());
} else {
- throw NonEinsumError(self->mod, block);
+ throw MakeScheduleError<NonEinsumError>(self->mod, block);
}
}
int n_writes = block->writes.size();
for (int i = 0; i < n_writes; ++i) {
const BufferVar& buffer = block->writes[i]->buffer;
if (buffer_used.count(buffer.get()) != 0) {
- throw NonEinsumError(self->mod, block);
+ throw MakeScheduleError<NonEinsumError>(self->mod, block);
}
buffer_used.insert(buffer.get());
if (ffi::Optional<ffi::Array<Var>> opt_indices =
CheckTrivialBufferAccess(block->writes[i])) {
result.output_buffers.push_back(buffer);
result.output_indices.Set(buffer, opt_indices.value());
} else {
- throw NonEinsumError(self->mod, block);
+ throw MakeScheduleError<NonEinsumError>(self->mod, block);
}
}
return result;
}
-class BufferNotAllocatedInScopeError : public ScheduleError {
+class BufferNotAllocatedInScopeError : public ScheduleErrorContextObj {
public:
explicit BufferNotAllocatedInScopeError(IRModule mod, BufferVar buffer)
: mod_(std::move(mod)), buffer_(std::move(buffer)) {}
@@ -277,7 +277,7 @@ class BufferNotAllocatedInScopeError : public ScheduleError
{
};
/*! \brief The schedule error class when the producer block cannot be padded.
*/
-class InvalidProducerError : public ScheduleError {
+class InvalidProducerError : public ScheduleErrorContextObj {
public:
explicit InvalidProducerError(IRModule mod, SBlock producer)
: mod_(std::move(mod)), producer_(std::move(producer)) {}
diff --git a/src/s_tir/schedule/primitive/reduction.cc
b/src/s_tir/schedule/primitive/reduction.cc
index f2d473fc9f..440810fa2e 100644
--- a/src/s_tir/schedule/primitive/reduction.cc
+++ b/src/s_tir/schedule/primitive/reduction.cc
@@ -110,7 +110,7 @@ class DecomposeReductionBlockReplacer : public StmtMutator {
SBlock new_reduction_block_;
};
-class LoopHeightError : public ScheduleError {
+class LoopHeightError : public ScheduleErrorContextObj {
public:
static void CheckLoopHigherThanReduceLoops(const IRModule& mod, const
SBlockNode* block,
const SBlockRealizeNode* realize,
@@ -136,7 +136,8 @@ class LoopHeightError : public ScheduleError {
};
if (ffi::StructuralWalk<ffi::WalkOrder::kPreOrder>(binding,
walkfn).has_value()) {
const ForNode* loop = TVM_SREF_TO_FOR(loop_sref);
- throw LoopHeightError(mod, ffi::GetRef<For>(loop),
ffi::GetRef<SBlock>(block));
+ throw MakeScheduleError<LoopHeightError>(mod, ffi::GetRef<For>(loop),
+ ffi::GetRef<SBlock>(block));
}
}
}
@@ -205,8 +206,8 @@ StmtSRef DecomposeReduction(ScheduleState self, const
StmtSRef& block_sref,
if (self->enable_check) {
// Cond 0. Check loop_sref is an ancestor of block_sref
if (std::find(loops.begin(), loops.end(), loop_sref) == loops.end()) {
- throw LoopPositionError(self->mod, ffi::GetRef<For>(loop),
ffi::GetRef<SBlock>(block),
- "decompose_reduction");
+ throw MakeScheduleError<LoopPositionError>(self->mod,
ffi::GetRef<For>(loop),
+ ffi::GetRef<SBlock>(block),
"decompose_reduction");
}
// Cond 1. Check block is reduction
CheckReductionBlock(self, block_sref, scope_root_sref);
@@ -553,7 +554,7 @@ GetReducerGetters() {
return ReducerRegistry::Global()->reducer_getters;
}
-class NotSerialLoopKindError : public ScheduleError {
+class NotSerialLoopKindError : public ScheduleErrorContextObj {
public:
explicit NotSerialLoopKindError(IRModule mod, For loop)
: mod_(std::move(mod)), loop_(std::move(loop)) {}
@@ -578,7 +579,7 @@ class NotSerialLoopKindError : public ScheduleError {
For loop_;
};
-class FactorAxisOutOfRangeError : public ScheduleError {
+class FactorAxisOutOfRangeError : public ScheduleErrorContextObj {
public:
explicit FactorAxisOutOfRangeError(IRModule mod, BufferVar buffer, int
factor_axis)
: mod_(std::move(mod)), buffer_(std::move(buffer)),
factor_axis_(factor_axis) {}
@@ -604,7 +605,7 @@ class FactorAxisOutOfRangeError : public ScheduleError {
static int CheckAndUpdate(const IRModule& mod, const BufferVar& buffer, int
factor_axis) {
int ndim = static_cast<int>(buffer->shape.size());
if (factor_axis < -(ndim + 1) || factor_axis > ndim) {
- throw FactorAxisOutOfRangeError(mod, buffer, factor_axis);
+ throw MakeScheduleError<FactorAxisOutOfRangeError>(mod, buffer,
factor_axis);
}
// If factor_axis is negative, convert it to a non-negative one.
if (factor_axis < 0) {
@@ -618,7 +619,7 @@ class FactorAxisOutOfRangeError : public ScheduleError {
int factor_axis_;
};
-class LoopPropertyError : public ScheduleError {
+class LoopPropertyError : public ScheduleErrorContextObj {
public:
enum ErrorType {
kDataParIterTouchRFactorLoop = 0,
@@ -678,7 +679,8 @@ class LoopPropertyError : public ScheduleError {
ffi::Array<SBlockRealize> children_of_outermost_loop =
GetChildBlockRealizeOnSRefTree(self->stmt2ref.at(loops[0].get()));
if (!children_of_outermost_loop[0]->block.same_as(block)) {
- throw LoopPropertyError(self->mod, loops[0],
kNotFirstChildBlockOfOutermostLoop);
+ throw MakeScheduleError<LoopPropertyError>(self->mod, loops[0],
+
kNotFirstChildBlockOfOutermostLoop);
}
bool meet_reduction_loop = false;
@@ -687,10 +689,11 @@ class LoopPropertyError : public ScheduleError {
bool reduction_touched = reduce_loop_vars.count(loop->loop_var.get());
if (data_par_touched && reduction_touched) {
- throw LoopPropertyError(self->mod, loop,
kLoopTouchedByBothKindsOfBlockIters);
+ throw MakeScheduleError<LoopPropertyError>(self->mod, loop,
+
kLoopTouchedByBothKindsOfBlockIters);
} else if (data_par_touched) {
if (loop.get() == rf_loop) {
- throw LoopPropertyError(self->mod, loop,
kDataParIterTouchRFactorLoop);
+ throw MakeScheduleError<LoopPropertyError>(self->mod, loop,
kDataParIterTouchRFactorLoop);
}
continue;
} else if (reduction_touched) {
@@ -700,7 +703,7 @@ class LoopPropertyError : public ScheduleError {
}
continue;
} else if (meet_reduction_loop && !is_one(loop->extent)) {
- throw LoopPropertyError(self->mod, loop,
kUnboundLoopUnderReductionLoop);
+ throw MakeScheduleError<LoopPropertyError>(self->mod, loop,
kUnboundLoopUnderReductionLoop);
}
}
}
@@ -1368,7 +1371,7 @@ StmtSRef RFactor(ScheduleState self, const StmtSRef&
rf_loop_sref, int factor_ax
}
const ForNode* rf_loop = TVM_SREF_TO_FOR(rf_loop_sref);
if (rf_loop->kind != ForKind::kSerial) {
- throw NotSerialLoopKindError(self->mod, ffi::GetRef<For>(rf_loop));
+ throw MakeScheduleError<NotSerialLoopKindError>(self->mod,
ffi::GetRef<For>(rf_loop));
}
// Step 2. Collect loop vars that are touched by data parallel block iters
and reduction block
diff --git a/src/s_tir/schedule/primitive/reorder_block_iter_var.cc
b/src/s_tir/schedule/primitive/reorder_block_iter_var.cc
index 6f6994c5ae..9dd28f0586 100644
--- a/src/s_tir/schedule/primitive/reorder_block_iter_var.cc
+++ b/src/s_tir/schedule/primitive/reorder_block_iter_var.cc
@@ -31,7 +31,7 @@ using namespace tvm::tirx;
* \brief The reorder index is not a valid permutation of
* [0, 1, ..., n-1] where n is the number of block iter vars.
*/
-class InvalidReorderIndex : public ScheduleError {
+class InvalidReorderIndex : public ScheduleErrorContextObj {
public:
explicit InvalidReorderIndex(IRModule mod, SBlock block, ffi::Array<int64_t>
new_order)
: mod_(mod), block_(block), new_order_(new_order) {}
@@ -101,7 +101,8 @@ void ReorderBlockIterVar(ScheduleState self, const
StmtSRef& block_sref,
return x >= 0 && x < static_cast<int>(num_block_itervars);
});
if (!is_full || !is_unique || !is_within_boundary) {
- throw InvalidReorderIndex(self->mod, ffi::GetRef<SBlock>(block_n),
new_order);
+ throw MakeScheduleError<InvalidReorderIndex>(self->mod,
ffi::GetRef<SBlock>(block_n),
+ new_order);
}
// find parent block
diff --git a/src/s_tir/schedule/primitive/rolling_buffer.cc
b/src/s_tir/schedule/primitive/rolling_buffer.cc
index f831ee10e6..d2ab7ec186 100644
--- a/src/s_tir/schedule/primitive/rolling_buffer.cc
+++ b/src/s_tir/schedule/primitive/rolling_buffer.cc
@@ -66,7 +66,7 @@ BufferRegion GetRelaxedBufferRegion(const SBlockRealize&
realize, const BufferRe
return BufferRegion(buffer_region->buffer, relaxed_region);
}
-class RollingBufferDependencyError : public ScheduleError {
+class RollingBufferDependencyError : public ScheduleErrorContextObj {
public:
explicit RollingBufferDependencyError(IRModule mod, SBlock block)
: mod_(mod), block_(std::move(block)) {}
@@ -95,13 +95,15 @@ class RollingBufferDependencyError : public ScheduleError {
for (const Dependency& producers : scope->GetDepsByDst(block_sref)) {
if (!(producers->kind == DepKind::kRAW)) {
const SBlockNode* block = TVM_SREF_TO_SBLOCK(block_sref);
- throw RollingBufferDependencyError(self->mod,
ffi::GetRef<SBlock>(block));
+ throw MakeScheduleError<RollingBufferDependencyError>(self->mod,
+
ffi::GetRef<SBlock>(block));
}
}
for (const Dependency& consumers : scope->GetDepsBySrc(block_sref)) {
if (!(consumers->kind == DepKind::kRAW)) {
const SBlockNode* block = TVM_SREF_TO_SBLOCK(block_sref);
- throw RollingBufferDependencyError(self->mod,
ffi::GetRef<SBlock>(block));
+ throw MakeScheduleError<RollingBufferDependencyError>(self->mod,
+
ffi::GetRef<SBlock>(block));
}
}
}
@@ -111,7 +113,7 @@ class RollingBufferDependencyError : public ScheduleError {
SBlock block_;
};
-class RollingBufferMatchError : public ScheduleError {
+class RollingBufferMatchError : public ScheduleErrorContextObj {
public:
RollingBufferMatchError(IRModule mod, SBlock block, BufferRegion
buffer_region)
: mod_(mod), block_(block), buffer_region_(buffer_region) {}
@@ -137,7 +139,7 @@ class RollingBufferMatchError : public ScheduleError {
BufferRegion buffer_region_;
};
-class RollingBufferInsertionError : public ScheduleError {
+class RollingBufferInsertionError : public ScheduleErrorContextObj {
public:
RollingBufferInsertionError(IRModule mod, BufferVar buffer, SBlock block)
: mod_(mod), buffer_(std::move(buffer)), block_(block) {}
@@ -170,7 +172,8 @@ class RollingBufferInfoCollector {
RollingBufferInfoCollector collector;
if (!collector.MatchRollingBuffer(block_sref, buffer_region)) {
const SBlockNode* block = TVM_SREF_TO_SBLOCK(block_sref);
- throw RollingBufferMatchError(mod, ffi::GetRef<SBlock>(block),
buffer_region);
+ throw MakeScheduleError<RollingBufferMatchError>(mod,
ffi::GetRef<SBlock>(block),
+ buffer_region);
}
return collector.info_;
}
@@ -438,7 +441,7 @@ void RollingBuffer(ScheduleState self, const StmtSRef&
block_sref, int write_buf
consumers_sref.push_back(block_sref);
StmtSRef lca = GetSRefLowestCommonAncestor(consumers_sref);
if (!lca->StmtAs<ForNode>()) {
- throw RollingBufferInsertionError(self->mod, buffer_region->buffer, block);
+ throw MakeScheduleError<RollingBufferInsertionError>(self->mod,
buffer_region->buffer, block);
}
for (auto it = loop_srefs.rbegin(); it != loop_srefs.rend(); ++it) {
diff --git a/src/s_tir/schedule/transform.cc b/src/s_tir/schedule/transform.cc
index 424a0128bd..4e7d6042d4 100644
--- a/src/s_tir/schedule/transform.cc
+++ b/src/s_tir/schedule/transform.cc
@@ -237,7 +237,7 @@ Stmt ReplaceBufferMutator::VisitStmt_(const SBlockNode*
block) {
void LeafBlockRemovalPlan(const ScheduleState& self, const StmtSRef&
leaf_block_sref,
Stmt* src_stmt, Stmt* tgt_stmt) {
- class OnlyLeafError : public ScheduleError {
+ class OnlyLeafError : public ScheduleErrorContextObj {
public:
explicit OnlyLeafError(IRModule mod, SBlock leaf_block, SBlock scope_root)
: mod_(mod), leaf_block_(leaf_block), scope_root_(scope_root) {}
@@ -300,7 +300,8 @@ void LeafBlockRemovalPlan(const ScheduleState& self, const
StmtSRef& leaf_block_
TVM_FFI_ICHECK(sref != nullptr && sref->stmt != nullptr);
const auto* leaf_block = TVM_SREF_TO_SBLOCK(leaf_block_sref);
const auto* scope_block = TVM_SREF_TO_SBLOCK(sref);
- throw OnlyLeafError(self->mod, ffi::GetRef<SBlock>(leaf_block),
ffi::GetRef<SBlock>(scope_block));
+ throw MakeScheduleError<OnlyLeafError>(self->mod,
ffi::GetRef<SBlock>(leaf_block),
+ ffi::GetRef<SBlock>(scope_block));
}
ffi::Optional<LoopRV> TileWithTensorIntrin(const s_tir::Schedule& sch,