annotate_device_regions.cc 3.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
 * 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 annotate_device_regions.cc
 * \brief Split device function from host.
 */
#include "tir/transforms/ir_utils.h"
25
26
#include <tvm/ffi/function.h>
#include <tvm/ffi/reflection/registry.h>
27
28
29
30
31
32
33
#include <tvm/ir/transform.h>
#include <tvm/target/target.h>
#include <tvm/tir/builtin.h>
#include <tvm/tir/expr.h>
#include <tvm/tir/stmt_functor.h>
#include <tvm/tir/transform.h>

34
35
#include <utility>

36
37
38
39
40
41
42
43
namespace tvm {
namespace tl {

using namespace tir;

class DeviceRegionAnnotater : public StmtMutator {
public:
  explicit DeviceRegionAnnotater(Target device_target)
44
      : device_target_(std::move(device_target)) {}
45
46
47
48

  Stmt VisitStmt_(const AttrStmtNode *op) final {
    if (op->attr_key == tvm::attr::kTarget) {
      // If a target attribute already exists, use it as-is.
49
      return tvm::ffi::GetRef<Stmt>(op);
50
51
52
53
54
    } else if (op->attr_key == tir::attr::thread_extent ||
               op->attr_key == tir::attr::pipeline_exec_scope ||
               op->attr_key == tir::attr::device_scope) {
      // These attributes are only allowed in device-side code, so
      // they should be annotated with the function's default target.
55
      Stmt body = tvm::ffi::GetRef<Stmt>(op);
56
57
58
59
60
61
62
63
64
65
66
67
68
      return AttrStmt(device_target_, tvm::attr::kTarget, 0, body);
    } else {
      // All other annotations are ignored
      return StmtMutator::VisitStmt_(op);
    }
  }

private:
  Target device_target_;
};

tvm::transform::Pass AnnotateDeviceRegions() {
  using namespace tir::transform;
69
70
  auto pass_func = [](PrimFunc func, const IRModule &mod,
                      const tvm::transform::PassContext &ctx) -> PrimFunc {
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    auto opt_target = func->GetAttr<Target>(tvm::attr::kTarget);
    ICHECK(opt_target) << "AnnotateDeviceRegions: Require the target attribute";
    Target target = opt_target.value();
    Target device_target = target.WithoutHost();

    if (target->GetHost()) {
      if (device_target->kind->name == "c") {
        // Annotate the function with the device target
        auto func_body = func->body;
        func.CopyOnWrite()->body =
            AttrStmt(device_target, tvm::attr::kTarget, 0, func_body);
      }

      DeviceRegionAnnotater mutator(target.WithoutHost());
      func.CopyOnWrite()->body = mutator(func->body);
    }
    return func;
  };

  return CreatePrimFuncPass(pass_func, 0, "tl.AnnotateDeviceRegions", {});
}

93
TVM_FFI_STATIC_INIT_BLOCK() {
94
95
96
  namespace refl = tvm::ffi::reflection;
  refl::GlobalDef().def("tl.transform.AnnotateDeviceRegions",
                        AnnotateDeviceRegions);
97
}
98
99
100

} // namespace tl
} // namespace tvm