@@ -36,7 +36,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
36
36
self . cx . context . new_unary_op ( None , operation, typ, a)
37
37
}
38
38
else {
39
- // TODO(antoyo): use __negdi2 and __negti2 instead?
40
39
let element_type = typ. dyncast_array ( ) . expect ( "element type" ) ;
41
40
let values = [
42
41
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> {
52
51
self . cx . context . new_unary_op ( None , UnaryOp :: Minus , a. get_type ( ) , a)
53
52
}
54
53
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 ) )
58
55
}
59
56
}
60
57
@@ -353,23 +350,63 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
353
350
( res. dereference ( None ) . to_rvalue ( ) , overflow)
354
351
}
355
352
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 > {
357
354
let a_type = lhs. get_type ( ) ;
358
355
let b_type = rhs. get_type ( ) ;
359
356
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 ( ) ;
373
410
let ( op, limit) =
374
411
match op {
375
412
IntPredicate :: IntEQ => {
0 commit comments