@@ -36,7 +36,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
3636 self . cx . context . new_unary_op ( None , operation, typ, a)
3737 }
3838 else {
39- // TODO(antoyo): use __negdi2 and __negti2 instead?
4039 let element_type = typ. dyncast_array ( ) . expect ( "element type" ) ;
4140 let values = [
4241 self . cx . context . new_unary_op ( None , UnaryOp :: BitwiseNegate , element_type, self . low ( a) ) ,
@@ -52,9 +51,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
5251 self . cx . context . new_unary_op ( None , UnaryOp :: Minus , a. get_type ( ) , a)
5352 }
5453 else {
55- let param_a = self . context . new_parameter ( None , a_type, "a" ) ;
56- let func = self . context . new_function ( None , FunctionType :: Extern , a_type, & [ param_a] , "__negti2" , false ) ;
57- self . context . new_call ( None , func, & [ a] )
54+ self . gcc_add ( self . gcc_not ( a) , self . gcc_int ( a_type, 1 ) )
5855 }
5956 }
6057
@@ -353,23 +350,63 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
353350 ( res. dereference ( None ) . to_rvalue ( ) , overflow)
354351 }
355352
356- pub fn gcc_icmp ( & self , op : IntPredicate , mut lhs : RValue < ' gcc > , mut rhs : RValue < ' gcc > ) -> RValue < ' gcc > {
353+ pub fn gcc_icmp ( & mut self , op : IntPredicate , mut lhs : RValue < ' gcc > , mut rhs : RValue < ' gcc > ) -> RValue < ' gcc > {
357354 let a_type = lhs. get_type ( ) ;
358355 let b_type = rhs. get_type ( ) ;
359356 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] ) ;
357+ // This algorithm is based on compiler-rt's __cmpti2:
358+ // https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/cmpti2.c#L21
359+ let result = self . current_func ( ) . new_local ( None , self . int_type , "icmp_result" ) ;
360+ let block1 = self . current_func ( ) . new_block ( "block1" ) ;
361+ let block2 = self . current_func ( ) . new_block ( "block2" ) ;
362+ let block3 = self . current_func ( ) . new_block ( "block3" ) ;
363+ let block4 = self . current_func ( ) . new_block ( "block4" ) ;
364+ let block5 = self . current_func ( ) . new_block ( "block5" ) ;
365+ let block6 = self . current_func ( ) . new_block ( "block6" ) ;
366+ let block7 = self . current_func ( ) . new_block ( "block7" ) ;
367+ let block8 = self . current_func ( ) . new_block ( "block8" ) ;
368+ let after = self . current_func ( ) . new_block ( "after" ) ;
369+
370+ let native_int_type = a_type. dyncast_array ( ) . expect ( "get element type" ) ;
371+ // NOTE: cast low to its unsigned type in order to perform a comparison correctly (e.g.
372+ // the sign is only on high).
373+ let unsigned_type = native_int_type. to_unsigned ( & self . cx ) ;
374+
375+ let lhs_low = self . context . new_cast ( None , self . low ( lhs) , unsigned_type) ;
376+ let rhs_low = self . context . new_cast ( None , self . low ( rhs) , unsigned_type) ;
377+
378+ let condition = self . context . new_comparison ( None , ComparisonOp :: LessThan , self . high ( lhs) , self . high ( rhs) ) ;
379+ self . llbb ( ) . end_with_conditional ( None , condition, block1, block2) ;
380+
381+ block1. add_assignment ( None , result, self . context . new_rvalue_zero ( self . int_type ) ) ;
382+ block1. end_with_jump ( None , after) ;
383+
384+ let condition = self . context . new_comparison ( None , ComparisonOp :: GreaterThan , self . high ( lhs) , self . high ( rhs) ) ;
385+ block2. end_with_conditional ( None , condition, block3, block4) ;
386+
387+ block3. add_assignment ( None , result, self . context . new_rvalue_from_int ( self . int_type , 2 ) ) ;
388+ block3. end_with_jump ( None , after) ;
389+
390+ let condition = self . context . new_comparison ( None , ComparisonOp :: LessThan , lhs_low, rhs_low) ;
391+ block4. end_with_conditional ( None , condition, block5, block6) ;
392+
393+ block5. add_assignment ( None , result, self . context . new_rvalue_zero ( self . int_type ) ) ;
394+ block5. end_with_jump ( None , after) ;
395+
396+ let condition = self . context . new_comparison ( None , ComparisonOp :: GreaterThan , lhs_low, rhs_low) ;
397+ block6. end_with_conditional ( None , condition, block7, block8) ;
398+
399+ block7. add_assignment ( None , result, self . context . new_rvalue_from_int ( self . int_type , 2 ) ) ;
400+ block7. end_with_jump ( None , after) ;
401+
402+ block8. add_assignment ( None , result, self . context . new_rvalue_one ( self . int_type ) ) ;
403+ block8. end_with_jump ( None , after) ;
404+
405+ // NOTE: since jumps were added in a place rustc does not expect, the current block in the
406+ // state need to be updated.
407+ self . switch_to_block ( after) ;
408+
409+ let cmp = result. to_rvalue ( ) ;
373410 let ( op, limit) =
374411 match op {
375412 IntPredicate :: IntEQ => {
0 commit comments