@@ -353,23 +353,63 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
353
353
( res. dereference ( None ) . to_rvalue ( ) , overflow)
354
354
}
355
355
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 > {
357
357
let a_type = lhs. get_type ( ) ;
358
358
let b_type = rhs. get_type ( ) ;
359
359
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 ( ) ;
373
413
let ( op, limit) =
374
414
match op {
375
415
IntPredicate :: IntEQ => {
0 commit comments