Merge commit 'e4fe941b11
' into subtree-update_cg_gcc_2023-10-25
This commit is contained in:
commit
c797cccda6
47 changed files with 2659 additions and 502 deletions
|
@ -1,3 +1,5 @@
|
|||
#[cfg(feature = "master")]
|
||||
use gccjit::FnAttribute;
|
||||
use gccjit::{ToLValue, ToRValue, Type};
|
||||
use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
@ -96,14 +98,23 @@ impl GccType for Reg {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct FnAbiGcc<'gcc> {
|
||||
pub return_type: Type<'gcc>,
|
||||
pub arguments_type: Vec<Type<'gcc>>,
|
||||
pub is_c_variadic: bool,
|
||||
pub on_stack_param_indices: FxHashSet<usize>,
|
||||
#[cfg(feature = "master")]
|
||||
pub fn_attributes: Vec<FnAttribute<'gcc>>,
|
||||
}
|
||||
|
||||
pub trait FnAbiGccExt<'gcc, 'tcx> {
|
||||
// TODO(antoyo): return a function pointer type instead?
|
||||
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>);
|
||||
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> FnAbiGcc<'gcc>;
|
||||
fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
|
||||
}
|
||||
|
||||
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>) {
|
||||
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> FnAbiGcc<'gcc> {
|
||||
let mut on_stack_param_indices = FxHashSet::default();
|
||||
|
||||
// This capacity calculation is approximate.
|
||||
|
@ -111,7 +122,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 }
|
||||
);
|
||||
|
||||
let return_ty =
|
||||
let return_type =
|
||||
match self.ret.mode {
|
||||
PassMode::Ignore => cx.type_void(),
|
||||
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
|
||||
|
@ -121,19 +132,24 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
cx.type_void()
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "master")]
|
||||
let mut non_null_args = Vec::new();
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
let apply_attrs = |ty: Type<'gcc>, attrs: &ArgAttributes| {
|
||||
if cx.sess().opts.optimize != config::OptLevel::No
|
||||
&& attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NoAlias)
|
||||
{
|
||||
ty.make_restrict()
|
||||
} else {
|
||||
ty
|
||||
let mut apply_attrs = |mut ty: Type<'gcc>, attrs: &ArgAttributes, arg_index: usize| {
|
||||
if cx.sess().opts.optimize == config::OptLevel::No {
|
||||
return ty;
|
||||
}
|
||||
if attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NoAlias) {
|
||||
ty = ty.make_restrict()
|
||||
}
|
||||
if attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NonNull) {
|
||||
non_null_args.push(arg_index as i32 + 1);
|
||||
}
|
||||
ty
|
||||
};
|
||||
#[cfg(not(feature = "master"))]
|
||||
let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes| {
|
||||
let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes, _arg_index: usize| {
|
||||
ty
|
||||
};
|
||||
|
||||
|
@ -141,8 +157,9 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
let arg_ty = match arg.mode {
|
||||
PassMode::Ignore => continue,
|
||||
PassMode::Pair(a, b) => {
|
||||
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 0), &a));
|
||||
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 1), &b));
|
||||
let arg_pos = argument_tys.len();
|
||||
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 0), &a, arg_pos));
|
||||
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 1), &b, arg_pos + 1));
|
||||
continue;
|
||||
}
|
||||
PassMode::Cast { ref cast, pad_i32 } => {
|
||||
|
@ -151,31 +168,53 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
argument_tys.push(Reg::i32().gcc_type(cx));
|
||||
}
|
||||
let ty = cast.gcc_type(cx);
|
||||
apply_attrs(ty, &cast.attrs)
|
||||
apply_attrs(ty, &cast.attrs, argument_tys.len())
|
||||
}
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: true } => {
|
||||
// This is a "byval" argument, so we don't apply the `restrict` attribute on it.
|
||||
on_stack_param_indices.insert(argument_tys.len());
|
||||
arg.memory_ty(cx)
|
||||
},
|
||||
PassMode::Direct(attrs) => apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs),
|
||||
PassMode::Direct(attrs) => apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs, argument_tys.len()),
|
||||
PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
|
||||
apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs)
|
||||
apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len())
|
||||
}
|
||||
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
|
||||
assert!(!on_stack);
|
||||
apply_attrs(apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs), &meta_attrs)
|
||||
let ty = apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len());
|
||||
apply_attrs(ty, &meta_attrs, argument_tys.len())
|
||||
}
|
||||
};
|
||||
argument_tys.push(arg_ty);
|
||||
}
|
||||
|
||||
(return_ty, argument_tys, self.c_variadic, on_stack_param_indices)
|
||||
#[cfg(feature = "master")]
|
||||
let fn_attrs = if non_null_args.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
vec![FnAttribute::NonNull(non_null_args)]
|
||||
};
|
||||
|
||||
FnAbiGcc {
|
||||
return_type,
|
||||
arguments_type: argument_tys,
|
||||
is_c_variadic: self.c_variadic,
|
||||
on_stack_param_indices,
|
||||
#[cfg(feature = "master")]
|
||||
fn_attributes: fn_attrs,
|
||||
}
|
||||
}
|
||||
|
||||
fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
|
||||
let (return_type, params, variadic, on_stack_param_indices) = self.gcc_type(cx);
|
||||
let pointer_type = cx.context.new_function_pointer_type(None, return_type, ¶ms, variadic);
|
||||
// FIXME(antoyo): Should we do something with `FnAbiGcc::fn_attributes`?
|
||||
let FnAbiGcc {
|
||||
return_type,
|
||||
arguments_type,
|
||||
is_c_variadic,
|
||||
on_stack_param_indices,
|
||||
..
|
||||
} = self.gcc_type(cx);
|
||||
let pointer_type = cx.context.new_function_pointer_type(None, return_type, &arguments_type, is_c_variadic);
|
||||
cx.on_stack_params.borrow_mut().insert(pointer_type.dyncast_function_ptr_type().expect("function ptr type"), on_stack_param_indices);
|
||||
pointer_type
|
||||
}
|
||||
|
|
|
@ -53,6 +53,9 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
|
|||
codegen_fn_attrs.inline
|
||||
};
|
||||
if let Some(attr) = inline_attr(cx, inline) {
|
||||
if let FnAttribute::AlwaysInline = attr {
|
||||
func.add_attribute(FnAttribute::Inline);
|
||||
}
|
||||
func.add_attribute(attr);
|
||||
}
|
||||
|
||||
|
|
|
@ -98,10 +98,11 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock
|
|||
.map(|string| &string[1..])
|
||||
.collect();
|
||||
|
||||
// TODO(antoyo): only set on x86 platforms.
|
||||
context.add_command_line_option("-masm=intel");
|
||||
if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" {
|
||||
context.add_command_line_option("-masm=intel");
|
||||
}
|
||||
|
||||
if !disabled_features.contains("avx") {
|
||||
if !disabled_features.contains("avx") && tcx.sess.target.arch == "x86_64" {
|
||||
// NOTE: we always enable AVX because the equivalent of llvm.x86.sse2.cmp.pd in GCC for
|
||||
// SSE2 is multiple builtins, so we use the AVX __builtin_ia32_cmppd instead.
|
||||
// FIXME(antoyo): use the proper builtins for llvm.x86.sse2.cmp.pd and similar.
|
||||
|
|
|
@ -751,9 +751,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
loaded_value.to_rvalue()
|
||||
}
|
||||
|
||||
fn volatile_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
|
||||
// TODO(antoyo): use ty.
|
||||
let ptr = self.context.new_cast(None, ptr, ptr.get_type().make_volatile());
|
||||
fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let ptr = self.context.new_cast(None, ptr, ty.make_volatile().make_pointer());
|
||||
ptr.dereference(None).to_rvalue()
|
||||
}
|
||||
|
||||
|
|
|
@ -424,35 +424,35 @@ impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
|
|||
}
|
||||
|
||||
fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
|
||||
self.unqualified() == cx.i8_type
|
||||
self.is_compatible_with(cx.i8_type)
|
||||
}
|
||||
|
||||
fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
|
||||
self.unqualified() == cx.u8_type
|
||||
self.is_compatible_with(cx.u8_type)
|
||||
}
|
||||
|
||||
fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
|
||||
self.unqualified() == cx.i16_type
|
||||
self.is_compatible_with(cx.i16_type)
|
||||
}
|
||||
|
||||
fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
|
||||
self.unqualified() == cx.u16_type
|
||||
self.is_compatible_with(cx.u16_type)
|
||||
}
|
||||
|
||||
fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
|
||||
self.unqualified() == cx.i32_type
|
||||
self.is_compatible_with(cx.i32_type)
|
||||
}
|
||||
|
||||
fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
|
||||
self.unqualified() == cx.u32_type
|
||||
self.is_compatible_with(cx.u32_type)
|
||||
}
|
||||
|
||||
fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
|
||||
self.unqualified() == cx.i64_type
|
||||
self.is_compatible_with(cx.i64_type)
|
||||
}
|
||||
|
||||
fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
|
||||
self.unqualified() == cx.u64_type
|
||||
self.is_compatible_with(cx.u64_type)
|
||||
}
|
||||
|
||||
fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
|
||||
|
|
|
@ -20,6 +20,7 @@ use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDat
|
|||
use rustc_target::spec::{HasTargetSpec, Target, TlsModel};
|
||||
|
||||
use crate::callee::get_fn;
|
||||
use crate::common::SignType;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FuncSig<'gcc> {
|
||||
|
@ -129,29 +130,57 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, tcx: TyCtxt<'tcx>, supports_128bit_integers: bool) -> Self {
|
||||
let check_overflow = tcx.sess.overflow_checks();
|
||||
|
||||
let i8_type = context.new_c_type(CType::Int8t);
|
||||
let i16_type = context.new_c_type(CType::Int16t);
|
||||
let i32_type = context.new_c_type(CType::Int32t);
|
||||
let i64_type = context.new_c_type(CType::Int64t);
|
||||
let u8_type = context.new_c_type(CType::UInt8t);
|
||||
let u16_type = context.new_c_type(CType::UInt16t);
|
||||
let u32_type = context.new_c_type(CType::UInt32t);
|
||||
let u64_type = context.new_c_type(CType::UInt64t);
|
||||
let create_type = |ctype, rust_type| {
|
||||
let layout = tcx.layout_of(ParamEnv::reveal_all().and(rust_type)).unwrap();
|
||||
let align = layout.align.abi.bytes();
|
||||
#[cfg(feature="master")]
|
||||
{
|
||||
context.new_c_type(ctype).get_aligned(align)
|
||||
}
|
||||
#[cfg(not(feature="master"))]
|
||||
{
|
||||
// Since libgccjit 12 doesn't contain the fix to compare aligned integer types,
|
||||
// only align u128 and i128.
|
||||
if layout.ty.int_size_and_signed(tcx).0.bytes() == 16 {
|
||||
context.new_c_type(ctype).get_aligned(align)
|
||||
}
|
||||
else {
|
||||
context.new_c_type(ctype)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let i8_type = create_type(CType::Int8t, tcx.types.i8);
|
||||
let i16_type = create_type(CType::Int16t, tcx.types.i16);
|
||||
let i32_type = create_type(CType::Int32t, tcx.types.i32);
|
||||
let i64_type = create_type(CType::Int64t, tcx.types.i64);
|
||||
let u8_type = create_type(CType::UInt8t, tcx.types.u8);
|
||||
let u16_type = create_type(CType::UInt16t, tcx.types.u16);
|
||||
let u32_type = create_type(CType::UInt32t, tcx.types.u32);
|
||||
let u64_type = create_type(CType::UInt64t, tcx.types.u64);
|
||||
|
||||
let (i128_type, u128_type) =
|
||||
if supports_128bit_integers {
|
||||
let i128_type = context.new_c_type(CType::Int128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?;
|
||||
let u128_type = context.new_c_type(CType::UInt128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?;
|
||||
let i128_type = create_type(CType::Int128t, tcx.types.i128);
|
||||
let u128_type = create_type(CType::UInt128t, tcx.types.u128);
|
||||
(i128_type, u128_type)
|
||||
}
|
||||
else {
|
||||
let i128_type = context.new_array_type(None, i64_type, 2);
|
||||
let u128_type = context.new_array_type(None, u64_type, 2);
|
||||
/*let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.i128)).unwrap();
|
||||
let i128_align = layout.align.abi.bytes();
|
||||
let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.u128)).unwrap();
|
||||
let u128_align = layout.align.abi.bytes();*/
|
||||
|
||||
// TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in
|
||||
// gcc_jit_context_new_array_constructor (it should not use reinterpret_cast).
|
||||
let i128_type = context.new_array_type(None, i64_type, 2)/*.get_aligned(i128_align)*/;
|
||||
let u128_type = context.new_array_type(None, u64_type, 2)/*.get_aligned(u128_align)*/;
|
||||
(i128_type, u128_type)
|
||||
};
|
||||
|
||||
let tls_model = to_gcc_tls_mode(tcx.sess.tls_model());
|
||||
|
||||
// TODO(antoyo): set alignment on those types as well.
|
||||
let float_type = context.new_type::<f32>();
|
||||
let double_type = context.new_type::<f64>();
|
||||
|
||||
|
@ -167,14 +196,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
let ulonglong_type = context.new_c_type(CType::ULongLong);
|
||||
let sizet_type = context.new_c_type(CType::SizeT);
|
||||
|
||||
let isize_type = context.new_c_type(CType::LongLong);
|
||||
let usize_type = context.new_c_type(CType::ULongLong);
|
||||
let usize_type = sizet_type;
|
||||
let isize_type = usize_type;
|
||||
let bool_type = context.new_type::<bool>();
|
||||
|
||||
// TODO(antoyo): only have those assertions on x86_64.
|
||||
assert_eq!(isize_type.get_size(), i64_type.get_size());
|
||||
assert_eq!(usize_type.get_size(), u64_type.get_size());
|
||||
|
||||
let mut functions = FxHashMap::default();
|
||||
let builtins = [
|
||||
"__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow",
|
||||
|
@ -192,7 +217,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
functions.insert(builtin.to_string(), context.get_builtin_function(builtin));
|
||||
}
|
||||
|
||||
Self {
|
||||
let mut cx = Self {
|
||||
check_overflow,
|
||||
codegen_unit,
|
||||
context,
|
||||
|
@ -254,7 +279,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
pointee_infos: Default::default(),
|
||||
structs_as_pointer: Default::default(),
|
||||
cleanup_blocks: Default::default(),
|
||||
}
|
||||
};
|
||||
// TODO(antoyo): instead of doing this, add SsizeT to libgccjit.
|
||||
cx.isize_type = usize_type.to_signed(&cx);
|
||||
cx
|
||||
}
|
||||
|
||||
pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
|
||||
|
|
|
@ -6,7 +6,7 @@ use rustc_middle::ty::Ty;
|
|||
use rustc_span::Symbol;
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
|
||||
use crate::abi::FnAbiGccExt;
|
||||
use crate::abi::{FnAbiGcc, FnAbiGccExt};
|
||||
use crate::context::CodegenCx;
|
||||
use crate::intrinsic::llvm;
|
||||
|
||||
|
@ -80,9 +80,20 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> {
|
||||
let (return_type, params, variadic, on_stack_param_indices) = fn_abi.gcc_type(self);
|
||||
let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, ¶ms, variadic);
|
||||
let FnAbiGcc {
|
||||
return_type,
|
||||
arguments_type,
|
||||
is_c_variadic,
|
||||
on_stack_param_indices,
|
||||
#[cfg(feature="master")]
|
||||
fn_attributes,
|
||||
} = fn_abi.gcc_type(self);
|
||||
let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &arguments_type, is_c_variadic);
|
||||
self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices);
|
||||
#[cfg(feature="master")]
|
||||
for fn_attr in fn_attributes {
|
||||
func.add_attribute(fn_attr);
|
||||
}
|
||||
func
|
||||
}
|
||||
|
||||
|
|
|
@ -198,9 +198,16 @@ pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) ->
|
|||
None
|
||||
}
|
||||
|
||||
fn arch_to_gcc(name: &str) -> &str {
|
||||
match name {
|
||||
"M68020" => "68020",
|
||||
_ => name,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_native(name: &str) -> &str {
|
||||
if name != "native" {
|
||||
return name;
|
||||
return arch_to_gcc(name);
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
|
|
|
@ -7,7 +7,9 @@ use std::convert::TryFrom;
|
|||
use gccjit::{ComparisonOp, FunctionType, RValue, ToRValue, Type, UnaryOp, BinaryOp};
|
||||
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
||||
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::{ParamEnv, Ty};
|
||||
use rustc_target::abi::{Endian, call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}};
|
||||
use rustc_target::spec;
|
||||
|
||||
use crate::builder::ToGccComp;
|
||||
use crate::{builder::Builder, common::{SignType, TypeReflection}, context::CodegenCx};
|
||||
|
@ -37,11 +39,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
}
|
||||
else {
|
||||
let element_type = typ.dyncast_array().expect("element type");
|
||||
let values = [
|
||||
self.from_low_high_rvalues(typ,
|
||||
self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.low(a)),
|
||||
self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.high(a)),
|
||||
];
|
||||
self.cx.context.new_array_constructor(None, typ, &values)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +101,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero);
|
||||
self.llbb().end_with_conditional(None, condition, then_block, else_block);
|
||||
|
||||
// TODO(antoyo): take endianness into account.
|
||||
let shift_value = self.gcc_sub(b, sixty_four);
|
||||
let high = self.high(a);
|
||||
let sign =
|
||||
|
@ -110,11 +110,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
else {
|
||||
zero
|
||||
};
|
||||
let values = [
|
||||
high >> shift_value,
|
||||
sign,
|
||||
];
|
||||
let array_value = self.context.new_array_constructor(None, a_type, &values);
|
||||
let array_value = self.from_low_high_rvalues(a_type, high >> shift_value, sign);
|
||||
then_block.add_assignment(None, result, array_value);
|
||||
then_block.end_with_jump(None, after_block);
|
||||
|
||||
|
@ -130,11 +126,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
let casted_low = self.context.new_cast(None, self.low(a), unsigned_type);
|
||||
let shifted_low = casted_low >> self.context.new_cast(None, b, unsigned_type);
|
||||
let shifted_low = self.context.new_cast(None, shifted_low, native_int_type);
|
||||
let values = [
|
||||
let array_value = self.from_low_high_rvalues(a_type,
|
||||
(high << shift_value) | shifted_low,
|
||||
high >> b,
|
||||
];
|
||||
let array_value = self.context.new_array_constructor(None, a_type, &values);
|
||||
);
|
||||
actual_else_block.add_assignment(None, result, array_value);
|
||||
actual_else_block.end_with_jump(None, after_block);
|
||||
|
||||
|
@ -314,18 +309,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
_ => unreachable!(),
|
||||
},
|
||||
};
|
||||
let a_type = lhs.get_type();
|
||||
let b_type = rhs.get_type();
|
||||
let param_a = self.context.new_parameter(None, a_type, "a");
|
||||
let param_b = self.context.new_parameter(None, b_type, "b");
|
||||
let result_field = self.context.new_field(None, a_type, "result");
|
||||
let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
|
||||
let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
|
||||
let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
|
||||
let result = self.context.new_call(None, func, &[lhs, rhs]);
|
||||
let overflow = result.access_field(None, overflow_field);
|
||||
let int_result = result.access_field(None, result_field);
|
||||
return (int_result, overflow);
|
||||
return self.operation_with_overflow(func_name, lhs, rhs);
|
||||
},
|
||||
_ => {
|
||||
match oop {
|
||||
|
@ -350,6 +334,54 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
(res.dereference(None).to_rvalue(), overflow)
|
||||
}
|
||||
|
||||
pub fn operation_with_overflow(&self, func_name: &str, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
|
||||
let a_type = lhs.get_type();
|
||||
let b_type = rhs.get_type();
|
||||
let param_a = self.context.new_parameter(None, a_type, "a");
|
||||
let param_b = self.context.new_parameter(None, b_type, "b");
|
||||
let result_field = self.context.new_field(None, a_type, "result");
|
||||
let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
|
||||
|
||||
let ret_ty = Ty::new_tup(self.tcx, &[self.tcx.types.i128, self.tcx.types.bool]);
|
||||
let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ret_ty)).unwrap();
|
||||
|
||||
let arg_abi = ArgAbi {
|
||||
layout,
|
||||
mode: PassMode::Direct(ArgAttributes::new()),
|
||||
};
|
||||
let mut fn_abi = FnAbi {
|
||||
args: vec![arg_abi.clone(), arg_abi.clone()].into_boxed_slice(),
|
||||
ret: arg_abi,
|
||||
c_variadic: false,
|
||||
fixed_count: 2,
|
||||
conv: Conv::C,
|
||||
can_unwind: false,
|
||||
};
|
||||
fn_abi.adjust_for_foreign_abi(self.cx, spec::abi::Abi::C {
|
||||
unwind: false,
|
||||
}).unwrap();
|
||||
|
||||
let indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
|
||||
|
||||
let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
|
||||
let result =
|
||||
if indirect {
|
||||
let return_value = self.current_func().new_local(None, return_type.as_type(), "return_value");
|
||||
let return_param_type = return_type.as_type().make_pointer();
|
||||
let return_param = self.context.new_parameter(None, return_param_type, "return_value");
|
||||
let func = self.context.new_function(None, FunctionType::Extern, self.type_void(), &[return_param, param_a, param_b], func_name, false);
|
||||
self.llbb().add_eval(None, self.context.new_call(None, func, &[return_value.get_address(None), lhs, rhs]));
|
||||
return_value.to_rvalue()
|
||||
}
|
||||
else {
|
||||
let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
|
||||
self.context.new_call(None, func, &[lhs, rhs])
|
||||
};
|
||||
let overflow = result.access_field(None, overflow_field);
|
||||
let int_result = result.access_field(None, result_field);
|
||||
return (int_result, overflow);
|
||||
}
|
||||
|
||||
pub fn gcc_icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let a_type = lhs.get_type();
|
||||
let b_type = rhs.get_type();
|
||||
|
@ -415,6 +447,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
IntPredicate::IntNE => {
|
||||
return self.context.new_comparison(None, ComparisonOp::NotEquals, cmp, self.context.new_rvalue_one(self.int_type));
|
||||
},
|
||||
// TODO(antoyo): cast to u128 for unsigned comparison. See below.
|
||||
IntPredicate::IntUGT => (ComparisonOp::Equals, 2),
|
||||
IntPredicate::IntUGE => (ComparisonOp::GreaterThanEquals, 1),
|
||||
IntPredicate::IntULT => (ComparisonOp::Equals, 0),
|
||||
|
@ -444,6 +477,18 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
rhs = self.context.new_cast(None, rhs, a_type);
|
||||
}
|
||||
}
|
||||
match op {
|
||||
IntPredicate::IntUGT | IntPredicate::IntUGE | IntPredicate::IntULT | IntPredicate::IntULE => {
|
||||
if !a_type.is_vector() {
|
||||
let unsigned_type = a_type.to_unsigned(&self.cx);
|
||||
lhs = self.context.new_cast(None, lhs, unsigned_type);
|
||||
rhs = self.context.new_cast(None, rhs, unsigned_type);
|
||||
}
|
||||
},
|
||||
// TODO(antoyo): we probably need to handle signed comparison for unsigned
|
||||
// integers.
|
||||
_ => (),
|
||||
}
|
||||
self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
|
||||
}
|
||||
}
|
||||
|
@ -455,11 +500,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
a ^ b
|
||||
}
|
||||
else {
|
||||
let values = [
|
||||
self.from_low_high_rvalues(a_type,
|
||||
self.low(a) ^ self.low(b),
|
||||
self.high(a) ^ self.high(b),
|
||||
];
|
||||
self.context.new_array_constructor(None, a_type, &values)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -505,12 +549,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero);
|
||||
self.llbb().end_with_conditional(None, condition, then_block, else_block);
|
||||
|
||||
// TODO(antoyo): take endianness into account.
|
||||
let values = [
|
||||
let array_value = self.from_low_high_rvalues(a_type,
|
||||
zero,
|
||||
self.low(a) << (b - sixty_four),
|
||||
];
|
||||
let array_value = self.context.new_array_constructor(None, a_type, &values);
|
||||
);
|
||||
then_block.add_assignment(None, result, array_value);
|
||||
then_block.end_with_jump(None, after_block);
|
||||
|
||||
|
@ -521,16 +563,16 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
b0_block.end_with_jump(None, after_block);
|
||||
|
||||
// NOTE: cast low to its unsigned type in order to perform a logical right shift.
|
||||
// TODO(antoyo): adjust this ^ comment.
|
||||
let unsigned_type = native_int_type.to_unsigned(&self.cx);
|
||||
let casted_low = self.context.new_cast(None, self.low(a), unsigned_type);
|
||||
let shift_value = self.context.new_cast(None, sixty_four - b, unsigned_type);
|
||||
let high_low = self.context.new_cast(None, casted_low >> shift_value, native_int_type);
|
||||
let values = [
|
||||
|
||||
let array_value = self.from_low_high_rvalues(a_type,
|
||||
self.low(a) << b,
|
||||
(self.high(a) << b) | high_low,
|
||||
];
|
||||
|
||||
let array_value = self.context.new_array_constructor(None, a_type, &values);
|
||||
);
|
||||
actual_else_block.add_assignment(None, result, array_value);
|
||||
actual_else_block.end_with_jump(None, after_block);
|
||||
|
||||
|
@ -546,16 +588,16 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
let arg_type = arg.get_type();
|
||||
if !self.is_native_int_type(arg_type) {
|
||||
let native_int_type = arg_type.dyncast_array().expect("get element type");
|
||||
let lsb = self.context.new_array_access(None, arg, self.context.new_rvalue_from_int(self.int_type, 0)).to_rvalue();
|
||||
let lsb = self.low(arg);
|
||||
let swapped_lsb = self.gcc_bswap(lsb, width / 2);
|
||||
let swapped_lsb = self.context.new_cast(None, swapped_lsb, native_int_type);
|
||||
let msb = self.context.new_array_access(None, arg, self.context.new_rvalue_from_int(self.int_type, 1)).to_rvalue();
|
||||
let msb = self.high(arg);
|
||||
let swapped_msb = self.gcc_bswap(msb, width / 2);
|
||||
let swapped_msb = self.context.new_cast(None, swapped_msb, native_int_type);
|
||||
|
||||
// NOTE: we also need to swap the two elements here, in addition to swapping inside
|
||||
// the elements themselves like done above.
|
||||
return self.context.new_array_constructor(None, arg_type, &[swapped_msb, swapped_lsb]);
|
||||
return self.from_low_high_rvalues(arg_type, swapped_msb, swapped_lsb);
|
||||
}
|
||||
|
||||
// TODO(antoyo): check if it's faster to use string literals and a
|
||||
|
@ -659,11 +701,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
else {
|
||||
assert!(!a_native && !b_native, "both types should either be native or non-native for or operation");
|
||||
let native_int_type = a_type.dyncast_array().expect("get element type");
|
||||
let values = [
|
||||
self.from_low_high_rvalues(a_type,
|
||||
self.context.new_binary_op(None, operation, native_int_type, self.low(a), self.low(b)),
|
||||
self.context.new_binary_op(None, operation, native_int_type, self.high(a), self.high(b)),
|
||||
];
|
||||
self.context.new_array_constructor(None, a_type, &values)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -687,11 +728,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
let zero = self.context.new_rvalue_zero(value_type);
|
||||
let is_negative = self.context.new_comparison(None, ComparisonOp::LessThan, value, zero);
|
||||
let is_negative = self.gcc_int_cast(is_negative, dest_element_type);
|
||||
let values = [
|
||||
self.from_low_high_rvalues(dest_typ,
|
||||
self.context.new_cast(None, value, dest_element_type),
|
||||
self.context.new_unary_op(None, UnaryOp::Minus, dest_element_type, is_negative),
|
||||
];
|
||||
self.context.new_array_constructor(None, dest_typ, &values)
|
||||
)
|
||||
}
|
||||
else {
|
||||
// Since u128 and i128 are the only types that can be unsupported, we know the type of
|
||||
|
@ -769,20 +809,47 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
fn high(&self, value: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, 1))
|
||||
let index =
|
||||
match self.sess().target.options.endian {
|
||||
Endian::Little => 1,
|
||||
Endian::Big => 0,
|
||||
};
|
||||
self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, index))
|
||||
.to_rvalue()
|
||||
}
|
||||
|
||||
fn low(&self, value: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, 0))
|
||||
let index =
|
||||
match self.sess().target.options.endian {
|
||||
Endian::Little => 0,
|
||||
Endian::Big => 1,
|
||||
};
|
||||
self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, index))
|
||||
.to_rvalue()
|
||||
}
|
||||
|
||||
fn from_low_high_rvalues(&self, typ: Type<'gcc>, low: RValue<'gcc>, high: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let (first, last) =
|
||||
match self.sess().target.options.endian {
|
||||
Endian::Little => (low, high),
|
||||
Endian::Big => (high, low),
|
||||
};
|
||||
|
||||
let values = [first, last];
|
||||
self.context.new_array_constructor(None, typ, &values)
|
||||
}
|
||||
|
||||
fn from_low_high(&self, typ: Type<'gcc>, low: i64, high: i64) -> RValue<'gcc> {
|
||||
let (first, last) =
|
||||
match self.sess().target.options.endian {
|
||||
Endian::Little => (low, high),
|
||||
Endian::Big => (high, low),
|
||||
};
|
||||
|
||||
let native_int_type = typ.dyncast_array().expect("get element type");
|
||||
let values = [
|
||||
self.context.new_rvalue_from_long(native_int_type, low),
|
||||
self.context.new_rvalue_from_long(native_int_type, high),
|
||||
self.context.new_rvalue_from_long(native_int_type, first),
|
||||
self.context.new_rvalue_from_long(native_int_type, last),
|
||||
];
|
||||
self.context.new_array_constructor(None, typ, &values)
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -432,15 +432,21 @@ pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool {
|
|||
|
||||
#[cfg(not(feature="master"))]
|
||||
pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
|
||||
match name {
|
||||
"llvm.x86.xgetbv" | "llvm.x86.sse2.pause" => {
|
||||
let gcc_name = "__builtin_trap";
|
||||
let func = cx.context.get_builtin_function(gcc_name);
|
||||
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
|
||||
return func;
|
||||
},
|
||||
_ => unimplemented!("unsupported LLVM intrinsic {}", name),
|
||||
}
|
||||
let gcc_name =
|
||||
match name {
|
||||
"llvm.x86.sse2.pause" => {
|
||||
// NOTE: pause is only a hint, so we use a dummy built-in because target built-ins
|
||||
// are not supported in libgccjit 12.
|
||||
"__builtin_inff"
|
||||
},
|
||||
"llvm.x86.xgetbv" => {
|
||||
"__builtin_trap"
|
||||
},
|
||||
_ => unimplemented!("unsupported LLVM intrinsic {}", name),
|
||||
};
|
||||
let func = cx.context.get_builtin_function(gcc_name);
|
||||
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
|
||||
return func;
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
|
|
|
@ -4,7 +4,9 @@ mod simd;
|
|||
#[cfg(feature="master")]
|
||||
use std::iter;
|
||||
|
||||
use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp, FunctionType};
|
||||
#[cfg(feature="master")]
|
||||
use gccjit::FunctionType;
|
||||
use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp};
|
||||
use rustc_codegen_ssa::MemFlags;
|
||||
use rustc_codegen_ssa::base::wants_msvc_seh;
|
||||
use rustc_codegen_ssa::common::IntPredicate;
|
||||
|
@ -143,11 +145,15 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
|
||||
sym::volatile_load | sym::unaligned_volatile_load => {
|
||||
let tp_ty = fn_args.type_at(0);
|
||||
let mut ptr = args[0].immediate();
|
||||
if let PassMode::Cast { 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);
|
||||
let ptr = args[0].immediate();
|
||||
let load =
|
||||
if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode {
|
||||
let gcc_ty = ty.gcc_type(self);
|
||||
self.volatile_load(gcc_ty, ptr)
|
||||
}
|
||||
else {
|
||||
self.volatile_load(self.layout_of(tp_ty).gcc_type(self), ptr)
|
||||
};
|
||||
// TODO(antoyo): set alignment.
|
||||
self.to_immediate(load, self.layout_of(tp_ty))
|
||||
}
|
||||
|
@ -819,75 +825,58 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
value
|
||||
};
|
||||
|
||||
if value_type.is_u128(&self.cx) {
|
||||
// TODO(antoyo): implement in the normal algorithm below to have a more efficient
|
||||
// implementation (that does not require a call to __popcountdi2).
|
||||
let popcount = self.context.get_builtin_function("__builtin_popcountll");
|
||||
// only break apart 128-bit ints if they're not natively supported
|
||||
// TODO(antoyo): remove this if/when native 128-bit integers land in libgccjit
|
||||
if value_type.is_u128(&self.cx) && !self.cx.supports_128bit_integers {
|
||||
let sixty_four = self.gcc_int(value_type, 64);
|
||||
let right_shift = self.gcc_lshr(value, sixty_four);
|
||||
let high = self.gcc_int_cast(right_shift, self.cx.ulonglong_type);
|
||||
let high = self.context.new_call(None, popcount, &[high]);
|
||||
let high = self.pop_count(high);
|
||||
let low = self.gcc_int_cast(value, self.cx.ulonglong_type);
|
||||
let low = self.context.new_call(None, popcount, &[low]);
|
||||
let low = self.pop_count(low);
|
||||
let res = high + low;
|
||||
return self.gcc_int_cast(res, result_type);
|
||||
}
|
||||
|
||||
// First step.
|
||||
let mask = self.context.new_rvalue_from_long(value_type, 0x5555555555555555);
|
||||
let left = value & mask;
|
||||
let shifted = value >> self.context.new_rvalue_from_int(value_type, 1);
|
||||
let right = shifted & mask;
|
||||
let value = left + right;
|
||||
// Use Wenger's algorithm for population count, gcc's seems to play better with it
|
||||
// for (int counter = 0; value != 0; counter++) {
|
||||
// value &= value - 1;
|
||||
// }
|
||||
let func = self.current_func.borrow().expect("func");
|
||||
let loop_head = func.new_block("head");
|
||||
let loop_body = func.new_block("body");
|
||||
let loop_tail = func.new_block("tail");
|
||||
|
||||
// Second step.
|
||||
let mask = self.context.new_rvalue_from_long(value_type, 0x3333333333333333);
|
||||
let left = value & mask;
|
||||
let shifted = value >> self.context.new_rvalue_from_int(value_type, 2);
|
||||
let right = shifted & mask;
|
||||
let value = left + right;
|
||||
let counter_type = self.int_type;
|
||||
let counter = self.current_func().new_local(None, counter_type, "popcount_counter");
|
||||
let val = self.current_func().new_local(None, value_type, "popcount_value");
|
||||
let zero = self.gcc_zero(counter_type);
|
||||
self.llbb().add_assignment(None, counter, zero);
|
||||
self.llbb().add_assignment(None, val, value);
|
||||
self.br(loop_head);
|
||||
|
||||
// Third step.
|
||||
let mask = self.context.new_rvalue_from_long(value_type, 0x0F0F0F0F0F0F0F0F);
|
||||
let left = value & mask;
|
||||
let shifted = value >> self.context.new_rvalue_from_int(value_type, 4);
|
||||
let right = shifted & mask;
|
||||
let value = left + right;
|
||||
// check if value isn't zero
|
||||
self.switch_to_block(loop_head);
|
||||
let zero = self.gcc_zero(value_type);
|
||||
let cond = self.gcc_icmp(IntPredicate::IntNE, val.to_rvalue(), zero);
|
||||
self.cond_br(cond, loop_body, loop_tail);
|
||||
|
||||
if value_type.is_u8(&self.cx) {
|
||||
return self.context.new_cast(None, value, result_type);
|
||||
}
|
||||
// val &= val - 1;
|
||||
self.switch_to_block(loop_body);
|
||||
let one = self.gcc_int(value_type, 1);
|
||||
let sub = self.gcc_sub(val.to_rvalue(), one);
|
||||
let op = self.gcc_and(val.to_rvalue(), sub);
|
||||
loop_body.add_assignment(None, val, op);
|
||||
|
||||
// Fourth step.
|
||||
let mask = self.context.new_rvalue_from_long(value_type, 0x00FF00FF00FF00FF);
|
||||
let left = value & mask;
|
||||
let shifted = value >> self.context.new_rvalue_from_int(value_type, 8);
|
||||
let right = shifted & mask;
|
||||
let value = left + right;
|
||||
// counter += 1
|
||||
let one = self.gcc_int(counter_type, 1);
|
||||
let op = self.gcc_add(counter.to_rvalue(), one);
|
||||
loop_body.add_assignment(None, counter, op);
|
||||
self.br(loop_head);
|
||||
|
||||
if value_type.is_u16(&self.cx) {
|
||||
return self.context.new_cast(None, value, result_type);
|
||||
}
|
||||
|
||||
// Fifth step.
|
||||
let mask = self.context.new_rvalue_from_long(value_type, 0x0000FFFF0000FFFF);
|
||||
let left = value & mask;
|
||||
let shifted = value >> self.context.new_rvalue_from_int(value_type, 16);
|
||||
let right = shifted & mask;
|
||||
let value = left + right;
|
||||
|
||||
if value_type.is_u32(&self.cx) {
|
||||
return self.context.new_cast(None, value, result_type);
|
||||
}
|
||||
|
||||
// Sixth step.
|
||||
let mask = self.context.new_rvalue_from_long(value_type, 0x00000000FFFFFFFF);
|
||||
let left = value & mask;
|
||||
let shifted = value >> self.context.new_rvalue_from_int(value_type, 32);
|
||||
let right = shifted & mask;
|
||||
let value = left + right;
|
||||
|
||||
self.context.new_cast(None, value, result_type)
|
||||
// end of loop
|
||||
self.switch_to_block(loop_tail);
|
||||
self.gcc_int_cast(counter.to_rvalue(), result_type)
|
||||
}
|
||||
|
||||
// Algorithm from: https://blog.regehr.org/archives/1063
|
||||
|
@ -947,15 +936,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
128 => "__rust_i128_addo",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let param_a = self.context.new_parameter(None, result_type, "a");
|
||||
let param_b = self.context.new_parameter(None, result_type, "b");
|
||||
let result_field = self.context.new_field(None, result_type, "result");
|
||||
let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
|
||||
let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
|
||||
let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
|
||||
let result = self.context.new_call(None, func, &[lhs, rhs]);
|
||||
let overflow = result.access_field(None, overflow_field);
|
||||
let int_result = result.access_field(None, result_field);
|
||||
let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs);
|
||||
self.llbb().add_assignment(None, res, int_result);
|
||||
overflow
|
||||
};
|
||||
|
@ -1017,15 +998,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
128 => "__rust_i128_subo",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let param_a = self.context.new_parameter(None, result_type, "a");
|
||||
let param_b = self.context.new_parameter(None, result_type, "b");
|
||||
let result_field = self.context.new_field(None, result_type, "result");
|
||||
let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
|
||||
let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
|
||||
let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
|
||||
let result = self.context.new_call(None, func, &[lhs, rhs]);
|
||||
let overflow = result.access_field(None, overflow_field);
|
||||
let int_result = result.access_field(None, result_field);
|
||||
let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs);
|
||||
self.llbb().add_assignment(None, res, int_result);
|
||||
overflow
|
||||
};
|
||||
|
@ -1197,7 +1170,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, codegen: &mut
|
|||
#[cfg(feature="master")]
|
||||
fn gen_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, name: &str, rust_fn_sig: ty::PolyFnSig<'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) {
|
||||
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
|
||||
let (typ, _, _, _) = fn_abi.gcc_type(cx);
|
||||
let return_type = fn_abi.gcc_type(cx).return_type;
|
||||
// FIXME(eddyb) find a nicer way to do this.
|
||||
cx.linkage.set(FunctionType::Internal);
|
||||
let func = cx.declare_fn(name, fn_abi);
|
||||
|
@ -1207,5 +1180,5 @@ fn gen_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, name: &str, rust_fn_sig
|
|||
let block = Builder::append_block(cx, func_val, "entry-block");
|
||||
let bx = Builder::build(cx, block);
|
||||
codegen(bx);
|
||||
(typ, func)
|
||||
(return_type, func)
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
* TODO(antoyo): remove the patches.
|
||||
*/
|
||||
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![cfg_attr(not(bootstrap), doc(rust_logo))]
|
||||
#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
|
||||
#![feature(
|
||||
|
@ -251,8 +252,9 @@ impl ExtraBackendMethods for GccCodegenBackend {
|
|||
temp_dir: None,
|
||||
};
|
||||
|
||||
// TODO(antoyo): only set for x86.
|
||||
mods.context.add_command_line_option("-masm=intel");
|
||||
if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" {
|
||||
mods.context.add_command_line_option("-masm=intel");
|
||||
}
|
||||
unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
|
||||
mods
|
||||
}
|
||||
|
|
|
@ -119,11 +119,11 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
fn type_f32(&self) -> Type<'gcc> {
|
||||
self.context.new_type::<f32>()
|
||||
self.float_type
|
||||
}
|
||||
|
||||
fn type_f64(&self) -> Type<'gcc> {
|
||||
self.context.new_type::<f64>()
|
||||
self.double_type
|
||||
}
|
||||
|
||||
fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> {
|
||||
|
@ -216,17 +216,17 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
value.get_type()
|
||||
}
|
||||
|
||||
fn type_array(&self, ty: Type<'gcc>, len: u64) -> Type<'gcc> {
|
||||
// TODO: remove this as well?
|
||||
/*if let Some(struct_type) = ty.is_struct() {
|
||||
#[cfg_attr(feature="master", allow(unused_mut))]
|
||||
fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
|
||||
#[cfg(not(feature="master"))]
|
||||
if let Some(struct_type) = ty.is_struct() {
|
||||
if struct_type.get_field_count() == 0 {
|
||||
// NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
|
||||
// size of usize::MAX in test_binary_search, we workaround this by setting the size to
|
||||
// zero for ZSTs.
|
||||
// FIXME(antoyo): fix gccjit API.
|
||||
len = 0;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
self.context.new_array_type(None, ty, len)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
|||
use rustc_target::abi::{self, Abi, Align, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants};
|
||||
use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
|
||||
|
||||
use crate::abi::{FnAbiGccExt, GccType};
|
||||
use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType};
|
||||
use crate::context::CodegenCx;
|
||||
use crate::type_::struct_fields;
|
||||
|
||||
|
@ -372,7 +372,13 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
|
||||
let (return_type, param_types, variadic, _) = fn_abi.gcc_type(self);
|
||||
self.context.new_function_pointer_type(None, return_type, ¶m_types, variadic)
|
||||
// FIXME(antoyo): Should we do something with `FnAbiGcc::fn_attributes`?
|
||||
let FnAbiGcc {
|
||||
return_type,
|
||||
arguments_type,
|
||||
is_c_variadic,
|
||||
..
|
||||
} = fn_abi.gcc_type(self);
|
||||
self.context.new_function_pointer_type(None, return_type, &arguments_type, is_c_variadic)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue