summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_codegen_gcc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_gcc')
-rw-r--r--compiler/rustc_codegen_gcc/example/alloc_system.rs2
-rw-r--r--compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch1
-rw-r--r--compiler/rustc_codegen_gcc/src/abi.rs43
-rw-r--r--compiler/rustc_codegen_gcc/src/archive.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs211
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/consts.rs18
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs24
-rw-r--r--compiler/rustc_codegen_gcc/src/errors.rs242
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs39
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs204
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs18
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/asm.rs9
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/int.rs2
15 files changed, 568 insertions, 259 deletions
diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs
index 5f66ca67f..89661918d 100644
--- a/compiler/rustc_codegen_gcc/example/alloc_system.rs
+++ b/compiler/rustc_codegen_gcc/example/alloc_system.rs
@@ -156,7 +156,7 @@ mod platform {
struct Header(*mut u8);
const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
- &mut *(ptr as *mut Header).offset(-1)
+ &mut *(ptr as *mut Header).sub(1)
}
unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
let aligned = ptr.add(align - (ptr as usize & (align - 1)));
diff --git a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch
index d5fa1cec0..c59a40df0 100644
--- a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch
+++ b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch
@@ -14,7 +14,6 @@ index 06c7be0..359e2e7 100644
@@ -75,7 +75,6 @@
#![feature(never_type)]
#![feature(unwrap_infallible)]
- #![feature(result_into_ok_or_err)]
-#![feature(portable_simd)]
#![feature(ptr_metadata)]
#![feature(once_cell)]
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index 0ed3e1fbe..6fb1cbfad 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -11,10 +11,6 @@ use crate::intrinsic::ArgAbiExt;
use crate::type_of::LayoutGccExt;
impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
- fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) {
- // TODO(antoyo)
- }
-
fn get_param(&mut self, index: usize) -> Self::Value {
let func = self.current_func();
let param = func.get_param(index as i32);
@@ -107,45 +103,24 @@ pub trait FnAbiGccExt<'gcc, 'tcx> {
impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>) {
let mut on_stack_param_indices = FxHashSet::default();
- let args_capacity: usize = self.args.iter().map(|arg|
- if arg.pad.is_some() {
- 1
- }
- else {
- 0
- } +
- if let PassMode::Pair(_, _) = arg.mode {
- 2
- } else {
- 1
- }
- ).sum();
+
+ // This capacity calculation is approximate.
let mut argument_tys = Vec::with_capacity(
- if let PassMode::Indirect { .. } = self.ret.mode {
- 1
- }
- else {
- 0
- } + args_capacity,
+ self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 }
);
let return_ty =
match self.ret.mode {
PassMode::Ignore => cx.type_void(),
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
- PassMode::Cast(cast) => cast.gcc_type(cx),
+ PassMode::Cast(ref cast, _) => cast.gcc_type(cx),
PassMode::Indirect { .. } => {
argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
cx.type_void()
}
};
- for arg in &self.args {
- // add padding
- if let Some(ty) = arg.pad {
- argument_tys.push(ty.gcc_type(cx));
- }
-
+ for arg in self.args.iter() {
let arg_ty = match arg.mode {
PassMode::Ignore => continue,
PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx),
@@ -157,7 +132,13 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
PassMode::Indirect { extra_attrs: Some(_), .. } => {
unimplemented!();
}
- PassMode::Cast(cast) => cast.gcc_type(cx),
+ PassMode::Cast(ref cast, pad_i32) => {
+ // add padding
+ if pad_i32 {
+ argument_tys.push(Reg::i32().gcc_type(cx));
+ }
+ cast.gcc_type(cx)
+ }
PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => {
on_stack_param_indices.insert(argument_tys.len());
arg.memory_ty(cx)
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
index f863abdcc..f18ae7ea5 100644
--- a/compiler/rustc_codegen_gcc/src/archive.rs
+++ b/compiler/rustc_codegen_gcc/src/archive.rs
@@ -1,6 +1,8 @@
use std::fs::File;
use std::path::{Path, PathBuf};
+use crate::errors::RanlibFailure;
+
use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
use rustc_session::Session;
@@ -45,6 +47,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
_lib_name: &str,
_dll_imports: &[DllImport],
_tmpdir: &Path,
+ _is_direct_dependency: bool,
) -> PathBuf {
unimplemented!();
}
@@ -181,7 +184,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
std::process::Command::new("ranlib").arg(output).status().expect("Couldn't run ranlib");
if !status.success() {
- self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
+ self.config.sess.emit_fatal(RanlibFailure::new(status.code()));
}
any_members
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 52fd66af0..c346dbd63 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -12,6 +12,7 @@ use std::borrow::Cow;
use crate::builder::Builder;
use crate::context::CodegenCx;
+use crate::errors::UnwindingInlineAsm;
use crate::type_of::LayoutGccExt;
use crate::callee::get_fn;
@@ -109,7 +110,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], _instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) {
if options.contains(InlineAsmOptions::MAY_UNWIND) {
self.sess()
- .struct_span_err(span[0], "GCC backend does not support unwinding from inline asm")
+ .create_err(UnwindingInlineAsm { span: span[0] })
.emit();
return;
}
@@ -497,7 +498,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
if options.contains(InlineAsmOptions::NORETURN) {
let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) };
- self.call(self.type_void(), builtin_unreachable, &[], None);
+ self.call(self.type_void(), None, builtin_unreachable, &[], None);
}
// Write results to outputs.
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 4d40dd099..a314b7cc2 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -15,8 +15,11 @@ use gccjit::{
Type,
UnaryOp,
};
+use rustc_apfloat::{ieee, Float, Round, Status};
use rustc_codegen_ssa::MemFlags;
-use rustc_codegen_ssa::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope};
+use rustc_codegen_ssa::common::{
+ AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
+};
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::{
@@ -31,6 +34,7 @@ use rustc_codegen_ssa::traits::{
StaticBuilderMethods,
};
use rustc_data_structures::fx::FxHashSet;
+use rustc_middle::bug;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_span::Span;
@@ -440,11 +444,23 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
self.block.end_with_switch(None, value, default_block, &gcc_cases);
}
- fn invoke(&mut self, typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
+ fn invoke(
+ &mut self,
+ typ: Type<'gcc>,
+ fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
+ func: RValue<'gcc>,
+ args: &[RValue<'gcc>],
+ then: Block<'gcc>,
+ catch: Block<'gcc>,
+ _funclet: Option<&Funclet>,
+ ) -> RValue<'gcc> {
// TODO(bjorn3): Properly implement unwinding.
- let call_site = self.call(typ, func, args, None);
+ let call_site = self.call(typ, None, func, args, None);
let condition = self.context.new_rvalue_from_int(self.bool_type, 1);
self.llbb().end_with_conditional(None, condition, then, catch);
+ if let Some(_fn_abi) = fn_abi {
+ // TODO(bjorn3): Apply function attributes
+ }
call_site
}
@@ -639,11 +655,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None)
}
- fn dynamic_alloca(&mut self, _ty: Type<'gcc>, _align: Align) -> RValue<'gcc> {
- unimplemented!();
- }
-
- fn array_alloca(&mut self, _ty: Type<'gcc>, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
+ fn byte_array_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
unimplemented!();
}
@@ -1223,16 +1235,27 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
// TODO(antoyo)
}
- fn call(&mut self, _typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], funclet: Option<&Funclet>) -> RValue<'gcc> {
+ fn call(
+ &mut self,
+ _typ: Type<'gcc>,
+ fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
+ func: RValue<'gcc>,
+ args: &[RValue<'gcc>],
+ funclet: Option<&Funclet>,
+ ) -> RValue<'gcc> {
// FIXME(antoyo): remove when having a proper API.
let gcc_func = unsafe { std::mem::transmute(func) };
- if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
+ let call = if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
self.function_call(func, args, funclet)
}
else {
// If it's a not function that was defined, it's a function pointer.
self.function_ptr_call(func, args, funclet)
+ };
+ if let Some(_fn_abi) = fn_abi {
+ // TODO(bjorn3): Apply function attributes
}
+ call
}
fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
@@ -1271,12 +1294,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
val
}
- fn fptoui_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option<RValue<'gcc>> {
- None
+ fn fptoui_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ self.fptoint_sat(false, val, dest_ty)
}
- fn fptosi_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option<RValue<'gcc>> {
- None
+ fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ self.fptoint_sat(true, val, dest_ty)
}
fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) {
@@ -1285,6 +1308,166 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
}
impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+ fn fptoint_sat(&mut self, signed: bool, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+ let src_ty = self.cx.val_ty(val);
+ let (float_ty, int_ty) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
+ assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
+ (self.cx.element_type(src_ty), self.cx.element_type(dest_ty))
+ } else {
+ (src_ty, dest_ty)
+ };
+
+ // FIXME(jistone): the following was originally the fallback SSA implementation, before LLVM 13
+ // added native `fptosi.sat` and `fptoui.sat` conversions, but it was used by GCC as well.
+ // Now that LLVM always relies on its own, the code has been moved to GCC, but the comments are
+ // still LLVM-specific. This should be updated, and use better GCC specifics if possible.
+
+ let int_width = self.cx.int_width(int_ty);
+ let float_width = self.cx.float_width(float_ty);
+ // LLVM's fpto[su]i returns undef when the input val is infinite, NaN, or does not fit into the
+ // destination integer type after rounding towards zero. This `undef` value can cause UB in
+ // safe code (see issue #10184), so we implement a saturating conversion on top of it:
+ // Semantically, the mathematical value of the input is rounded towards zero to the next
+ // mathematical integer, and then the result is clamped into the range of the destination
+ // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
+ // the destination integer type. NaN is mapped to 0.
+ //
+ // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
+ // a value representable in int_ty.
+ // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
+ // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
+ // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
+ // representable. Note that this only works if float_ty's exponent range is sufficiently large.
+ // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
+ // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
+ // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
+ // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
+ // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
+ let int_max = |signed: bool, int_width: u64| -> u128 {
+ let shift_amount = 128 - int_width;
+ if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
+ };
+ let int_min = |signed: bool, int_width: u64| -> i128 {
+ if signed { i128::MIN >> (128 - int_width) } else { 0 }
+ };
+
+ let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
+ let rounded_min =
+ ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
+ assert_eq!(rounded_min.status, Status::OK);
+ let rounded_max =
+ ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
+ assert!(rounded_max.value.is_finite());
+ (rounded_min.value.to_bits(), rounded_max.value.to_bits())
+ };
+ let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
+ let rounded_min =
+ ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
+ assert_eq!(rounded_min.status, Status::OK);
+ let rounded_max =
+ ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
+ assert!(rounded_max.value.is_finite());
+ (rounded_min.value.to_bits(), rounded_max.value.to_bits())
+ };
+ // To implement saturation, we perform the following steps:
+ //
+ // 1. Cast val to an integer with fpto[su]i. This may result in undef.
+ // 2. Compare val to f_min and f_max, and use the comparison results to select:
+ // a) int_ty::MIN if val < f_min or val is NaN
+ // b) int_ty::MAX if val > f_max
+ // c) the result of fpto[su]i otherwise
+ // 3. If val is NaN, return 0.0, otherwise return the result of step 2.
+ //
+ // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the
+ // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of
+ // undef does not introduce any non-determinism either.
+ // More importantly, the above procedure correctly implements saturating conversion.
+ // Proof (sketch):
+ // If val is NaN, 0 is returned by definition.
+ // Otherwise, val is finite or infinite and thus can be compared with f_min and f_max.
+ // This yields three cases to consider:
+ // (1) if val in [f_min, f_max], the result of fpto[su]i is returned, which agrees with
+ // saturating conversion for inputs in that range.
+ // (2) if val > f_max, then val is larger than int_ty::MAX. This holds even if f_max is rounded
+ // (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger
+ // than int_ty::MAX. Because val is larger than int_ty::MAX, the return value of int_ty::MAX
+ // is correct.
+ // (3) if val < f_min, then val is smaller than int_ty::MIN. As shown earlier, f_min exactly equals
+ // int_ty::MIN and therefore the return value of int_ty::MIN is correct.
+ // QED.
+
+ let float_bits_to_llval = |bx: &mut Self, bits| {
+ let bits_llval = match float_width {
+ 32 => bx.cx().const_u32(bits as u32),
+ 64 => bx.cx().const_u64(bits as u64),
+ n => bug!("unsupported float width {}", n),
+ };
+ bx.bitcast(bits_llval, float_ty)
+ };
+ let (f_min, f_max) = match float_width {
+ 32 => compute_clamp_bounds_single(signed, int_width),
+ 64 => compute_clamp_bounds_double(signed, int_width),
+ n => bug!("unsupported float width {}", n),
+ };
+ let f_min = float_bits_to_llval(self, f_min);
+ let f_max = float_bits_to_llval(self, f_max);
+ let int_max = self.cx.const_uint_big(int_ty, int_max(signed, int_width));
+ let int_min = self.cx.const_uint_big(int_ty, int_min(signed, int_width) as u128);
+ let zero = self.cx.const_uint(int_ty, 0);
+
+ // If we're working with vectors, constants must be "splatted": the constant is duplicated
+ // into each lane of the vector. The algorithm stays the same, we are just using the
+ // same constant across all lanes.
+ let maybe_splat = |bx: &mut Self, val| {
+ if bx.cx().type_kind(dest_ty) == TypeKind::Vector {
+ bx.vector_splat(bx.vector_length(dest_ty), val)
+ } else {
+ val
+ }
+ };
+ let f_min = maybe_splat(self, f_min);
+ let f_max = maybe_splat(self, f_max);
+ let int_max = maybe_splat(self, int_max);
+ let int_min = maybe_splat(self, int_min);
+ let zero = maybe_splat(self, zero);
+
+ // Step 1 ...
+ let fptosui_result = if signed { self.fptosi(val, dest_ty) } else { self.fptoui(val, dest_ty) };
+ let less_or_nan = self.fcmp(RealPredicate::RealULT, val, f_min);
+ let greater = self.fcmp(RealPredicate::RealOGT, val, f_max);
+
+ // Step 2: We use two comparisons and two selects, with %s1 being the
+ // result:
+ // %less_or_nan = fcmp ult %val, %f_min
+ // %greater = fcmp olt %val, %f_max
+ // %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
+ // %s1 = select %greater, int_ty::MAX, %s0
+ // Note that %less_or_nan uses an *unordered* comparison. This
+ // comparison is true if the operands are not comparable (i.e., if val is
+ // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
+ // val is NaN.
+ //
+ // Performance note: Unordered comparison can be lowered to a "flipped"
+ // comparison and a negation, and the negation can be merged into the
+ // select. Therefore, it not necessarily any more expensive than an
+ // ordered ("normal") comparison. Whether these optimizations will be
+ // performed is ultimately up to the backend, but at least x86 does
+ // perform them.
+ let s0 = self.select(less_or_nan, int_min, fptosui_result);
+ let s1 = self.select(greater, int_max, s0);
+
+ // Step 3: NaN replacement.
+ // For unsigned types, the above step already yielded int_ty::MIN == 0 if val is NaN.
+ // Therefore we only need to execute this step for signed integer types.
+ if signed {
+ // LLVM has no isNaN predicate, so we use (val == val) instead
+ let cmp = self.fcmp(RealPredicate::RealOEQ, val, val);
+ self.select(cmp, s1, zero)
+ } else {
+ s1
+ }
+ }
+
#[cfg(feature="master")]
pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> {
let struct_type = mask.get_type().is_struct().expect("mask of struct type");
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index ccb6cbbc2..aa1c271c3 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -158,10 +158,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
None
}
- fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> {
- self.const_undef(self.type_ix(0))
- }
-
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
match cv {
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index c0b8d2181..81f533288 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -14,6 +14,7 @@ use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRan
use crate::base;
use crate::context::CodegenCx;
+use crate::errors::LinkageConstOrMutType;
use crate::type_of::LayoutGccExt;
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
@@ -127,7 +128,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
//
// We could remove this hack whenever we decide to drop macOS 10.10 support.
if self.tcx.sess.target.options.is_like_osx {
- // The `inspect` method is okay here because we checked relocations, and
+ // The `inspect` method is okay here because we checked for provenance, and
// because we are doing this access to inspect the final interpreter state
// (not as part of the interpreter execution).
//
@@ -296,17 +297,17 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAllocation<'tcx>) -> RValue<'gcc> {
let alloc = alloc.inner();
- let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
+ let mut llvals = Vec::with_capacity(alloc.provenance().len() + 1);
let dl = cx.data_layout();
let pointer_size = dl.pointer_size.bytes() as usize;
let mut next_offset = 0;
- for &(offset, alloc_id) in alloc.relocations().iter() {
+ for &(offset, alloc_id) in alloc.provenance().iter() {
let offset = offset.bytes();
assert_eq!(offset as usize as u64, offset);
let offset = offset as usize;
if offset > next_offset {
- // This `inspect` is okay since we have checked that it is not within a relocation, it
+ // This `inspect` is okay since we have checked that it is not within a pointer with provenance, it
// is within the bounds of the allocation, and it doesn't affect interpreter execution
// (we inspect the result after interpreter execution). Any undef byte is replaced with
// some arbitrary byte value.
@@ -319,7 +320,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
read_target_uint( dl.endian,
// This `inspect` is okay since it is within the bounds of the allocation, it doesn't
// affect interpreter execution (we inspect the result after interpreter execution),
- // and we properly interpret the relocation as a relocation pointer offset.
+ // and we properly interpret the provenance as a relocation pointer offset.
alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
)
.expect("const_alloc_to_llvm: could not read relocation pointer")
@@ -336,7 +337,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
}
if alloc.len() >= next_offset {
let range = next_offset..alloc.len();
- // This `inspect` is okay since we have check that it is after all relocations, it is
+ // This `inspect` is okay since we have check that it is after all provenance, it is
// within the bounds of the allocation, and it doesn't affect interpreter execution (we
// inspect the result after interpreter execution). Any undef byte is replaced with some
// arbitrary byte value.
@@ -368,10 +369,7 @@ fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &Codeg
cx.layout_of(mt.ty).gcc_type(cx, true)
}
else {
- cx.sess().span_fatal(
- span,
- "must have type `*const T` or `*mut T` due to `#[linkage]` attribute",
- )
+ cx.sess().emit_fatal(LinkageConstOrMutType { span: span })
};
// Declare a symbol `foo` with the desired linkage.
let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage));
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 478f6d893..62a61eb85 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::mono::CodegenUnit;
use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers};
use rustc_session::Session;
-use rustc_span::Span;
+use rustc_span::{Span, source_map::respan};
use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
use rustc_target::spec::{HasTargetSpec, Target, TlsModel};
@@ -293,7 +293,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
self.is_native_int_type(typ) || self.is_non_native_int_type(typ) || typ.is_compatible_with(self.bool_type)
}
- pub fn sess(&self) -> &Session {
+ pub fn sess(&self) -> &'tcx Session {
&self.tcx.sess
}
@@ -416,10 +416,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
self.codegen_unit
}
- fn used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
- unimplemented!();
- }
-
fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) {
// TODO(antoyo)
}
@@ -428,10 +424,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
// TODO(antoyo)
}
- fn create_used_variable(&self) {
- unimplemented!();
- }
-
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
if self.get_declared_value("main").is_none() {
Some(self.declare_cfn("main", fn_type))
@@ -443,14 +435,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
None
}
}
-
- fn compiler_used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
- unimplemented!()
- }
-
- fn create_compiler_used_variable(&self) {
- unimplemented!()
- }
}
impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> {
@@ -477,7 +461,7 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
if let LayoutError::SizeOverflow(_) = err {
- self.sess().span_fatal(span, &err.to_string())
+ self.sess().emit_fatal(respan(span, err))
} else {
span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
}
@@ -495,7 +479,7 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
- self.sess().span_fatal(span, &err.to_string())
+ self.sess().emit_fatal(respan(span, err))
} else {
match fn_abi_request {
FnAbiRequest::OfFnPtr { sig, extra_args } => {
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs
new file mode 100644
index 000000000..15ad90f90
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -0,0 +1,242 @@
+use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
+use rustc_macros::Diagnostic;
+use rustc_middle::ty::Ty;
+use rustc_span::{Span, Symbol};
+use std::borrow::Cow;
+
+struct ExitCode(Option<i32>);
+
+impl IntoDiagnosticArg for ExitCode {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ let ExitCode(exit_code) = self;
+ match exit_code {
+ Some(t) => t.into_diagnostic_arg(),
+ None => DiagnosticArgValue::Str(Cow::Borrowed("<signal>")),
+ }
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_ranlib_failure)]
+pub(crate) struct RanlibFailure {
+ exit_code: ExitCode,
+}
+
+impl RanlibFailure {
+ pub fn new(exit_code: Option<i32>) -> Self {
+ RanlibFailure { exit_code: ExitCode(exit_code) }
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_basic_integer, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationBasicInteger<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_invalid_float_vector, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub elem_ty: &'a str,
+ pub vec_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_not_float, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationNotFloat<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_unrecognized, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationUnrecognized {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_expected_signed_unsigned, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub elem_ty: Ty<'a>,
+ pub vec_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_element, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_ty: Ty<'a>,
+ pub elem_ty: Ty<'a>,
+ pub ret_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_invalid_bitmask, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+ pub expected_int_bits: u64,
+ pub expected_bytes: u64,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_simd_shuffle, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_expected_simd, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub position: &'a str,
+ pub found_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_mask_type, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationMaskType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_return_length, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationReturnLength<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_len: u64,
+ pub ret_ty: Ty<'a>,
+ pub out_len: u64,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_return_length_input_type, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_len: u64,
+ pub in_ty: Ty<'a>,
+ pub ret_ty: Ty<'a>,
+ pub out_len: u64,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_return_element, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationReturnElement<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_elem: Ty<'a>,
+ pub in_ty: Ty<'a>,
+ pub ret_ty: Ty<'a>,
+ pub out_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_return_type, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationReturnType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_elem: Ty<'a>,
+ pub in_ty: Ty<'a>,
+ pub ret_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_inserted_type, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationInsertedType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_elem: Ty<'a>,
+ pub in_ty: Ty<'a>,
+ pub out_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_return_integer_type, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ret_ty: Ty<'a>,
+ pub out_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_mismatched_lengths, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationMismatchedLengths {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub m_len: u64,
+ pub v_len: u64,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_cast, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_ty: Ty<'a>,
+ pub in_elem: Ty<'a>,
+ pub ret_ty: Ty<'a>,
+ pub out_elem: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_operation, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_ty: Ty<'a>,
+ pub in_elem: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_linkage_const_or_mut_type)]
+pub(crate) struct LinkageConstOrMutType {
+ #[primary_span]
+ pub span: Span
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_lto_not_supported)]
+pub(crate) struct LTONotSupported;
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_unwinding_inline_asm)]
+pub(crate) struct UnwindingInlineAsm {
+ #[primary_span]
+ pub span: Span
+}
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 5fbdedac0..49be6c649 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -4,7 +4,7 @@ mod simd;
use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp, FunctionType};
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::base::wants_msvc_seh;
-use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error};
+use rustc_codegen_ssa::common::IntPredicate;
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods};
@@ -20,6 +20,7 @@ use crate::abi::GccType;
use crate::builder::Builder;
use crate::common::{SignType, TypeReflection};
use crate::context::CodegenCx;
+use crate::errors::InvalidMonomorphizationBasicInteger;
use crate::type_of::LayoutGccExt;
use crate::intrinsic::simd::generic_simd_intrinsic;
@@ -99,7 +100,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
_ if simple.is_some() => {
// FIXME(antoyo): remove this cast when the API supports function.
let func = unsafe { std::mem::transmute(simple.expect("simple")) };
- self.call(self.type_void(), func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
+ self.call(self.type_void(), None, func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
},
sym::likely => {
self.expect(args[0].immediate(), true)
@@ -130,7 +131,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = substs.type_at(0);
let mut ptr = args[0].immediate();
- if let PassMode::Cast(ty) = fn_abi.ret.mode {
+ if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
}
let load = self.volatile_load(ptr.get_type(), ptr);
@@ -242,15 +243,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
_ => bug!(),
},
None => {
- span_invalid_monomorphization_error(
- tcx.sess,
- span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic integer type, found `{}`",
- name, ty
- ),
- );
+ tcx.sess.emit_err(InvalidMonomorphizationBasicInteger { span, name, ty });
return;
}
}
@@ -309,6 +302,18 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
return;
}
+ sym::ptr_mask => {
+ let usize_type = self.context.new_type::<usize>();
+ let void_ptr_type = self.context.new_type::<*const ()>();
+
+ let ptr = args[0].immediate();
+ let mask = args[1].immediate();
+
+ let addr = self.bitcast(ptr, usize_type);
+ let masked = self.and(addr, mask);
+ self.bitcast(masked, void_ptr_type)
+ },
+
_ if name_str.starts_with("simd_") => {
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
Ok(llval) => llval,
@@ -320,7 +325,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
};
if !fn_abi.ret.is_ignore() {
- if let PassMode::Cast(ty) = fn_abi.ret.mode {
+ if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
let ptr = self.pointercast(result.llval, ptr_llty);
self.store(llval, ptr, result.align);
@@ -336,7 +341,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
fn abort(&mut self) {
let func = self.context.get_builtin_function("abort");
let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
- self.call(self.type_void(), func, &[], None);
+ self.call(self.type_void(), None, func, &[], None);
}
fn assume(&mut self, value: Self::Value) {
@@ -416,7 +421,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
else if self.is_unsized_indirect() {
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
}
- else if let PassMode::Cast(cast) = self.mode {
+ else if let PassMode::Cast(ref cast, _) = self.mode {
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
let can_store_through_cast_ptr = false;
@@ -481,7 +486,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
PassMode::Indirect { extra_attrs: Some(_), .. } => {
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
},
- PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(_) => {
+ PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(..) => {
let next_arg = next();
self.store(bx, next_arg, dst);
},
@@ -1119,7 +1124,7 @@ fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<
// NOTE: the `|| true` here is to use the panic=abort strategy with panic=unwind too
if bx.sess().panic_strategy() == PanicStrategy::Abort || true {
// TODO(bjorn3): Properly implement unwinding and remove the `|| true` once this is done.
- bx.call(bx.type_void(), try_func, &[data], None);
+ bx.call(bx.type_void(), None, try_func, &[data], None);
// Return 0 unconditionally from the intrinsic call;
// we can never unwind.
let ret_align = bx.tcx.data_layout.i32_align.abi;
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index 2401f3350..12e416f62 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -2,7 +2,7 @@ use std::cmp::Ordering;
use gccjit::{BinaryOp, RValue, Type, ToRValue};
use rustc_codegen_ssa::base::compare_simd_types;
-use rustc_codegen_ssa::common::{TypeKind, span_invalid_monomorphization_error};
+use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::mir::operand::OperandRef;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
@@ -14,43 +14,48 @@ use rustc_span::{Span, Symbol, sym};
use rustc_target::abi::Align;
use crate::builder::Builder;
+use crate::errors::{
+ InvalidMonomorphizationInvalidFloatVector,
+ InvalidMonomorphizationNotFloat,
+ InvalidMonomorphizationUnrecognized,
+ InvalidMonomorphizationExpectedSignedUnsigned,
+ InvalidMonomorphizationUnsupportedElement,
+ InvalidMonomorphizationInvalidBitmask,
+ InvalidMonomorphizationSimdShuffle,
+ InvalidMonomorphizationExpectedSimd,
+ InvalidMonomorphizationMaskType,
+ InvalidMonomorphizationReturnLength,
+ InvalidMonomorphizationReturnLengthInputType,
+ InvalidMonomorphizationReturnElement,
+ InvalidMonomorphizationReturnType,
+ InvalidMonomorphizationInsertedType,
+ InvalidMonomorphizationReturnIntegerType,
+ InvalidMonomorphizationMismatchedLengths,
+ InvalidMonomorphizationUnsupportedCast,
+ InvalidMonomorphizationUnsupportedOperation
+};
use crate::intrinsic;
pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result<RValue<'gcc>, ()> {
// macros for error handling:
- #[allow(unused_macro_rules)]
- macro_rules! emit_error {
- ($msg: tt) => {
- emit_error!($msg, )
- };
- ($msg: tt, $($fmt: tt)*) => {
- span_invalid_monomorphization_error(
- bx.sess(), span,
- &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
- name, $($fmt)*));
- }
- }
-
macro_rules! return_error {
- ($($fmt: tt)*) => {
+ ($err:expr) => {
{
- emit_error!($($fmt)*);
+ bx.sess().emit_err($err);
return Err(());
}
}
}
-
macro_rules! require {
- ($cond: expr, $($fmt: tt)*) => {
+ ($cond:expr, $err:expr) => {
if !$cond {
- return_error!($($fmt)*);
+ return_error!($err);
}
- };
+ }
}
-
macro_rules! require_simd {
($ty: expr, $position: expr) => {
- require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
+ require!($ty.is_simd(), InvalidMonomorphizationExpectedSimd { span, name, position: $position, found_ty: $ty })
};
}
@@ -82,10 +87,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
bx.load(int_ty, ptr, Align::ONE)
}
_ => return_error!(
- "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`",
- mask_ty,
- expected_int_bits,
- expected_bytes
+ InvalidMonomorphizationInvalidBitmask { span, name, ty: mask_ty, expected_int_bits, expected_bytes }
),
};
@@ -127,18 +129,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
require!(
in_len == out_len,
- "expected return type with length {} (same as input type `{}`), \
- found `{}` with length {}",
- in_len,
- in_ty,
- ret_ty,
- out_len
+ InvalidMonomorphizationReturnLengthInputType { span, name, in_len, in_ty, ret_ty, out_len }
);
require!(
bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
- "expected return type with integer elements, found `{}` with non-integer `{}`",
- ret_ty,
- out_ty
+ InvalidMonomorphizationReturnIntegerType {span, name, ret_ty, out_ty}
);
return Ok(compare_simd_types(
@@ -163,8 +158,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
})
}
_ => return_error!(
- "simd_shuffle index must be an array of `u32`, got `{}`",
- args[2].layout.ty
+ InvalidMonomorphizationSimdShuffle { span, name, ty: args[2].layout.ty }
),
}
}
@@ -179,19 +173,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
require!(
out_len == n,
- "expected return type of length {}, found `{}` with length {}",
- n,
- ret_ty,
- out_len
+ InvalidMonomorphizationReturnLength { span, name, in_len: n, ret_ty, out_len }
);
require!(
in_elem == out_ty,
- "expected return element type `{}` (element of input `{}`), \
- found `{}` with element type `{}`",
- in_elem,
- in_ty,
- ret_ty,
- out_ty
+ InvalidMonomorphizationReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
);
let vector = args[2].immediate();
@@ -207,10 +193,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
if name == sym::simd_insert {
require!(
in_elem == arg_tys[2],
- "expected inserted type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- arg_tys[2]
+ InvalidMonomorphizationInsertedType { span, name, in_elem, in_ty, out_ty: arg_tys[2] }
);
let vector = args[0].immediate();
let index = args[1].immediate();
@@ -263,10 +246,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
if name == sym::simd_extract {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty }
);
let vector = args[0].immediate();
return Ok(bx.context.new_vector_access(None, vector, args[1].immediate()).to_rvalue());
@@ -279,13 +259,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
require!(
m_len == v_len,
- "mismatched lengths: mask length `{}` != other vector length `{}`",
- m_len,
- v_len
+ InvalidMonomorphizationMismatchedLengths { span, name, m_len, v_len }
);
match m_elem_ty.kind() {
ty::Int(_) => {}
- _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty),
+ _ => return_error!(InvalidMonomorphizationMaskType { span, name, ty: m_elem_ty }),
}
return Ok(bx.vector_select(args[0].immediate(), args[1].immediate(), args[2].immediate()));
}
@@ -295,12 +273,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!(
in_len == out_len,
- "expected return type with length {} (same as input type `{}`), \
- found `{}` with length {}",
- in_len,
- in_ty,
- ret_ty,
- out_len
+ InvalidMonomorphizationReturnLengthInputType { span, name, in_len, in_ty, ret_ty, out_len }
);
// casting cares about nominal type, not just structural type
if in_elem == out_elem {
@@ -412,13 +385,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
}
_ => { /* Unsupported. Fallthrough. */ }
}
- require!(
- false,
- "unsupported cast from `{}` with element `{}` to `{}` with element `{}`",
- in_ty,
- in_elem,
- ret_ty,
- out_elem
+ return_error!(
+ InvalidMonomorphizationUnsupportedCast { span, name, in_ty, in_elem, ret_ty, out_elem }
);
}
@@ -431,10 +399,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
})*
_ => {},
}
- require!(false,
- "unsupported operation on `{}` with element `{}`",
- in_ty,
- in_elem)
+ return_error!(InvalidMonomorphizationUnsupportedOperation { span, name, in_ty, in_elem })
})*
}
}
@@ -448,23 +413,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
span: Span,
args: &[OperandRef<'tcx, RValue<'gcc>>],
) -> Result<RValue<'gcc>, ()> {
- macro_rules! emit_error {
- ($msg: tt, $($fmt: tt)*) => {
- span_invalid_monomorphization_error(
- bx.sess(), span,
- &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
- name, $($fmt)*));
- }
- }
macro_rules! return_error {
- ($($fmt: tt)*) => {
+ ($err:expr) => {
{
- emit_error!($($fmt)*);
+ bx.sess().emit_err($err);
return Err(());
}
}
}
-
let (elem_ty_str, elem_ty) =
if let ty::Float(f) = in_elem.kind() {
let elem_ty = bx.cx.type_float_from_ty(*f);
@@ -472,16 +428,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
32 => ("f32", elem_ty),
64 => ("f64", elem_ty),
_ => {
- return_error!(
- "unsupported element type `{}` of floating-point vector `{}`",
- f.name_str(),
- in_ty
- );
+ return_error!(InvalidMonomorphizationInvalidFloatVector { span, name, elem_ty: f.name_str(), vec_ty: in_ty });
}
}
}
else {
- return_error!("`{}` is not a floating-point type", in_ty);
+ return_error!(InvalidMonomorphizationNotFloat { span, name, ty: in_ty });
};
let vec_ty = bx.cx.type_vector(elem_ty, in_len);
@@ -504,12 +456,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
- _ => return_error!("unrecognized intrinsic `{}`", name),
+ _ => return_error!(InvalidMonomorphizationUnrecognized { span, name })
};
let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
let function = intrinsic::llvm::intrinsic(llvm_name, &bx.cx);
let function: RValue<'gcc> = unsafe { std::mem::transmute(function) };
- let c = bx.call(fn_ty, function, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
+ let c = bx.call(fn_ty, None, function, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
Ok(c)
}
@@ -557,10 +509,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
})*
_ => {},
}
- require!(false,
- "unsupported operation on `{}` with element `{}`",
- in_ty,
- in_elem)
+ return_error!(InvalidMonomorphizationUnsupportedOperation { span, name, in_ty, in_elem })
})*
}
}
@@ -579,12 +528,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)),
ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)),
_ => {
- return_error!(
- "expected element type `{}` of vector type `{}` \
- to be a signed or unsigned integer type",
- arg_tys[0].simd_size_and_type(bx.tcx()).1,
- arg_tys[0]
- );
+ return_error!(InvalidMonomorphizationExpectedSignedUnsigned {
+ span,
+ name,
+ elem_ty: arg_tys[0].simd_size_and_type(bx.tcx()).1,
+ vec_ty: arg_tys[0],
+ });
}
};
let builtin_name =
@@ -617,10 +566,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
if name == sym::$name {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty }
);
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
@@ -644,13 +590,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
Ok(bx.vector_reduce_op(args[0].immediate(), $vec_op))
}
}
- _ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
- in_ty,
- in_elem,
- ret_ty
- ),
+ _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }),
};
}
};
@@ -676,20 +616,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
if name == sym::$name {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty }
);
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) | ty::Float(_) => Ok(bx.$reduction(args[0].immediate())),
- _ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
- in_ty,
- in_elem,
- ret_ty
- ),
+ _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }),
};
}
};
@@ -704,22 +635,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
let input = if !$boolean {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty }
);
args[0].immediate()
} else {
match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {}
- _ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
- in_ty,
- in_elem,
- ret_ty
- ),
+ _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }),
}
// boolean reductions operate on vectors of i1s:
@@ -733,11 +655,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) })
}
_ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
- in_ty,
- in_elem,
- ret_ty
+ InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }
),
};
}
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 8a206c036..accd02ab0 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -18,12 +18,16 @@
#![recursion_limit="256"]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
+extern crate rustc_apfloat;
extern crate rustc_ast;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_hir;
+extern crate rustc_macros;
extern crate rustc_metadata;
extern crate rustc_middle;
extern crate rustc_session;
@@ -49,6 +53,7 @@ mod context;
mod coverageinfo;
mod debuginfo;
mod declare;
+mod errors;
mod int;
mod intrinsic;
mod mono_item;
@@ -58,6 +63,7 @@ mod type_of;
use std::any::Any;
use std::sync::{Arc, Mutex};
+use crate::errors::LTONotSupported;
use gccjit::{Context, OptimizationLevel, CType};
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
@@ -96,7 +102,7 @@ pub struct GccCodegenBackend {
impl CodegenBackend for GccCodegenBackend {
fn init(&self, sess: &Session) {
if sess.lto() != Lto::No {
- sess.warn("LTO is not supported. You may get a linker error.");
+ sess.emit_warning(LTONotSupported {});
}
let temp_dir = TempDir::new().expect("cannot create temporary directory");
@@ -165,15 +171,6 @@ impl ExtraBackendMethods for GccCodegenBackend {
Ok(())
})
}
-
- fn target_cpu<'b>(&self, _sess: &'b Session) -> &'b str {
- unimplemented!();
- }
-
- fn tune_cpu<'b>(&self, _sess: &'b Session) -> Option<&'b str> {
- None
- // TODO(antoyo)
- }
}
pub struct ModuleBuffer;
@@ -204,7 +201,6 @@ impl WriteBackendMethods for GccCodegenBackend {
type Module = GccContext;
type TargetMachine = ();
type ModuleBuffer = ModuleBuffer;
- type Context = ();
type ThinData = ();
type ThinBuffer = ThinBuffer;
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
index 46abbb553..38c1eac7a 100644
--- a/compiler/rustc_codegen_gcc/tests/run/asm.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs
@@ -3,11 +3,12 @@
// Run-time:
// status: 0
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const)]
use std::arch::{asm, global_asm};
-global_asm!("
+global_asm!(
+ "
.global add_asm
add_asm:
mov rax, rdi
@@ -132,7 +133,9 @@ fn main() {
assert_eq!(x, 43);
// check sym fn
- extern "C" fn foo() -> u64 { 42 }
+ extern "C" fn foo() -> u64 {
+ 42
+ }
let x: u64;
unsafe {
asm!("call {}", sym foo, lateout("rax") x);
diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs
index 2b90e4ae8..75779622b 100644
--- a/compiler/rustc_codegen_gcc/tests/run/int.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/int.rs
@@ -3,7 +3,7 @@
// Run-time:
// status: 0
-#![feature(bench_black_box, const_black_box, core_intrinsics, start)]
+#![feature(const_black_box, core_intrinsics, start)]
#![no_std]