builder.copy_to_folder(&src, &target_bin_dir);
}
+ // Warn windows-gnu users that the bundled GCC cannot compile C files
+ builder.create(
+ &target_bin_dir.join("GCC-WARNING.txt"),
+ "gcc.exe contained in this folder cannot be used for compiling C files - it is only\
+ used as a linker. In order to be able to compile projects containing C code use\
+ the GCC provided by MinGW or Cygwin."
+ );
+
//Copy platform libs to platform-specific lib directory
let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
let mut abi = Abi::Aggregate { sized: true };
if tag.value.size(dl) == size {
abi = Abi::Scalar(tag.clone());
- } else if !tag.is_bool() {
- // HACK(nox): Blindly using ScalarPair for all tagged enums
- // where applicable leads to Option<u8> being handled as {i1, i8},
- // which later confuses SROA and some loop optimisations,
- // ultimately leading to the repeat-trusted-len test
- // failing. We make the trade-off of using ScalarPair only
- // for types where the tag isn't a boolean.
+ } else {
+ // Try to use a ScalarPair for all tagged enums.
let mut common_prim = None;
for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) {
let offsets = match layout_variant.fields {
PassMode::Ignore => continue,
PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
PassMode::Pair(..) => {
- llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0));
- llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1));
+ llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true));
+ llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
continue;
}
PassMode::Cast(cast) => cast.llvm_type(cx),
}
let (lldata, llextra) = result.unwrap();
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
- (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0)),
- bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1)))
+ (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0, true)),
+ bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1, true)))
}
_ => bug!("unsize_thin_ptr: called on bad types"),
}
pub fn to_immediate(bx: &Builder, val: ValueRef, layout: layout::TyLayout) -> ValueRef {
if let layout::Abi::Scalar(ref scalar) = layout.abi {
- if scalar.is_bool() {
- return bx.trunc(val, Type::i1(bx.cx));
- }
+ return to_immediate_scalar(bx, val, scalar);
+ }
+ val
+}
+
+pub fn to_immediate_scalar(bx: &Builder, val: ValueRef, scalar: &layout::Scalar) -> ValueRef {
+ if scalar.is_bool() {
+ return bx.trunc(val, Type::i1(bx.cx));
}
val
}
use rustc_data_structures::sync::Lrc;
use base;
-use common::{self, CodegenCx, C_null, C_undef, C_usize};
+use common::{CodegenCx, C_null, C_undef, C_usize};
use builder::{Builder, MemFlags};
use value::Value;
use type_of::LayoutLlvmExt;
bx.cx,
a,
a_scalar,
- layout.scalar_pair_element_llvm_type(bx.cx, 0),
+ layout.scalar_pair_element_llvm_type(bx.cx, 0, true),
);
let b_llval = scalar_to_llvm(
bx.cx,
b,
b_scalar,
- layout.scalar_pair_element_llvm_type(bx.cx, 1),
+ layout.scalar_pair_element_llvm_type(bx.cx, 1, true),
);
OperandValue::Pair(a_llval, b_llval)
},
self, llty);
// Reconstruct the immediate aggregate.
let mut llpair = C_undef(llty);
- llpair = bx.insert_value(llpair, a, 0);
- llpair = bx.insert_value(llpair, b, 1);
+ llpair = bx.insert_value(llpair, base::from_immediate(bx, a), 0);
+ llpair = bx.insert_value(llpair, base::from_immediate(bx, b), 1);
llpair
} else {
self.immediate()
llval: ValueRef,
layout: TyLayout<'tcx>)
-> OperandRef<'tcx> {
- let val = if layout.is_llvm_scalar_pair() {
+ let val = if let layout::Abi::ScalarPair(ref a, ref b) = layout.abi {
debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}",
llval, layout);
// Deconstruct the immediate aggregate.
- OperandValue::Pair(bx.extract_value(llval, 0),
- bx.extract_value(llval, 1))
+ let a_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 0), a);
+ let b_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 1), b);
+ OperandValue::Pair(a_llval, b_llval)
} else {
OperandValue::Immediate(llval)
};
*llval = bx.bitcast(*llval, field.immediate_llvm_type(bx.cx));
}
OperandValue::Pair(ref mut a, ref mut b) => {
- *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0));
- *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1));
+ *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0, true));
+ *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1, true));
}
OperandValue::Ref(..) => bug!()
}
}
OperandValue::Pair(a, b) => {
for (i, &x) in [a, b].iter().enumerate() {
- let mut llptr = bx.struct_gep(dest.llval, i as u64);
- // Make sure to always store i1 as i8.
- if common::val_ty(x) == Type::i1(bx.cx) {
- llptr = bx.pointercast(llptr, Type::i8p(bx.cx));
- }
+ let llptr = bx.struct_gep(dest.llval, i as u64);
let val = base::from_immediate(bx, x);
bx.store_with_flags(val, llptr, dest.align, flags);
}
OperandValue::Immediate(base::to_immediate(bx, llval, self.layout))
} else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi {
let load = |i, scalar: &layout::Scalar| {
- let mut llptr = bx.struct_gep(self.llval, i as u64);
- // Make sure to always load i1 as i8.
- if scalar.is_bool() {
- llptr = bx.pointercast(llptr, Type::i8p(bx.cx));
- }
+ let llptr = bx.struct_gep(self.llval, i as u64);
let load = bx.load(llptr, self.align);
scalar_load_metadata(load, scalar);
if scalar.is_bool() {
// HACK(eddyb) have to bitcast pointers
// until LLVM removes pointee types.
let lldata = bx.pointercast(lldata,
- cast.scalar_pair_element_llvm_type(bx.cx, 0));
+ cast.scalar_pair_element_llvm_type(bx.cx, 0, true));
OperandValue::Pair(lldata, llextra)
}
OperandValue::Immediate(lldata) => {
if let OperandValue::Pair(data_ptr, meta) = operand.val {
if cast.is_llvm_scalar_pair() {
let data_cast = bx.pointercast(data_ptr,
- cast.scalar_pair_element_llvm_type(bx.cx, 0));
+ cast.scalar_pair_element_llvm_type(bx.cx, 0, true));
OperandValue::Pair(data_cast, meta)
} else { // cast to thin-ptr
// Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
}
layout::Abi::ScalarPair(..) => {
return Type::struct_(cx, &[
- layout.scalar_pair_element_llvm_type(cx, 0),
- layout.scalar_pair_element_llvm_type(cx, 1),
+ layout.scalar_pair_element_llvm_type(cx, 0, false),
+ layout.scalar_pair_element_llvm_type(cx, 1, false),
], false);
}
layout::Abi::Uninhabited |
fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>,
scalar: &layout::Scalar, offset: Size) -> Type;
fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>,
- index: usize) -> Type;
+ index: usize, immediate: bool) -> Type;
fn llvm_field_index(&self, index: usize) -> u64;
fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size)
-> Option<PointeeInfo>;
}
fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>,
- index: usize) -> Type {
+ index: usize, immediate: bool) -> Type {
// HACK(eddyb) special-case fat pointers until LLVM removes
// pointee types, to avoid bitcasting every `OperandRef::deref`.
match self.ty.sty {
}
ty::TyAdt(def, _) if def.is_box() => {
let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
- return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index);
+ return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
}
_ => {}
}
};
let scalar = [a, b][index];
- // Make sure to return the same type `immediate_llvm_type` would,
- // to avoid dealing with two types and the associated conversions.
- // This means that `(bool, bool)` is represented as `{i1, i1}`,
- // both in memory and as an immediate, while `bool` is typically
- // `i8` in memory and only `i1` when immediate. While we need to
- // load/store `bool` as `i8` to avoid crippling LLVM optimizations,
- // `i1` in a LLVM aggregate is valid and mostly equivalent to `i8`.
- if scalar.is_bool() {
+ // Make sure to return the same type `immediate_llvm_type` would when
+ // dealing with an immediate pair. This means that `(bool, bool)` is
+ // effectively represented as `{i8, i8}` in memory and two `i1`s as an
+ // immediate, just like `bool` is typically `i8` in memory and only `i1`
+ // when immediate. We need to load/store `bool` as `i8` to avoid
+ // crippling LLVM optimizations or triggering other LLVM bugs with `i1`.
+ if immediate && scalar.is_bool() {
return Type::i1(cx);
}
// Temporarily have stack size set to 16MB to deal with nom-using crates failing
const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB
- #[cfg(unix)]
+ #[cfg(all(unix,not(target_os = "haiku")))]
let spawn_thread = unsafe {
// Fetch the current resource limits
let mut rlim = libc::rlimit {
#[cfg(windows)]
let spawn_thread = false;
+ #[cfg(target_os = "haiku")]
+ let spawn_thread = unsafe {
+ // Haiku does not have setrlimit implemented for the stack size.
+ // By default it does have the 16 MB stack limit, but we check this in
+ // case the minimum STACK_SIZE changes or Haiku's defaults change.
+ let mut rlim = libc::rlimit {
+ rlim_cur: 0,
+ rlim_max: 0,
+ };
+ if libc::getrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
+ let err = io::Error::last_os_error();
+ error!("in_rustc_thread: error calling getrlimit: {}", err);
+ true
+ } else if rlim.rlim_cur >= STACK_SIZE {
+ false
+ } else {
+ true
+ }
+ };
+
#[cfg(not(any(windows,unix)))]
let spawn_thread = true;
x
}
-// CHECK: i16 @enum_id_2(i16)
+// CHECK: { i8, i8 } @enum_id_2(i1 zeroext %x.0, i8 %x.1)
#[no_mangle]
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
x
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK: define { i8, i8 } @pair_bool_bool(i1 zeroext %pair.0, i1 zeroext %pair.1)
+#[no_mangle]
+pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) {
+ pair
+}
+
+// CHECK: define { i8, i32 } @pair_bool_i32(i1 zeroext %pair.0, i32 %pair.1)
+#[no_mangle]
+pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) {
+ pair
+}
+
+// CHECK: define { i32, i8 } @pair_i32_bool(i32 %pair.0, i1 zeroext %pair.1)
+#[no_mangle]
+pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) {
+ pair
+}
+
+// CHECK: define { i8, i8 } @pair_and_or(i1 zeroext %arg0.0, i1 zeroext %arg0.1)
+#[no_mangle]
+pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) {
+ // Make sure it can operate directly on the unpacked args
+ // CHECK: and i1 %arg0.0, %arg0.1
+ // CHECK: or i1 %arg0.0, %arg0.1
+ (a && b, a || b)
+}
+
+// CHECK: define void @pair_branches(i1 zeroext %arg0.0, i1 zeroext %arg0.1)
+#[no_mangle]
+pub fn pair_branches((a, b): (bool, bool)) {
+ // Make sure it can branch directly on the unpacked bool args
+ // CHECK: br i1 %arg0.0
+ if a {
+ println!("Hello!");
+ }
+ // CHECK: br i1 %arg0.1
+ if b {
+ println!("Goodbye!");
+ }
+}