/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /*! * \file tvm/s_tir/transform.h * \brief S-TIR specific transformation passes. */ #ifndef TVM_S_TIR_TRANSFORM_H_ #define TVM_S_TIR_TRANSFORM_H_ #include #include #include #include #include namespace tvm { namespace s_tir { /*! * \brief Renew the definition nodes for a TIR, including Var, Buffer and IterVar. * This pass works as a simple DeepCopy to duplicate a function with different Vars and * Buffers but the same behavior * \param func The input PrimFunc. * \return The renewed func. */ TVM_DLL tirx::PrimFunc RenewDefs(const tirx::PrimFunc& func); namespace transform { using tirx::transform::CreatePrimFuncPass; using tvm::transform::Pass; using tvm::transform::PassContext; /*! * \brief Canonicalize loop to start from zero . * \return The pass. */ TVM_DLL Pass CanonicalizeLoop(); /*! * \brief Lower cross-thread reduction from thread * bindings to intrinsic function calls. * \return The pass. */ TVM_DLL Pass LowerCrossThreadReduction(); /*! * \brief Lower block init stmt into IfThenElse stmts * \return The pass. */ TVM_DLL Pass LowerInitBlock(); /*! * \brief Locate the buffer allocation to the exact position (usually is * the lca of buffer access). This pass will inject opaque block * with alloc_buffers at the allocation site. * \return The pass. */ TVM_DLL Pass PlanAndUpdateBufferAllocationLocation(); /*! * \brief Substitute all the block vars with the PrimExprs they are bound to, indicated by the * corresponding iter_values in BlockRealize, for opaque blocks by removing all *. the iter_values in BlockRealize and iter_vars in Block. * \return The pass. */ TVM_DLL Pass ConvertBlocksToOpaque(); /*! * \brief Lift the same thread bindings to their LCA loops * \return The pass. */ TVM_DLL Pass LiftThreadBinding(); /*! * \brief Compact the buffer access region by removing the buffer regions that are not accessed, * i.e. narrowing the buffer shape and adjust the access region if necessary. * * Before narrowing, `B` is a `[16, 16]` buffer, but only a skinny vector `B[i, 0:16]` is accessed. * * \code * * for i in range(0, 16): * with T.sblock(): * B = T.alloc_buffer(16, 16) * for j in range(0, 16): * B[i, j] = A[i, j] + 1 * for j in range(0, 16): * C[i, j] = B[i, j] + 1 * * \endcode * * This pass narrows the buffer shape and adjust its accessed region accordingly. * In this particular case, because only a `1 * 16` vector of `B` is accessed, * the pass narrows `B` to shape `[1, 16]`, and changes the access to `B[i, j]` to `B[0, j]`. * * \code * * for i in range(0, 16): * with T.sblock(): * B = T.alloc_buffer(1, 16) * for j in range(0, 16): * B[0, j] = A[i, j] + 1 * for j in range(0, 16): * C[i, j] = B[0, j] + 1 * * \endcode * * \param is_strict ensure the compacted shape always smaller than the original shape. * otherwise it allows to grow the shape to match actual accessed buffer regions. * \return The pass. */ TVM_DLL Pass CompactBufferAllocation(bool is_strict = true); /*! * \brief Remove match buffers inside the block. Also, it will validate the binding. * \return The pass. */ TVM_DLL Pass LowerMatchBuffer(); /*! * \brief Inject permuted layout for shared memory. * \return The pass. */ TVM_DLL Pass InjectPermutedLayout(); /*! * \brief Transform Mma scope (m16n8k8.matrixA/B/C) to local scope with layout transformation. * \return The pass. */ TVM_DLL Pass TransformMmaBufferLayout(); /*! * \brief Remove the block to ensure that the TIR can not be scheduled again. * \return The pass. */ TVM_DLL Pass LowerOpaqueBlock(); /*! * \brief Unify all the thread bindings for "blockIdx.x/y/z", "threadIdx.x/y/z", and * "vthread.x/y/z". Before the unification, two vars that are bound to a thread axis (e.g., * "threadIdx.x") use different IterVars and variables in their AttrStmts. After the * unification, we use a consolidated IterVar and a variable for them. * \return The pass. * \note `vthread` is a legacy behavior that will be deprecated, though thread bindings of `vthread` * are still also unified in this pass. Please use `vthread.x`, `vthread.y` and `vthread.z` * instead. */ TVM_DLL Pass UnifyThreadBinding(); /*! * \brief This pass transforms annotated loops into pipelined ones where producers and consumers * are overlapped with the information provided in loop annotations, which enables optimization * techniques like prefetching and pipeline parallelism. * * The pipeline scope consists of the direct children of the annotated loop (ignoring SBlockRealize, * SBlock, SeqStmt), and the number of children is denoted by `n` in the documentation. * * The following annotations are used to guide the loop transformation: * * 1) Loop annotation `software_pipeline_stage` defines the pipeline stage. * An array of `n` integers, and each element should be in range [0, max_stage], * where max_stage is the maximum (inclusive) stage. * 2) Loop annotation `software_pipeline_order` defines the pipeline order. * An array of `n` integers, a permutation of [0, 1, ..., num_components - 1]; * 3) SBlock annotation `double_buffer_scope` controls certain buffer sizes to allow decoupling of * read/write dependency. It's an integer index of the write regions of the block. * * Every annotated loop is transformed into a loop with three blocks as its direct children: * * 1) Prologue block, where components whose stage is less than `max_stage` is executed; * * 2) Body block, where all the components are executed; * * 3) Epilogue block, where only components whose stage is greater than 0 will be executed. * The execution order is controlled by the annotation `software_pipeline_order`, * and thus could be different than the original order. * * Note: For nested software pipelines, the inner software pipeline will be generated first, * which may affect the number of the direct children of the outer loop. * In this case, the annotations for the outer software * pipeline should include the result of the inner software pipeline, * which is the three blocks as discussed above. * * \return The IR transform pass. */ TVM_DLL Pass InjectSoftwarePipeline(); /*! * \brief Automatically do memory optimizations for auto copy blocks * \return The pass. */ TVM_DLL Pass LowerAutoCopy(); /*! * \brief Add the explicit local stage for the shared memory access on GPU. * \return The pass. */ TVM_DLL Pass ManifestSharedMemoryLocalStage(); /*! \brief Annotate irregular loop mark. */ TVM_DLL Pass AnnotateIrregularLoop(); /*! * \brief partition loops in the stmt. * * \return The pass. */ TVM_DLL Pass LoopPartition(); /*! * \brief Inject virtual thread loops. * * \return The pass. */ TVM_DLL Pass InjectVirtualThread(); /*! * \brief Inject double buffer statements. * * \return The pass. */ TVM_DLL Pass InjectDoubleBuffer(); /*! * \brief Hoist loop-invariant IfThenElse nodes to * outside the eligible loops. * * \param variant The variant of the pass. * variant can have any one of following values ["basic", ""(Default)]. * \return The pass. */ TVM_DLL Pass HoistIfThenElse(tvm::ffi::String variant = ""); /*! * \brief Hoist loop-invariant expressions to outside the eligible loops. * * Can hoist conditionals used in IfThenElse statements and * expressions, bindings of variables in Let statements and * expressions, or boolean expressions, configurable to enable/disable * each hoistable type. * * \return The pass. */ TVM_DLL Pass HoistExpression(); /*! * \brief Renormalize the split pattern from floordiv(floormod()) to floormod(floordiv()). * \return The pass. */ TVM_DLL Pass RenormalizeSplitPattern(); /*! * \brief Detect and rewrite unsafe select that contains memory access. * \return The pass. */ TVM_DLL Pass RewriteUnsafeSelect(); /*! * \brief Instruments bound checkers. * \return The pass. */ TVM_DLL Pass InstrumentBoundCheckers(); /*! * \brief Rewrite global to local memory copy on CUDA with ldg32 instruction. * \param enable_inject Whether to enable injection. * \return The pass. */ TVM_DLL Pass InjectPTXLDG32(bool enable_inject = true); /*! * \brief Insert intrinsic calls to instrument function and loop level profiling. * \return The pass. */ TVM_DLL Pass InstrumentProfileIntrinsics(); /*! * \brief Lower VTCM allocations. * \return The pass. */ TVM_DLL Pass LowerVtcmAlloc(); /*! * \brief Insert sync between parallel read/write of shared buffers. * \param storage_scope The storage scope considered. * \return The pass. */ TVM_DLL Pass ThreadSync(tvm::ffi::String storage_scope); /*! * \brief Infer the TensorCore fragment information using tensor intrinsics. * \return The pass. */ TVM_DLL Pass InferFragment(); /*! * \brief Lower cross thread allreduce. * \return The pass. */ TVM_DLL Pass LowerThreadAllreduce(); /*! * \brief Lower Async TIR primitives to DMA copy and wait builtins. * \return The pass. */ TVM_DLL Pass LowerAsyncDMA(); /*! * \brief Rewrite global to shared memory copy on CUDA with asynchronous copy. * \return The pass. */ TVM_DLL Pass InjectPTXAsyncCopy(); /*! * \brief Merge multiple TIR-level shared memory allocations into one. * \return The pass. */ TVM_DLL Pass MergeSharedMemoryAllocations(); /*! * \brief Set default thread bindings for GPU PrimFuncs. * \return The pass. */ TVM_DLL Pass DefaultGPUSchedule(); /*! * \brief Remove weight layout rewrite block before benchmark. * \param skip_tensor_rewrite Whether to skip tensor rewrite. * \return The pass. */ TVM_DLL Pass RemoveWeightLayoutRewriteBlock(bool skip_tensor_rewrite = false); /*! * \brief Remove stores of tirx::builtin::undef. * \return The pass. */ TVM_DLL Pass RemoveStoreUndef(); /*! * \brief Decorate all the function's body as device function. * \return The pass. */ TVM_DLL Pass DecorateDeviceScope(); /*! * \brief Eliminate branches by leveraging buffer assumptions (T.assume). * \return The pass. */ TVM_DLL Pass UseAssumeToReduceBranches(); } // namespace transform } // namespace s_tir } // namespace tvm #endif // TVM_S_TIR_TRANSFORM_H_