Skip to content
This repository was archived by the owner on Apr 28, 2023. It is now read-only.

Commit 07d1c00

Browse files
author
Sven Verdoolaege
committed
emitHalideExpr: print parentheses around compound nested expressions
Despite what the original comment claims, the expression in the output that corresponds to a variable in the input may not be an identifier by itself. Since the variable may appear in a Halide expression at any position (e.g., as an argument to "-" or "*"), parentheses need to be put around the expression if it is anything other than an identifier or a non-negative number.
1 parent aad84fc commit 07d1c00

File tree

3 files changed

+52
-10
lines changed

3 files changed

+52
-10
lines changed

src/core/polyhedral/cuda/codegen.cc

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -495,22 +495,34 @@ isl::multi_aff makeMultiAffAccess(
495495
return ma;
496496
}
497497

498+
namespace {
499+
bool is_identifier_or_nonnegative_integer(isl::ast_expr expr) {
500+
if (isl_ast_expr_get_type(expr.get()) == isl_ast_expr_id)
501+
return true;
502+
if (isl_ast_expr_get_type(expr.get()) != isl_ast_expr_int)
503+
return false;
504+
return isl::manage(isl_ast_expr_get_val(expr.get())).is_nonneg();
505+
}
506+
} // namespace
507+
498508
void emitHalideExpr(
499509
const Halide::Expr& e,
500510
const CodegenStatementContext& context,
501511
const map<string, string>& substitutions) {
502512
class EmitHalide : public Halide::Internal::IRPrinter {
503513
using Halide::Internal::IRPrinter::visit;
504514
void visit(const Halide::Internal::Variable* op) {
505-
// This is probably needlessly indirect, given that we just have
506-
// a name to look up somewhere.
507515
auto pwAff = tc::polyhedral::detail::makeAffFromMappedExpr(
508516
Halide::Expr(op), context);
509517
// Use a temporary isl::ast_build to print the expression.
510518
// Ideally, this should use the build at the point
511519
// where the user statement was created.
512520
auto astBuild = isl::ast_build::from_context(pwAff.domain());
513-
auto s = astBuild.expr_from(pwAff).to_C_str();
521+
auto expr = astBuild.expr_from(pwAff);
522+
auto s = expr.to_C_str();
523+
if (!is_identifier_or_nonnegative_integer(expr)) {
524+
s = "(" + s + ")";
525+
}
514526
context.ss << s;
515527
}
516528
void visit(const Halide::Internal::Call* op) {

test/test_mapper.cc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def fun(float(N, M) A, float(N, M) B) -> (C) {
186186
float32 (*B)[M] = reinterpret_cast<float32 (*)[M]>(pB);
187187
for (int c1 = 16 * b1; c1 < M; c1 += 4096) {
188188
if (M >= t1 + c1 + 1) {
189-
C[t0 + 16 * b0][t1 + c1] = (A[t0 + 16 * b0][t1 + c1] + B[t0 + 16 * b0][t1 + c1]);
189+
C[(t0 + 16 * b0)][(t1 + c1)] = (A[(t0 + 16 * b0)][(t1 + c1)] + B[(t0 + 16 * b0)][(t1 + c1)]);
190190
}
191191
}
192192
}
@@ -318,9 +318,9 @@ constexpr auto kExpectedMatmul_64_64_64 =
318318
for (int c1 = 0; c1 <= 63; c1 += 16) {
319319
for (int c2 = t1; c2 <= 15; c2 += 8) {
320320
for (int c3 = 0; c3 <= 15; c3 += 1) {
321-
O[c0 + c2][c1 + c3] = 0.000000f;
321+
O[(c0 + c2)][(c1 + c3)] = 0.000000f;
322322
for (int c4 = t0; c4 <= 63; c4 += 32) {
323-
O[c0 + c2][c1 + c3] = (O[c0 + c2][c1 + c3] + (A[c0 + c2][c4]*B[c4][c1 + c3]));
323+
O[(c0 + c2)][(c1 + c3)] = (O[(c0 + c2)][(c1 + c3)] + (A[(c0 + c2)][c4]*B[c4][(c1 + c3)]));
324324
}
325325
}
326326
}
@@ -443,7 +443,7 @@ TEST_F(PolyhedralMapperTest, Unroll1D) {
443443
auto mscop = MappedScop::makeWithOuterBlockInnerThreadStrategy(
444444
std::move(scop), mappingOptions);
445445
auto code = std::get<0>(mscop->codegen(specializedName));
446-
std::string expected("C[64 * b0 + c2][t0 + 64 * b1]");
446+
std::string expected("C[(64 * b0 + c2)][(t0 + 64 * b1)]");
447447
ASSERT_TRUE(code.find(expected) != std::string::npos) << code;
448448
}
449449

@@ -462,7 +462,7 @@ TEST_F(PolyhedralMapperTest, Unroll2D) {
462462
auto mscop = MappedScop::makeWithOuterBlockInnerThreadStrategy(
463463
std::move(scop), mappingOptions);
464464
auto code = std::get<0>(mscop->codegen(specializedName));
465-
std::string expected("C[t1 + 64 * b0 + 32][t0 + 64 * b1 + 32]");
465+
std::string expected("C[(t1 + 64 * b0 + 32)][(t0 + 64 * b1 + 32)]");
466466
ASSERT_TRUE(code.find(expected) != std::string::npos);
467467
}
468468

@@ -712,7 +712,7 @@ TEST_F(PolyhedralMapperTest, ReductionMM1D) {
712712
auto code = codegenMapped(kTcMM, mappingOptions);
713713
using tc::code::cuda::kCUBReductionName;
714714
EXPECT_TRUE(code.find(kCUBReductionName) != std::string::npos);
715-
EXPECT_TRUE(code.find("C[c0 + c3][t0 + c1] = (C") != std::string::npos);
715+
EXPECT_TRUE(code.find("C[(c0 + c3)][(t0 + c1)] = (C") != std::string::npos);
716716
}
717717

718718
/*
@@ -730,7 +730,7 @@ TEST_F(PolyhedralMapperTest, ReductionMM2D) {
730730
auto code = codegenMapped(kTcMM, mappingOptions);
731731
using tc::code::cuda::kCUBReductionName;
732732
EXPECT_TRUE(code.find(kCUBReductionName) != std::string::npos);
733-
EXPECT_TRUE(code.find("C[t1 + c0][t0 + c1] = (C") != std::string::npos);
733+
EXPECT_TRUE(code.find("C[(t1 + c0)][(t0 + c1)] = (C") != std::string::npos);
734734
}
735735

736736
int main(int argc, char** argv) {

test/test_tc_mapper_bugs.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,36 @@ TEST(Halide2Isl, MinInUpperBound) {
761761
atCompl.compile("graph2", inputs, options);
762762
}
763763

764+
// Check that nested expressions are properly formatted.
765+
// In particular, as soon as the tensor size X is larger than the tile size,
766+
// the expression for "xp" is a sum of multiple loop iterators
767+
// in the generated code. Parentheses need to be placed around
768+
// these expressions to ensure the end result is, say, "-(c1 + c3)"
769+
// rather than "-c1 + c3".
770+
// The actual convolution is one where the output is equal to the input.
771+
TEST(Convolution, NestedExpressions) {
772+
auto convolution = "convolution";
773+
auto TC = std::string(R"TC(
774+
def convolution(float(X) A, float(Xp) K) -> (B) {
775+
B(x) +=! A(xp) * K(X - 1 + x - xp) where xp in 0:X
776+
}
777+
)TC");
778+
int X = 33;
779+
at::Tensor A = at::CUDA(at::kFloat).zeros({X});
780+
at::Tensor K = at::CUDA(at::kFloat).zeros({2 * X - 1});
781+
A[10] = 1;
782+
K[X - 1] = 1;
783+
std::vector<at::Tensor> inputs = {A, K};
784+
std::vector<at::Tensor> outputs;
785+
tc::ATenCompilationUnit<tc::CudaTcExecutor> cu;
786+
cu.define(TC);
787+
auto options = tc::CudaMappingOptions::makeNaiveCudaMappingOptions();
788+
auto handle = cu.compile(convolution, inputs, options);
789+
cu.run(convolution, inputs, outputs, handle);
790+
auto B = outputs[0];
791+
CHECK_EQ(at::Scalar(B[10]).toFloat(), 1);
792+
}
793+
764794
int main(int argc, char** argv) {
765795
::testing::InitGoogleTest(&argc, argv);
766796
::gflags::ParseCommandLineFlags(&argc, &argv, true);

0 commit comments

Comments
 (0)