@@ -353,23 +353,63 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
353353 ( res. dereference ( None ) . to_rvalue ( ) , overflow)
354354 }
355355
356- pub fn gcc_icmp ( & self , op : IntPredicate , mut lhs : RValue < ' gcc > , mut rhs : RValue < ' gcc > ) -> RValue < ' gcc > {
356+ pub fn gcc_icmp ( & mut self , op : IntPredicate , mut lhs : RValue < ' gcc > , mut rhs : RValue < ' gcc > ) -> RValue < ' gcc > {
357357 let a_type = lhs. get_type ( ) ;
358358 let b_type = rhs. get_type ( ) ;
359359 if self . is_non_native_int_type ( a_type) || self . is_non_native_int_type ( b_type) {
360- let signed = a_type. is_compatible_with ( self . i128_type ) ;
361- let sign =
362- if signed {
363- ""
364- }
365- else {
366- "u"
367- } ;
368- let func_name = format ! ( "__{}cmpti2" , sign) ;
369- let param_a = self . context . new_parameter ( None , a_type, "a" ) ;
370- let param_b = self . context . new_parameter ( None , b_type, "b" ) ;
371- let func = self . context . new_function ( None , FunctionType :: Extern , self . int_type , & [ param_a, param_b] , func_name, false ) ;
372- let cmp = self . context . new_call ( None , func, & [ lhs, rhs] ) ;
360+ // This algorithm is based on compiler-rt's __cmpti2:
361+ // https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/cmpti2.c#L21
362+ let result = self . current_func ( ) . new_local ( None , self . int_type , "icmp_result" ) ;
363+ let block1 = self . current_func ( ) . new_block ( "block1" ) ;
364+ let block2 = self . current_func ( ) . new_block ( "block2" ) ;
365+ let block3 = self . current_func ( ) . new_block ( "block3" ) ;
366+ let block4 = self . current_func ( ) . new_block ( "block4" ) ;
367+ let block5 = self . current_func ( ) . new_block ( "block5" ) ;
368+ let block6 = self . current_func ( ) . new_block ( "block6" ) ;
369+ let block7 = self . current_func ( ) . new_block ( "block7" ) ;
370+ let block8 = self . current_func ( ) . new_block ( "block8" ) ;
371+ let after = self . current_func ( ) . new_block ( "after" ) ;
372+
373+ let native_int_type = a_type. dyncast_array ( ) . expect ( "get element type" ) ;
374+ // NOTE: cast low to its unsigned type in order to perform a comparison correctly (e.g.
375+ // the sign is only on high).
376+ let unsigned_type = native_int_type. to_unsigned ( & self . cx ) ;
377+
378+ let lhs_low = self . context . new_cast ( None , self . low ( lhs) , unsigned_type) ;
379+ let rhs_low = self . context . new_cast ( None , self . low ( rhs) , unsigned_type) ;
380+
381+ let condition = self . context . new_comparison ( None , ComparisonOp :: LessThan , self . high ( lhs) , self . high ( rhs) ) ;
382+ self . llbb ( ) . end_with_conditional ( None , condition, block1, block2) ;
383+
384+ block1. add_assignment ( None , result, self . context . new_rvalue_zero ( self . int_type ) ) ;
385+ block1. end_with_jump ( None , after) ;
386+
387+ let condition = self . context . new_comparison ( None , ComparisonOp :: GreaterThan , self . high ( lhs) , self . high ( rhs) ) ;
388+ block2. end_with_conditional ( None , condition, block3, block4) ;
389+
390+ block3. add_assignment ( None , result, self . context . new_rvalue_from_int ( self . int_type , 2 ) ) ;
391+ block3. end_with_jump ( None , after) ;
392+
393+ let condition = self . context . new_comparison ( None , ComparisonOp :: LessThan , lhs_low, rhs_low) ;
394+ block4. end_with_conditional ( None , condition, block5, block6) ;
395+
396+ block5. add_assignment ( None , result, self . context . new_rvalue_zero ( self . int_type ) ) ;
397+ block5. end_with_jump ( None , after) ;
398+
399+ let condition = self . context . new_comparison ( None , ComparisonOp :: GreaterThan , lhs_low, rhs_low) ;
400+ block6. end_with_conditional ( None , condition, block7, block8) ;
401+
402+ block7. add_assignment ( None , result, self . context . new_rvalue_from_int ( self . int_type , 2 ) ) ;
403+ block7. end_with_jump ( None , after) ;
404+
405+ block8. add_assignment ( None , result, self . context . new_rvalue_one ( self . int_type ) ) ;
406+ block8. end_with_jump ( None , after) ;
407+
408+ // NOTE: since jumps were added in a place rustc does not expect, the current block in the
409+ // state need to be updated.
410+ self . switch_to_block ( after) ;
411+
412+ let cmp = result. to_rvalue ( ) ;
373413 let ( op, limit) =
374414 match op {
375415 IntPredicate :: IntEQ => {
0 commit comments