leaningtech / cheerp-meta

Cheerp - a C/C++ compiler for Web applications - compiles to WebAssembly and JavaScript
https://labs.leaningtech.com/cheerp
Other
1.02k stars 50 forks source link

Another compilation timeout #132

Closed zyz9740 closed 1 year ago

zyz9740 commented 1 year ago

emi_compile_timeout.zip

We found a case which causes timeout in O2 and O3. You can try to reproduce it.

carlopi commented 1 year ago

I do reproduce.

For -O2, the timeout happens inside CFGStackifier::runOpt with this somehow degenerate CFG (note BasicBlock af.i.i):

; Function Attrs: nofree norecurse nounwind
define internal fastcc void @main() unnamed_addr #0 section "asmjs" {
entry:
  store i32* @b, i32** @d, align 4, !tbaa !5
  %0 = load volatile i32**, i32*** undef, align 4, !tbaa !5
  %1 = load i32*, i32** %0, align 4, !tbaa !5
  %2 = bitcast i32* %1 to i64*
  %3 = load i64, i64* %2, align 8
  %4 = load i32, i32* @b, align 4, !tbaa !9
  %cmp1.i.i.i = icmp sgt i32 %4, 0
  %5 = shl i64 %3, 32
  %cmp.i.i.i = icmp sgt i64 %5, 0
  %or.cond.i.i.i = and i1 %cmp.i.i.i, %cmp1.i.i.i
  %conv2.i.i = sext i32 %4 to i64
  %sub.i.i.i = sub nsw i64 9223372036854775807, %conv2.i.i
  %conv1.i.i = ashr exact i64 %5, 32
  %cmp3.i.i.i = icmp slt i64 %sub.i.i.i, %conv1.i.i
  %or.cond10.i.i.i = select i1 %or.cond.i.i.i, i1 %cmp3.i.i.i, i1 false
  br i1 %or.cond10.i.i.i, label %if.then.i.i, label %safe_add_func_int64_t_s_s.exit.i.i

safe_add_func_int64_t_s_s.exit.i.i:               ; preds = %entry
  %6 = and i64 %conv1.i.i, %conv2.i.i
  %7 = icmp slt i64 %6, 0
  %sub8.i.i.i = sub nsw i64 -9223372036854775808, %conv2.i.i
  %cmp9.i.i.i = icmp sgt i64 %sub8.i.i.i, %conv1.i.i
  %or.cond12.i.i.i = select i1 %7, i1 %cmp9.i.i.i, i1 false
  %add.i.i.i = select i1 %or.cond12.i.i.i, i64 0, i64 %conv2.i.i
  %spec.select.i.i.i = sub nsw i64 0, %conv1.i.i
  %tobool.not.i.i = icmp eq i64 %add.i.i.i, %spec.select.i.i.i
  br i1 %tobool.not.i.i, label %af.preheader.i.i, label %if.then.i.i

af.preheader.i.i:                                 ; preds = %safe_add_func_int64_t_s_s.exit.i.i
  %.b = load i1, i1* @g, align 1
  br i1 %.b, label %af.i.i, label %if.end.i.i

if.then.i.i:                                      ; preds = %safe_add_func_int64_t_s_s.exit.i.i, %entry
  store i1 true, i1* @g, align 1
  br label %j.exit

af.i.i:                                           ; preds = %af.preheader.i.i, %af.i.i
  br label %af.i.i

if.end.i.i:                                       ; preds = %af.preheader.i.i
  %8 = load volatile i32**, i32*** @f, align 4, !tbaa !5
  br label %j.exit

j.exit:                                           ; preds = %if.end.i.i, %if.then.i.i
  ret void
}

Thanks for reporting this.

carlopi commented 1 year ago

This is indeed due to slightly different handling between clang and clang++ for the mustprogress attribute (and this in turn reflects the fact that such an infinite loop in C++ is UB while in C is valid).

In general /opt/cheerp/bin/clang++ is more seriously tested and the main target for us, and this might not be the only case where we assume that degenerates CFG such as this ones have to be optimized out by a previous compilation stage.

carlopi commented 1 year ago

Thanks for the test case, we have a solution, will be merged with the next batch.

carlopi commented 1 year ago

Fixed + merged. Thanks!