1 #include "CodeGen_GPU_Dev.h"
2 #include "Bounds.h"
3 #include "IRVisitor.h"
4 
5 namespace Halide {
6 namespace Internal {
7 
~CodeGen_GPU_Dev()8 CodeGen_GPU_Dev::~CodeGen_GPU_Dev() {
9 }
10 
is_gpu_var(const std::string & name)11 bool CodeGen_GPU_Dev::is_gpu_var(const std::string &name) {
12     return is_gpu_block_var(name) || is_gpu_thread_var(name);
13 }
14 
is_gpu_block_var(const std::string & name)15 bool CodeGen_GPU_Dev::is_gpu_block_var(const std::string &name) {
16     return (ends_with(name, ".__block_id_x") ||
17             ends_with(name, ".__block_id_y") ||
18             ends_with(name, ".__block_id_z") ||
19             ends_with(name, ".__block_id_w"));
20 }
21 
is_gpu_thread_var(const std::string & name)22 bool CodeGen_GPU_Dev::is_gpu_thread_var(const std::string &name) {
23     return (ends_with(name, ".__thread_id_x") ||
24             ends_with(name, ".__thread_id_y") ||
25             ends_with(name, ".__thread_id_z") ||
26             ends_with(name, ".__thread_id_w"));
27 }
28 
29 namespace {
30 // Check to see if an expression is uniform within a block.
31 // This is done by checking to see if the expression depends on any GPU
32 // thread indices.
33 class IsBlockUniform : public IRVisitor {
34     using IRVisitor::visit;
35 
visit(const Variable * op)36     void visit(const Variable *op) override {
37         if (CodeGen_GPU_Dev::is_gpu_thread_var(op->name)) {
38             result = false;
39         }
40     }
41 
42 public:
43     bool result;
44 
IsBlockUniform()45     IsBlockUniform()
46         : result(true) {
47     }
48 };
49 }  // namespace
50 
is_block_uniform(const Expr & expr)51 bool CodeGen_GPU_Dev::is_block_uniform(const Expr &expr) {
52     IsBlockUniform v;
53     expr.accept(&v);
54     return v.result;
55 }
56 
57 namespace {
58 // Check to see if a buffer is a candidate for constant memory storage.
59 // A buffer is a candidate for constant memory if it is never written to,
60 // and loads are uniform within the workgroup.
61 class IsBufferConstant : public IRVisitor {
62     using IRVisitor::visit;
63 
visit(const Store * op)64     void visit(const Store *op) override {
65         if (op->name == buffer) {
66             result = false;
67         }
68         if (result) {
69             IRVisitor::visit(op);
70         }
71     }
72 
visit(const Load * op)73     void visit(const Load *op) override {
74         if (op->name == buffer &&
75             !CodeGen_GPU_Dev::is_block_uniform(op->index)) {
76             result = false;
77         }
78         if (result) {
79             IRVisitor::visit(op);
80         }
81     }
82 
83 public:
84     bool result;
85     const std::string &buffer;
86 
IsBufferConstant(const std::string & b)87     IsBufferConstant(const std::string &b)
88         : result(true), buffer(b) {
89     }
90 };
91 }  // namespace
92 
is_buffer_constant(const Stmt & kernel,const std::string & buffer)93 bool CodeGen_GPU_Dev::is_buffer_constant(const Stmt &kernel,
94                                          const std::string &buffer) {
95     IsBufferConstant v(buffer);
96     kernel.accept(&v);
97     return v.result;
98 }
99 
100 }  // namespace Internal
101 }  // namespace Halide
102