@@ -166,6 +166,7 @@ struct Sema {
166
166
}
167
167
return expr_to_type.at (ref);
168
168
}
169
+
169
170
// associate a type with this expression
170
171
TreeRef withType (TreeRef expr, TreeRef type) {
171
172
auto inserted = expr_to_type.emplace (expr, type).second ;
@@ -179,6 +180,7 @@ struct Sema {
179
180
}
180
181
return TensorType (typ);
181
182
}
183
+
182
184
TreeRef matchAllTypes (TreeRef list, TreeRef matched_type = nullptr ) {
183
185
for (auto e : list->trees ()) {
184
186
if (!matched_type)
@@ -188,23 +190,27 @@ struct Sema {
188
190
}
189
191
return matched_type;
190
192
}
193
+
191
194
TreeRef expectIntegral (TreeRef e) {
192
195
if (TypeInfo (typeOfExpr (e)).code () == TypeInfo::Float) {
193
196
throw ErrorReport (e) << " expected integral type but found "
194
197
<< kindToString (typeOfExpr (e)->kind ());
195
198
}
196
199
return e;
197
200
}
201
+
198
202
void expectBool (TreeRef anchor, int token) {
199
203
if (token != TK_BOOL) {
200
204
throw ErrorReport (anchor)
201
205
<< " expected boolean but found " << kindToString (token);
202
206
}
203
207
}
208
+
204
209
TreeRef expectBool (TreeRef exp) {
205
210
expectBool (exp, typeOfExpr (exp)->kind ());
206
211
return exp;
207
212
}
213
+
208
214
TreeRef lookupVarOrCreateIndex (Ident ident) {
209
215
TreeRef type = lookup (ident, false );
210
216
if (!type) {
@@ -216,6 +222,7 @@ struct Sema {
216
222
}
217
223
return type;
218
224
}
225
+
219
226
TreeRef checkExp (TreeRef exp, bool allow_access) {
220
227
switch (exp->kind ()) {
221
228
case TK_APPLY: {
@@ -339,6 +346,7 @@ struct Sema {
339
346
throw ErrorReport (exp) << " NYI - semantic checking for " << exp;
340
347
}
341
348
}
349
+
342
350
// This is the entry function for semantic analysis. It is called by
343
351
// tc2halide to associate type with each node of the tree and to also make
344
352
// sure that the tree is sematically correct. For example: a variable
@@ -352,7 +360,7 @@ struct Sema {
352
360
//
353
361
// Type checking is also done by small amount of code
354
362
//
355
- // The method 'withType' can be used to associate the type with a given node
363
+ // The method 'withType' is used to associate the type with a given node
356
364
//
357
365
TreeRef checkFunction (TreeRef func_) {
358
366
auto func = Def (func_);
@@ -385,21 +393,27 @@ struct Sema {
385
393
Def::create (func.range (), func.name (), params_, returns_, statements_);
386
394
return r;
387
395
}
396
+
388
397
TreeRef indexType (TreeRef anchor) {
389
- return c (TK_INT32, anchor->range (), {});
398
+ return createCompound (TK_INT32, anchor->range (), {});
390
399
}
400
+
391
401
TreeRef dimType (TreeRef anchor) {
392
402
return indexType (anchor);
393
403
}
404
+
394
405
TreeRef floatType (TreeRef anchor) {
395
- return c (TK_FLOAT, anchor->range (), {});
406
+ return createCompound (TK_FLOAT, anchor->range (), {});
396
407
}
408
+
397
409
TreeRef boolType (TreeRef anchor) {
398
- return c (TK_BOOL, anchor->range (), {});
410
+ return createCompound (TK_BOOL, anchor->range (), {});
399
411
}
412
+
400
413
void checkDim (Ident dim) {
401
414
insert (env, dim, dimType (dim), false );
402
415
}
416
+
403
417
TreeRef checkTensorType (TreeRef type) {
404
418
auto tt = TensorType (type);
405
419
for (const auto & d : tt.dims ()) {
@@ -409,18 +423,21 @@ struct Sema {
409
423
}
410
424
return type;
411
425
}
426
+
412
427
TreeRef checkParam (TreeRef param) {
413
428
auto p = Param (param);
414
429
TreeRef type_ = checkTensorType (p.type ());
415
430
insert (env, p.ident (), type_, true );
416
431
live_input_names.insert (p.ident ().name ());
417
432
return param;
418
433
}
434
+
419
435
TreeRef checkReturn (TreeRef ret) {
420
436
auto r = Param (ret);
421
437
TreeRef real_type = lookup (env, r.ident (), true );
422
438
return ret;
423
439
}
440
+
424
441
TreeRef checkList (TreeRef list, std::function<TreeRef(TreeRef)> fn) {
425
442
TC_ASSERT (list, list->kind () == TK_LIST);
426
443
TreeList r;
@@ -429,6 +446,7 @@ struct Sema {
429
446
}
430
447
return List::create (list->range (), std::move (r));
431
448
}
449
+
432
450
TreeRef checkRangeConstraint (RangeConstraint rc) {
433
451
// RCs are checked _before_ the rhs of the TC, so
434
452
// it is possible the index is not in the environment yet
@@ -441,11 +459,13 @@ struct Sema {
441
459
auto e = expectIntegral (checkExp (rc.end (), false ));
442
460
return RangeConstraint::create (rc.range (), rc.ident (), s, e);
443
461
}
462
+
444
463
TreeRef checkLet (Let l) {
445
464
auto rhs = checkExp (l.rhs (), true );
446
465
insert (let_env, l.name (), typeOfExpr (rhs), true );
447
466
return Let::create (l.range (), l.name (), rhs);
448
467
}
468
+
449
469
TreeRef checkWhereClause (TreeRef ref) {
450
470
if (ref->kind () == TK_LET) {
451
471
return checkLet (Let (ref));
@@ -456,6 +476,7 @@ struct Sema {
456
476
return checkRangeConstraint (RangeConstraint (ref));
457
477
}
458
478
}
479
+
459
480
// Semantic checking for the statements/comprehensions in a TC Def.
460
481
TreeRef checkStmt (TreeRef stmt_) {
461
482
auto stmt = Comprehension (stmt_);
@@ -467,11 +488,13 @@ struct Sema {
467
488
insert (index_env, index, typ, true );
468
489
}
469
490
470
- // make dimension variables for each dimension of the output tensor
491
+ // check that the input is not used for output - inputs are immutable
471
492
std::string name = stmt.ident ().name ();
472
493
if (inputParameters.count (name) > 0 ) {
473
494
throw ErrorReport (stmt_) << " TC inputs are immutable" ;
474
495
}
496
+
497
+ // make dimension variables for each dimension of the output tensor
475
498
TreeList output_indices;
476
499
int n = stmt.indices ().size ();
477
500
for (int i = 0 ; i < n; ++i) {
@@ -578,6 +601,7 @@ struct Sema {
578
601
579
602
return result;
580
603
}
604
+
581
605
static bool isUninitializedReductionOperation (TreeRef assignment) {
582
606
switch (assignment->kind ()) {
583
607
case TK_PLUS_EQ:
@@ -589,6 +613,7 @@ struct Sema {
589
613
return false ;
590
614
}
591
615
}
616
+
592
617
bool isNotInplace (TreeRef assignment) {
593
618
switch (assignment->kind ()) {
594
619
case TK_PLUS_EQ_B:
@@ -600,6 +625,7 @@ struct Sema {
600
625
return false ;
601
626
}
602
627
}
628
+
603
629
std::string dumpEnv () {
604
630
std::stringstream ss;
605
631
std::vector<std::pair<std::string, TreeRef>> elems (env.begin (), env.end ());
@@ -618,6 +644,7 @@ struct Sema {
618
644
619
645
private:
620
646
using Env = std::unordered_map<std::string, TreeRef>;
647
+
621
648
void
622
649
insert (Env& the_env, Ident ident, TreeRef value, bool must_be_undefined) {
623
650
std::string name = ident.name ();
@@ -630,6 +657,7 @@ struct Sema {
630
657
throw ErrorReport (ident) << name << " already defined" ;
631
658
}
632
659
}
660
+
633
661
TreeRef lookup (Ident ident, bool required) {
634
662
TreeRef v = lookup (index_env, ident, false );
635
663
if (!v)
@@ -638,6 +666,7 @@ struct Sema {
638
666
v = lookup (env, ident, required);
639
667
return v;
640
668
}
669
+
641
670
TreeRef lookup (Env& the_env, Ident ident, bool required) {
642
671
std::string name = ident.name ();
643
672
auto it = the_env.find (name);
@@ -647,10 +676,12 @@ struct Sema {
647
676
}
648
677
return it == the_env.end () ? nullptr : it->second ;
649
678
}
650
- TreeRef c (int kind, const SourceRange& range, TreeList&& trees) {
679
+
680
+ TreeRef createCompound (int kind, const SourceRange& range, TreeList&& trees) {
651
681
return Compound::create (kind, range, std::move (trees));
652
682
}
653
- TreeRef s (const std::string& s) {
683
+
684
+ TreeRef createString (const std::string& s) {
654
685
return String::create (s);
655
686
}
656
687
0 commit comments