Tensor Comprehensions
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
sema.h
Go to the documentation of this file.
1 
16 #pragma once
17 
18 #include <unordered_set>
19 
20 #include "tc/lang/builtins.h"
21 #include "tc/lang/error_report.h"
22 #include "tc/lang/tree.h"
23 #include "tc/lang/tree_views.h"
24 
25 namespace lang {
26 
27 // modified from Halide. It would be weird for Sema to take a halide
28 // dependency for this trivial functionality, and it allows us to
29 // modify the behavior in the future
30 struct TypeInfo {
31  enum Code { Int, UInt, Float };
32  TypeInfo(Code code_, uint8_t bits_) : code_(code_), bits_(bits_) {}
33  TypeInfo(TreeRef scalar_type) {
34  switch (scalar_type->kind()) {
35 #define TYPE_INFO_OPTION(tok, c, b) \
36  case tok: \
37  code_ = c; \
38  bits_ = b; \
39  break;
40  TYPE_INFO_OPTION(TK_BOOL, UInt, 1)
41  TYPE_INFO_OPTION(TK_UINT8, UInt, 8)
42  TYPE_INFO_OPTION(TK_UINT16, UInt, 16)
43  TYPE_INFO_OPTION(TK_UINT32, UInt, 32)
44  TYPE_INFO_OPTION(TK_UINT64, UInt, 64)
45  TYPE_INFO_OPTION(TK_INT8, Int, 8)
46  TYPE_INFO_OPTION(TK_INT16, Int, 16)
47  TYPE_INFO_OPTION(TK_INT32, Int, 32)
48  TYPE_INFO_OPTION(TK_INT64, Int, 64)
49  TYPE_INFO_OPTION(TK_FLOAT, Float, 32)
50  TYPE_INFO_OPTION(TK_DOUBLE, Float, 64)
51 #undef TYPE_INFO_OPTION
52  default:
53  throw ErrorReport(scalar_type)
54  << "Unhandled TC scalar type: " << scalar_type;
55  }
56  }
57  int toScalarToken() const {
58  switch (code()) {
59  case UInt:
60  switch (bits()) {
61  case 1:
62  return TK_BOOL;
63  case 8:
64  return TK_UINT8;
65  case 16:
66  return TK_UINT16;
67  case 32:
68  return TK_UINT32;
69  case 64:
70  return TK_UINT64;
71  }
72  case Int:
73  switch (bits()) {
74  case 8:
75  return TK_INT8;
76  case 16:
77  return TK_INT16;
78  case 32:
79  return TK_INT32;
80  case 64:
81  return TK_INT64;
82  }
83  case Float:
84  switch (bits()) {
85  case 32:
86  return TK_FLOAT;
87  case 64:
88  return TK_DOUBLE;
89  }
90  }
91  throw std::runtime_error("Unknown type info?");
92  }
93  Code code() const {
94  return code_;
95  }
96  uint8_t bits() const {
97  return bits_;
98  }
99  bool is_float() const {
100  return code_ == Float;
101  }
102  bool is_uint() const {
103  return code_ == UInt;
104  }
105 
106  private:
108  uint8_t bits_;
109 };
110 
111 static inline bool operator==(TypeInfo a, TypeInfo b) {
112  return a.bits() == b.bits() && a.code() == b.code();
113 }
114 
115 static inline TreeRef match_types(TreeRef a, TreeRef b) {
116  TypeInfo ta(a);
117  TypeInfo tb(b);
118  if (ta == tb)
119  return a;
120 
121  if (!ta.is_float() && tb.is_float()) {
122  // int(a) * float(b) -> float(b)
123  // uint(a) * float(b) -> float(b)
124  return b;
125  } else if (ta.is_float() && !tb.is_float()) {
126  return a;
127  } else if (ta.is_float() && tb.is_float()) {
128  // float(a) * float(b) -> float(max(a, b))
129  if (ta.bits() > tb.bits())
130  return a;
131  else
132  return b;
133  } else if (ta.is_uint() && tb.is_uint()) {
134  // uint(a) * uint(b) -> uint(max(a, b))
135  if (ta.bits() > tb.bits())
136  return a;
137  else
138  return b;
139  } else if (!ta.is_float() && !tb.is_float()) {
140  // int(a) * (u)int(b) -> int(max(a, b))
141  int bits = std::max(ta.bits(), tb.bits());
142  return Compound::create(
143  TypeInfo(TypeInfo::Int, bits).toScalarToken(), a->range(), {});
144  } else {
145  throw ErrorReport(b) << "Could not match types: "
146  << kindToString(ta.toScalarToken()) << ", "
147  << kindToString(tb.toScalarToken());
148  }
149 }
150 
158 struct Sema {
159  std::unordered_map<TreeRef, TreeRef> expr_to_type;
160 
162  if (expr_to_type.count(ref) == 0) {
163  throw ErrorReport(ref)
164  << "INTERNAL ERROR: type not in map for expression " << ref;
165  }
166  return expr_to_type.at(ref);
167  }
168  // associate a type with this expression
170  auto inserted = expr_to_type.emplace(expr, type).second;
171  TC_ASSERT(expr, inserted);
172  return expr;
173  }
174 
176  if (typ->kind() != TK_TENSOR_TYPE) {
177  throw ErrorReport(loc) << "expected a tensor but found a scalar";
178  }
179  return TensorType(typ);
180  }
181  TreeRef matchAllTypes(TreeRef list, TreeRef matched_type = nullptr) {
182  for (auto e : list->trees()) {
183  if (!matched_type)
184  matched_type = typeOfExpr(e);
185  else
186  matched_type = match_types(matched_type, typeOfExpr(e));
187  }
188  return matched_type;
189  }
191  if (TypeInfo(typeOfExpr(e)).code() == TypeInfo::Float) {
192  throw ErrorReport(e) << " expected integral type but found "
193  << kindToString(typeOfExpr(e)->kind());
194  }
195  return e;
196  }
197  void expectBool(TreeRef anchor, int token) {
198  if (token != TK_BOOL) {
199  throw ErrorReport(anchor)
200  << "expected boolean but found " << kindToString(token);
201  }
202  }
204  expectBool(exp, typeOfExpr(exp)->kind());
205  return exp;
206  }
208  TreeRef type = lookup(ident, false);
209  if (!type) {
210  // variable exp is not defined, so a reduction variable is created
211  // a reduction variable index i
212  type = indexType(ident);
213  insert(index_env, ident, type, true);
214  reduction_variables.push_back(ident);
215  }
216  return type;
217  }
218  TreeRef checkExp(TreeRef exp, bool allow_access) {
219  switch (exp->kind()) {
220  case TK_APPLY: {
221  auto a = Apply(exp);
222  if (!allow_access
223  /* && live_input_names.count(a.name().name()) == 0 */) {
224  // We want to allow access to inputs in this context, but it
225  // isn't yet supported
226  throw ErrorReport(exp)
227  << "tensor accesses cannot be used in this context";
228  }
229 
230  // also handle built-in functions log, exp, etc.
231  auto ident = a.name();
232  if (builtin_functions.count(ident.name()) > 0) {
233  auto nargs = builtin_functions[ident.name()];
234  if (nargs != a.arguments().size()) {
235  throw ErrorReport(exp) << "expected " << nargs << " but found "
236  << a.arguments().size();
237  }
238  auto args = checkExp(a.arguments(), allow_access);
239  // [BUILTIN TYPE MATCHING]
240  // for now we assume, dangerously, that all built in are just
241  // float or double
242  // numeric functions and should propagate their types like +, -, *,
243  // div
244  auto type = matchAllTypes(args, floatType(exp));
245  return withType(
246  BuiltIn::create(exp->range(), ident.name(), args, type), type);
247  }
248  auto type = expectTensorType(ident, lookup(ident, true));
249  if (type.dims().size() != a.arguments().size()) {
250  throw ErrorReport(a)
251  << "expected " << type.dims().size() << " dimensions but found "
252  << a.arguments().size() << " dimensions.";
253  }
254  auto checked = checkExp(a.arguments(), allow_access);
255  for (auto t : checked->trees()) {
256  expectIntegral(t);
257  }
258  return withType(
259  Access::create(exp->range(), ident, checked),
260  type.scalarTypeTree());
261  } break;
262  case TK_IDENT: {
263  auto ident = Ident(exp);
264  auto type = lookupVarOrCreateIndex(ident);
265  if (type->kind() == TK_TENSOR_TYPE) {
266  auto tt = TensorType(type);
267  if (tt.dims().size() != 0) {
268  throw ErrorReport(exp)
269  << "expected a scalar but found a tensor expression.";
270  }
271  return checkExp(
273  ident.range(), ident, List::create(ident.range(), {})),
274  allow_access);
275  }
276  return withType(exp, type);
277  } break;
278  case '.': {
279  auto s = Select(exp);
280  auto ident = s.name();
281  expectTensorType(ident, lookup(ident, true));
282  return withType(exp, dimType(s));
283  } break;
284  case '+':
285  case '-':
286  case '*':
287  case '/':
288  case TK_MIN:
289  case TK_MAX: {
290  auto nexp =
291  exp->map([&](TreeRef c) { return checkExp(c, allow_access); });
292  return withType(nexp, matchAllTypes(nexp));
293  } break;
294  case TK_EQ:
295  case TK_NE:
296  case TK_GE:
297  case TK_LE:
298  case '<':
299  case '>': {
300  auto nexp =
301  exp->map([&](TreeRef c) { return checkExp(c, allow_access); });
302  // make sure the types match but the return type
303  // is always bool
304  matchAllTypes(nexp);
305  return withType(nexp, boolType(exp));
306  } break;
307  case TK_AND:
308  case TK_OR:
309  case '!': {
310  auto nexp =
311  exp->map([&](TreeRef c) { return checkExp(c, allow_access); });
312  expectBool(exp, matchAllTypes(nexp)->kind());
313  return withType(nexp, boolType(exp));
314  } break;
315  case '?': {
316  auto nexp =
317  exp->map([&](TreeRef c) { return checkExp(c, allow_access); });
318  expectBool(nexp->tree(0));
319  auto rtype =
320  match_types(typeOfExpr(nexp->tree(1)), typeOfExpr(nexp->tree(2)));
321  return withType(nexp, rtype);
322  }
323  case TK_CONST: {
324  auto c = Const(exp);
325  return withType(exp, c.type());
326  } break;
327  case TK_CAST: {
328  auto c = Cast(exp);
329  auto nexp = checkExp(c.value(), allow_access);
330  // currently this does not error, but we may want it to in the future
331  match_types(typeOfExpr(nexp), c.type());
332  return withType(Cast::create(c.range(), nexp, c.type()), c.type());
333  }
334  case TK_LIST: {
335  return exp->map([&](TreeRef c) { return checkExp(c, allow_access); });
336  } break;
337  default:
338  throw ErrorReport(exp) << "NYI - semantic checking for " << exp;
339  }
340  }
342  auto func = Def(func_);
343  auto params_ =
344  checkList(func.params(), [&](TreeRef r) { return checkParam(r); });
345 
346  for (auto r : func.returns()) {
347  if (!r.typeIsInferred()) {
348  annotated_output_types.emplace(r.ident().name(), r.tensorType());
349  }
350  }
351 
352  for (auto p : func.params())
353  nonTemporaries.insert(p.ident().name());
354  for (auto r : func.returns())
355  nonTemporaries.insert(r.ident().name());
356 
357  auto statements_ =
358  checkList(func.statements(), [&](TreeRef r) { return checkStmt(r); });
359  auto returns_ =
360  checkList(func.returns(), [&](TreeRef r) { return checkReturn(r); });
361  auto r =
362  Def::create(func.range(), func.name(), params_, returns_, statements_);
363  return r;
364  }
366  return c(TK_INT32, anchor->range(), {});
367  }
369  return indexType(anchor);
370  }
372  return c(TK_FLOAT, anchor->range(), {});
373  }
375  return c(TK_BOOL, anchor->range(), {});
376  }
377  void checkDim(Ident dim) {
378  insert(env, dim, dimType(dim), false);
379  }
381  auto tt = TensorType(type);
382  for (const auto& d : tt.dims()) {
383  // dims may also be constants
384  if (d->kind() == TK_IDENT)
385  checkDim(Ident(d));
386  }
387  return type;
388  }
390  auto p = Param(param);
391  TreeRef type_ = checkTensorType(p.type());
392  insert(env, p.ident(), type_, true);
393  live_input_names.insert(p.ident().name());
394  return param;
395  }
397  auto r = Param(ret);
398  TreeRef real_type = lookup(env, r.ident(), true);
399  return ret;
400  }
401  TreeRef checkList(TreeRef list, std::function<TreeRef(TreeRef)> fn) {
402  TC_ASSERT(list, list->kind() == TK_LIST);
403  TreeList r;
404  for (auto e : list->trees()) {
405  r.push_back(fn(e));
406  }
407  return List::create(list->range(), std::move(r));
408  }
410  // RCs are checked _before_ the rhs of the TC, so
411  // it is possible the index is not in the environment yet
412  // calling lookupOrCreate ensures it exists
414  // calling looking directly in the index_env ensures that
415  // we are actually constraining an index and not some other variable
416  lookup(index_env, rc.ident(), true);
417  auto s = expectIntegral(checkExp(rc.start(), false));
418  auto e = expectIntegral(checkExp(rc.end(), false));
419  return RangeConstraint::create(rc.range(), rc.ident(), s, e);
420  }
422  auto rhs = checkExp(l.rhs(), true);
423  insert(let_env, l.name(), typeOfExpr(rhs), true);
424  return Let::create(l.range(), l.name(), rhs);
425  }
427  if (ref->kind() == TK_LET) {
428  return checkLet(Let(ref));
429  } else if (ref->kind() == TK_EXISTS) {
430  auto exp = checkExp(Exists(ref).exp(), true);
431  return Exists::create(ref->range(), exp);
432  } else {
434  }
435  }
437  auto stmt = Comprehension(stmt_);
438 
439  // register index variables (non-reductions)
440  for (const auto& index : stmt.indices()) {
441  std::string idx = index.name();
442  auto typ = indexType(index);
443  insert(index_env, index, typ, true);
444  }
445 
446  // make dimension variables for each dimension of the output tensor
447  std::string name = stmt.ident().name();
448  TreeList output_indices;
449  int n = stmt.indices().size();
450  for (int i = 0; i < n; ++i) {
451  auto new_var =
452  Ident::create(stmt.range(), name + "." + std::to_string(i));
453  output_indices.push_back(new_var);
454  }
455 
456  // where clauses are checked _before_ the rhs because they
457  // introduce let bindings that are in scope for the rhs
458  auto where_clauses_ = stmt.whereClauses().map(
459  [&](TreeRef rc) { return checkWhereClause(rc); });
460 
461  TreeRef rhs_ = checkExp(stmt.rhs(), true);
462  TreeRef scalar_type = typeOfExpr(rhs_);
463 
464  // if this statement will be returned and it is annotated in the return list
465  // with a type (e.g. float(A,B)) then force the tensor to be that type
466  // and check that the number of dimensions are consistent
467  auto output_annotation = annotated_output_types.find(stmt.ident().name());
468  if (output_annotation != annotated_output_types.end()) {
469  auto tt = TensorType(output_annotation->second);
470  auto matched_type = match_types(scalar_type, tt.scalarTypeTree());
471  if (tt.scalarTypeTree()->kind() != matched_type->kind()) {
472  throw ErrorReport(stmt)
473  << " attempting to assign type "
474  << kindToString(scalar_type->kind()) << " to narrower type "
475  << kindToString(tt.scalarTypeTree()->kind())
476  << " without an explicit cast";
477  }
478  if (tt.dims().size() != stmt.indices().size()) {
479  throw ErrorReport(stmt)
480  << " tensor defined with " << stmt.indices().size()
481  << " dimensions but declared as an output with " << tt.dims().size()
482  << " dimensions.";
483  }
484  }
485 
486  auto type = TensorType::create(
487  stmt.range(),
488  scalar_type,
489  List::create(stmt.range(), std::move(output_indices)));
490  insert(env, stmt.ident(), type, false);
491 
492  // if we redefined an input, it is no longer valid for range expressions
493  live_input_names.erase(stmt.ident().name());
494 
495  auto equivalent_statement_ = stmt.equivalent().map([&](Equivalent eq) {
496  auto indices_ = eq.accesses().map(
497  [&](TreeRef index) { return checkExp(index, true); });
498  return Equivalent::create(eq.range(), eq.name(), indices_);
499  });
500 
501  TreeRef assignment = stmt.assignment();
502  // For semantic consistency we allow overwriting reductions like +=!
503  // to be used in the language when there are no actual reduction dimensions.
504  // Later compile stages assume that there is at least one reduction
505  // dimension so if a reduction is specified and there are no reduction
506  // dimensions, we revert back to assignment here.
507  if (reduction_variables.size() == 0 && isNotInplace(assignment)) {
508  assignment = Compound::create('=', assignment->range(), {});
509  }
510 
511  if (reduction_variables.size() > 0 && stmt.assignment()->kind() == '=') {
512  throw ErrorReport(stmt) << "this statement includes reduction variable '"
513  << Ident(reduction_variables.back()).name()
514  << "' but does not specify a reduction.";
515  }
516  TreeRef reduction_variable_list =
517  List::create(stmt.ident().range(), std::move(reduction_variables));
519  stmt.range(),
520  stmt.ident(),
521  stmt.indices(),
522  stmt.assignment(),
523  rhs_,
524  where_clauses_,
525  equivalent_statement_,
526  reduction_variable_list);
527 
528  if (nonTemporaries.count(stmt.ident().name()) == 0) {
529  throw ErrorReport(stmt)
530  << stmt.ident().name()
531  << " is not listed as an input or output to this function. Temporaries tensors are not yet implemented";
532  }
533 
534  // clear the per-statement environments to get ready for the next statement
535  index_env.clear();
536  let_env.clear();
537 
538  return result;
539  }
540  bool isNotInplace(TreeRef assignment) {
541  switch (assignment->kind()) {
542  case TK_PLUS_EQ_B:
543  case TK_TIMES_EQ_B:
544  case TK_MIN_EQ_B:
545  case TK_MAX_EQ_B:
546  return true;
547  default:
548  return false;
549  }
550  }
551  std::string dumpEnv() {
552  std::stringstream ss;
553  std::vector<std::pair<std::string, TreeRef>> elems(env.begin(), env.end());
554  std::sort(
555  elems.begin(),
556  elems.end(),
557  [](const std::pair<std::string, TreeRef>& t,
558  const std::pair<std::string, TreeRef>& t2) {
559  return t.first < t2.first;
560  });
561  for (auto p : elems) {
562  ss << p.first << ": " << p.second;
563  }
564  return ss.str();
565  }
566 
567  private:
568  using Env = std::unordered_map<std::string, TreeRef>;
569  void
570  insert(Env& the_env, Ident ident, TreeRef value, bool must_be_undefined) {
571  std::string name = ident.name();
572  if (builtin_functions.count(name) > 0) {
573  throw ErrorReport(ident)
574  << "'" << name << "' is a built-in function and cannot be redefined";
575  }
576  auto it = the_env.emplace(name, value);
577  if (must_be_undefined && !it.second) {
578  throw ErrorReport(ident) << name << " already defined";
579  }
580  }
581  TreeRef lookup(Ident ident, bool required) {
582  TreeRef v = lookup(index_env, ident, false);
583  if (!v)
584  v = lookup(let_env, ident, false);
585  if (!v)
586  v = lookup(env, ident, required);
587  return v;
588  }
589  TreeRef lookup(Env& the_env, Ident ident, bool required) {
590  std::string name = ident.name();
591  auto it = the_env.find(name);
592  if (required && it == the_env.end()) {
593  throw ErrorReport(ident)
594  << "undefined variable " << name << " used here.";
595  }
596  return it == the_env.end() ? nullptr : it->second;
597  }
598  TreeRef c(int kind, const SourceRange& range, TreeList&& trees) {
599  return Compound::create(kind, range, std::move(trees));
600  }
601  TreeRef s(const std::string& s) {
602  return String::create(s);
603  }
604 
605  std::vector<TreeRef> reduction_variables; // per-statement
606  Env index_env; // per-statement
607  Env let_env; // per-statement, used for where i = <exp>
608 
609  Env env; // name -> type
610  Env annotated_output_types; // name -> type, for all annotated returns types
611  // identifiers that currently refer to an input tensor
612  // values in these tensors are allowed in range expressions
613  // if you write to an input, using it in a range expression is no longer
614  // allowed
615  std::unordered_set<std::string> live_input_names;
616 
617  std::unordered_set<std::string> nonTemporaries;
618 };
619 } // namespace lang
static TreeRef create(const SourceRange &range, TreeRef name, TreeRef paramlist, TreeRef retlist, TreeRef stmts_list)
Definition: tree_views.h:348
TreeRef lookup(Ident ident, bool required)
Definition: sema.h:581
static TreeRef create(const SourceRange &range, const std::string &name, TreeRef accesses)
Definition: tree_views.h:244
std::unordered_set< std::string > live_input_names
Definition: sema.h:615
Env let_env
Definition: sema.h:607
const std::string & name() const
Definition: tree_views.h:118
TreeRef matchAllTypes(TreeRef list, TreeRef matched_type=nullptr)
Definition: sema.h:181
TreeRef rhs() const
Definition: tree_views.h:411
bool isNotInplace(TreeRef assignment)
Definition: sema.h:540
uint8_t bits() const
Definition: sema.h:96
Ident name() const
Definition: tree_views.h:408
static TreeRef create(const SourceRange &range, const std::string &name, TreeRef arguments, TreeRef type)
Definition: tree_views.h:171
TreeRef withType(TreeRef expr, TreeRef type)
Definition: sema.h:169
Definition: tree_views.h:256
TreeRef start() const
Definition: tree_views.h:267
std::unordered_map< TreeRef, TreeRef > expr_to_type
Definition: sema.h:159
TreeRef checkExp(TreeRef exp, bool allow_access)
Definition: sema.h:218
Definition: tree_views.h:374
TreeRef typeOfExpr(TreeRef ref)
Definition: sema.h:161
TensorType expectTensorType(TreeRef loc, TreeRef typ)
Definition: sema.h:175
void checkDim(Ident dim)
Definition: sema.h:377
TypeInfo(Code code_, uint8_t bits_)
Definition: sema.h:32
TreeRef checkRangeConstraint(RangeConstraint rc)
Definition: sema.h:409
Definition: sema.h:31
TreeRef lookup(Env &the_env, Ident ident, bool required)
Definition: sema.h:589
Definition: sema.h:30
void expectBool(TreeRef anchor, int token)
Definition: sema.h:197
TreeRef floatType(TreeRef anchor)
Definition: sema.h:371
TreeRef checkLet(Let l)
Definition: sema.h:421
static TreeRef create(const SourceRange &range, TreeRef ident, TreeRef start, TreeRef end)
Definition: tree_views.h:261
Definition: tree_views.h:389
Definition: tree_views.h:275
TreeRef c(int kind, const SourceRange &range, TreeList &&trees)
Definition: sema.h:598
static TreeRef create(const SourceRange &range, TreeRef name, TreeRef arguments)
Definition: tree_views.h:149
Definition: tree_views.h:109
bool is_float() const
Definition: sema.h:99
TreeRef dimType(TreeRef anchor)
Definition: sema.h:368
Definition: tree_views.h:359
static TreeRef create(Args &&...args)
Definition: tree.h:100
TreeRef checkParam(TreeRef param)
Definition: sema.h:389
ApplyLike< TK_APPLY > Apply
Definition: tree_views.h:153
Definition: lexer.h:303
static TreeRef create(const SourceRange &range, TreeRef value, TreeRef type)
Definition: tree_views.h:399
static TreeRef create(const SourceRange &range, TreeRef name, TreeRef rhs)
Definition: tree_views.h:414
Definition: sema.h:31
Definition: tree_views.h:330
void insert(Env &the_env, Ident ident, TreeRef value, bool must_be_undefined)
Definition: sema.h:570
Definition: tree_views.h:404
Code code() const
Definition: sema.h:93
std::vector< TreeRef > reduction_variables
Definition: sema.h:605
#define TYPE_INFO_OPTION(tok, c, b)
Ident ident() const
Definition: tree_views.h:264
std::unordered_map< std::string, TreeRef > Env
Definition: sema.h:568
const SourceRange & range() const
Definition: tree_views.h:29
Env annotated_output_types
Definition: sema.h:610
TreeRef checkFunction(TreeRef func_)
Definition: sema.h:341
static TreeRef create(const SourceRange &range, TreeRef ident, TreeRef indices, TreeRef assignment, TreeRef rhs, TreeRef range_constraints, TreeRef equivalent, TreeRef reduction_variables)
Definition: tree_views.h:279
TreeRef indexType(TreeRef anchor)
Definition: sema.h:365
Env index_env
Definition: sema.h:606
std::vector< TreeRef > TreeList
Definition: tree.h:45
TreeRef lookupVarOrCreateIndex(Ident ident)
Definition: sema.h:207
TreeRef checkReturn(TreeRef ret)
Definition: sema.h:396
TreeRef checkWhereClause(TreeRef ref)
Definition: sema.h:426
TreeRef s(const std::string &s)
Definition: sema.h:601
Code
Definition: sema.h:31
int toScalarToken() const
Definition: sema.h:57
static TreeRef create(const SourceRange &range, const std::string &name)
Definition: tree_views.h:127
static TreeRef create(const SourceRange &range, TreeRef scalar_type_, TreeRef dims_)
Definition: tree_views.h:191
std::string dumpEnv()
Definition: sema.h:551
TreeRef expectBool(TreeRef exp)
Definition: sema.h:203
bool is_uint() const
Definition: sema.h:102
Definition: sema.h:31
static TreeRef create(const SourceRange &range, TreeList elements)
Definition: tree_views.h:85
std::unordered_set< std::string > nonTemporaries
Definition: sema.h:617
std::string kindToString(int kind)
TreeRef checkTensorType(TreeRef type)
Definition: sema.h:380
Definition: tree_views.h:186
TreeRef checkList(TreeRef list, std::function< TreeRef(TreeRef)> fn)
Definition: sema.h:401
ListView< TreeRef > accesses() const
Definition: tree_views.h:251
TreeRef checkStmt(TreeRef stmt_)
Definition: sema.h:436
Definition: sema.h:158
TypeInfo(TreeRef scalar_type)
Definition: sema.h:33
Definition: tree_views.h:239
TreeRef expectIntegral(TreeRef e)
Definition: sema.h:190
Definition: error_report.h:22
Env env
Definition: sema.h:609
Definition: tree_views.h:419
static TreeRef create(int kind, const SourceRange &range_, TreeList &&trees_)
Definition: tree.h:155
Definition: tree_views.h:211
const std::string & name() const
Definition: tree_views.h:248
static TreeRef create(const SourceRange &range, TreeRef exp)
Definition: tree_views.h:426
Code code_
Definition: sema.h:107
uint8_t bits_
Definition: sema.h:108
std::shared_ptr< Tree > TreeRef
Definition: tree.h:44
TreeRef end() const
Definition: tree_views.h:270
TreeRef boolType(TreeRef anchor)
Definition: sema.h:374
#define TC_ASSERT(ctx, cond)
Definition: error_report.h:55