<div dir="ltr"><div><div><div><div><div><div><div><div>I'm writing a front end for an existing interpreted language with slightly odd semantics for primitive values.<br></div>Similar to the values in a database table, any value could be null, even for non-pointer types.<br>
</div>For example a boolean variable could be true, false, or null.<br></div><div>To model this behaviour, I'm passing an {i1, [type]} around for every numeric type. And using insertvalue / extractvalue all over the place.<br>
<br></div>So when compiling this simple CS example;<br><br>function long fib (long al_x)<br>long ll_i=0, ll_ret=0, ll_last=0, ll_last2=1<br><br>if isnull(al_x) then<br> return al_x<br>end if<br><br>ll_i=1<br>do while ll_i<=al_x<br>
ll_ret=ll_last+ll_last2<br> ll_last2=ll_last<br> ll_last=ll_ret<br> ll_i++<br>loop<br>return ll_ret<br>end function<br><br></div>With the following function passes;<br> FunctionPasses->add(new DataLayout(*JITEngine->getDataLayout()));<br>
FunctionPasses->add(createBasicAliasAnalysisPass());<br> FunctionPasses->add(createPromoteMemoryToRegisterPass());<br> FunctionPasses->add(createInstructionCombiningPass());<br> FunctionPasses->add(createReassociatePass());<br>
FunctionPasses->add(createGVNPass());<br> FunctionPasses->add(createCFGSimplificationPass());<br><br></div>Which does a pretty good job of cleaning up most of the messy & verbose code generated by my front end.<br>
<br></div>I end up with the following bitcode;<br><br>define x86_stdcallcc { i1, i32 } @fib({ i1, i32 } %arg_al_x) {<br>entry:<br> %"3_4" = extractvalue { i1, i32 } %arg_al_x, 0<br> br i1 %"3_4", label %Line15_Offset120, label %Line8_Offset38<br>
<br>Line8_Offset38: ; preds = %Line9_Offset52, %entry<br> %ll_last2.0 = phi { i1, i32 } [ %ll_last.0, %Line9_Offset52 ], [ { i1 false, i32 1 }, %entry ]<br> %ll_last.0 = phi { i1, i32 } [ %"9_64_composed", %Line9_Offset52 ], [ zeroinitializer, %entry ]<br>
%ll_i.0 = phi { i1, i32 } [ %"12_98", %Line9_Offset52 ], [ { i1 false, i32 1 }, %entry ]<br> %"8_38_isnull" = extractvalue { i1, i32 } %ll_i.0, 0<br> %"8_38_value" = extractvalue { i1, i32 } %ll_i.0, 1<br>
%"8_42_value" = extractvalue { i1, i32 } %arg_al_x, 1<br> %"8_46_value" = icmp sle i32 %"8_38_value", %"8_42_value"<br> %"8_48_not_null" = xor i1 %"8_38_isnull", true<br>
%"8_48_and_not_null" = and i1 %"8_46_value", %"8_48_not_null"<br> br i1 %"8_48_and_not_null", label %Line9_Offset52, label %Line15_Offset120<br><br>Line9_Offset52: ; preds = %Line8_Offset38<br>
%"9_60_isnull" = extractvalue { i1, i32 } %ll_last2.0, 0<br> %"9_56_isnull" = extractvalue { i1, i32 } %ll_last.0, 0<br> %"9_64_isnull" = or i1 %"9_56_isnull", %"9_60_isnull"<br>
%"9_56_value" = extractvalue { i1, i32 } %ll_last.0, 1<br> %"9_60_value" = extractvalue { i1, i32 } %ll_last2.0, 1<br> %"9_64" = add i32 %"9_56_value", %"9_60_value"<br>
%0 = insertvalue { i1, i32 } zeroinitializer, i1 %"9_64_isnull", 0<br> %"9_64_composed" = insertvalue { i1, i32 } %0, i32 %"9_64", 1<br> %"12_98_value" = add i32 %"8_38_value", 1<br>
%1 = insertvalue { i1, i32 } zeroinitializer, i1 %"8_38_isnull", 0<br> %"12_98" = insertvalue { i1, i32 } %1, i32 %"12_98_value", 1<br> br label %Line8_Offset38<br><br>Line15_Offset120: ; preds = %Line8_Offset38, %entry<br>
%_return_value.0 = phi { i1, i32 } [ %arg_al_x, %entry ], [ %ll_last.0, %Line8_Offset38 ]<br> ret { i1, i32 } %_return_value.0<br>}<br><br></div>None of the local variables in this example can ever be null. Each of these extractvalue expressions will always evaluate to i1 0;<br>
<br> %"8_38_isnull" = extractvalue { i1, i32 } %ll_i.0, 0<br> %"9_60_isnull" = extractvalue { i1, i32 } %ll_last2.0, 0<br> %"9_56_isnull" = extractvalue { i1, i32 } %ll_last.0, 0<br><br></div>
Is there an existing function pass I could add that would clean this up? Or is this example just slightly too complex?<br></div>