1 //! Module to handle integer operations. 2 //! This module exists because some integer types are not supported on some gcc platforms, e.g. 3 //! 128-bit integers on 32-bit platforms and thus require to be handled manually. 4 5 use std::convert::TryFrom; 6 7 use gccjit::{ComparisonOp, FunctionType, RValue, ToRValue, Type, UnaryOp, BinaryOp}; 8 use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; 9 use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp}; 10 use rustc_middle::ty::Ty; 11 12 use crate::builder::ToGccComp; 13 use crate::{builder::Builder, common::{SignType, TypeReflection}, context::CodegenCx}; 14 15 impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { gcc_urem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>16 pub fn gcc_urem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 17 // 128-bit unsigned %: __umodti3 18 self.multiplicative_operation(BinaryOp::Modulo, "mod", false, a, b) 19 } 20 gcc_srem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>21 pub fn gcc_srem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 22 // 128-bit signed %: __modti3 23 self.multiplicative_operation(BinaryOp::Modulo, "mod", true, a, b) 24 } 25 gcc_not(&self, a: RValue<'gcc>) -> RValue<'gcc>26 pub fn gcc_not(&self, a: RValue<'gcc>) -> RValue<'gcc> { 27 let typ = a.get_type(); 28 if self.is_native_int_type_or_bool(typ) { 29 let operation = 30 if typ.is_bool() { 31 UnaryOp::LogicalNegate 32 } 33 else { 34 UnaryOp::BitwiseNegate 35 }; 36 self.cx.context.new_unary_op(None, operation, typ, a) 37 } 38 else { 39 // TODO(antoyo): use __negdi2 and __negti2 instead? 40 let element_type = typ.dyncast_array().expect("element type"); 41 let values = [ 42 self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.low(a)), 43 self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.high(a)), 44 ]; 45 self.cx.context.new_array_constructor(None, typ, &values) 46 } 47 } 48 gcc_neg(&self, a: RValue<'gcc>) -> RValue<'gcc>49 pub fn gcc_neg(&self, a: RValue<'gcc>) -> RValue<'gcc> { 50 let a_type = a.get_type(); 51 if self.is_native_int_type(a_type) { 52 self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) 53 } 54 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]) 58 } 59 } 60 gcc_and(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>61 pub fn gcc_and(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 62 self.cx.bitwise_operation(BinaryOp::BitwiseAnd, a, b) 63 } 64 gcc_lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>65 pub fn gcc_lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 66 let a_type = a.get_type(); 67 let b_type = b.get_type(); 68 let a_native = self.is_native_int_type(a_type); 69 let b_native = self.is_native_int_type(b_type); 70 if a_native && b_native { 71 // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by a signed number. 72 // TODO(antoyo): cast to unsigned to do a logical shift if that does not work. 73 if a_type.is_signed(self) != b_type.is_signed(self) { 74 let b = self.context.new_cast(None, b, a_type); 75 a >> b 76 } 77 else { 78 a >> b 79 } 80 } 81 else if a_native && !b_native { 82 self.gcc_lshr(a, self.gcc_int_cast(b, a_type)) 83 } 84 else { 85 // NOTE: we cannot use the lshr builtin because it's calling hi() (to get the most 86 // significant half of the number) which uses lshr. 87 88 let native_int_type = a_type.dyncast_array().expect("get element type"); 89 90 let func = self.current_func(); 91 let then_block = func.new_block("then"); 92 let else_block = func.new_block("else"); 93 let after_block = func.new_block("after"); 94 let b0_block = func.new_block("b0"); 95 let actual_else_block = func.new_block("actual_else"); 96 97 let result = func.new_local(None, a_type, "shiftResult"); 98 99 let sixty_four = self.gcc_int(native_int_type, 64); 100 let sixty_three = self.gcc_int(native_int_type, 63); 101 let zero = self.gcc_zero(native_int_type); 102 let b = self.gcc_int_cast(b, native_int_type); 103 let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero); 104 self.llbb().end_with_conditional(None, condition, then_block, else_block); 105 106 // TODO(antoyo): take endianness into account. 107 let shift_value = self.gcc_sub(b, sixty_four); 108 let high = self.high(a); 109 let sign = 110 if a_type.is_signed(self) { 111 high >> sixty_three 112 } 113 else { 114 zero 115 }; 116 let values = [ 117 high >> shift_value, 118 sign, 119 ]; 120 let array_value = self.context.new_array_constructor(None, a_type, &values); 121 then_block.add_assignment(None, result, array_value); 122 then_block.end_with_jump(None, after_block); 123 124 let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero); 125 else_block.end_with_conditional(None, condition, b0_block, actual_else_block); 126 127 b0_block.add_assignment(None, result, a); 128 b0_block.end_with_jump(None, after_block); 129 130 let shift_value = self.gcc_sub(sixty_four, b); 131 // NOTE: cast low to its unsigned type in order to perform a logical right shift. 132 let unsigned_type = native_int_type.to_unsigned(&self.cx); 133 let casted_low = self.context.new_cast(None, self.low(a), unsigned_type); 134 let shifted_low = casted_low >> self.context.new_cast(None, b, unsigned_type); 135 let shifted_low = self.context.new_cast(None, shifted_low, native_int_type); 136 let values = [ 137 (high << shift_value) | shifted_low, 138 high >> b, 139 ]; 140 let array_value = self.context.new_array_constructor(None, a_type, &values); 141 actual_else_block.add_assignment(None, result, array_value); 142 actual_else_block.end_with_jump(None, after_block); 143 144 // NOTE: since jumps were added in a place rustc does not expect, the current block in the 145 // state need to be updated. 146 self.switch_to_block(after_block); 147 148 result.to_rvalue() 149 } 150 } 151 additive_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc>152 fn additive_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { 153 let a_type = a.get_type(); 154 let b_type = b.get_type(); 155 if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) { 156 if a_type != b_type { 157 if a_type.is_vector() { 158 // Vector types need to be bitcast. 159 // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. 160 b = self.context.new_bitcast(None, b, a.get_type()); 161 } 162 else { 163 b = self.context.new_cast(None, b, a.get_type()); 164 } 165 } 166 self.context.new_binary_op(None, operation, a_type, a, b) 167 } 168 else { 169 let signed = a_type.is_compatible_with(self.i128_type); 170 let func_name = 171 match (operation, signed) { 172 (BinaryOp::Plus, true) => "__rust_i128_add", 173 (BinaryOp::Plus, false) => "__rust_u128_add", 174 (BinaryOp::Minus, true) => "__rust_i128_sub", 175 (BinaryOp::Minus, false) => "__rust_u128_sub", 176 _ => unreachable!("unexpected additive operation {:?}", operation), 177 }; 178 let param_a = self.context.new_parameter(None, a_type, "a"); 179 let param_b = self.context.new_parameter(None, b_type, "b"); 180 let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); 181 self.context.new_call(None, func, &[a, b]) 182 } 183 } 184 gcc_add(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>185 pub fn gcc_add(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 186 self.additive_operation(BinaryOp::Plus, a, b) 187 } 188 gcc_mul(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>189 pub fn gcc_mul(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 190 self.multiplicative_operation(BinaryOp::Mult, "mul", true, a, b) 191 } 192 gcc_sub(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>193 pub fn gcc_sub(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 194 self.additive_operation(BinaryOp::Minus, a, b) 195 } 196 multiplicative_operation(&self, operation: BinaryOp, operation_name: &str, signed: bool, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>197 fn multiplicative_operation(&self, operation: BinaryOp, operation_name: &str, signed: bool, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 198 let a_type = a.get_type(); 199 let b_type = b.get_type(); 200 if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) { 201 self.context.new_binary_op(None, operation, a_type, a, b) 202 } 203 else { 204 let sign = 205 if signed { 206 "" 207 } 208 else { 209 "u" 210 }; 211 let func_name = format!("__{}{}ti3", sign, operation_name); 212 let param_a = self.context.new_parameter(None, a_type, "a"); 213 let param_b = self.context.new_parameter(None, b_type, "b"); 214 let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false); 215 self.context.new_call(None, func, &[a, b]) 216 } 217 } 218 gcc_sdiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>219 pub fn gcc_sdiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 220 // TODO(antoyo): check if the types are signed? 221 // 128-bit, signed: __divti3 222 // TODO(antoyo): convert the arguments to signed? 223 self.multiplicative_operation(BinaryOp::Divide, "div", true, a, b) 224 } 225 gcc_udiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>226 pub fn gcc_udiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 227 // 128-bit, unsigned: __udivti3 228 self.multiplicative_operation(BinaryOp::Divide, "div", false, a, b) 229 } 230 gcc_checked_binop(&self, oop: OverflowOp, typ: Ty<'_>, lhs: <Self as BackendTypes>::Value, rhs: <Self as BackendTypes>::Value) -> (<Self as BackendTypes>::Value, <Self as BackendTypes>::Value)231 pub fn gcc_checked_binop(&self, oop: OverflowOp, typ: Ty<'_>, lhs: <Self as BackendTypes>::Value, rhs: <Self as BackendTypes>::Value) -> (<Self as BackendTypes>::Value, <Self as BackendTypes>::Value) { 232 use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*}; 233 234 let new_kind = 235 match typ.kind() { 236 Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), 237 Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)), 238 t @ (Uint(_) | Int(_)) => t.clone(), 239 _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), 240 }; 241 242 // TODO(antoyo): remove duplication with intrinsic? 243 let name = 244 if self.is_native_int_type(lhs.get_type()) { 245 match oop { 246 OverflowOp::Add => 247 match new_kind { 248 Int(I8) => "__builtin_add_overflow", 249 Int(I16) => "__builtin_add_overflow", 250 Int(I32) => "__builtin_sadd_overflow", 251 Int(I64) => "__builtin_saddll_overflow", 252 Int(I128) => "__builtin_add_overflow", 253 254 Uint(U8) => "__builtin_add_overflow", 255 Uint(U16) => "__builtin_add_overflow", 256 Uint(U32) => "__builtin_uadd_overflow", 257 Uint(U64) => "__builtin_uaddll_overflow", 258 Uint(U128) => "__builtin_add_overflow", 259 260 _ => unreachable!(), 261 }, 262 OverflowOp::Sub => 263 match new_kind { 264 Int(I8) => "__builtin_sub_overflow", 265 Int(I16) => "__builtin_sub_overflow", 266 Int(I32) => "__builtin_ssub_overflow", 267 Int(I64) => "__builtin_ssubll_overflow", 268 Int(I128) => "__builtin_sub_overflow", 269 270 Uint(U8) => "__builtin_sub_overflow", 271 Uint(U16) => "__builtin_sub_overflow", 272 Uint(U32) => "__builtin_usub_overflow", 273 Uint(U64) => "__builtin_usubll_overflow", 274 Uint(U128) => "__builtin_sub_overflow", 275 276 _ => unreachable!(), 277 }, 278 OverflowOp::Mul => 279 match new_kind { 280 Int(I8) => "__builtin_mul_overflow", 281 Int(I16) => "__builtin_mul_overflow", 282 Int(I32) => "__builtin_smul_overflow", 283 Int(I64) => "__builtin_smulll_overflow", 284 Int(I128) => "__builtin_mul_overflow", 285 286 Uint(U8) => "__builtin_mul_overflow", 287 Uint(U16) => "__builtin_mul_overflow", 288 Uint(U32) => "__builtin_umul_overflow", 289 Uint(U64) => "__builtin_umulll_overflow", 290 Uint(U128) => "__builtin_mul_overflow", 291 292 _ => unreachable!(), 293 }, 294 } 295 } 296 else { 297 match new_kind { 298 Int(I128) | Uint(U128) => { 299 let func_name = 300 match oop { 301 OverflowOp::Add => 302 match new_kind { 303 Int(I128) => "__rust_i128_addo", 304 Uint(U128) => "__rust_u128_addo", 305 _ => unreachable!(), 306 }, 307 OverflowOp::Sub => 308 match new_kind { 309 Int(I128) => "__rust_i128_subo", 310 Uint(U128) => "__rust_u128_subo", 311 _ => unreachable!(), 312 }, 313 OverflowOp::Mul => 314 match new_kind { 315 Int(I128) => "__rust_i128_mulo", // TODO(antoyo): use __muloti4d instead? 316 Uint(U128) => "__rust_u128_mulo", 317 _ => unreachable!(), 318 }, 319 }; 320 let a_type = lhs.get_type(); 321 let b_type = rhs.get_type(); 322 let param_a = self.context.new_parameter(None, a_type, "a"); 323 let param_b = self.context.new_parameter(None, b_type, "b"); 324 let result_field = self.context.new_field(None, a_type, "result"); 325 let overflow_field = self.context.new_field(None, self.bool_type, "overflow"); 326 let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]); 327 let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false); 328 let result = self.context.new_call(None, func, &[lhs, rhs]); 329 let overflow = result.access_field(None, overflow_field); 330 let int_result = result.access_field(None, result_field); 331 return (int_result, overflow); 332 }, 333 _ => { 334 match oop { 335 OverflowOp::Mul => 336 match new_kind { 337 Int(I32) => "__mulosi4", 338 Int(I64) => "__mulodi4", 339 _ => unreachable!(), 340 }, 341 _ => unimplemented!("overflow operation for {:?}", new_kind), 342 } 343 } 344 } 345 }; 346 347 let intrinsic = self.context.get_builtin_function(&name); 348 let res = self.current_func() 349 // TODO(antoyo): is it correct to use rhs type instead of the parameter typ? 350 .new_local(None, rhs.get_type(), "binopResult") 351 .get_address(None); 352 let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None); 353 (res.dereference(None).to_rvalue(), overflow) 354 } 355 gcc_icmp(&self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc>356 pub fn gcc_icmp(&self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> { 357 let a_type = lhs.get_type(); 358 let b_type = rhs.get_type(); 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]); 373 let (op, limit) = 374 match op { 375 IntPredicate::IntEQ => { 376 return self.context.new_comparison(None, ComparisonOp::Equals, cmp, self.context.new_rvalue_one(self.int_type)); 377 }, 378 IntPredicate::IntNE => { 379 return self.context.new_comparison(None, ComparisonOp::NotEquals, cmp, self.context.new_rvalue_one(self.int_type)); 380 }, 381 IntPredicate::IntUGT => (ComparisonOp::Equals, 2), 382 IntPredicate::IntUGE => (ComparisonOp::GreaterThanEquals, 1), 383 IntPredicate::IntULT => (ComparisonOp::Equals, 0), 384 IntPredicate::IntULE => (ComparisonOp::LessThanEquals, 1), 385 IntPredicate::IntSGT => (ComparisonOp::Equals, 2), 386 IntPredicate::IntSGE => (ComparisonOp::GreaterThanEquals, 1), 387 IntPredicate::IntSLT => (ComparisonOp::Equals, 0), 388 IntPredicate::IntSLE => (ComparisonOp::LessThanEquals, 1), 389 }; 390 self.context.new_comparison(None, op, cmp, self.context.new_rvalue_from_int(self.int_type, limit)) 391 } 392 else if a_type.get_pointee().is_some() && b_type.get_pointee().is_some() { 393 // NOTE: gcc cannot compare pointers to different objects, but rustc does that, so cast them to usize. 394 lhs = self.context.new_bitcast(None, lhs, self.usize_type); 395 rhs = self.context.new_bitcast(None, rhs, self.usize_type); 396 self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) 397 } 398 else { 399 if a_type != b_type { 400 // NOTE: because libgccjit cannot compare function pointers. 401 if a_type.dyncast_function_ptr_type().is_some() && b_type.dyncast_function_ptr_type().is_some() { 402 lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer()); 403 rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer()); 404 } 405 // NOTE: hack because we try to cast a vector type to the same vector type. 406 else if format!("{:?}", a_type) != format!("{:?}", b_type) { 407 rhs = self.context.new_cast(None, rhs, a_type); 408 } 409 } 410 self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) 411 } 412 } 413 gcc_xor(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>414 pub fn gcc_xor(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 415 let a_type = a.get_type(); 416 let b_type = b.get_type(); 417 if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) { 418 a ^ b 419 } 420 else { 421 let values = [ 422 self.low(a) ^ self.low(b), 423 self.high(a) ^ self.high(b), 424 ]; 425 self.context.new_array_constructor(None, a_type, &values) 426 } 427 } 428 gcc_shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>429 pub fn gcc_shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 430 let a_type = a.get_type(); 431 let b_type = b.get_type(); 432 let a_native = self.is_native_int_type(a_type); 433 let b_native = self.is_native_int_type(b_type); 434 if a_native && b_native { 435 // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number. 436 if a_type.is_unsigned(self) && b_type.is_signed(self) { 437 let a = self.context.new_cast(None, a, b_type); 438 let result = a << b; 439 self.context.new_cast(None, result, a_type) 440 } 441 else if a_type.is_signed(self) && b_type.is_unsigned(self) { 442 let b = self.context.new_cast(None, b, a_type); 443 a << b 444 } 445 else { 446 a << b 447 } 448 } 449 else if a_native && !b_native { 450 self.gcc_shl(a, self.gcc_int_cast(b, a_type)) 451 } 452 else { 453 // NOTE: we cannot use the ashl builtin because it's calling widen_hi() which uses ashl. 454 let native_int_type = a_type.dyncast_array().expect("get element type"); 455 456 let func = self.current_func(); 457 let then_block = func.new_block("then"); 458 let else_block = func.new_block("else"); 459 let after_block = func.new_block("after"); 460 let b0_block = func.new_block("b0"); 461 let actual_else_block = func.new_block("actual_else"); 462 463 let result = func.new_local(None, a_type, "shiftResult"); 464 465 let b = self.gcc_int_cast(b, native_int_type); 466 let sixty_four = self.gcc_int(native_int_type, 64); 467 let zero = self.gcc_zero(native_int_type); 468 let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero); 469 self.llbb().end_with_conditional(None, condition, then_block, else_block); 470 471 // TODO(antoyo): take endianness into account. 472 let values = [ 473 zero, 474 self.low(a) << (b - sixty_four), 475 ]; 476 let array_value = self.context.new_array_constructor(None, a_type, &values); 477 then_block.add_assignment(None, result, array_value); 478 then_block.end_with_jump(None, after_block); 479 480 let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero); 481 else_block.end_with_conditional(None, condition, b0_block, actual_else_block); 482 483 b0_block.add_assignment(None, result, a); 484 b0_block.end_with_jump(None, after_block); 485 486 // NOTE: cast low to its unsigned type in order to perform a logical right shift. 487 let unsigned_type = native_int_type.to_unsigned(&self.cx); 488 let casted_low = self.context.new_cast(None, self.low(a), unsigned_type); 489 let shift_value = self.context.new_cast(None, sixty_four - b, unsigned_type); 490 let high_low = self.context.new_cast(None, casted_low >> shift_value, native_int_type); 491 let values = [ 492 self.low(a) << b, 493 (self.high(a) << b) | high_low, 494 ]; 495 496 let array_value = self.context.new_array_constructor(None, a_type, &values); 497 actual_else_block.add_assignment(None, result, array_value); 498 actual_else_block.end_with_jump(None, after_block); 499 500 // NOTE: since jumps were added in a place rustc does not expect, the current block in the 501 // state need to be updated. 502 self.switch_to_block(after_block); 503 504 result.to_rvalue() 505 } 506 } 507 gcc_bswap(&mut self, mut arg: RValue<'gcc>, width: u64) -> RValue<'gcc>508 pub fn gcc_bswap(&mut self, mut arg: RValue<'gcc>, width: u64) -> RValue<'gcc> { 509 let arg_type = arg.get_type(); 510 if !self.is_native_int_type(arg_type) { 511 let native_int_type = arg_type.dyncast_array().expect("get element type"); 512 let lsb = self.context.new_array_access(None, arg, self.context.new_rvalue_from_int(self.int_type, 0)).to_rvalue(); 513 let swapped_lsb = self.gcc_bswap(lsb, width / 2); 514 let swapped_lsb = self.context.new_cast(None, swapped_lsb, native_int_type); 515 let msb = self.context.new_array_access(None, arg, self.context.new_rvalue_from_int(self.int_type, 1)).to_rvalue(); 516 let swapped_msb = self.gcc_bswap(msb, width / 2); 517 let swapped_msb = self.context.new_cast(None, swapped_msb, native_int_type); 518 519 // NOTE: we also need to swap the two elements here, in addition to swapping inside 520 // the elements themselves like done above. 521 return self.context.new_array_constructor(None, arg_type, &[swapped_msb, swapped_lsb]); 522 } 523 524 // TODO(antoyo): check if it's faster to use string literals and a 525 // match instead of format!. 526 let bswap = self.cx.context.get_builtin_function(&format!("__builtin_bswap{}", width)); 527 // FIXME(antoyo): this cast should not be necessary. Remove 528 // when having proper sized integer types. 529 let param_type = bswap.get_param(0).to_rvalue().get_type(); 530 if param_type != arg_type { 531 arg = self.bitcast(arg, param_type); 532 } 533 self.cx.context.new_call(None, bswap, &[arg]) 534 } 535 } 536 537 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { gcc_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc>538 pub fn gcc_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { 539 if self.is_native_int_type_or_bool(typ) { 540 self.context.new_rvalue_from_long(typ, i64::try_from(int).expect("i64::try_from")) 541 } 542 else { 543 // NOTE: set the sign in high. 544 self.from_low_high(typ, int, -(int.is_negative() as i64)) 545 } 546 } 547 gcc_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc>548 pub fn gcc_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> { 549 if self.is_native_int_type_or_bool(typ) { 550 self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64) 551 } 552 else { 553 self.from_low_high(typ, int as i64, 0) 554 } 555 } 556 gcc_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc>557 pub fn gcc_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> { 558 let low = num as u64; 559 let high = (num >> 64) as u64; 560 if num >> 64 != 0 { 561 // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()? 562 if self.is_native_int_type(typ) { 563 let low = self.context.new_rvalue_from_long(self.u64_type, low as i64); 564 let high = self.context.new_rvalue_from_long(typ, high as i64); 565 566 let sixty_four = self.context.new_rvalue_from_long(typ, 64); 567 let shift = high << sixty_four; 568 shift | self.context.new_cast(None, low, typ) 569 } 570 else { 571 self.from_low_high(typ, low as i64, high as i64) 572 } 573 } 574 else if typ.is_i128(self) { 575 let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64); 576 self.gcc_int_cast(num, typ) 577 } 578 else { 579 self.gcc_uint(typ, num as u64) 580 } 581 } 582 gcc_zero(&self, typ: Type<'gcc>) -> RValue<'gcc>583 pub fn gcc_zero(&self, typ: Type<'gcc>) -> RValue<'gcc> { 584 if self.is_native_int_type_or_bool(typ) { 585 self.context.new_rvalue_zero(typ) 586 } 587 else { 588 self.from_low_high(typ, 0, 0) 589 } 590 } 591 gcc_int_width(&self, typ: Type<'gcc>) -> u64592 pub fn gcc_int_width(&self, typ: Type<'gcc>) -> u64 { 593 if self.is_native_int_type_or_bool(typ) { 594 typ.get_size() as u64 * 8 595 } 596 else { 597 // NOTE: the only unsupported types are u128 and i128. 598 128 599 } 600 } 601 bitwise_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc>602 fn bitwise_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { 603 let a_type = a.get_type(); 604 let b_type = b.get_type(); 605 let a_native = self.is_native_int_type_or_bool(a_type); 606 let b_native = self.is_native_int_type_or_bool(b_type); 607 if a_type.is_vector() && b_type.is_vector() { 608 self.context.new_binary_op(None, operation, a_type, a, b) 609 } 610 else if a_native && b_native { 611 if a_type != b_type { 612 b = self.context.new_cast(None, b, a_type); 613 } 614 self.context.new_binary_op(None, operation, a_type, a, b) 615 } 616 else { 617 assert!(!a_native && !b_native, "both types should either be native or non-native for or operation"); 618 let native_int_type = a_type.dyncast_array().expect("get element type"); 619 let values = [ 620 self.context.new_binary_op(None, operation, native_int_type, self.low(a), self.low(b)), 621 self.context.new_binary_op(None, operation, native_int_type, self.high(a), self.high(b)), 622 ]; 623 self.context.new_array_constructor(None, a_type, &values) 624 } 625 } 626 gcc_or(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>627 pub fn gcc_or(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { 628 self.bitwise_operation(BinaryOp::BitwiseOr, a, b) 629 } 630 631 // TODO(antoyo): can we use https://github.com/rust-lang/compiler-builtins/blob/master/src/int/mod.rs#L379 instead? gcc_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>632 pub fn gcc_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { 633 let value_type = value.get_type(); 634 if self.is_native_int_type_or_bool(dest_typ) && self.is_native_int_type_or_bool(value_type) { 635 self.context.new_cast(None, value, dest_typ) 636 } 637 else if self.is_native_int_type_or_bool(dest_typ) { 638 self.context.new_cast(None, self.low(value), dest_typ) 639 } 640 else if self.is_native_int_type_or_bool(value_type) { 641 let dest_element_type = dest_typ.dyncast_array().expect("get element type"); 642 643 // NOTE: set the sign of the value. 644 let zero = self.context.new_rvalue_zero(value_type); 645 let is_negative = self.context.new_comparison(None, ComparisonOp::LessThan, value, zero); 646 let is_negative = self.gcc_int_cast(is_negative, dest_element_type); 647 let values = [ 648 self.context.new_cast(None, value, dest_element_type), 649 self.context.new_unary_op(None, UnaryOp::Minus, dest_element_type, is_negative), 650 ]; 651 self.context.new_array_constructor(None, dest_typ, &values) 652 } 653 else { 654 // Since u128 and i128 are the only types that can be unsupported, we know the type of 655 // value and the destination type have the same size, so a bitcast is fine. 656 657 // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. 658 self.context.new_bitcast(None, value, dest_typ) 659 } 660 } 661 int_to_float_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>662 fn int_to_float_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { 663 let value_type = value.get_type(); 664 if self.is_native_int_type_or_bool(value_type) { 665 return self.context.new_cast(None, value, dest_typ); 666 } 667 668 let name_suffix = 669 match self.type_kind(dest_typ) { 670 TypeKind::Float => "tisf", 671 TypeKind::Double => "tidf", 672 kind => panic!("cannot cast a non-native integer to type {:?}", kind), 673 }; 674 let sign = 675 if signed { 676 "" 677 } 678 else { 679 "un" 680 }; 681 let func_name = format!("__float{}{}", sign, name_suffix); 682 let param = self.context.new_parameter(None, value_type, "n"); 683 let func = self.context.new_function(None, FunctionType::Extern, dest_typ, &[param], func_name, false); 684 self.context.new_call(None, func, &[value]) 685 } 686 gcc_int_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>687 pub fn gcc_int_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { 688 self.int_to_float_cast(true, value, dest_typ) 689 } 690 gcc_uint_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>691 pub fn gcc_uint_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { 692 self.int_to_float_cast(false, value, dest_typ) 693 } 694 float_to_int_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>695 fn float_to_int_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { 696 let value_type = value.get_type(); 697 if self.is_native_int_type_or_bool(dest_typ) { 698 return self.context.new_cast(None, value, dest_typ); 699 } 700 701 let name_suffix = 702 match self.type_kind(value_type) { 703 TypeKind::Float => "sfti", 704 TypeKind::Double => "dfti", 705 kind => panic!("cannot cast a {:?} to non-native integer", kind), 706 }; 707 let sign = 708 if signed { 709 "" 710 } 711 else { 712 "uns" 713 }; 714 let func_name = format!("__fix{}{}", sign, name_suffix); 715 let param = self.context.new_parameter(None, value_type, "n"); 716 let func = self.context.new_function(None, FunctionType::Extern, dest_typ, &[param], func_name, false); 717 self.context.new_call(None, func, &[value]) 718 } 719 gcc_float_to_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>720 pub fn gcc_float_to_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { 721 self.float_to_int_cast(true, value, dest_typ) 722 } 723 gcc_float_to_uint_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>724 pub fn gcc_float_to_uint_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { 725 self.float_to_int_cast(false, value, dest_typ) 726 } 727 high(&self, value: RValue<'gcc>) -> RValue<'gcc>728 fn high(&self, value: RValue<'gcc>) -> RValue<'gcc> { 729 self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, 1)) 730 .to_rvalue() 731 } 732 low(&self, value: RValue<'gcc>) -> RValue<'gcc>733 fn low(&self, value: RValue<'gcc>) -> RValue<'gcc> { 734 self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, 0)) 735 .to_rvalue() 736 } 737 from_low_high(&self, typ: Type<'gcc>, low: i64, high: i64) -> RValue<'gcc>738 fn from_low_high(&self, typ: Type<'gcc>, low: i64, high: i64) -> RValue<'gcc> { 739 let native_int_type = typ.dyncast_array().expect("get element type"); 740 let values = [ 741 self.context.new_rvalue_from_long(native_int_type, low), 742 self.context.new_rvalue_from_long(native_int_type, high), 743 ]; 744 self.context.new_array_constructor(None, typ, &values) 745 } 746 } 747