2015年4月28日 星期二

avoid implicit type conversion in ternary operation

failed case on llvm 3.6

uint convert_uint_sat_rte(float x);

int main() {

  float x1;

  x1 = 9223373136366403584.000000f;
  uint r1 = convert_uint_sat_rte(x1);
  printf("%x\n", r1);
}
uint convert_uint_sat_rte(float x)
{
  return bigger(x) ? 0xffffffff: (small(x) ? 0 : rintf(x));
}


clang 3.6 + O2 get blow IR


define i32 @convert_uint_sat_rte(float %x) #0 {
entry:
  %call = call fastcc i32 @bigger(float %x)
  %tobool = icmp ne i32 %call, 0
  br i1 %tobool, label %cond.end6, label %cond.false
cond.false:                                       ; preds = %entry
  %call1 = call fastcc i32 @small(float %x)
  %tobool2 = icmp ne i32 %call1, 0
  br i1 %tobool2, label %cond.end6, label %cond.false4
cond.false4:                                      ; preds = %cond.false
  %call5 = call fastcc float @mce_rintf(float %x)
  br label %cond.end6
cond.end6:                                        ; preds = %cond.false4, %cond.false, %entry
  %cond7 = phi float [ 0x41F0000000000000, %entry ], [ %call5, %cond.false4 ], [ 0.000000e+00, %cond.false ]
  %conv = fptoui float %cond7 to i32
  ret i32 %conv

}

instructionCommbing will optimize phi instruction as below

cond.end6:                                        ; preds = %cond.false4, %cond.false, %entry
%cond7 = phi float [ fptoui(0x41F0000000000000), %entry ], [fptoui (call5), %cond.false4 ], [fptoui(0.000000e+00, %cond.false ]
  ret i32 %cond7

but 0x41F0000000000000 is bigger than float representation so result phi is


%cond7 = phi i32 [ undef, %entry ], [ %phitmp, %mce_rintf.exit ], [ 0, %cond.false ]


undef will generate failed code, 
3.5 is fine because without this patch

WHY:
in C99, float 's rank is > any integer, so in this case



return bigger(x) ? 0xffffffff: (small(x) ? 0 : rintf(x));

0 and 0xfffffffff will promoted as float , but 0xfffffffff is too big (0x41F0000000000000 = 0xffffffff in double type representation)
rewrite as blow code will got correct result with O2 ( but it's strange O0 can get correct result)



return bigger(x) ? 0xffffffff: (small(x) ? 0 : (uint) rintf(x));

gcc 4.9 default open -fdelete-null-pointer-checks


#include
int foo(int *a, int size){

memset (a, 0, size);
if (a != NULL)
   return 1;
else
   return 0;
}



this function always return 1

gcc 4.9 default opens -fdelete-null-pointer-checks
but memset's first funtion parameters is "nonull attribute", so else section will be removed