Taichi: Support break in non-parallel for statements

Created on 11 Mar 2020  ·  34Comments  ·  Source: taichi-dev/taichi

Concisely describe the proposed feature

@ti.kernel
def sums():
  for i in range(n):
    is_prime[i] = 1
    for j in range(i):
       if i % j == 0:
         is_prime[i] = 0
       if j * j > i:
         break # This is not supported now...

Describe the solution you'd like (if any)
Add an IR pass that lower non-parallel fors with break statements into while statements.
While statements already support breaks (WhileControlStmt).

feature request welcome contribution

Most helpful comment

Can we lower RangeForStmt into WhileStmt? So no reludent work is necessary on each backend.
Also StructForStmt? I'm not super clear about the diff between them. May work some degree?

We can only lower non-parallel for loops into while. Struct-for loops are always parallel.

All 34 comments

Can we lower RangeForStmt into WhileStmt? So no reludent work is necessary on each backend.
Also StructForStmt? I'm not super clear about the diff between them. May work some degree?

Can we lower RangeForStmt into WhileStmt? So no reludent work is necessary on each backend.
Also StructForStmt? I'm not super clear about the diff between them. May work some degree?

We can only lower non-parallel for loops into while. Struct-for loops are always parallel.

Btw, break in parallel ones aren't allowed, right? (break have a clear assumption of serial execution...)

Btw, break in parallel ones aren't allowed, right? (break have a clear assumption of serial execution...)

exactly!

Can we lower RangeForStmt into WhileStmt? So no reludent work is necessary on each backend.
Also StructForStmt? I'm not super clear about the diff between them. May work some degree?

We can only lower non-parallel for loops into while. Struct-for loops are always parallel.

Great! I decided to work on this today.

Nice! Before you start, keep in mind that we only want to lower non-parallel range-for statements that contain at least one FrontendBreakStmt. For loops that live at the outer-most scope are automatically parallel. We should implement this within the lower pass when FrontendBreakStmt has not been lowered into WhileControlStmt.

Before I could compile, I need to ask how to deal with the spdlog submodule? Keeps fatal error: 'spdlog/fmt/bundled/color.h' file not found though I've cloned spdlog there into external/spdlog...

git submodule update?

Didn't have any response... Tried removing the whole dir and run that, dir not created.

Try git submodule init?

I would suggest not to introduce a submodule... since their API could change by time. And contributors will stuck with dealing color.h file not found for a long time...

Working after init then update!

I would suggest not to introduce a submodule... since their API could change by time. And contributors will stuck with dealing color.h file not found for a long time...

Yeah I know submodules can be confusing, but using them makes it easy to upgrade our dependencies frequently. Also, it leads to a clearer git history compared to copy-pasting files with huge changesets.

I hate submodules :(

尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
  (提交或丢弃子模组中未跟踪或修改的内容)
        修改:     external/spdlog (新提交, 修改的内容)

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")

Make me can't happily git add . anymore.
Tried .gitignore, didn't work...

I hate them too but they are used by a lot of mature open-source projects.

Make me can't happily git add . anymore.
Tried .gitignore, didn't work...

The submodules will not be changed frequently. Maybe we can add a submodule tutorial to Contributor Guideline.

Super slow receving spdlog in GFW :(

接收对象中:  69% (12579/18034), 14.22 MiB | 28.00 KiB/s

Can I specify --depth=1 to that? Didn't move for a few miniutes...

It works!

I hate them too but they are used by a lot of mature open-source projects.

Make me can't happily git add . anymore.
Tried .gitignore, didn't work...

The submodules will not be changed frequently. Maybe we can add a submodule tutorial to Contributor Guideline.

To tell them run git submodule init&update after git clone?
Or this is automatically done for new-cloners?

I believe for git clone --recursive this is automatic

I also found taichi_assets may be not appreciated by some users, containing some meshes used by mpm examples which may not be so useful for some people.. Is this cloned by git clone --recursive?

No, it's no longer an existing submodule. It's just part of the module list. Not sure if we will need it sometime later so I kept the git URL.

Good. Can't found a good place in taichi/transforms/xx.cpp's, shall I create a taichi/transforms/for_by_while.cpp?

I would suggest implementing this in lower_ast.cpp: https://github.com/taichi-dev/taichi/issues/578#issuecomment-597395981

You might also want to create a pass in analysis named find_serial_range_fors_with_break that returns an std::set<Stmt *> of fors to lower into while.

I would suggest implementing this in lower_ast.cpp: #578 (comment)

But FrontendBreakStmt is also in lower_ast.cpp.

You might also want to create a pass in analysis named find_serial_range_fors_with_break that returns an std::set<Stmt *> of fors to lower into while.

So only those fors_with_break are lowered into while?

But FrontendBreakStmt is also in lower_ast.cpp.

Yes, that's why we should first do an analysis pass before FrontendBreakStmts are lower into WhileControlStmt.

So only those fors_with_break are lowered into while?

Exactly!

So only those fors_with_break are lowered into while?

Exactly!

What I was thinking about was, translate FrontendForStmt into GlobalTempStmt + WhileStmt:

for i in range(233):
i = 0
tmp_range_max = 233
while i < tmp_range_max:

So break could be done simpler and else could be added just once.

I guess using a local AllocaStmt is easier? You might have multiple instances of serial fors running in parallel so allocating GlobalTemp would be tricky.

[E 03/11/20 13:54:26.793] [ir.h:BinaryOpStmt@972] !lhs->is<AllocaStmt>()

Why not allow me to binary cmp_lt with alloca-ed loop_var..

You probably need a LocalLoadStmt to convert that local pointer to a local value?

May works but:
no known conversion from 'taichi::lang::AllocaStmt *' to 'LaneAttribute<taichi::lang::LocalAddress>'
How can I make LocalLoad load an alloca variable?

Stmt::make<LocaLoadStmt>(LaneAttribute<LocalAddress>(alloca, 0))?

Ok now, using LaneAttribute<LocalAddress>(LocalAddress(alloca, 0)). Would you like to add a (T args...) initializer to LaneAttribute?
Now keep [E 03/12/20 22:15:10.195] [ir.h:replace_with@1345] location != -1.
Seems we can't find FrontendForStmt in its parent but FrontendWhileStmt (which I copied codes from) can.

Well done by @archibate.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

g1n0st picture g1n0st  ·  3Comments

archibate picture archibate  ·  4Comments

yuanming-hu picture yuanming-hu  ·  4Comments

GeoffreyPlitt picture GeoffreyPlitt  ·  4Comments

yuanming-hu picture yuanming-hu  ·  3Comments