commit
d0ecf0c262
27 changed files with 3742 additions and 2627 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
@ -49,6 +49,9 @@ jobs:
|
|||
# `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests.
|
||||
run: sudo apt-get install ninja-build ripgrep llvm-14-tools
|
||||
|
||||
- name: Install rustfmt
|
||||
run: rustup component add rustfmt
|
||||
|
||||
- name: Download artifact
|
||||
run: curl -LO https://github.com/antoyo/gcc/releases/latest/download/${{ matrix.libgccjit_version.gcc }}
|
||||
|
||||
|
@ -92,6 +95,9 @@ jobs:
|
|||
run: |
|
||||
./y.sh test --release --clean --build-sysroot ${{ matrix.commands }}
|
||||
|
||||
- name: Check formatting
|
||||
run: cargo fmt -- --check
|
||||
|
||||
duplicates:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
|
|
@ -1 +1 @@
|
|||
ignore = ["/src", "/tests"]
|
||||
use_small_heuristics = "Max"
|
||||
|
|
107
src/abi.rs
107
src/abi.rs
|
@ -18,17 +18,16 @@ impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
fn get_param(&mut self, index: usize) -> Self::Value {
|
||||
let func = self.current_func();
|
||||
let param = func.get_param(index as i32);
|
||||
let on_stack =
|
||||
if let Some(on_stack_param_indices) = self.on_stack_function_params.borrow().get(&func) {
|
||||
on_stack_param_indices.contains(&index)
|
||||
}
|
||||
else {
|
||||
false
|
||||
};
|
||||
let on_stack = if let Some(on_stack_param_indices) =
|
||||
self.on_stack_function_params.borrow().get(&func)
|
||||
{
|
||||
on_stack_param_indices.contains(&index)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if on_stack {
|
||||
param.to_lvalue().get_address(None)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
param.to_rvalue()
|
||||
}
|
||||
}
|
||||
|
@ -37,13 +36,14 @@ impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
impl GccType for CastTarget {
|
||||
fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> {
|
||||
let rest_gcc_unit = self.rest.unit.gcc_type(cx);
|
||||
let (rest_count, rem_bytes) =
|
||||
if self.rest.unit.size.bytes() == 0 {
|
||||
(0, 0)
|
||||
}
|
||||
else {
|
||||
(self.rest.total.bytes() / self.rest.unit.size.bytes(), self.rest.total.bytes() % self.rest.unit.size.bytes())
|
||||
};
|
||||
let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 {
|
||||
(0, 0)
|
||||
} else {
|
||||
(
|
||||
self.rest.total.bytes() / self.rest.unit.size.bytes(),
|
||||
self.rest.total.bytes() % self.rest.unit.size.bytes(),
|
||||
)
|
||||
};
|
||||
|
||||
if self.prefix.iter().all(|x| x.is_none()) {
|
||||
// Simplify to a single unit when there is no prefix and size <= unit size
|
||||
|
@ -61,9 +61,7 @@ impl GccType for CastTarget {
|
|||
let mut args: Vec<_> = self
|
||||
.prefix
|
||||
.iter()
|
||||
.flat_map(|option_reg| {
|
||||
option_reg.map(|reg| reg.gcc_type(cx))
|
||||
})
|
||||
.flat_map(|option_reg| option_reg.map(|reg| reg.gcc_type(cx)))
|
||||
.chain((0..rest_count).map(|_| rest_gcc_unit))
|
||||
.collect();
|
||||
|
||||
|
@ -86,12 +84,10 @@ impl GccType for Reg {
|
|||
fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> {
|
||||
match self.kind {
|
||||
RegKind::Integer => cx.type_ix(self.size.bits()),
|
||||
RegKind::Float => {
|
||||
match self.size.bits() {
|
||||
32 => cx.type_f32(),
|
||||
64 => cx.type_f64(),
|
||||
_ => bug!("unsupported float: {:?}", self),
|
||||
}
|
||||
RegKind::Float => match self.size.bits() {
|
||||
32 => cx.type_f32(),
|
||||
64 => cx.type_f64(),
|
||||
_ => bug!("unsupported float: {:?}", self),
|
||||
},
|
||||
RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()),
|
||||
}
|
||||
|
@ -119,19 +115,18 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
|
||||
// This capacity calculation is approximate.
|
||||
let mut argument_tys = Vec::with_capacity(
|
||||
self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 }
|
||||
self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 },
|
||||
);
|
||||
|
||||
let return_type =
|
||||
match self.ret.mode {
|
||||
PassMode::Ignore => cx.type_void(),
|
||||
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_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()
|
||||
}
|
||||
};
|
||||
let return_type = match self.ret.mode {
|
||||
PassMode::Ignore => cx.type_void(),
|
||||
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_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()
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "master")]
|
||||
let mut non_null_args = Vec::new();
|
||||
|
||||
|
@ -149,17 +144,23 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
ty
|
||||
};
|
||||
#[cfg(not(feature = "master"))]
|
||||
let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes, _arg_index: usize| {
|
||||
ty
|
||||
};
|
||||
let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes, _arg_index: usize| ty;
|
||||
|
||||
for arg in self.args.iter() {
|
||||
let arg_ty = match arg.mode {
|
||||
PassMode::Ignore => continue,
|
||||
PassMode::Pair(a, 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));
|
||||
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 } => {
|
||||
|
@ -174,14 +175,17 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
// 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, argument_tys.len()),
|
||||
}
|
||||
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, argument_tys.len())
|
||||
}
|
||||
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
|
||||
assert!(!on_stack);
|
||||
let ty = apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len());
|
||||
let ty =
|
||||
apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len());
|
||||
apply_attrs(ty, &meta_attrs, argument_tys.len())
|
||||
}
|
||||
};
|
||||
|
@ -207,15 +211,14 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
|
||||
fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
|
||||
// FIXME(antoyo): Should we do something with `FnAbiGcc::fn_attributes`?
|
||||
let FnAbiGcc {
|
||||
return_type,
|
||||
arguments_type,
|
||||
is_c_variadic,
|
||||
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,
|
||||
..
|
||||
} = 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::FnAttribute;
|
||||
use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type};
|
||||
use rustc_ast::expand::allocator::{
|
||||
|
@ -11,15 +11,20 @@ use rustc_session::config::OomStrategy;
|
|||
|
||||
use crate::GccContext;
|
||||
|
||||
pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) {
|
||||
pub(crate) unsafe fn codegen(
|
||||
tcx: TyCtxt<'_>,
|
||||
mods: &mut GccContext,
|
||||
_module_name: &str,
|
||||
kind: AllocatorKind,
|
||||
alloc_error_handler_kind: AllocatorKind,
|
||||
) {
|
||||
let context = &mods.context;
|
||||
let usize =
|
||||
match tcx.sess.target.pointer_width {
|
||||
16 => context.new_type::<u16>(),
|
||||
32 => context.new_type::<u32>(),
|
||||
64 => context.new_type::<u64>(),
|
||||
tws => bug!("Unsupported target word size for int: {}", tws),
|
||||
};
|
||||
let usize = match tcx.sess.target.pointer_width {
|
||||
16 => context.new_type::<u16>(),
|
||||
32 => context.new_type::<u32>(),
|
||||
64 => context.new_type::<u64>(),
|
||||
tws => bug!("Unsupported target word size for int: {}", tws),
|
||||
};
|
||||
let i8 = context.new_type::<i8>();
|
||||
let i8p = i8.make_pointer();
|
||||
|
||||
|
@ -85,24 +90,42 @@ fn create_wrapper_function(
|
|||
) {
|
||||
let void = context.new_type::<()>();
|
||||
|
||||
let args: Vec<_> = types.iter().enumerate()
|
||||
let args: Vec<_> = types
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
|
||||
.collect();
|
||||
let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, from_name, false);
|
||||
let func = context.new_function(
|
||||
None,
|
||||
FunctionType::Exported,
|
||||
output.unwrap_or(void),
|
||||
&args,
|
||||
from_name,
|
||||
false,
|
||||
);
|
||||
|
||||
if tcx.sess.default_hidden_visibility() {
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
||||
}
|
||||
if tcx.sess.must_emit_unwind_tables() {
|
||||
// TODO(antoyo): emit unwind tables.
|
||||
}
|
||||
|
||||
let args: Vec<_> = types.iter().enumerate()
|
||||
let args: Vec<_> = types
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
|
||||
.collect();
|
||||
let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, to_name, false);
|
||||
#[cfg(feature="master")]
|
||||
let callee = context.new_function(
|
||||
None,
|
||||
FunctionType::Extern,
|
||||
output.unwrap_or(void),
|
||||
&args,
|
||||
to_name,
|
||||
false,
|
||||
);
|
||||
#[cfg(feature = "master")]
|
||||
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
||||
|
||||
let block = func.new_block("entry");
|
||||
|
@ -116,8 +139,7 @@ fn create_wrapper_function(
|
|||
//llvm::LLVMSetTailCall(ret, True);
|
||||
if output.is_some() {
|
||||
block.end_with_return(None, ret);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
block.end_with_void_return(None);
|
||||
}
|
||||
|
||||
|
|
217
src/asm.rs
217
src/asm.rs
|
@ -2,7 +2,10 @@ use gccjit::{LValue, RValue, ToRValue, Type};
|
|||
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_codegen_ssa::mir::operand::OperandValue;
|
||||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||
use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
|
||||
use rustc_codegen_ssa::traits::{
|
||||
AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef,
|
||||
InlineAsmOperandRef,
|
||||
};
|
||||
|
||||
use rustc_middle::{bug, ty::Instance};
|
||||
use rustc_span::Span;
|
||||
|
@ -11,11 +14,10 @@ use rustc_target::asm::*;
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::callee::get_fn;
|
||||
use crate::context::CodegenCx;
|
||||
use crate::errors::UnwindingInlineAsm;
|
||||
use crate::type_of::LayoutGccExt;
|
||||
use crate::callee::get_fn;
|
||||
|
||||
|
||||
// Rust asm! and GCC Extended Asm semantics differ substantially.
|
||||
//
|
||||
|
@ -68,7 +70,6 @@ use crate::callee::get_fn;
|
|||
const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t";
|
||||
const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix";
|
||||
|
||||
|
||||
struct AsmOutOperand<'a, 'tcx, 'gcc> {
|
||||
rust_idx: usize,
|
||||
constraint: &'a str,
|
||||
|
@ -76,13 +77,13 @@ struct AsmOutOperand<'a, 'tcx, 'gcc> {
|
|||
readwrite: bool,
|
||||
|
||||
tmp_var: LValue<'gcc>,
|
||||
out_place: Option<PlaceRef<'tcx, RValue<'gcc>>>
|
||||
out_place: Option<PlaceRef<'tcx, RValue<'gcc>>>,
|
||||
}
|
||||
|
||||
struct AsmInOperand<'a, 'tcx> {
|
||||
rust_idx: usize,
|
||||
constraint: Cow<'a, str>,
|
||||
val: RValue<'tcx>
|
||||
val: RValue<'tcx>,
|
||||
}
|
||||
|
||||
impl AsmOutOperand<'_, '_, '_> {
|
||||
|
@ -102,16 +103,21 @@ impl AsmOutOperand<'_, '_, '_> {
|
|||
|
||||
enum ConstraintOrRegister {
|
||||
Constraint(&'static str),
|
||||
Register(&'static str)
|
||||
Register(&'static str),
|
||||
}
|
||||
|
||||
|
||||
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>)>) {
|
||||
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().dcx()
|
||||
.create_err(UnwindingInlineAsm { span: span[0] })
|
||||
.emit();
|
||||
self.sess().dcx().create_err(UnwindingInlineAsm { span: span[0] }).emit();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -157,32 +163,40 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
use ConstraintOrRegister::*;
|
||||
|
||||
let (constraint, ty) = match (reg_to_gcc(reg), place) {
|
||||
(Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx)),
|
||||
(Constraint(constraint), Some(place)) => {
|
||||
(constraint, place.layout.gcc_type(self.cx))
|
||||
}
|
||||
// When `reg` is a class and not an explicit register but the out place is not specified,
|
||||
// we need to create an unused output variable to assign the output to. This var
|
||||
// needs to be of a type that's "compatible" with the register class, but specific type
|
||||
// doesn't matter.
|
||||
(Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())),
|
||||
(Constraint(constraint), None) => {
|
||||
(constraint, dummy_output_type(self.cx, reg.reg_class()))
|
||||
}
|
||||
(Register(_), Some(_)) => {
|
||||
// left for the next pass
|
||||
continue
|
||||
},
|
||||
continue;
|
||||
}
|
||||
(Register(reg_name), None) => {
|
||||
// `clobber_abi` can add lots of clobbers that are not supported by the target,
|
||||
// such as AVX-512 registers, so we just ignore unsupported registers
|
||||
let is_target_supported = reg.reg_class().supported_types(asm_arch).iter()
|
||||
.any(|&(_, feature)| {
|
||||
if let Some(feature) = feature {
|
||||
self.tcx.asm_target_features(instance.def_id()).contains(&feature)
|
||||
} else {
|
||||
true // Register class is unconditionally supported
|
||||
}
|
||||
});
|
||||
let is_target_supported =
|
||||
reg.reg_class().supported_types(asm_arch).iter().any(
|
||||
|&(_, feature)| {
|
||||
if let Some(feature) = feature {
|
||||
self.tcx
|
||||
.asm_target_features(instance.def_id())
|
||||
.contains(&feature)
|
||||
} else {
|
||||
true // Register class is unconditionally supported
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if is_target_supported && !clobbers.contains(®_name) {
|
||||
clobbers.push(reg_name);
|
||||
}
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -193,7 +207,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
late,
|
||||
readwrite: false,
|
||||
tmp_var,
|
||||
out_place: place
|
||||
out_place: place,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -202,23 +216,22 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
inputs.push(AsmInOperand {
|
||||
constraint: Cow::Borrowed(constraint),
|
||||
rust_idx,
|
||||
val: value.immediate()
|
||||
val: value.immediate(),
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// left for the next pass
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
|
||||
let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
|
||||
constraint
|
||||
}
|
||||
else {
|
||||
// left for the next pass
|
||||
continue
|
||||
};
|
||||
let constraint =
|
||||
if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
|
||||
constraint
|
||||
} else {
|
||||
// left for the next pass
|
||||
continue;
|
||||
};
|
||||
|
||||
// Rustc frontend guarantees that input and output types are "compatible",
|
||||
// so we can just use input var's type for the output variable.
|
||||
|
@ -249,7 +262,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
inputs.push(AsmInOperand {
|
||||
constraint,
|
||||
rust_idx,
|
||||
val: in_value.immediate()
|
||||
val: in_value.immediate(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +280,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
InlineAsmOperandRef::SymStatic { def_id } => {
|
||||
// TODO(@Amanieu): Additional mangling is needed on
|
||||
// some targets to add a leading underscore (Mach-O).
|
||||
constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
|
||||
constants_len +=
|
||||
self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,10 +294,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
|
||||
let out_place = if let Some(place) = place {
|
||||
place
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// processed in the previous pass
|
||||
continue
|
||||
continue;
|
||||
};
|
||||
|
||||
let ty = out_place.layout.gcc_type(self.cx);
|
||||
|
@ -296,7 +309,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
late,
|
||||
readwrite: false,
|
||||
tmp_var,
|
||||
out_place: Some(out_place)
|
||||
out_place: Some(out_place),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -314,7 +327,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
inputs.push(AsmInOperand {
|
||||
constraint: "r".into(),
|
||||
rust_idx,
|
||||
val: reg_var.to_rvalue()
|
||||
val: reg_var.to_rvalue(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -342,7 +355,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
inputs.push(AsmInOperand {
|
||||
constraint,
|
||||
rust_idx,
|
||||
val: in_value.immediate()
|
||||
val: in_value.immediate(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -373,7 +386,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
|
||||
// 3. Build the template string
|
||||
|
||||
let mut template_str = String::with_capacity(estimate_template_length(template, constants_len, att_dialect));
|
||||
let mut template_str =
|
||||
String::with_capacity(estimate_template_length(template, constants_len, att_dialect));
|
||||
if att_dialect {
|
||||
template_str.push_str(ATT_SYNTAX_INS);
|
||||
}
|
||||
|
@ -383,16 +397,15 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
InlineAsmTemplatePiece::String(ref string) => {
|
||||
for char in string.chars() {
|
||||
// TODO(antoyo): might also need to escape | if rustc doesn't do it.
|
||||
let escaped_char =
|
||||
match char {
|
||||
'%' => "%%",
|
||||
'{' => "%{",
|
||||
'}' => "%}",
|
||||
_ => {
|
||||
template_str.push(char);
|
||||
continue;
|
||||
},
|
||||
};
|
||||
let escaped_char = match char {
|
||||
'%' => "%%",
|
||||
'{' => "%{",
|
||||
'}' => "%}",
|
||||
_ => {
|
||||
template_str.push(char);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
template_str.push_str(escaped_char);
|
||||
}
|
||||
}
|
||||
|
@ -408,9 +421,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
};
|
||||
|
||||
match rust_operands[operand_idx] {
|
||||
InlineAsmOperandRef::Out { reg, .. } => {
|
||||
InlineAsmOperandRef::Out { reg, .. } => {
|
||||
let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
|
||||
let gcc_index = outputs.iter()
|
||||
let gcc_index = outputs
|
||||
.iter()
|
||||
.position(|op| operand_idx == op.rust_idx)
|
||||
.expect("wrong rust index");
|
||||
push_to_template(modifier, gcc_index);
|
||||
|
@ -418,7 +432,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
|
||||
InlineAsmOperandRef::In { reg, .. } => {
|
||||
let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
|
||||
let in_gcc_index = inputs.iter()
|
||||
let in_gcc_index = inputs
|
||||
.iter()
|
||||
.position(|op| operand_idx == op.rust_idx)
|
||||
.expect("wrong rust index");
|
||||
let gcc_index = in_gcc_index + outputs.len();
|
||||
|
@ -429,7 +444,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
|
||||
|
||||
// The input register is tied to the output, so we can just use the index of the output register
|
||||
let gcc_index = outputs.iter()
|
||||
let gcc_index = outputs
|
||||
.iter()
|
||||
.position(|op| operand_idx == op.rust_idx)
|
||||
.expect("wrong rust index");
|
||||
push_to_template(modifier, gcc_index);
|
||||
|
@ -496,7 +512,8 @@ 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) };
|
||||
let builtin_unreachable: RValue<'gcc> =
|
||||
unsafe { std::mem::transmute(builtin_unreachable) };
|
||||
self.call(self.type_void(), None, None, builtin_unreachable, &[], None);
|
||||
}
|
||||
|
||||
|
@ -517,19 +534,23 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn estimate_template_length(template: &[InlineAsmTemplatePiece], constants_len: usize, att_dialect: bool) -> usize {
|
||||
let len: usize = template.iter().map(|piece| {
|
||||
match *piece {
|
||||
InlineAsmTemplatePiece::String(ref string) => {
|
||||
string.len()
|
||||
fn estimate_template_length(
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
constants_len: usize,
|
||||
att_dialect: bool,
|
||||
) -> usize {
|
||||
let len: usize = template
|
||||
.iter()
|
||||
.map(|piece| {
|
||||
match *piece {
|
||||
InlineAsmTemplatePiece::String(ref string) => string.len(),
|
||||
InlineAsmTemplatePiece::Placeholder { .. } => {
|
||||
// '%' + 1 char modifier + 1 char index
|
||||
3
|
||||
}
|
||||
}
|
||||
InlineAsmTemplatePiece::Placeholder { .. } => {
|
||||
// '%' + 1 char modifier + 1 char index
|
||||
3
|
||||
}
|
||||
}
|
||||
})
|
||||
.sum();
|
||||
})
|
||||
.sum();
|
||||
|
||||
// increase it by 5% to account for possible '%' signs that'll be duplicated
|
||||
// I pulled the number out of blue, but should be fair enough
|
||||
|
@ -562,7 +583,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
|
|||
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
},
|
||||
}
|
||||
// They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
|
||||
InlineAsmRegOrRegClass::RegClass(reg) => match reg {
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
|
||||
|
@ -610,7 +631,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
|
|||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
|
||||
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
|
||||
unreachable!("clobber-only")
|
||||
},
|
||||
}
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
|
||||
|
@ -637,7 +658,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
|
|||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::Err => unreachable!(),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
ConstraintOrRegister::Constraint(constraint)
|
||||
|
@ -653,7 +674,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
|
|||
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
|
||||
unimplemented!()
|
||||
}
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)=> cx.type_i32(),
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(),
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
|
||||
|
@ -686,7 +707,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
|
|||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
|
||||
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
|
||||
unreachable!("clobber-only")
|
||||
},
|
||||
}
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => cx.type_f32(),
|
||||
|
@ -704,9 +725,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
|
|||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
},
|
||||
}
|
||||
InlineAsmRegClass::S390x(
|
||||
S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr
|
||||
S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr,
|
||||
) => cx.type_i32(),
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
|
||||
InlineAsmRegClass::Err => unreachable!(),
|
||||
|
@ -714,7 +735,13 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
|
|||
}
|
||||
|
||||
impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef<'tcx>], options: InlineAsmOptions, _line_spans: &[Span]) {
|
||||
fn codegen_global_asm(
|
||||
&self,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[GlobalAsmOperandRef<'tcx>],
|
||||
options: InlineAsmOptions,
|
||||
_line_spans: &[Span],
|
||||
) {
|
||||
let asm_arch = self.tcx.sess.asm_arch.unwrap();
|
||||
|
||||
// Default to Intel syntax on x86
|
||||
|
@ -732,15 +759,17 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
let mut index = 0;
|
||||
while index < string.len() {
|
||||
// NOTE: gcc does not allow inline comment, so remove them.
|
||||
let comment_index = string[index..].find("//")
|
||||
let comment_index = string[index..]
|
||||
.find("//")
|
||||
.map(|comment_index| comment_index + index)
|
||||
.unwrap_or(string.len());
|
||||
template_str.push_str(&string[index..comment_index]);
|
||||
index = string[comment_index..].find('\n')
|
||||
index = string[comment_index..]
|
||||
.find('\n')
|
||||
.map(|index| index + comment_index)
|
||||
.unwrap_or(string.len());
|
||||
}
|
||||
},
|
||||
}
|
||||
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => {
|
||||
match operands[operand_idx] {
|
||||
GlobalAsmOperandRef::Const { ref string } => {
|
||||
|
@ -782,14 +811,22 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option<char>) -> Option<char> {
|
||||
fn modifier_to_gcc(
|
||||
arch: InlineAsmArch,
|
||||
reg: InlineAsmRegClass,
|
||||
modifier: Option<char>,
|
||||
) -> Option<char> {
|
||||
// The modifiers can be retrieved from
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/Modifiers.html#Modifiers
|
||||
match reg {
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier,
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
|
||||
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
|
||||
if modifier == Some('v') { None } else { modifier }
|
||||
if modifier == Some('v') {
|
||||
None
|
||||
} else {
|
||||
modifier
|
||||
}
|
||||
}
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
|
@ -821,7 +858,13 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
|
|||
}
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier {
|
||||
None => if arch == InlineAsmArch::X86_64 { Some('q') } else { Some('k') },
|
||||
None => {
|
||||
if arch == InlineAsmArch::X86_64 {
|
||||
Some('q')
|
||||
} else {
|
||||
Some('k')
|
||||
}
|
||||
}
|
||||
Some('l') => Some('b'),
|
||||
Some('h') => Some('h'),
|
||||
Some('x') => Some('w'),
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::FnAttribute;
|
||||
use gccjit::Function;
|
||||
use rustc_attr::InstructionSetAttr;
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_attr::InlineAttr;
|
||||
use rustc_middle::ty;
|
||||
#[cfg(feature="master")]
|
||||
use rustc_attr::InstructionSetAttr;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use crate::{context::CodegenCx, errors::TiedTargetFeatures};
|
||||
use crate::gcc_util::{check_tied_features, to_gcc_features};
|
||||
use crate::{context::CodegenCx, errors::TiedTargetFeatures};
|
||||
|
||||
/// Get GCC attribute for the provided inline heuristic.
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
#[inline]
|
||||
fn inline_attr<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, inline: InlineAttr) -> Option<FnAttribute<'gcc>> {
|
||||
fn inline_attr<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
inline: InlineAttr,
|
||||
) -> Option<FnAttribute<'gcc>> {
|
||||
match inline {
|
||||
InlineAttr::Hint => Some(FnAttribute::Inline),
|
||||
InlineAttr::Always => Some(FnAttribute::AlwaysInline),
|
||||
|
@ -34,24 +37,22 @@ fn inline_attr<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, inline: InlineAttr) -> Op
|
|||
/// attributes.
|
||||
pub fn from_fn_attrs<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
#[cfg_attr(not(feature="master"), allow(unused_variables))]
|
||||
func: Function<'gcc>,
|
||||
#[cfg_attr(not(feature = "master"), allow(unused_variables))] func: Function<'gcc>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
) {
|
||||
let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
|
||||
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
{
|
||||
let inline =
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
|
||||
InlineAttr::Never
|
||||
}
|
||||
else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
|
||||
InlineAttr::Hint
|
||||
}
|
||||
else {
|
||||
codegen_fn_attrs.inline
|
||||
};
|
||||
let inline = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
|
||||
InlineAttr::Never
|
||||
} else if codegen_fn_attrs.inline == InlineAttr::None
|
||||
&& instance.def.requires_inline(cx.tcx)
|
||||
{
|
||||
InlineAttr::Hint
|
||||
} else {
|
||||
codegen_fn_attrs.inline
|
||||
};
|
||||
if let Some(attr) = inline_attr(cx, inline) {
|
||||
if let FnAttribute::AlwaysInline = attr {
|
||||
func.add_attribute(FnAttribute::Inline);
|
||||
|
@ -70,18 +71,21 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
let function_features =
|
||||
codegen_fn_attrs.target_features.iter().map(|features| features.as_str()).collect::<Vec<&str>>();
|
||||
let function_features = codegen_fn_attrs
|
||||
.target_features
|
||||
.iter()
|
||||
.map(|features| features.as_str())
|
||||
.collect::<Vec<&str>>();
|
||||
|
||||
if let Some(features) = check_tied_features(cx.tcx.sess, &function_features.iter().map(|features| (*features, true)).collect()) {
|
||||
let span = cx.tcx
|
||||
if let Some(features) = check_tied_features(
|
||||
cx.tcx.sess,
|
||||
&function_features.iter().map(|features| (*features, true)).collect(),
|
||||
) {
|
||||
let span = cx
|
||||
.tcx
|
||||
.get_attr(instance.def_id(), sym::target_feature)
|
||||
.map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
|
||||
cx.tcx.dcx().create_err(TiedTargetFeatures {
|
||||
features: features.join(", "),
|
||||
span,
|
||||
})
|
||||
.emit();
|
||||
cx.tcx.dcx().create_err(TiedTargetFeatures { features: features.join(", "), span }).emit();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -105,24 +109,25 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
|
|||
// compiling Rust for Linux:
|
||||
// SSE register return with SSE disabled
|
||||
// TODO(antoyo): support soft-float and retpoline-external-thunk.
|
||||
if feature.contains("soft-float") || feature.contains("retpoline-external-thunk") || *feature == "-sse" {
|
||||
if feature.contains("soft-float")
|
||||
|| feature.contains("retpoline-external-thunk")
|
||||
|| *feature == "-sse"
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
if feature.starts_with('-') {
|
||||
Some(format!("no{}", feature))
|
||||
}
|
||||
else if feature.starts_with('+') {
|
||||
} else if feature.starts_with('+') {
|
||||
Some(feature[1..].to_string())
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Some(feature.to_string())
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
if !target_features.is_empty() {
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
func.add_attribute(FnAttribute::Target(&target_features));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/// GCC requires to use the same toolchain for the whole compilation when doing LTO.
|
||||
/// So, we need the same version/commit of the linker (gcc) and lto front-end binaries (lto1,
|
||||
/// lto-wrapper, liblto_plugin.so).
|
||||
|
||||
// FIXME(antoyo): the executables compiled with LTO are bigger than those compiled without LTO.
|
||||
// Since it is the opposite for cg_llvm, check if this is normal.
|
||||
//
|
||||
|
@ -17,7 +16,6 @@
|
|||
// /usr/bin/ld: warning: type of symbol `_RNvNvNvNtCs5JWOrf9uCus_5rayon11thread_pool19WORKER_THREAD_STATE7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o
|
||||
// /usr/bin/ld: warning: type of symbol `_RNvNvNvNvNtNtNtCsAj5i4SGTR7_3std4sync4mpmc5waker17current_thread_id5DUMMY7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o
|
||||
// /usr/bin/ld: warning: incremental linking of LTO and non-LTO objects; using -flinker-output=nolto-rel which will bypass whole program optimization
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -30,18 +28,16 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
|
|||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_errors::{FatalError, DiagCtxt};
|
||||
use rustc_errors::{DiagCtxt, FatalError};
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
|
||||
use rustc_session::config::{CrateType, Lto};
|
||||
use tempfile::{TempDir, tempdir};
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
use crate::back::write::save_temp_bitcode;
|
||||
use crate::errors::{
|
||||
DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib,
|
||||
};
|
||||
use crate::{GccCodegenBackend, GccContext, to_gcc_opt_level};
|
||||
use crate::errors::{DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib};
|
||||
use crate::{to_gcc_opt_level, GccCodegenBackend, GccContext};
|
||||
|
||||
/// We keep track of the computed LTO cache keys from the previous
|
||||
/// session to determine which CGUs we can reuse.
|
||||
|
@ -61,7 +57,10 @@ struct LtoData {
|
|||
tmp_path: TempDir,
|
||||
}
|
||||
|
||||
fn prepare_lto(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &DiagCtxt) -> Result<LtoData, FatalError> {
|
||||
fn prepare_lto(
|
||||
cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
dcx: &DiagCtxt,
|
||||
) -> Result<LtoData, FatalError> {
|
||||
let export_threshold = match cgcx.lto {
|
||||
// We're just doing LTO for our one crate
|
||||
Lto::ThinLocal => SymbolExportLevel::Rust,
|
||||
|
@ -72,14 +71,13 @@ fn prepare_lto(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &DiagCtxt) -> Resu
|
|||
Lto::No => panic!("didn't request LTO but we're doing LTO"),
|
||||
};
|
||||
|
||||
let tmp_path =
|
||||
match tempdir() {
|
||||
Ok(tmp_path) => tmp_path,
|
||||
Err(error) => {
|
||||
eprintln!("Cannot create temporary directory: {}", error);
|
||||
return Err(FatalError);
|
||||
},
|
||||
};
|
||||
let tmp_path = match tempdir() {
|
||||
Ok(tmp_path) => tmp_path,
|
||||
Err(error) => {
|
||||
eprintln!("Cannot create temporary directory: {}", error);
|
||||
return Err(FatalError);
|
||||
}
|
||||
};
|
||||
|
||||
let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| {
|
||||
if info.level.is_below_threshold(export_threshold) || info.used {
|
||||
|
@ -125,8 +123,7 @@ fn prepare_lto(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &DiagCtxt) -> Resu
|
|||
let exported_symbols =
|
||||
cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
|
||||
{
|
||||
let _timer =
|
||||
cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold");
|
||||
let _timer = cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold");
|
||||
symbols_below_threshold
|
||||
.extend(exported_symbols[&cnum].iter().filter_map(symbol_filter));
|
||||
}
|
||||
|
@ -170,10 +167,9 @@ fn prepare_lto(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &DiagCtxt) -> Resu
|
|||
}
|
||||
|
||||
fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> {
|
||||
fs::write(path, obj)
|
||||
.map_err(|error| LtoBitcodeFromRlib {
|
||||
gcc_err: format!("write object file to temp dir: {}", error)
|
||||
})
|
||||
fs::write(path, obj).map_err(|error| LtoBitcodeFromRlib {
|
||||
gcc_err: format!("write object file to temp dir: {}", error),
|
||||
})
|
||||
}
|
||||
|
||||
/// Performs fat LTO by merging all modules into a single one and returning it
|
||||
|
@ -186,13 +182,25 @@ pub(crate) fn run_fat(
|
|||
let dcx = cgcx.create_dcx();
|
||||
let lto_data = prepare_lto(cgcx, &dcx)?;
|
||||
/*let symbols_below_threshold =
|
||||
lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/
|
||||
fat_lto(cgcx, &dcx, modules, cached_modules, lto_data.upstream_modules, lto_data.tmp_path,
|
||||
lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/
|
||||
fat_lto(
|
||||
cgcx,
|
||||
&dcx,
|
||||
modules,
|
||||
cached_modules,
|
||||
lto_data.upstream_modules,
|
||||
lto_data.tmp_path,
|
||||
//&symbols_below_threshold,
|
||||
)
|
||||
}
|
||||
|
||||
fn fat_lto(cgcx: &CodegenContext<GccCodegenBackend>, _dcx: &DiagCtxt, modules: Vec<FatLtoInput<GccCodegenBackend>>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, tmp_path: TempDir,
|
||||
fn fat_lto(
|
||||
cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
_dcx: &DiagCtxt,
|
||||
modules: Vec<FatLtoInput<GccCodegenBackend>>,
|
||||
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
|
||||
mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
|
||||
tmp_path: TempDir,
|
||||
//symbols_below_threshold: &[*const libc::c_char],
|
||||
) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> {
|
||||
let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module");
|
||||
|
@ -298,10 +306,15 @@ fn fat_lto(cgcx: &CodegenContext<GccCodegenBackend>, _dcx: &DiagCtxt, modules: V
|
|||
match bc_decoded {
|
||||
SerializedModule::Local(ref module_buffer) => {
|
||||
module.module_llvm.should_combine_object_files = true;
|
||||
module.module_llvm.context.add_driver_option(module_buffer.0.to_str().expect("path"));
|
||||
},
|
||||
module
|
||||
.module_llvm
|
||||
.context
|
||||
.add_driver_option(module_buffer.0.to_str().expect("path"));
|
||||
}
|
||||
SerializedModule::FromRlib(_) => unimplemented!("from rlib"),
|
||||
SerializedModule::FromUncompressedFile(_) => unimplemented!("from uncompressed file"),
|
||||
SerializedModule::FromUncompressedFile(_) => {
|
||||
unimplemented!("from uncompressed file")
|
||||
}
|
||||
}
|
||||
serialized_bitcode.push(bc_decoded);
|
||||
}
|
||||
|
@ -309,13 +322,13 @@ fn fat_lto(cgcx: &CodegenContext<GccCodegenBackend>, _dcx: &DiagCtxt, modules: V
|
|||
|
||||
// Internalize everything below threshold to help strip out more modules and such.
|
||||
/*unsafe {
|
||||
let ptr = symbols_below_threshold.as_ptr();
|
||||
llvm::LLVMRustRunRestrictionPass(
|
||||
llmod,
|
||||
ptr as *const *const libc::c_char,
|
||||
symbols_below_threshold.len() as libc::size_t,
|
||||
);*/
|
||||
save_temp_bitcode(cgcx, &module, "lto.after-restriction");
|
||||
let ptr = symbols_below_threshold.as_ptr();
|
||||
llvm::LLVMRustRunRestrictionPass(
|
||||
llmod,
|
||||
ptr as *const *const libc::c_char,
|
||||
symbols_below_threshold.len() as libc::size_t,
|
||||
);*/
|
||||
save_temp_bitcode(cgcx, &module, "lto.after-restriction");
|
||||
//}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
use std::{env, fs};
|
||||
|
||||
use gccjit::OutputKind;
|
||||
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
|
||||
use rustc_codegen_ssa::back::link::ensure_removed;
|
||||
use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
|
||||
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
|
||||
use rustc_errors::DiagCtxt;
|
||||
use rustc_fs_util::link_or_copy;
|
||||
use rustc_session::config::OutputType;
|
||||
use rustc_span::fatal_error::FatalError;
|
||||
use rustc_target::spec::SplitDebuginfo;
|
||||
|
||||
use crate::{GccCodegenBackend, GccContext};
|
||||
use crate::errors::CopyBitcode;
|
||||
use crate::{GccCodegenBackend, GccContext};
|
||||
|
||||
pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &DiagCtxt, module: ModuleCodegen<GccContext>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
|
||||
pub(crate) unsafe fn codegen(
|
||||
cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
dcx: &DiagCtxt,
|
||||
module: ModuleCodegen<GccContext>,
|
||||
config: &ModuleConfig,
|
||||
) -> Result<CompiledModule, FatalError> {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name);
|
||||
{
|
||||
let context = &module.module_llvm.context;
|
||||
|
@ -51,7 +56,8 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &Dia
|
|||
.generic_activity_with_arg("GCC_module_codegen_emit_bitcode", &*module.name);
|
||||
context.add_command_line_option("-flto=auto");
|
||||
context.add_command_line_option("-flto-partition=one");
|
||||
context.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
|
||||
context
|
||||
.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
|
||||
}
|
||||
|
||||
if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
|
||||
|
@ -65,7 +71,8 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &Dia
|
|||
context.add_command_line_option("-flto-partition=one");
|
||||
context.add_command_line_option("-ffat-lto-objects");
|
||||
// TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
|
||||
context.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
|
||||
context
|
||||
.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,9 +82,8 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &Dia
|
|||
}
|
||||
|
||||
if config.emit_asm {
|
||||
let _timer = cgcx
|
||||
.prof
|
||||
.generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name);
|
||||
let _timer =
|
||||
cgcx.prof.generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name);
|
||||
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
|
||||
context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str"));
|
||||
}
|
||||
|
@ -90,7 +96,9 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &Dia
|
|||
if env::var("CG_GCCJIT_DUMP_MODULE_NAMES").as_deref() == Ok("1") {
|
||||
println!("Module {}", module.name);
|
||||
}
|
||||
if env::var("CG_GCCJIT_DUMP_ALL_MODULES").as_deref() == Ok("1") || env::var("CG_GCCJIT_DUMP_MODULE").as_deref() == Ok(&module.name) {
|
||||
if env::var("CG_GCCJIT_DUMP_ALL_MODULES").as_deref() == Ok("1")
|
||||
|| env::var("CG_GCCJIT_DUMP_MODULE").as_deref() == Ok(&module.name)
|
||||
{
|
||||
println!("Dumping reproducer {}", module.name);
|
||||
let _ = fs::create_dir("/tmp/reproducers");
|
||||
// FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by
|
||||
|
@ -118,10 +126,15 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &Dia
|
|||
context.add_driver_option("-fuse-linker-plugin");
|
||||
|
||||
// NOTE: this doesn't actually generate an executable. With the above flags, it combines the .o files together in another .o.
|
||||
context.compile_to_file(OutputKind::Executable, obj_out.to_str().expect("path to str"));
|
||||
}
|
||||
else {
|
||||
context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str"));
|
||||
context.compile_to_file(
|
||||
OutputKind::Executable,
|
||||
obj_out.to_str().expect("path to str"),
|
||||
);
|
||||
} else {
|
||||
context.compile_to_file(
|
||||
OutputKind::ObjectFile,
|
||||
obj_out.to_str().expect("path to str"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,11 +162,19 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &Dia
|
|||
))
|
||||
}
|
||||
|
||||
pub(crate) fn link(_cgcx: &CodegenContext<GccCodegenBackend>, _dcx: &DiagCtxt, mut _modules: Vec<ModuleCodegen<GccContext>>) -> Result<ModuleCodegen<GccContext>, FatalError> {
|
||||
pub(crate) fn link(
|
||||
_cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
_dcx: &DiagCtxt,
|
||||
mut _modules: Vec<ModuleCodegen<GccContext>>,
|
||||
) -> Result<ModuleCodegen<GccContext>, FatalError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
pub(crate) fn save_temp_bitcode(cgcx: &CodegenContext<GccCodegenBackend>, _module: &ModuleCodegen<GccContext>, _name: &str) {
|
||||
pub(crate) fn save_temp_bitcode(
|
||||
cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
_module: &ModuleCodegen<GccContext>,
|
||||
_name: &str,
|
||||
) {
|
||||
if !cgcx.save_temps {
|
||||
return;
|
||||
}
|
||||
|
|
55
src/base.rs
55
src/base.rs
|
@ -2,29 +2,26 @@ use std::collections::HashSet;
|
|||
use std::env;
|
||||
use std::time::Instant;
|
||||
|
||||
use gccjit::{
|
||||
FunctionType,
|
||||
GlobalKind,
|
||||
};
|
||||
use rustc_middle::dep_graph;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
#[cfg(feature="master")]
|
||||
use rustc_middle::mir::mono::Visibility;
|
||||
use rustc_middle::mir::mono::Linkage;
|
||||
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
|
||||
use gccjit::{FunctionType, GlobalKind};
|
||||
use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
|
||||
use rustc_codegen_ssa::mono_item::MonoItemExt;
|
||||
use rustc_codegen_ssa::traits::DebugInfoMethods;
|
||||
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
|
||||
use rustc_middle::dep_graph;
|
||||
use rustc_middle::mir::mono::Linkage;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_middle::mir::mono::Visibility;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
|
||||
use crate::{LockedTargetInfo, gcc_util, new_context};
|
||||
use crate::GccContext;
|
||||
use crate::builder::Builder;
|
||||
use crate::context::CodegenCx;
|
||||
use crate::GccContext;
|
||||
use crate::{gcc_util, new_context, LockedTargetInfo};
|
||||
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
pub fn visibility_to_gcc(linkage: Visibility) -> gccjit::Visibility {
|
||||
match linkage {
|
||||
Visibility::Default => gccjit::Visibility::Default,
|
||||
|
@ -66,7 +63,11 @@ pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: LockedTargetInfo) -> (ModuleCodegen<GccContext>, u64) {
|
||||
pub fn compile_codegen_unit(
|
||||
tcx: TyCtxt<'_>,
|
||||
cgu_name: Symbol,
|
||||
target_info: LockedTargetInfo,
|
||||
) -> (ModuleCodegen<GccContext>, u64) {
|
||||
let prof_timer = tcx.prof.generic_activity("codegen_module");
|
||||
let start_time = Instant::now();
|
||||
|
||||
|
@ -85,7 +86,10 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock
|
|||
// the time we needed for codegenning it.
|
||||
let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;
|
||||
|
||||
fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, target_info): (Symbol, LockedTargetInfo)) -> ModuleCodegen<GccContext> {
|
||||
fn module_codegen(
|
||||
tcx: TyCtxt<'_>,
|
||||
(cgu_name, target_info): (Symbol, LockedTargetInfo),
|
||||
) -> ModuleCodegen<GccContext> {
|
||||
let cgu = tcx.codegen_unit(cgu_name);
|
||||
// Instantiate monomorphizations without filling out definitions yet...
|
||||
let context = new_context(tcx);
|
||||
|
@ -95,7 +99,12 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock
|
|||
context.add_driver_option("-fexceptions");
|
||||
}
|
||||
|
||||
let disabled_features: HashSet<_> = tcx.sess.opts.cg.target_feature.split(',')
|
||||
let disabled_features: HashSet<_> = tcx
|
||||
.sess
|
||||
.opts
|
||||
.cg
|
||||
.target_feature
|
||||
.split(',')
|
||||
.filter(|feature| feature.starts_with('-'))
|
||||
.map(|string| &string[1..])
|
||||
.collect();
|
||||
|
@ -129,7 +138,13 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock
|
|||
context.add_command_line_option(&format!("-march={}", target_cpu));
|
||||
}
|
||||
|
||||
if tcx.sess.opts.unstable_opts.function_sections.unwrap_or(tcx.sess.target.function_sections) {
|
||||
if tcx
|
||||
.sess
|
||||
.opts
|
||||
.unstable_opts
|
||||
.function_sections
|
||||
.unwrap_or(tcx.sess.target.function_sections)
|
||||
{
|
||||
context.add_command_line_option("-ffunction-sections");
|
||||
context.add_command_line_option("-fdata-sections");
|
||||
}
|
||||
|
@ -190,11 +205,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock
|
|||
|
||||
ModuleCodegen {
|
||||
name: cgu_name.to_string(),
|
||||
module_llvm: GccContext {
|
||||
context,
|
||||
should_combine_object_files: false,
|
||||
temp_dir: None,
|
||||
},
|
||||
module_llvm: GccContext { context, should_combine_object_files: false, temp_dir: None },
|
||||
kind: ModuleKind::Regular,
|
||||
}
|
||||
}
|
||||
|
|
1417
src/builder.rs
1417
src/builder.rs
File diff suppressed because it is too large
Load diff
253
src/callee.rs
253
src/callee.rs
|
@ -1,8 +1,8 @@
|
|||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::{FnAttribute, Visibility};
|
||||
use gccjit::{FunctionType, Function};
|
||||
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
||||
use gccjit::{Function, FunctionType};
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
|
||||
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
||||
|
||||
use crate::attributes;
|
||||
use crate::context::CodegenCx;
|
||||
|
@ -28,145 +28,144 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
|
|||
|
||||
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
|
||||
|
||||
let func =
|
||||
if let Some(_func) = cx.get_declared_value(&sym) {
|
||||
// FIXME(antoyo): we never reach this because get_declared_value only returns global variables
|
||||
// and here we try to get a function.
|
||||
unreachable!();
|
||||
/*
|
||||
// Create a fn pointer with the new signature.
|
||||
let ptrty = fn_abi.ptr_to_gcc_type(cx);
|
||||
let func = if let Some(_func) = cx.get_declared_value(&sym) {
|
||||
// FIXME(antoyo): we never reach this because get_declared_value only returns global variables
|
||||
// and here we try to get a function.
|
||||
unreachable!();
|
||||
/*
|
||||
// Create a fn pointer with the new signature.
|
||||
let ptrty = fn_abi.ptr_to_gcc_type(cx);
|
||||
|
||||
// This is subtle and surprising, but sometimes we have to bitcast
|
||||
// the resulting fn pointer. The reason has to do with external
|
||||
// functions. If you have two crates that both bind the same C
|
||||
// library, they may not use precisely the same types: for
|
||||
// example, they will probably each declare their own structs,
|
||||
// which are distinct types from LLVM's point of view (nominal
|
||||
// types).
|
||||
//
|
||||
// Now, if those two crates are linked into an application, and
|
||||
// they contain inlined code, you can wind up with a situation
|
||||
// where both of those functions wind up being loaded into this
|
||||
// application simultaneously. In that case, the same function
|
||||
// (from LLVM's point of view) requires two types. But of course
|
||||
// LLVM won't allow one function to have two types.
|
||||
//
|
||||
// What we currently do, therefore, is declare the function with
|
||||
// one of the two types (whichever happens to come first) and then
|
||||
// bitcast as needed when the function is referenced to make sure
|
||||
// it has the type we expect.
|
||||
//
|
||||
// This can occur on either a crate-local or crate-external
|
||||
// reference. It also occurs when testing libcore and in some
|
||||
// other weird situations. Annoying.
|
||||
if cx.val_ty(func) != ptrty {
|
||||
// TODO(antoyo): cast the pointer.
|
||||
func
|
||||
}
|
||||
else {
|
||||
func
|
||||
}*/
|
||||
// This is subtle and surprising, but sometimes we have to bitcast
|
||||
// the resulting fn pointer. The reason has to do with external
|
||||
// functions. If you have two crates that both bind the same C
|
||||
// library, they may not use precisely the same types: for
|
||||
// example, they will probably each declare their own structs,
|
||||
// which are distinct types from LLVM's point of view (nominal
|
||||
// types).
|
||||
//
|
||||
// Now, if those two crates are linked into an application, and
|
||||
// they contain inlined code, you can wind up with a situation
|
||||
// where both of those functions wind up being loaded into this
|
||||
// application simultaneously. In that case, the same function
|
||||
// (from LLVM's point of view) requires two types. But of course
|
||||
// LLVM won't allow one function to have two types.
|
||||
//
|
||||
// What we currently do, therefore, is declare the function with
|
||||
// one of the two types (whichever happens to come first) and then
|
||||
// bitcast as needed when the function is referenced to make sure
|
||||
// it has the type we expect.
|
||||
//
|
||||
// This can occur on either a crate-local or crate-external
|
||||
// reference. It also occurs when testing libcore and in some
|
||||
// other weird situations. Annoying.
|
||||
if cx.val_ty(func) != ptrty {
|
||||
// TODO(antoyo): cast the pointer.
|
||||
func
|
||||
}
|
||||
else {
|
||||
cx.linkage.set(FunctionType::Extern);
|
||||
let func = cx.declare_fn(&sym, &fn_abi);
|
||||
func
|
||||
}*/
|
||||
} else {
|
||||
cx.linkage.set(FunctionType::Extern);
|
||||
let func = cx.declare_fn(&sym, &fn_abi);
|
||||
|
||||
attributes::from_fn_attrs(cx, func, instance);
|
||||
attributes::from_fn_attrs(cx, func, instance);
|
||||
|
||||
let instance_def_id = instance.def_id();
|
||||
let instance_def_id = instance.def_id();
|
||||
|
||||
// TODO(antoyo): set linkage and attributes.
|
||||
// TODO(antoyo): set linkage and attributes.
|
||||
|
||||
// Apply an appropriate linkage/visibility value to our item that we
|
||||
// just declared.
|
||||
//
|
||||
// This is sort of subtle. Inside our codegen unit we started off
|
||||
// compilation by predefining all our own `MonoItem` instances. That
|
||||
// is, everything we're codegenning ourselves is already defined. That
|
||||
// means that anything we're actually codegenning in this codegen unit
|
||||
// will have hit the above branch in `get_declared_value`. As a result,
|
||||
// we're guaranteed here that we're declaring a symbol that won't get
|
||||
// defined, or in other words we're referencing a value from another
|
||||
// codegen unit or even another crate.
|
||||
//
|
||||
// So because this is a foreign value we blanket apply an external
|
||||
// linkage directive because it's coming from a different object file.
|
||||
// The visibility here is where it gets tricky. This symbol could be
|
||||
// referencing some foreign crate or foreign library (an `extern`
|
||||
// block) in which case we want to leave the default visibility. We may
|
||||
// also, though, have multiple codegen units. It could be a
|
||||
// monomorphization, in which case its expected visibility depends on
|
||||
// whether we are sharing generics or not. The important thing here is
|
||||
// that the visibility we apply to the declaration is the same one that
|
||||
// has been applied to the definition (wherever that definition may be).
|
||||
let is_generic = instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some();
|
||||
// Apply an appropriate linkage/visibility value to our item that we
|
||||
// just declared.
|
||||
//
|
||||
// This is sort of subtle. Inside our codegen unit we started off
|
||||
// compilation by predefining all our own `MonoItem` instances. That
|
||||
// is, everything we're codegenning ourselves is already defined. That
|
||||
// means that anything we're actually codegenning in this codegen unit
|
||||
// will have hit the above branch in `get_declared_value`. As a result,
|
||||
// we're guaranteed here that we're declaring a symbol that won't get
|
||||
// defined, or in other words we're referencing a value from another
|
||||
// codegen unit or even another crate.
|
||||
//
|
||||
// So because this is a foreign value we blanket apply an external
|
||||
// linkage directive because it's coming from a different object file.
|
||||
// The visibility here is where it gets tricky. This symbol could be
|
||||
// referencing some foreign crate or foreign library (an `extern`
|
||||
// block) in which case we want to leave the default visibility. We may
|
||||
// also, though, have multiple codegen units. It could be a
|
||||
// monomorphization, in which case its expected visibility depends on
|
||||
// whether we are sharing generics or not. The important thing here is
|
||||
// that the visibility we apply to the declaration is the same one that
|
||||
// has been applied to the definition (wherever that definition may be).
|
||||
let is_generic =
|
||||
instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some();
|
||||
|
||||
if is_generic {
|
||||
// This is a monomorphization. Its expected visibility depends
|
||||
// on whether we are in share-generics mode.
|
||||
if is_generic {
|
||||
// This is a monomorphization. Its expected visibility depends
|
||||
// on whether we are in share-generics mode.
|
||||
|
||||
if cx.tcx.sess.opts.share_generics() {
|
||||
// We are in share_generics mode.
|
||||
if cx.tcx.sess.opts.share_generics() {
|
||||
// We are in share_generics mode.
|
||||
|
||||
if let Some(instance_def_id) = instance_def_id.as_local() {
|
||||
// This is a definition from the current crate. If the
|
||||
// definition is unreachable for downstream crates or
|
||||
// the current crate does not re-export generics, the
|
||||
// definition of the instance will have been declared
|
||||
// as `hidden`.
|
||||
if cx.tcx.is_unreachable_local_definition(instance_def_id)
|
||||
|| !cx.tcx.local_crate_exports_generics()
|
||||
{
|
||||
#[cfg(feature="master")]
|
||||
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
|
||||
}
|
||||
} else {
|
||||
// This is a monomorphization of a generic function
|
||||
// defined in an upstream crate.
|
||||
if instance.upstream_monomorphization(tcx).is_some() {
|
||||
// This is instantiated in another crate. It cannot
|
||||
// be `hidden`.
|
||||
} else {
|
||||
// This is a local instantiation of an upstream definition.
|
||||
// If the current crate does not re-export it
|
||||
// (because it is a C library or an executable), it
|
||||
// will have been declared `hidden`.
|
||||
if !cx.tcx.local_crate_exports_generics() {
|
||||
#[cfg(feature="master")]
|
||||
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// When not sharing generics, all instances are in the same
|
||||
// crate and have hidden visibility
|
||||
#[cfg(feature="master")]
|
||||
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
|
||||
}
|
||||
} else {
|
||||
// This is a non-generic function
|
||||
if cx.tcx.is_codegened_item(instance_def_id) {
|
||||
// This is a function that is instantiated in the local crate
|
||||
|
||||
if instance_def_id.is_local() {
|
||||
// This is function that is defined in the local crate.
|
||||
// If it is not reachable, it is hidden.
|
||||
if !cx.tcx.is_reachable_non_generic(instance_def_id) {
|
||||
#[cfg(feature="master")]
|
||||
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
|
||||
}
|
||||
} else {
|
||||
// This is a function from an upstream crate that has
|
||||
// been instantiated here. These are always hidden.
|
||||
#[cfg(feature="master")]
|
||||
if let Some(instance_def_id) = instance_def_id.as_local() {
|
||||
// This is a definition from the current crate. If the
|
||||
// definition is unreachable for downstream crates or
|
||||
// the current crate does not re-export generics, the
|
||||
// definition of the instance will have been declared
|
||||
// as `hidden`.
|
||||
if cx.tcx.is_unreachable_local_definition(instance_def_id)
|
||||
|| !cx.tcx.local_crate_exports_generics()
|
||||
{
|
||||
#[cfg(feature = "master")]
|
||||
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
|
||||
}
|
||||
} else {
|
||||
// This is a monomorphization of a generic function
|
||||
// defined in an upstream crate.
|
||||
if instance.upstream_monomorphization(tcx).is_some() {
|
||||
// This is instantiated in another crate. It cannot
|
||||
// be `hidden`.
|
||||
} else {
|
||||
// This is a local instantiation of an upstream definition.
|
||||
// If the current crate does not re-export it
|
||||
// (because it is a C library or an executable), it
|
||||
// will have been declared `hidden`.
|
||||
if !cx.tcx.local_crate_exports_generics() {
|
||||
#[cfg(feature = "master")]
|
||||
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// When not sharing generics, all instances are in the same
|
||||
// crate and have hidden visibility
|
||||
#[cfg(feature = "master")]
|
||||
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
|
||||
}
|
||||
} else {
|
||||
// This is a non-generic function
|
||||
if cx.tcx.is_codegened_item(instance_def_id) {
|
||||
// This is a function that is instantiated in the local crate
|
||||
|
||||
if instance_def_id.is_local() {
|
||||
// This is function that is defined in the local crate.
|
||||
// If it is not reachable, it is hidden.
|
||||
if !cx.tcx.is_reachable_non_generic(instance_def_id) {
|
||||
#[cfg(feature = "master")]
|
||||
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
|
||||
}
|
||||
} else {
|
||||
// This is a function from an upstream crate that has
|
||||
// been instantiated here. These are always hidden.
|
||||
#[cfg(feature = "master")]
|
||||
func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func
|
||||
};
|
||||
func
|
||||
};
|
||||
|
||||
cx.function_instances.borrow_mut().insert(instance, func);
|
||||
|
||||
|
|
168
src/common.rs
168
src/common.rs
|
@ -1,14 +1,9 @@
|
|||
use gccjit::LValue;
|
||||
use gccjit::{RValue, Type, ToRValue};
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BaseTypeMethods,
|
||||
ConstMethods,
|
||||
MiscMethods,
|
||||
StaticMethods,
|
||||
};
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::ty::layout::{LayoutOf};
|
||||
use gccjit::{RValue, ToRValue, Type};
|
||||
use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, MiscMethods, StaticMethods};
|
||||
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_target::abi::{self, HasDataLayout, Pointer};
|
||||
|
||||
use crate::consts::const_alloc_to_gcc;
|
||||
|
@ -40,9 +35,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) ->
|
|||
let byte_type = context.new_type::<u8>();
|
||||
let typ = context.new_array_type(None, byte_type, bytes.len() as u64);
|
||||
let elements: Vec<_> =
|
||||
bytes.iter()
|
||||
.map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
|
||||
.collect();
|
||||
bytes.iter().map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)).collect();
|
||||
context.new_array_constructor(None, typ, &elements)
|
||||
}
|
||||
|
||||
|
@ -54,23 +47,20 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> {
|
||||
if type_is_pointer(typ) {
|
||||
self.context.new_null(typ)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
self.const_int(typ, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
|
||||
let local = self.current_func.borrow().expect("func")
|
||||
.new_local(None, typ, "undefined");
|
||||
let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined");
|
||||
if typ.is_struct().is_some() {
|
||||
// NOTE: hack to workaround a limitation of the rustc API: see comment on
|
||||
// CodegenCx.structs_as_pointer
|
||||
let pointer = local.get_address(None);
|
||||
self.structs_as_pointer.borrow_mut().insert(pointer);
|
||||
pointer
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
local.to_rvalue()
|
||||
}
|
||||
}
|
||||
|
@ -143,16 +133,15 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
.or_insert_with(|| (s.to_owned(), self.global_string(s)))
|
||||
.1;
|
||||
let len = s.len();
|
||||
let cs = self.const_ptrcast(str_global.get_address(None),
|
||||
let cs = self.const_ptrcast(
|
||||
str_global.get_address(None),
|
||||
self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self)),
|
||||
);
|
||||
(cs, self.const_usize(len as u64))
|
||||
}
|
||||
|
||||
fn const_struct(&self, values: &[RValue<'gcc>], packed: bool) -> RValue<'gcc> {
|
||||
let fields: Vec<_> = values.iter()
|
||||
.map(|value| value.get_type())
|
||||
.collect();
|
||||
let fields: Vec<_> = values.iter().map(|value| value.get_type()).collect();
|
||||
// TODO(antoyo): cache the type? It's anonymous, so probably not.
|
||||
let typ = self.type_struct(&fields, packed);
|
||||
let struct_type = typ.is_struct().expect("struct type");
|
||||
|
@ -178,9 +167,10 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
// FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
|
||||
// the paths for floating-point values.
|
||||
if ty == self.float_type {
|
||||
return self.context.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64);
|
||||
}
|
||||
else if ty == self.double_type {
|
||||
return self
|
||||
.context
|
||||
.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64);
|
||||
} else if ty == self.double_type {
|
||||
return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64));
|
||||
}
|
||||
|
||||
|
@ -192,8 +182,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
// FIXME(antoyo): fix bitcast to work in constant contexts.
|
||||
// TODO(antoyo): perhaps only use bitcast for pointers?
|
||||
self.context.new_cast(None, value, ty)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// TODO(bjorn3): assert size is correct
|
||||
self.const_bitcast(value, ty)
|
||||
}
|
||||
|
@ -201,42 +190,41 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
Scalar::Ptr(ptr, _size) => {
|
||||
let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative
|
||||
let alloc_id = prov.alloc_id();
|
||||
let base_addr =
|
||||
match self.tcx.global_alloc(alloc_id) {
|
||||
GlobalAlloc::Memory(alloc) => {
|
||||
let init = const_alloc_to_gcc(self, alloc);
|
||||
let alloc = alloc.inner();
|
||||
let value =
|
||||
match alloc.mutability {
|
||||
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
|
||||
_ => self.static_addr_of(init, alloc.align, None),
|
||||
};
|
||||
if !self.sess().fewer_names() {
|
||||
// TODO(antoyo): set value name.
|
||||
}
|
||||
value
|
||||
},
|
||||
GlobalAlloc::Function(fn_instance) => {
|
||||
self.get_fn_addr(fn_instance)
|
||||
},
|
||||
GlobalAlloc::VTable(ty, trait_ref) => {
|
||||
let alloc = self.tcx.global_alloc(self.tcx.vtable_allocation((ty, trait_ref))).unwrap_memory();
|
||||
let init = const_alloc_to_gcc(self, alloc);
|
||||
self.static_addr_of(init, alloc.inner().align, None)
|
||||
let base_addr = match self.tcx.global_alloc(alloc_id) {
|
||||
GlobalAlloc::Memory(alloc) => {
|
||||
let init = const_alloc_to_gcc(self, alloc);
|
||||
let alloc = alloc.inner();
|
||||
let value = match alloc.mutability {
|
||||
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
|
||||
_ => self.static_addr_of(init, alloc.align, None),
|
||||
};
|
||||
if !self.sess().fewer_names() {
|
||||
// TODO(antoyo): set value name.
|
||||
}
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
assert!(self.tcx.is_static(def_id));
|
||||
self.get_static(def_id).get_address(None)
|
||||
},
|
||||
};
|
||||
value
|
||||
}
|
||||
GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance),
|
||||
GlobalAlloc::VTable(ty, trait_ref) => {
|
||||
let alloc = self
|
||||
.tcx
|
||||
.global_alloc(self.tcx.vtable_allocation((ty, trait_ref)))
|
||||
.unwrap_memory();
|
||||
let init = const_alloc_to_gcc(self, alloc);
|
||||
self.static_addr_of(init, alloc.inner().align, None)
|
||||
}
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
assert!(self.tcx.is_static(def_id));
|
||||
self.get_static(def_id).get_address(None)
|
||||
}
|
||||
};
|
||||
let ptr_type = base_addr.get_type();
|
||||
let base_addr = self.const_bitcast(base_addr, self.usize_type);
|
||||
let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
|
||||
let offset =
|
||||
self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
|
||||
let ptr = self.const_bitcast(base_addr + offset, ptr_type);
|
||||
if !matches!(layout.primitive(), Pointer(_)) {
|
||||
self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
self.const_bitcast(ptr, ty)
|
||||
}
|
||||
}
|
||||
|
@ -261,7 +249,9 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
|
||||
self.context.new_array_access(None, base_addr, self.const_usize(offset.bytes())).get_address(None)
|
||||
self.context
|
||||
.new_array_access(None, base_addr, self.const_usize(offset.bytes()))
|
||||
.get_address(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,35 +274,25 @@ impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> {
|
|||
fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
|
||||
if self.is_u8(cx) {
|
||||
cx.i8_type
|
||||
}
|
||||
else if self.is_u16(cx) {
|
||||
} else if self.is_u16(cx) {
|
||||
cx.i16_type
|
||||
}
|
||||
else if self.is_u32(cx) {
|
||||
} else if self.is_u32(cx) {
|
||||
cx.i32_type
|
||||
}
|
||||
else if self.is_u64(cx) {
|
||||
} else if self.is_u64(cx) {
|
||||
cx.i64_type
|
||||
}
|
||||
else if self.is_u128(cx) {
|
||||
} else if self.is_u128(cx) {
|
||||
cx.i128_type
|
||||
}
|
||||
else if self.is_uchar(cx) {
|
||||
} else if self.is_uchar(cx) {
|
||||
cx.char_type
|
||||
}
|
||||
else if self.is_ushort(cx) {
|
||||
} else if self.is_ushort(cx) {
|
||||
cx.short_type
|
||||
}
|
||||
else if self.is_uint(cx) {
|
||||
} else if self.is_uint(cx) {
|
||||
cx.int_type
|
||||
}
|
||||
else if self.is_ulong(cx) {
|
||||
} else if self.is_ulong(cx) {
|
||||
cx.long_type
|
||||
}
|
||||
else if self.is_ulonglong(cx) {
|
||||
} else if self.is_ulonglong(cx) {
|
||||
cx.longlong_type
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
@ -320,41 +300,31 @@ impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> {
|
|||
fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
|
||||
if self.is_i8(cx) {
|
||||
cx.u8_type
|
||||
}
|
||||
else if self.is_i16(cx) {
|
||||
} else if self.is_i16(cx) {
|
||||
cx.u16_type
|
||||
}
|
||||
else if self.is_i32(cx) {
|
||||
} else if self.is_i32(cx) {
|
||||
cx.u32_type
|
||||
}
|
||||
else if self.is_i64(cx) {
|
||||
} else if self.is_i64(cx) {
|
||||
cx.u64_type
|
||||
}
|
||||
else if self.is_i128(cx) {
|
||||
} else if self.is_i128(cx) {
|
||||
cx.u128_type
|
||||
}
|
||||
else if self.is_char(cx) {
|
||||
} else if self.is_char(cx) {
|
||||
cx.uchar_type
|
||||
}
|
||||
else if self.is_short(cx) {
|
||||
} else if self.is_short(cx) {
|
||||
cx.ushort_type
|
||||
}
|
||||
else if self.is_int(cx) {
|
||||
} else if self.is_int(cx) {
|
||||
cx.uint_type
|
||||
}
|
||||
else if self.is_long(cx) {
|
||||
} else if self.is_long(cx) {
|
||||
cx.ulong_type
|
||||
}
|
||||
else if self.is_longlong(cx) {
|
||||
} else if self.is_longlong(cx) {
|
||||
cx.ulonglong_type
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TypeReflection<'gcc, 'tcx> {
|
||||
pub trait TypeReflection<'gcc, 'tcx> {
|
||||
fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
|
||||
fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
|
||||
fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
|
||||
|
|
133
src/consts.rs
133
src/consts.rs
|
@ -2,12 +2,14 @@
|
|||
use gccjit::{FnAttribute, VarAttribute, Visibility};
|
||||
use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue};
|
||||
use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::mir::interpret::{
|
||||
self, read_target_uint, ConstAllocation, ErrorHandled, Scalar as InterpScalar,
|
||||
};
|
||||
use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
|
||||
|
||||
|
@ -16,7 +18,11 @@ use crate::context::CodegenCx;
|
|||
use crate::errors::InvalidMinimumAlignment;
|
||||
use crate::type_of::LayoutGccExt;
|
||||
|
||||
fn set_global_alignment<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, gv: LValue<'gcc>, mut align: Align) {
|
||||
fn set_global_alignment<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
gv: LValue<'gcc>,
|
||||
mut align: Align,
|
||||
) {
|
||||
// The target may require greater alignment for globals than the type does.
|
||||
// Note: GCC and Clang also allow `__attribute__((aligned))` on variables,
|
||||
// which can force it to be smaller. Rust doesn't support this yet.
|
||||
|
@ -48,7 +54,9 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
let global_value = self.static_addr_of_mut(cv, align, kind);
|
||||
#[cfg(feature = "master")]
|
||||
self.global_lvalues.borrow().get(&global_value)
|
||||
self.global_lvalues
|
||||
.borrow()
|
||||
.get(&global_value)
|
||||
.expect("`static_addr_of_mut` did not add the global to `self.global_lvalues`")
|
||||
.global_set_readonly();
|
||||
self.const_globals.borrow_mut().insert(cv, global_value);
|
||||
|
@ -58,25 +66,22 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
|
|||
fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
|
||||
let attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||
|
||||
let value =
|
||||
match codegen_static_initializer(&self, def_id) {
|
||||
Ok((value, _)) => value,
|
||||
// Error has already been reported
|
||||
Err(_) => return,
|
||||
};
|
||||
let value = match codegen_static_initializer(&self, def_id) {
|
||||
Ok((value, _)) => value,
|
||||
// Error has already been reported
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let global = self.get_static(def_id);
|
||||
|
||||
// boolean SSA values are i1, but they have to be stored in i8 slots,
|
||||
// otherwise some LLVM optimization passes don't work as expected
|
||||
let val_llty = self.val_ty(value);
|
||||
let value =
|
||||
if val_llty == self.type_i1() {
|
||||
unimplemented!();
|
||||
}
|
||||
else {
|
||||
value
|
||||
};
|
||||
let value = if val_llty == self.type_i1() {
|
||||
unimplemented!();
|
||||
} else {
|
||||
value
|
||||
};
|
||||
|
||||
let instance = Instance::mono(self.tcx, def_id);
|
||||
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
|
||||
|
@ -149,7 +154,9 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
|
|||
// TODO(antoyo): set link section.
|
||||
}
|
||||
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED) || attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||
|| attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||
{
|
||||
self.add_used_global(global.to_rvalue());
|
||||
}
|
||||
}
|
||||
|
@ -166,29 +173,33 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
#[cfg_attr(not(feature="master"), allow(unused_variables))]
|
||||
#[cfg_attr(not(feature = "master"), allow(unused_variables))]
|
||||
pub fn add_used_function(&self, function: Function<'gcc>) {
|
||||
#[cfg(feature = "master")]
|
||||
function.add_attribute(FnAttribute::Used);
|
||||
}
|
||||
|
||||
pub fn static_addr_of_mut(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
|
||||
let global =
|
||||
match kind {
|
||||
Some(kind) if !self.tcx.sess.fewer_names() => {
|
||||
let name = self.generate_local_symbol_name(kind);
|
||||
// TODO(antoyo): check if it's okay that no link_section is set.
|
||||
pub fn static_addr_of_mut(
|
||||
&self,
|
||||
cv: RValue<'gcc>,
|
||||
align: Align,
|
||||
kind: Option<&str>,
|
||||
) -> RValue<'gcc> {
|
||||
let global = match kind {
|
||||
Some(kind) if !self.tcx.sess.fewer_names() => {
|
||||
let name = self.generate_local_symbol_name(kind);
|
||||
// TODO(antoyo): check if it's okay that no link_section is set.
|
||||
|
||||
let typ = self.val_ty(cv).get_aligned(align.bytes());
|
||||
let global = self.declare_private_global(&name[..], typ);
|
||||
global
|
||||
}
|
||||
_ => {
|
||||
let typ = self.val_ty(cv).get_aligned(align.bytes());
|
||||
let global = self.declare_unnamed_global(typ);
|
||||
global
|
||||
},
|
||||
};
|
||||
let typ = self.val_ty(cv).get_aligned(align.bytes());
|
||||
let global = self.declare_private_global(&name[..], typ);
|
||||
global
|
||||
}
|
||||
_ => {
|
||||
let typ = self.val_ty(cv).get_aligned(align.bytes());
|
||||
let global = self.declare_unnamed_global(typ);
|
||||
global
|
||||
}
|
||||
};
|
||||
global.global_set_initializer_rvalue(cv);
|
||||
// TODO(antoyo): set unnamed address.
|
||||
let rvalue = global.get_address(None);
|
||||
|
@ -215,8 +226,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
|
||||
let sym = self.tcx.symbol_name(instance).name;
|
||||
|
||||
let global =
|
||||
if def_id.is_local() && !self.tcx.is_foreign_item(def_id) {
|
||||
let global = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) {
|
||||
let llty = self.layout_of(ty).gcc_type(self);
|
||||
if let Some(global) = self.get_declared_value(sym) {
|
||||
if self.val_ty(global) != self.type_ptr_to(llty) {
|
||||
|
@ -278,7 +288,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAllocation<'tcx>) -> RValue<'gcc> {
|
||||
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.provenance().ptrs().len() + 1);
|
||||
let dl = cx.data_layout();
|
||||
|
@ -300,14 +313,14 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
|
|||
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset);
|
||||
llvals.push(cx.const_bytes(bytes));
|
||||
}
|
||||
let ptr_offset =
|
||||
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 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")
|
||||
let ptr_offset = 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 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")
|
||||
as u64;
|
||||
|
||||
let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
|
||||
|
@ -317,7 +330,10 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
|
|||
interpret::Pointer::new(prov, Size::from_bytes(ptr_offset)),
|
||||
&cx.tcx,
|
||||
),
|
||||
abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) },
|
||||
abi::Scalar::Initialized {
|
||||
value: Primitive::Pointer(address_space),
|
||||
valid_range: WrappingRange::full(dl.pointer_size),
|
||||
},
|
||||
cx.type_i8p_ext(address_space),
|
||||
));
|
||||
next_offset = offset + pointer_size;
|
||||
|
@ -337,17 +353,29 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
|
|||
cx.const_struct(&llvals, true)
|
||||
}
|
||||
|
||||
pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
|
||||
pub fn codegen_static_initializer<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
def_id: DefId,
|
||||
) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
|
||||
let alloc = cx.tcx.eval_static_initializer(def_id)?;
|
||||
Ok((const_alloc_to_gcc(cx, alloc), alloc))
|
||||
}
|
||||
|
||||
fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str) -> LValue<'gcc> {
|
||||
fn check_and_apply_linkage<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
attrs: &CodegenFnAttrs,
|
||||
ty: Ty<'tcx>,
|
||||
sym: &str,
|
||||
) -> LValue<'gcc> {
|
||||
let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
|
||||
let gcc_type = cx.layout_of(ty).gcc_type(cx);
|
||||
if let Some(linkage) = attrs.import_linkage {
|
||||
// Declare a symbol `foo` with the desired linkage.
|
||||
let global1 = cx.declare_global_with_linkage(&sym, cx.type_i8(), base::global_linkage_to_gcc(linkage));
|
||||
let global1 = cx.declare_global_with_linkage(
|
||||
&sym,
|
||||
cx.type_i8(),
|
||||
base::global_linkage_to_gcc(linkage),
|
||||
);
|
||||
|
||||
// Declare an internal global `extern_with_linkage_foo` which
|
||||
// is initialized with the address of `foo`. If `foo` is
|
||||
|
@ -363,8 +391,7 @@ fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &Codeg
|
|||
global2.global_set_initializer_rvalue(value);
|
||||
// TODO(antoyo): use global_set_initializer() when it will work.
|
||||
global2
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Generate an external declaration.
|
||||
// FIXME(nagisa): investigate whether it can be changed into define_global
|
||||
|
||||
|
|
246
src/context.rs
246
src/context.rs
|
@ -1,22 +1,25 @@
|
|||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type};
|
||||
use rustc_codegen_ssa::base::wants_msvc_seh;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BackendTypes,
|
||||
BaseTypeMethods,
|
||||
MiscMethods,
|
||||
use gccjit::{
|
||||
Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type,
|
||||
};
|
||||
use rustc_codegen_ssa::base::wants_msvc_seh;
|
||||
use rustc_codegen_ssa::errors as ssa_errors;
|
||||
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, MiscMethods};
|
||||
use rustc_data_structures::base_n;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::mir::mono::CodegenUnit;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::layout::{
|
||||
FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError,
|
||||
LayoutOfHelpers, TyAndLayout,
|
||||
};
|
||||
use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::layout::{FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{Span, source_map::respan};
|
||||
use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
|
||||
use rustc_span::{source_map::respan, Span};
|
||||
use rustc_target::abi::{
|
||||
call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
|
||||
};
|
||||
use rustc_target::spec::{HasTargetSpec, Target, TlsModel};
|
||||
|
||||
use crate::callee::get_fn;
|
||||
|
@ -81,7 +84,8 @@ pub struct CodegenCx<'gcc, 'tcx> {
|
|||
/// Cache function instances of monomorphic and polymorphic items
|
||||
pub function_instances: RefCell<FxHashMap<Instance<'tcx>, Function<'gcc>>>,
|
||||
/// Cache generated vtables
|
||||
pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
|
||||
pub vtables:
|
||||
RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
|
||||
|
||||
// TODO(antoyo): improve the SSA API to not require those.
|
||||
/// Mapping from function pointer type to indexes of on stack parameters.
|
||||
|
@ -121,24 +125,28 @@ pub struct CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
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 {
|
||||
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 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")]
|
||||
#[cfg(feature = "master")]
|
||||
{
|
||||
context.new_c_type(ctype).get_aligned(align)
|
||||
}
|
||||
#[cfg(not(feature="master"))]
|
||||
#[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 {
|
||||
} else {
|
||||
context.new_c_type(ctype)
|
||||
}
|
||||
}
|
||||
|
@ -153,24 +161,22 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
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 = create_type(CType::Int128t, tcx.types.i128);
|
||||
let u128_type = create_type(CType::UInt128t, tcx.types.u128);
|
||||
(i128_type, u128_type)
|
||||
}
|
||||
else {
|
||||
/*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();*/
|
||||
let (i128_type, u128_type) = if supports_128bit_integers {
|
||||
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 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)
|
||||
};
|
||||
// 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());
|
||||
|
||||
|
@ -196,16 +202,65 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
|
||||
let mut functions = FxHashMap::default();
|
||||
let builtins = [
|
||||
"__builtin_unreachable", "abort", "__builtin_expect", /*"__builtin_expect_with_probability",*/
|
||||
"__builtin_constant_p", "__builtin_add_overflow", "__builtin_mul_overflow", "__builtin_saddll_overflow",
|
||||
/*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/
|
||||
"__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow",
|
||||
"__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow",
|
||||
"__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos",
|
||||
"powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf",
|
||||
"fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf",
|
||||
"ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round",
|
||||
|
||||
"__builtin_unreachable",
|
||||
"abort",
|
||||
"__builtin_expect", /*"__builtin_expect_with_probability",*/
|
||||
"__builtin_constant_p",
|
||||
"__builtin_add_overflow",
|
||||
"__builtin_mul_overflow",
|
||||
"__builtin_saddll_overflow",
|
||||
/*"__builtin_sadd_overflow",*/
|
||||
"__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/
|
||||
"__builtin_ssubll_overflow",
|
||||
/*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow",
|
||||
"__builtin_uaddll_overflow",
|
||||
"__builtin_uadd_overflow",
|
||||
"__builtin_umulll_overflow",
|
||||
"__builtin_umul_overflow",
|
||||
"__builtin_usubll_overflow",
|
||||
"__builtin_usub_overflow",
|
||||
"sqrtf",
|
||||
"sqrt",
|
||||
"__builtin_powif",
|
||||
"__builtin_powi",
|
||||
"sinf",
|
||||
"sin",
|
||||
"cosf",
|
||||
"cos",
|
||||
"powf",
|
||||
"pow",
|
||||
"expf",
|
||||
"exp",
|
||||
"exp2f",
|
||||
"exp2",
|
||||
"logf",
|
||||
"log",
|
||||
"log10f",
|
||||
"log10",
|
||||
"log2f",
|
||||
"log2",
|
||||
"fmaf",
|
||||
"fma",
|
||||
"fabsf",
|
||||
"fabs",
|
||||
"fminf",
|
||||
"fmin",
|
||||
"fmaxf",
|
||||
"fmax",
|
||||
"copysignf",
|
||||
"copysign",
|
||||
"floorf",
|
||||
"floor",
|
||||
"ceilf",
|
||||
"ceil",
|
||||
"truncf",
|
||||
"trunc",
|
||||
"rintf",
|
||||
"rint",
|
||||
"nearbyintf",
|
||||
"nearbyint",
|
||||
"roundf",
|
||||
"round",
|
||||
];
|
||||
|
||||
for builtin in builtins.iter() {
|
||||
|
@ -282,8 +337,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
|
||||
pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
|
||||
let function: Function<'gcc> = unsafe { std::mem::transmute(value) };
|
||||
debug_assert!(self.functions.borrow().values().any(|value| *value == function),
|
||||
"{:?} ({:?}) is not a function", value, value.get_type());
|
||||
debug_assert!(
|
||||
self.functions.borrow().values().any(|value| *value == function),
|
||||
"{:?} ({:?}) is not a function",
|
||||
value,
|
||||
value.get_type()
|
||||
);
|
||||
function
|
||||
}
|
||||
|
||||
|
@ -305,13 +364,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.supports_128bit_integers &&
|
||||
(self.u128_type.is_compatible_with(typ) || self.i128_type.is_compatible_with(typ))
|
||||
self.supports_128bit_integers
|
||||
&& (self.u128_type.is_compatible_with(typ) || self.i128_type.is_compatible_with(typ))
|
||||
}
|
||||
|
||||
pub fn is_non_native_int_type(&self, typ: Type<'gcc>) -> bool {
|
||||
!self.supports_128bit_integers &&
|
||||
(self.u128_type.is_compatible_with(typ) || self.i128_type.is_compatible_with(typ))
|
||||
!self.supports_128bit_integers
|
||||
&& (self.u128_type.is_compatible_with(typ) || self.i128_type.is_compatible_with(typ))
|
||||
}
|
||||
|
||||
pub fn is_native_int_type_or_bool(&self, typ: Type<'gcc>) -> bool {
|
||||
|
@ -319,18 +378,23 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn is_int_type_or_bool(&self, typ: Type<'gcc>) -> bool {
|
||||
self.is_native_int_type(typ) || self.is_non_native_int_type(typ) || typ.is_compatible_with(self.bool_type)
|
||||
self.is_native_int_type(typ)
|
||||
|| self.is_non_native_int_type(typ)
|
||||
|| typ.is_compatible_with(self.bool_type)
|
||||
}
|
||||
|
||||
pub fn sess(&self) -> &'tcx Session {
|
||||
&self.tcx.sess
|
||||
}
|
||||
|
||||
pub fn bitcast_if_needed(&self, value: RValue<'gcc>, expected_type: Type<'gcc>) -> RValue<'gcc> {
|
||||
pub fn bitcast_if_needed(
|
||||
&self,
|
||||
value: RValue<'gcc>,
|
||||
expected_type: Type<'gcc>,
|
||||
) -> RValue<'gcc> {
|
||||
if value.get_type() != expected_type {
|
||||
self.context.new_bitcast(None, value, expected_type)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +414,9 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
fn vtables(&self) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
|
||||
fn vtables(
|
||||
&self,
|
||||
) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
|
||||
&self.vtables
|
||||
}
|
||||
|
||||
|
@ -364,13 +430,11 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
|
||||
let func_name = self.tcx.symbol_name(instance).name;
|
||||
|
||||
let func =
|
||||
if self.intrinsics.borrow().contains_key(func_name) {
|
||||
self.intrinsics.borrow()[func_name].clone()
|
||||
}
|
||||
else {
|
||||
get_fn(self, instance)
|
||||
};
|
||||
let func = if self.intrinsics.borrow().contains_key(func_name) {
|
||||
self.intrinsics.borrow()[func_name].clone()
|
||||
} else {
|
||||
get_fn(self, instance)
|
||||
};
|
||||
let ptr = func.get_address(None);
|
||||
|
||||
// TODO(antoyo): don't do this twice: i.e. in declare_fn and here.
|
||||
|
@ -407,37 +471,34 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
return llpersonality;
|
||||
}
|
||||
let tcx = self.tcx;
|
||||
let func =
|
||||
match tcx.lang_items().eh_personality() {
|
||||
Some(def_id) if !wants_msvc_seh(self.sess()) => {
|
||||
let instance =
|
||||
ty::Instance::resolve(
|
||||
tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
def_id,
|
||||
ty::List::empty(),
|
||||
)
|
||||
.unwrap().unwrap();
|
||||
let func = match tcx.lang_items().eh_personality() {
|
||||
Some(def_id) if !wants_msvc_seh(self.sess()) => {
|
||||
let instance = ty::Instance::resolve(
|
||||
tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
def_id,
|
||||
ty::List::empty(),
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let symbol_name = tcx.symbol_name(instance).name;
|
||||
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
|
||||
self.linkage.set(FunctionType::Extern);
|
||||
let func = self.declare_fn(symbol_name, &fn_abi);
|
||||
let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
|
||||
func
|
||||
},
|
||||
_ => {
|
||||
let name =
|
||||
if wants_msvc_seh(self.sess()) {
|
||||
"__CxxFrameHandler3"
|
||||
}
|
||||
else {
|
||||
"rust_eh_personality"
|
||||
};
|
||||
let func = self.declare_func(name, self.type_i32(), &[], true);
|
||||
unsafe { std::mem::transmute(func) }
|
||||
}
|
||||
};
|
||||
let symbol_name = tcx.symbol_name(instance).name;
|
||||
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
|
||||
self.linkage.set(FunctionType::Extern);
|
||||
let func = self.declare_fn(symbol_name, &fn_abi);
|
||||
let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
|
||||
func
|
||||
}
|
||||
_ => {
|
||||
let name = if wants_msvc_seh(self.sess()) {
|
||||
"__CxxFrameHandler3"
|
||||
} else {
|
||||
"rust_eh_personality"
|
||||
};
|
||||
let func = self.declare_func(name, self.type_i32(), &[], true);
|
||||
unsafe { std::mem::transmute(func) }
|
||||
}
|
||||
};
|
||||
// TODO(antoyo): apply target cpu attributes.
|
||||
self.eh_personality.set(Some(func));
|
||||
func
|
||||
|
@ -467,8 +528,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
let entry_name = self.sess().target.entry_name.as_ref();
|
||||
if self.get_declared_value(entry_name).is_none() {
|
||||
Some(self.declare_entry_fn(entry_name, fn_type, ()))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// If the symbol already exists, it is an error: for example, the user wrote
|
||||
// #[no_mangle] extern "C" fn main(..) {..}
|
||||
// instead of #[start]
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
use crate::rustc_index::Idx;
|
||||
use gccjit::{Location, RValue};
|
||||
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
|
||||
use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::{Body, self, SourceScope};
|
||||
use rustc_middle::mir::{self, Body, SourceScope};
|
||||
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol};
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
use rustc_target::abi::Size;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use crate::rustc_index::Idx;
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::builder::Builder;
|
||||
|
@ -25,15 +25,15 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
|
|||
fn dbg_var_addr(
|
||||
&mut self,
|
||||
_dbg_var: Self::DIVariable,
|
||||
dbg_loc: Self::DILocation,
|
||||
variable_alloca: Self::Value,
|
||||
_dbg_loc: Self::DILocation,
|
||||
_variable_alloca: Self::Value,
|
||||
_direct_offset: Size,
|
||||
_indirect_offsets: &[Size],
|
||||
_fragment: Option<Range<Size>>,
|
||||
) {
|
||||
// FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here.
|
||||
#[cfg(feature = "master")]
|
||||
variable_alloca.set_location(dbg_loc);
|
||||
_variable_alloca.set_location(_dbg_loc);
|
||||
}
|
||||
|
||||
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
|
||||
|
@ -43,11 +43,10 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
|
|||
/// FIXME(tempdragon): Currently, this function is not yet implemented. It seems that the
|
||||
/// debug name and the mangled name should both be included in the LValues.
|
||||
/// Besides, a function to get the rvalue type(m_is_lvalue) should also be included.
|
||||
fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) {
|
||||
}
|
||||
fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) {}
|
||||
|
||||
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) {
|
||||
self.loc = Some(dbg_loc);
|
||||
self.location = Some(dbg_loc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +85,7 @@ fn compute_mir_scopes<'gcc, 'tcx>(
|
|||
|
||||
/// Update the `debug_context`, adding new scope to it,
|
||||
/// if it's not added as is denoted in `instantiated`.
|
||||
///
|
||||
///
|
||||
/// # Souce of Origin
|
||||
/// Copied from `create_scope_map.rs` of rustc_codegen_llvm
|
||||
/// FIXME(tempdragon/?): Add Scope Support Here.
|
||||
|
@ -119,16 +118,14 @@ fn make_mir_scope<'gcc, 'tcx>(
|
|||
return;
|
||||
};
|
||||
|
||||
if let Some(vars) = variables
|
||||
{
|
||||
if !vars.contains(scope)
|
||||
&& scope_data.inlined.is_none() {
|
||||
// Do not create a DIScope if there are no variables defined in this
|
||||
// MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
|
||||
debug_context.scopes[scope] = parent_scope;
|
||||
instantiated.insert(scope);
|
||||
return;
|
||||
}
|
||||
if let Some(vars) = variables {
|
||||
if !vars.contains(scope) && scope_data.inlined.is_none() {
|
||||
// Do not create a DIScope if there are no variables defined in this
|
||||
// MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
|
||||
debug_context.scopes[scope] = parent_scope;
|
||||
instantiated.insert(scope);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let loc = cx.lookup_debug_loc(scope_data.span.lo());
|
||||
|
@ -145,7 +142,7 @@ fn make_mir_scope<'gcc, 'tcx>(
|
|||
let p_inlined_at = parent_scope.inlined_at;
|
||||
// TODO(tempdragon): dbg_scope: Add support for scope extension here.
|
||||
inlined_at.or(p_inlined_at);
|
||||
|
||||
|
||||
debug_context.scopes[scope] = DebugScope {
|
||||
dbg_scope,
|
||||
inlined_at,
|
||||
|
@ -216,7 +213,6 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
llfn: RValue<'gcc>,
|
||||
mir: &mir::Body<'tcx>,
|
||||
) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> {
|
||||
// TODO(antoyo)
|
||||
if self.sess().opts.debuginfo == DebugInfo::None {
|
||||
return None;
|
||||
}
|
||||
|
@ -278,33 +274,27 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
span: Span,
|
||||
) -> Self::DILocation {
|
||||
let pos = span.lo();
|
||||
let DebugLoc{file, line, col} = self.lookup_debug_loc(pos);
|
||||
let DebugLoc { file, line, col } = self.lookup_debug_loc(pos);
|
||||
let loc = match &file.name {
|
||||
rustc_span::FileName::Real(name) => match name {
|
||||
rustc_span::RealFileName::LocalPath(name) => {
|
||||
if let Some(name) = name.to_str() {
|
||||
self.context
|
||||
.new_location(name, line as i32, col as i32)
|
||||
} else{
|
||||
Location::null()
|
||||
}
|
||||
}
|
||||
rustc_span::RealFileName::Remapped {
|
||||
local_path,
|
||||
virtual_name:_,
|
||||
} => if let Some(name) = local_path.as_ref() {
|
||||
if let Some(name) = name.to_str(){
|
||||
self.context.new_location(
|
||||
name,
|
||||
line as i32,
|
||||
col as i32,
|
||||
)
|
||||
self.context.new_location(name, line as i32, col as i32)
|
||||
} else {
|
||||
Location::null()
|
||||
}
|
||||
} else{
|
||||
Location::null()
|
||||
},
|
||||
}
|
||||
rustc_span::RealFileName::Remapped { local_path, virtual_name: _ } => {
|
||||
if let Some(name) = local_path.as_ref() {
|
||||
if let Some(name) = name.to_str() {
|
||||
self.context.new_location(name, line as i32, col as i32)
|
||||
} else {
|
||||
Location::null()
|
||||
}
|
||||
} else {
|
||||
Location::null()
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => Location::null(),
|
||||
};
|
||||
|
|
219
src/declare.rs
219
src/declare.rs
|
@ -1,6 +1,6 @@
|
|||
use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::{FnAttribute, ToRValue};
|
||||
use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
|
||||
use rustc_codegen_ssa::traits::BaseTypeMethods;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Symbol;
|
||||
|
@ -11,7 +11,13 @@ use crate::context::CodegenCx;
|
|||
use crate::intrinsic::llvm;
|
||||
|
||||
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
||||
pub fn get_or_insert_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
|
||||
pub fn get_or_insert_global(
|
||||
&self,
|
||||
name: &str,
|
||||
ty: Type<'gcc>,
|
||||
is_tls: bool,
|
||||
link_section: Option<Symbol>,
|
||||
) -> LValue<'gcc> {
|
||||
if self.globals.borrow().contains_key(name) {
|
||||
let typ = self.globals.borrow()[name].get_type();
|
||||
let global = self.context.new_global(None, GlobalKind::Imported, typ, name);
|
||||
|
@ -22,8 +28,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
global.set_link_section(link_section.as_str());
|
||||
}
|
||||
global
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
self.declare_global(name, ty, GlobalKind::Exported, is_tls, link_section)
|
||||
}
|
||||
}
|
||||
|
@ -33,19 +38,37 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
self.context.new_global(None, GlobalKind::Internal, ty, &name)
|
||||
}
|
||||
|
||||
pub fn declare_global_with_linkage(&self, name: &str, ty: Type<'gcc>, linkage: GlobalKind) -> LValue<'gcc> {
|
||||
pub fn declare_global_with_linkage(
|
||||
&self,
|
||||
name: &str,
|
||||
ty: Type<'gcc>,
|
||||
linkage: GlobalKind,
|
||||
) -> LValue<'gcc> {
|
||||
let global = self.context.new_global(None, linkage, ty, name);
|
||||
let global_address = global.get_address(None);
|
||||
self.globals.borrow_mut().insert(name.to_string(), global_address);
|
||||
global
|
||||
}
|
||||
|
||||
pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> Function<'gcc> {
|
||||
pub fn declare_func(
|
||||
&self,
|
||||
name: &str,
|
||||
return_type: Type<'gcc>,
|
||||
params: &[Type<'gcc>],
|
||||
variadic: bool,
|
||||
) -> Function<'gcc> {
|
||||
self.linkage.set(FunctionType::Extern);
|
||||
declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic)
|
||||
}
|
||||
|
||||
pub fn declare_global(&self, name: &str, ty: Type<'gcc>, global_kind: GlobalKind, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
|
||||
pub fn declare_global(
|
||||
&self,
|
||||
name: &str,
|
||||
ty: Type<'gcc>,
|
||||
global_kind: GlobalKind,
|
||||
is_tls: bool,
|
||||
link_section: Option<Symbol>,
|
||||
) -> LValue<'gcc> {
|
||||
let global = self.context.new_global(None, global_kind, ty, name);
|
||||
if is_tls {
|
||||
global.set_tls_model(self.tls_model);
|
||||
|
@ -65,13 +88,25 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
global
|
||||
}
|
||||
|
||||
pub fn declare_entry_fn(&self, name: &str, _fn_type: Type<'gcc>, callconv: () /*llvm::CCallConv*/) -> RValue<'gcc> {
|
||||
pub fn declare_entry_fn(
|
||||
&self,
|
||||
name: &str,
|
||||
_fn_type: Type<'gcc>,
|
||||
callconv: (), /*llvm::CCallConv*/
|
||||
) -> RValue<'gcc> {
|
||||
// TODO(antoyo): use the fn_type parameter.
|
||||
let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
|
||||
let return_type = self.type_i32();
|
||||
let variadic = false;
|
||||
self.linkage.set(FunctionType::Exported);
|
||||
let func = declare_raw_fn(self, name, callconv, return_type, &[self.type_i32(), const_string], variadic);
|
||||
let func = declare_raw_fn(
|
||||
self,
|
||||
name,
|
||||
callconv,
|
||||
return_type,
|
||||
&[self.type_i32(), const_string],
|
||||
variadic,
|
||||
);
|
||||
// NOTE: it is needed to set the current_func here as well, because get_fn() is not called
|
||||
// for the main function.
|
||||
*self.current_func.borrow_mut() = Some(func);
|
||||
|
@ -85,19 +120,32 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
arguments_type,
|
||||
is_c_variadic,
|
||||
on_stack_param_indices,
|
||||
#[cfg(feature="master")]
|
||||
#[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);
|
||||
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")]
|
||||
#[cfg(feature = "master")]
|
||||
for fn_attr in fn_attributes {
|
||||
func.add_attribute(fn_attr);
|
||||
}
|
||||
func
|
||||
}
|
||||
|
||||
pub fn define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
|
||||
pub fn define_global(
|
||||
&self,
|
||||
name: &str,
|
||||
ty: Type<'gcc>,
|
||||
is_tls: bool,
|
||||
link_section: Option<Symbol>,
|
||||
) -> LValue<'gcc> {
|
||||
self.get_or_insert_global(name, ty, is_tls, link_section)
|
||||
}
|
||||
|
||||
|
@ -111,64 +159,84 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*llvm::CallConv*/, return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool) -> Function<'gcc> {
|
||||
fn declare_raw_fn<'gcc>(
|
||||
cx: &CodegenCx<'gcc, '_>,
|
||||
name: &str,
|
||||
_callconv: (), /*llvm::CallConv*/
|
||||
return_type: Type<'gcc>,
|
||||
param_types: &[Type<'gcc>],
|
||||
variadic: bool,
|
||||
) -> Function<'gcc> {
|
||||
if name.starts_with("llvm.") {
|
||||
let intrinsic = llvm::intrinsic(name, cx);
|
||||
cx.intrinsics.borrow_mut().insert(name.to_string(), intrinsic);
|
||||
return intrinsic;
|
||||
}
|
||||
let func =
|
||||
if cx.functions.borrow().contains_key(name) {
|
||||
cx.functions.borrow()[name]
|
||||
}
|
||||
else {
|
||||
let params: Vec<_> = param_types.into_iter().enumerate()
|
||||
.map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name.
|
||||
let func = if cx.functions.borrow().contains_key(name) {
|
||||
cx.functions.borrow()[name]
|
||||
} else {
|
||||
let params: Vec<_> = param_types
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, param)| {
|
||||
cx.context.new_parameter(None, *param, &format!("param{}", index))
|
||||
}) // TODO(antoyo): set name.
|
||||
.collect();
|
||||
#[cfg(not(feature = "master"))]
|
||||
let name = mangle_name(name);
|
||||
let func =
|
||||
cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, &name, variadic);
|
||||
cx.functions.borrow_mut().insert(name.to_string(), func);
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
if name == "rust_eh_personality" {
|
||||
// NOTE: GCC will sometimes change the personality function set on a function from
|
||||
// rust_eh_personality to __gcc_personality_v0 as an optimization.
|
||||
// As such, we need to create a weak alias from __gcc_personality_v0 to
|
||||
// rust_eh_personality in order to avoid a linker error.
|
||||
// This needs to be weak in order to still allow using the standard
|
||||
// __gcc_personality_v0 when the linking to it.
|
||||
// Since aliases don't work (maybe because of a bug in LTO partitioning?), we
|
||||
// create a wrapper function that calls rust_eh_personality.
|
||||
|
||||
let params: Vec<_> = param_types
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, param)| {
|
||||
cx.context.new_parameter(None, *param, &format!("param{}", index))
|
||||
}) // TODO(antoyo): set name.
|
||||
.collect();
|
||||
#[cfg(not(feature="master"))]
|
||||
let name = mangle_name(name);
|
||||
let func = cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, &name, variadic);
|
||||
cx.functions.borrow_mut().insert(name.to_string(), func);
|
||||
let gcc_func = cx.context.new_function(
|
||||
None,
|
||||
FunctionType::Exported,
|
||||
return_type,
|
||||
¶ms,
|
||||
"__gcc_personality_v0",
|
||||
variadic,
|
||||
);
|
||||
|
||||
#[cfg(feature="master")]
|
||||
if name == "rust_eh_personality" {
|
||||
// NOTE: GCC will sometimes change the personality function set on a function from
|
||||
// rust_eh_personality to __gcc_personality_v0 as an optimization.
|
||||
// As such, we need to create a weak alias from __gcc_personality_v0 to
|
||||
// rust_eh_personality in order to avoid a linker error.
|
||||
// This needs to be weak in order to still allow using the standard
|
||||
// __gcc_personality_v0 when the linking to it.
|
||||
// Since aliases don't work (maybe because of a bug in LTO partitioning?), we
|
||||
// create a wrapper function that calls rust_eh_personality.
|
||||
// We need a normal extern function for the crates that access rust_eh_personality
|
||||
// without defining it, otherwise we'll get a compiler error.
|
||||
//
|
||||
// For the crate defining it, that needs to be a weak alias instead.
|
||||
gcc_func.add_attribute(FnAttribute::Weak);
|
||||
|
||||
let params: Vec<_> = param_types.into_iter().enumerate()
|
||||
.map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name.
|
||||
.collect();
|
||||
let gcc_func = cx.context.new_function(None, FunctionType::Exported, return_type, ¶ms, "__gcc_personality_v0", variadic);
|
||||
|
||||
// We need a normal extern function for the crates that access rust_eh_personality
|
||||
// without defining it, otherwise we'll get a compiler error.
|
||||
//
|
||||
// For the crate defining it, that needs to be a weak alias instead.
|
||||
gcc_func.add_attribute(FnAttribute::Weak);
|
||||
|
||||
let block = gcc_func.new_block("start");
|
||||
let mut args = vec![];
|
||||
for param in ¶ms {
|
||||
args.push(param.to_rvalue());
|
||||
}
|
||||
let call = cx.context.new_call(None, func, &args);
|
||||
if return_type == cx.type_void() {
|
||||
block.add_eval(None, call);
|
||||
block.end_with_void_return(None);
|
||||
}
|
||||
else {
|
||||
block.end_with_return(None, call);
|
||||
}
|
||||
let block = gcc_func.new_block("start");
|
||||
let mut args = vec![];
|
||||
for param in ¶ms {
|
||||
args.push(param.to_rvalue());
|
||||
}
|
||||
let call = cx.context.new_call(None, func, &args);
|
||||
if return_type == cx.type_void() {
|
||||
block.add_eval(None, call);
|
||||
block.end_with_void_return(None);
|
||||
} else {
|
||||
block.end_with_return(None, call);
|
||||
}
|
||||
}
|
||||
|
||||
func
|
||||
};
|
||||
func
|
||||
};
|
||||
|
||||
// TODO(antoyo): set function calling convention.
|
||||
// TODO(antoyo): set unnamed address.
|
||||
|
@ -183,15 +251,22 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll
|
|||
// FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _.
|
||||
// Unsupported characters: `$`, `.` and `*`.
|
||||
// FIXME(antoyo): `*` might not be expected: https://github.com/rust-lang/rust/issues/116979#issuecomment-1840926865
|
||||
#[cfg(not(feature="master"))]
|
||||
#[cfg(not(feature = "master"))]
|
||||
fn mangle_name(name: &str) -> String {
|
||||
name.replace(|char: char| {
|
||||
if !char.is_alphanumeric() && char != '_' {
|
||||
debug_assert!("$.*".contains(char), "Unsupported char in function name {}: {}", name, char);
|
||||
true
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}, "_")
|
||||
name.replace(
|
||||
|char: char| {
|
||||
if !char.is_alphanumeric() && char != '_' {
|
||||
debug_assert!(
|
||||
"$.*".contains(char),
|
||||
"Unsupported char in function name {}: {}",
|
||||
name,
|
||||
char
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
"_",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl
|
|||
let mut diag = DiagnosticBuilder::new(
|
||||
dcx,
|
||||
level,
|
||||
fluent::codegen_gcc_target_feature_disable_or_enable
|
||||
fluent::codegen_gcc_target_feature_disable_or_enable,
|
||||
);
|
||||
if let Some(span) = self.span {
|
||||
diag.span(span);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::Context;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
|
@ -7,7 +7,10 @@ use rustc_middle::bug;
|
|||
use rustc_session::Session;
|
||||
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
|
||||
|
||||
use crate::errors::{PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
|
||||
use crate::errors::{
|
||||
PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature,
|
||||
UnknownCTargetFeaturePrefix,
|
||||
};
|
||||
|
||||
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
||||
/// `--target` and similar).
|
||||
|
@ -44,7 +47,10 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
// -Ctarget-features
|
||||
let supported_features = sess.target.supported_target_features();
|
||||
let mut featsmap = FxHashMap::default();
|
||||
let feats = sess.opts.cg.target_feature
|
||||
let feats = sess
|
||||
.opts
|
||||
.cg
|
||||
.target_feature
|
||||
.split(',')
|
||||
.filter_map(|s| {
|
||||
let enable_disable = match s.chars().next() {
|
||||
|
@ -69,16 +75,14 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature =
|
||||
if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
else {
|
||||
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||
};
|
||||
} else {
|
||||
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
|
||||
|
@ -95,18 +99,18 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
// passing requests down to GCC. This means that all in-language
|
||||
// features also work on the command line instead of having two
|
||||
// different names when the GCC name and the Rust name differ.
|
||||
Some(to_gcc_features(sess, feature)
|
||||
.iter()
|
||||
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
|
||||
.map(|feature| {
|
||||
if enable_disable == '-' {
|
||||
format!("-{}", feature)
|
||||
}
|
||||
else {
|
||||
feature.to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
Some(
|
||||
to_gcc_features(sess, feature)
|
||||
.iter()
|
||||
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
|
||||
.map(|feature| {
|
||||
if enable_disable == '-' {
|
||||
format!("-{}", feature)
|
||||
} else {
|
||||
feature.to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.flatten();
|
||||
|
@ -184,7 +188,10 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]>
|
|||
|
||||
// Given a map from target_features to whether they are enabled or disabled,
|
||||
// ensure only valid combinations are allowed.
|
||||
pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) -> Option<&'static [&'static str]> {
|
||||
pub fn check_tied_features(
|
||||
sess: &Session,
|
||||
features: &FxHashMap<&str, bool>,
|
||||
) -> Option<&'static [&'static str]> {
|
||||
for tied in sess.target.tied_target_features() {
|
||||
// Tied features must be set to the same value, or not set at all
|
||||
let mut tied_iter = tied.iter();
|
||||
|
@ -199,7 +206,7 @@ pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) ->
|
|||
fn arch_to_gcc(name: &str) -> &str {
|
||||
match name {
|
||||
"M68020" => "68020",
|
||||
_ => name,
|
||||
_ => name,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,15 +215,13 @@ fn handle_native(name: &str) -> &str {
|
|||
return arch_to_gcc(name);
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
{
|
||||
// Get the native arch.
|
||||
let context = Context::default();
|
||||
context.get_target_info().arch().unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
context.get_target_info().arch().unwrap().to_str().unwrap()
|
||||
}
|
||||
#[cfg(not(feature="master"))]
|
||||
#[cfg(not(feature = "master"))]
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
|
|
932
src/int.rs
932
src/int.rs
File diff suppressed because it is too large
Load diff
|
@ -3,94 +3,185 @@ use std::borrow::Cow;
|
|||
use gccjit::{Function, FunctionPtrType, RValue, ToRValue, UnaryOp};
|
||||
use rustc_codegen_ssa::traits::BuilderMethods;
|
||||
|
||||
use crate::{context::CodegenCx, builder::Builder};
|
||||
use crate::{builder::Builder, context::CodegenCx};
|
||||
|
||||
pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, 'tcx>, gcc_func: FunctionPtrType<'gcc>, mut args: Cow<'b, [RValue<'gcc>]>, func_name: &str, original_function_name: Option<&String>) -> Cow<'b, [RValue<'gcc>]> {
|
||||
pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
|
||||
builder: &Builder<'a, 'gcc, 'tcx>,
|
||||
gcc_func: FunctionPtrType<'gcc>,
|
||||
mut args: Cow<'b, [RValue<'gcc>]>,
|
||||
func_name: &str,
|
||||
original_function_name: Option<&String>,
|
||||
) -> Cow<'b, [RValue<'gcc>]> {
|
||||
// Some LLVM intrinsics do not map 1-to-1 to GCC intrinsics, so we add the missing
|
||||
// arguments here.
|
||||
if gcc_func.get_param_count() != args.len() {
|
||||
match &*func_name {
|
||||
// NOTE: the following intrinsics have a different number of parameters in LLVM and GCC.
|
||||
"__builtin_ia32_prold512_mask" | "__builtin_ia32_pmuldq512_mask" | "__builtin_ia32_pmuludq512_mask"
|
||||
| "__builtin_ia32_pmaxsd512_mask" | "__builtin_ia32_pmaxsq512_mask" | "__builtin_ia32_pmaxsq256_mask"
|
||||
| "__builtin_ia32_pmaxsq128_mask" | "__builtin_ia32_pmaxud512_mask" | "__builtin_ia32_pmaxuq512_mask"
|
||||
| "__builtin_ia32_pminsd512_mask" | "__builtin_ia32_pminsq512_mask" | "__builtin_ia32_pminsq256_mask"
|
||||
| "__builtin_ia32_pminsq128_mask" | "__builtin_ia32_pminud512_mask" | "__builtin_ia32_pminuq512_mask"
|
||||
| "__builtin_ia32_prolq512_mask" | "__builtin_ia32_prorq512_mask" | "__builtin_ia32_pslldi512_mask"
|
||||
| "__builtin_ia32_psrldi512_mask" | "__builtin_ia32_psllqi512_mask" | "__builtin_ia32_psrlqi512_mask"
|
||||
| "__builtin_ia32_pslld512_mask" | "__builtin_ia32_psrld512_mask" | "__builtin_ia32_psllq512_mask"
|
||||
| "__builtin_ia32_psrlq512_mask" | "__builtin_ia32_psrad512_mask" | "__builtin_ia32_psraq512_mask"
|
||||
| "__builtin_ia32_psradi512_mask" | "__builtin_ia32_psraqi512_mask" | "__builtin_ia32_psrav16si_mask"
|
||||
| "__builtin_ia32_psrav8di_mask" | "__builtin_ia32_prolvd512_mask" | "__builtin_ia32_prorvd512_mask"
|
||||
| "__builtin_ia32_prolvq512_mask" | "__builtin_ia32_prorvq512_mask" | "__builtin_ia32_psllv16si_mask"
|
||||
| "__builtin_ia32_psrlv16si_mask" | "__builtin_ia32_psllv8di_mask" | "__builtin_ia32_psrlv8di_mask"
|
||||
| "__builtin_ia32_permvarsi512_mask" | "__builtin_ia32_vpermilvarps512_mask"
|
||||
| "__builtin_ia32_vpermilvarpd512_mask" | "__builtin_ia32_permvardi512_mask"
|
||||
| "__builtin_ia32_permvarsf512_mask" | "__builtin_ia32_permvarqi512_mask"
|
||||
| "__builtin_ia32_permvarqi256_mask" | "__builtin_ia32_permvarqi128_mask"
|
||||
| "__builtin_ia32_vpmultishiftqb512_mask" | "__builtin_ia32_vpmultishiftqb256_mask"
|
||||
| "__builtin_ia32_vpmultishiftqb128_mask"
|
||||
=> {
|
||||
"__builtin_ia32_prold512_mask"
|
||||
| "__builtin_ia32_pmuldq512_mask"
|
||||
| "__builtin_ia32_pmuludq512_mask"
|
||||
| "__builtin_ia32_pmaxsd512_mask"
|
||||
| "__builtin_ia32_pmaxsq512_mask"
|
||||
| "__builtin_ia32_pmaxsq256_mask"
|
||||
| "__builtin_ia32_pmaxsq128_mask"
|
||||
| "__builtin_ia32_pmaxud512_mask"
|
||||
| "__builtin_ia32_pmaxuq512_mask"
|
||||
| "__builtin_ia32_pminsd512_mask"
|
||||
| "__builtin_ia32_pminsq512_mask"
|
||||
| "__builtin_ia32_pminsq256_mask"
|
||||
| "__builtin_ia32_pminsq128_mask"
|
||||
| "__builtin_ia32_pminud512_mask"
|
||||
| "__builtin_ia32_pminuq512_mask"
|
||||
| "__builtin_ia32_prolq512_mask"
|
||||
| "__builtin_ia32_prorq512_mask"
|
||||
| "__builtin_ia32_pslldi512_mask"
|
||||
| "__builtin_ia32_psrldi512_mask"
|
||||
| "__builtin_ia32_psllqi512_mask"
|
||||
| "__builtin_ia32_psrlqi512_mask"
|
||||
| "__builtin_ia32_pslld512_mask"
|
||||
| "__builtin_ia32_psrld512_mask"
|
||||
| "__builtin_ia32_psllq512_mask"
|
||||
| "__builtin_ia32_psrlq512_mask"
|
||||
| "__builtin_ia32_psrad512_mask"
|
||||
| "__builtin_ia32_psraq512_mask"
|
||||
| "__builtin_ia32_psradi512_mask"
|
||||
| "__builtin_ia32_psraqi512_mask"
|
||||
| "__builtin_ia32_psrav16si_mask"
|
||||
| "__builtin_ia32_psrav8di_mask"
|
||||
| "__builtin_ia32_prolvd512_mask"
|
||||
| "__builtin_ia32_prorvd512_mask"
|
||||
| "__builtin_ia32_prolvq512_mask"
|
||||
| "__builtin_ia32_prorvq512_mask"
|
||||
| "__builtin_ia32_psllv16si_mask"
|
||||
| "__builtin_ia32_psrlv16si_mask"
|
||||
| "__builtin_ia32_psllv8di_mask"
|
||||
| "__builtin_ia32_psrlv8di_mask"
|
||||
| "__builtin_ia32_permvarsi512_mask"
|
||||
| "__builtin_ia32_vpermilvarps512_mask"
|
||||
| "__builtin_ia32_vpermilvarpd512_mask"
|
||||
| "__builtin_ia32_permvardi512_mask"
|
||||
| "__builtin_ia32_permvarsf512_mask"
|
||||
| "__builtin_ia32_permvarqi512_mask"
|
||||
| "__builtin_ia32_permvarqi256_mask"
|
||||
| "__builtin_ia32_permvarqi128_mask"
|
||||
| "__builtin_ia32_vpmultishiftqb512_mask"
|
||||
| "__builtin_ia32_vpmultishiftqb256_mask"
|
||||
| "__builtin_ia32_vpmultishiftqb128_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let arg3_type = gcc_func.get_param_type(2);
|
||||
let first_arg = builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue();
|
||||
let first_arg = builder
|
||||
.current_func()
|
||||
.new_local(None, arg3_type, "undefined_for_intrinsic")
|
||||
.to_rvalue();
|
||||
new_args.push(first_arg);
|
||||
let arg4_type = gcc_func.get_param_type(3);
|
||||
let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
|
||||
new_args.push(minus_one);
|
||||
args = new_args.into();
|
||||
},
|
||||
"__builtin_ia32_pmaxuq256_mask" | "__builtin_ia32_pmaxuq128_mask" | "__builtin_ia32_pminuq256_mask"
|
||||
| "__builtin_ia32_pminuq128_mask" | "__builtin_ia32_prold256_mask" | "__builtin_ia32_prold128_mask"
|
||||
| "__builtin_ia32_prord512_mask" | "__builtin_ia32_prord256_mask" | "__builtin_ia32_prord128_mask"
|
||||
| "__builtin_ia32_prolq256_mask" | "__builtin_ia32_prolq128_mask" | "__builtin_ia32_prorq256_mask"
|
||||
| "__builtin_ia32_prorq128_mask" | "__builtin_ia32_psraq256_mask" | "__builtin_ia32_psraq128_mask"
|
||||
| "__builtin_ia32_psraqi256_mask" | "__builtin_ia32_psraqi128_mask" | "__builtin_ia32_psravq256_mask"
|
||||
| "__builtin_ia32_psravq128_mask" | "__builtin_ia32_prolvd256_mask" | "__builtin_ia32_prolvd128_mask"
|
||||
| "__builtin_ia32_prorvd256_mask" | "__builtin_ia32_prorvd128_mask" | "__builtin_ia32_prolvq256_mask"
|
||||
| "__builtin_ia32_prolvq128_mask" | "__builtin_ia32_prorvq256_mask" | "__builtin_ia32_prorvq128_mask"
|
||||
| "__builtin_ia32_permvardi256_mask" | "__builtin_ia32_permvardf512_mask" | "__builtin_ia32_permvardf256_mask"
|
||||
| "__builtin_ia32_pmulhuw512_mask" | "__builtin_ia32_pmulhw512_mask" | "__builtin_ia32_pmulhrsw512_mask"
|
||||
| "__builtin_ia32_pmaxuw512_mask" | "__builtin_ia32_pmaxub512_mask" | "__builtin_ia32_pmaxsw512_mask"
|
||||
| "__builtin_ia32_pmaxsb512_mask" | "__builtin_ia32_pminuw512_mask" | "__builtin_ia32_pminub512_mask"
|
||||
| "__builtin_ia32_pminsw512_mask" | "__builtin_ia32_pminsb512_mask"
|
||||
| "__builtin_ia32_pmaddwd512_mask" | "__builtin_ia32_pmaddubsw512_mask" | "__builtin_ia32_packssdw512_mask"
|
||||
| "__builtin_ia32_packsswb512_mask" | "__builtin_ia32_packusdw512_mask" | "__builtin_ia32_packuswb512_mask"
|
||||
| "__builtin_ia32_pavgw512_mask" | "__builtin_ia32_pavgb512_mask" | "__builtin_ia32_psllw512_mask"
|
||||
| "__builtin_ia32_psllwi512_mask" | "__builtin_ia32_psllv32hi_mask" | "__builtin_ia32_psrlw512_mask"
|
||||
| "__builtin_ia32_psrlwi512_mask" | "__builtin_ia32_psllv16hi_mask" | "__builtin_ia32_psllv8hi_mask"
|
||||
| "__builtin_ia32_psrlv32hi_mask" | "__builtin_ia32_psraw512_mask" | "__builtin_ia32_psrawi512_mask"
|
||||
| "__builtin_ia32_psrlv16hi_mask" | "__builtin_ia32_psrlv8hi_mask" | "__builtin_ia32_psrav32hi_mask"
|
||||
| "__builtin_ia32_permvarhi512_mask" | "__builtin_ia32_pshufb512_mask" | "__builtin_ia32_psrav16hi_mask"
|
||||
| "__builtin_ia32_psrav8hi_mask" | "__builtin_ia32_permvarhi256_mask" | "__builtin_ia32_permvarhi128_mask"
|
||||
=> {
|
||||
}
|
||||
"__builtin_ia32_pmaxuq256_mask"
|
||||
| "__builtin_ia32_pmaxuq128_mask"
|
||||
| "__builtin_ia32_pminuq256_mask"
|
||||
| "__builtin_ia32_pminuq128_mask"
|
||||
| "__builtin_ia32_prold256_mask"
|
||||
| "__builtin_ia32_prold128_mask"
|
||||
| "__builtin_ia32_prord512_mask"
|
||||
| "__builtin_ia32_prord256_mask"
|
||||
| "__builtin_ia32_prord128_mask"
|
||||
| "__builtin_ia32_prolq256_mask"
|
||||
| "__builtin_ia32_prolq128_mask"
|
||||
| "__builtin_ia32_prorq256_mask"
|
||||
| "__builtin_ia32_prorq128_mask"
|
||||
| "__builtin_ia32_psraq256_mask"
|
||||
| "__builtin_ia32_psraq128_mask"
|
||||
| "__builtin_ia32_psraqi256_mask"
|
||||
| "__builtin_ia32_psraqi128_mask"
|
||||
| "__builtin_ia32_psravq256_mask"
|
||||
| "__builtin_ia32_psravq128_mask"
|
||||
| "__builtin_ia32_prolvd256_mask"
|
||||
| "__builtin_ia32_prolvd128_mask"
|
||||
| "__builtin_ia32_prorvd256_mask"
|
||||
| "__builtin_ia32_prorvd128_mask"
|
||||
| "__builtin_ia32_prolvq256_mask"
|
||||
| "__builtin_ia32_prolvq128_mask"
|
||||
| "__builtin_ia32_prorvq256_mask"
|
||||
| "__builtin_ia32_prorvq128_mask"
|
||||
| "__builtin_ia32_permvardi256_mask"
|
||||
| "__builtin_ia32_permvardf512_mask"
|
||||
| "__builtin_ia32_permvardf256_mask"
|
||||
| "__builtin_ia32_pmulhuw512_mask"
|
||||
| "__builtin_ia32_pmulhw512_mask"
|
||||
| "__builtin_ia32_pmulhrsw512_mask"
|
||||
| "__builtin_ia32_pmaxuw512_mask"
|
||||
| "__builtin_ia32_pmaxub512_mask"
|
||||
| "__builtin_ia32_pmaxsw512_mask"
|
||||
| "__builtin_ia32_pmaxsb512_mask"
|
||||
| "__builtin_ia32_pminuw512_mask"
|
||||
| "__builtin_ia32_pminub512_mask"
|
||||
| "__builtin_ia32_pminsw512_mask"
|
||||
| "__builtin_ia32_pminsb512_mask"
|
||||
| "__builtin_ia32_pmaddwd512_mask"
|
||||
| "__builtin_ia32_pmaddubsw512_mask"
|
||||
| "__builtin_ia32_packssdw512_mask"
|
||||
| "__builtin_ia32_packsswb512_mask"
|
||||
| "__builtin_ia32_packusdw512_mask"
|
||||
| "__builtin_ia32_packuswb512_mask"
|
||||
| "__builtin_ia32_pavgw512_mask"
|
||||
| "__builtin_ia32_pavgb512_mask"
|
||||
| "__builtin_ia32_psllw512_mask"
|
||||
| "__builtin_ia32_psllwi512_mask"
|
||||
| "__builtin_ia32_psllv32hi_mask"
|
||||
| "__builtin_ia32_psrlw512_mask"
|
||||
| "__builtin_ia32_psrlwi512_mask"
|
||||
| "__builtin_ia32_psllv16hi_mask"
|
||||
| "__builtin_ia32_psllv8hi_mask"
|
||||
| "__builtin_ia32_psrlv32hi_mask"
|
||||
| "__builtin_ia32_psraw512_mask"
|
||||
| "__builtin_ia32_psrawi512_mask"
|
||||
| "__builtin_ia32_psrlv16hi_mask"
|
||||
| "__builtin_ia32_psrlv8hi_mask"
|
||||
| "__builtin_ia32_psrav32hi_mask"
|
||||
| "__builtin_ia32_permvarhi512_mask"
|
||||
| "__builtin_ia32_pshufb512_mask"
|
||||
| "__builtin_ia32_psrav16hi_mask"
|
||||
| "__builtin_ia32_psrav8hi_mask"
|
||||
| "__builtin_ia32_permvarhi256_mask"
|
||||
| "__builtin_ia32_permvarhi128_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let arg3_type = gcc_func.get_param_type(2);
|
||||
let vector_type = arg3_type.dyncast_vector().expect("vector type");
|
||||
let zero = builder.context.new_rvalue_zero(vector_type.get_element_type());
|
||||
let num_units = vector_type.get_num_units();
|
||||
let first_arg = builder.context.new_rvalue_from_vector(None, arg3_type, &vec![zero; num_units]);
|
||||
let first_arg =
|
||||
builder.context.new_rvalue_from_vector(None, arg3_type, &vec![zero; num_units]);
|
||||
new_args.push(first_arg);
|
||||
let arg4_type = gcc_func.get_param_type(3);
|
||||
let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
|
||||
new_args.push(minus_one);
|
||||
args = new_args.into();
|
||||
},
|
||||
"__builtin_ia32_dbpsadbw512_mask" | "__builtin_ia32_dbpsadbw256_mask" | "__builtin_ia32_dbpsadbw128_mask" => {
|
||||
}
|
||||
"__builtin_ia32_dbpsadbw512_mask"
|
||||
| "__builtin_ia32_dbpsadbw256_mask"
|
||||
| "__builtin_ia32_dbpsadbw128_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let arg4_type = gcc_func.get_param_type(3);
|
||||
let vector_type = arg4_type.dyncast_vector().expect("vector type");
|
||||
let zero = builder.context.new_rvalue_zero(vector_type.get_element_type());
|
||||
let num_units = vector_type.get_num_units();
|
||||
let first_arg = builder.context.new_rvalue_from_vector(None, arg4_type, &vec![zero; num_units]);
|
||||
let first_arg =
|
||||
builder.context.new_rvalue_from_vector(None, arg4_type, &vec![zero; num_units]);
|
||||
new_args.push(first_arg);
|
||||
let arg5_type = gcc_func.get_param_type(4);
|
||||
let minus_one = builder.context.new_rvalue_from_int(arg5_type, -1);
|
||||
new_args.push(minus_one);
|
||||
args = new_args.into();
|
||||
},
|
||||
"__builtin_ia32_vplzcntd_512_mask" | "__builtin_ia32_vplzcntd_256_mask" | "__builtin_ia32_vplzcntd_128_mask"
|
||||
| "__builtin_ia32_vplzcntq_512_mask" | "__builtin_ia32_vplzcntq_256_mask" | "__builtin_ia32_vplzcntq_128_mask" => {
|
||||
}
|
||||
"__builtin_ia32_vplzcntd_512_mask"
|
||||
| "__builtin_ia32_vplzcntd_256_mask"
|
||||
| "__builtin_ia32_vplzcntd_128_mask"
|
||||
| "__builtin_ia32_vplzcntq_512_mask"
|
||||
| "__builtin_ia32_vplzcntq_256_mask"
|
||||
| "__builtin_ia32_vplzcntq_128_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
// Remove last arg as it doesn't seem to be used in GCC and is always false.
|
||||
new_args.pop();
|
||||
|
@ -98,37 +189,45 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
|
|||
let vector_type = arg2_type.dyncast_vector().expect("vector type");
|
||||
let zero = builder.context.new_rvalue_zero(vector_type.get_element_type());
|
||||
let num_units = vector_type.get_num_units();
|
||||
let first_arg = builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]);
|
||||
let first_arg =
|
||||
builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]);
|
||||
new_args.push(first_arg);
|
||||
let arg3_type = gcc_func.get_param_type(2);
|
||||
let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1);
|
||||
new_args.push(minus_one);
|
||||
args = new_args.into();
|
||||
},
|
||||
"__builtin_ia32_vpconflictsi_512_mask" | "__builtin_ia32_vpconflictsi_256_mask"
|
||||
| "__builtin_ia32_vpconflictsi_128_mask" | "__builtin_ia32_vpconflictdi_512_mask"
|
||||
| "__builtin_ia32_vpconflictdi_256_mask" | "__builtin_ia32_vpconflictdi_128_mask" => {
|
||||
}
|
||||
"__builtin_ia32_vpconflictsi_512_mask"
|
||||
| "__builtin_ia32_vpconflictsi_256_mask"
|
||||
| "__builtin_ia32_vpconflictsi_128_mask"
|
||||
| "__builtin_ia32_vpconflictdi_512_mask"
|
||||
| "__builtin_ia32_vpconflictdi_256_mask"
|
||||
| "__builtin_ia32_vpconflictdi_128_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let arg2_type = gcc_func.get_param_type(1);
|
||||
let vector_type = arg2_type.dyncast_vector().expect("vector type");
|
||||
let zero = builder.context.new_rvalue_zero(vector_type.get_element_type());
|
||||
let num_units = vector_type.get_num_units();
|
||||
let first_arg = builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]);
|
||||
let first_arg =
|
||||
builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]);
|
||||
new_args.push(first_arg);
|
||||
let arg3_type = gcc_func.get_param_type(2);
|
||||
let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1);
|
||||
new_args.push(minus_one);
|
||||
args = new_args.into();
|
||||
},
|
||||
"__builtin_ia32_pternlogd512_mask" | "__builtin_ia32_pternlogd256_mask"
|
||||
| "__builtin_ia32_pternlogd128_mask" | "__builtin_ia32_pternlogq512_mask"
|
||||
| "__builtin_ia32_pternlogq256_mask" | "__builtin_ia32_pternlogq128_mask" => {
|
||||
}
|
||||
"__builtin_ia32_pternlogd512_mask"
|
||||
| "__builtin_ia32_pternlogd256_mask"
|
||||
| "__builtin_ia32_pternlogd128_mask"
|
||||
| "__builtin_ia32_pternlogq512_mask"
|
||||
| "__builtin_ia32_pternlogq256_mask"
|
||||
| "__builtin_ia32_pternlogq128_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let arg5_type = gcc_func.get_param_type(4);
|
||||
let minus_one = builder.context.new_rvalue_from_int(arg5_type, -1);
|
||||
new_args.push(minus_one);
|
||||
args = new_args.into();
|
||||
},
|
||||
}
|
||||
"__builtin_ia32_vfmaddps512_mask" | "__builtin_ia32_vfmaddpd512_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
|
||||
|
@ -154,24 +253,33 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
|
|||
}
|
||||
|
||||
args = new_args.into();
|
||||
},
|
||||
"__builtin_ia32_addps512_mask" | "__builtin_ia32_addpd512_mask"
|
||||
| "__builtin_ia32_subps512_mask" | "__builtin_ia32_subpd512_mask"
|
||||
| "__builtin_ia32_mulps512_mask" | "__builtin_ia32_mulpd512_mask"
|
||||
| "__builtin_ia32_divps512_mask" | "__builtin_ia32_divpd512_mask"
|
||||
| "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask"
|
||||
| "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask" => {
|
||||
}
|
||||
"__builtin_ia32_addps512_mask"
|
||||
| "__builtin_ia32_addpd512_mask"
|
||||
| "__builtin_ia32_subps512_mask"
|
||||
| "__builtin_ia32_subpd512_mask"
|
||||
| "__builtin_ia32_mulps512_mask"
|
||||
| "__builtin_ia32_mulpd512_mask"
|
||||
| "__builtin_ia32_divps512_mask"
|
||||
| "__builtin_ia32_divpd512_mask"
|
||||
| "__builtin_ia32_maxps512_mask"
|
||||
| "__builtin_ia32_maxpd512_mask"
|
||||
| "__builtin_ia32_minps512_mask"
|
||||
| "__builtin_ia32_minpd512_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let last_arg = new_args.pop().expect("last arg");
|
||||
let arg3_type = gcc_func.get_param_type(2);
|
||||
let undefined = builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue();
|
||||
let undefined = builder
|
||||
.current_func()
|
||||
.new_local(None, arg3_type, "undefined_for_intrinsic")
|
||||
.to_rvalue();
|
||||
new_args.push(undefined);
|
||||
let arg4_type = gcc_func.get_param_type(3);
|
||||
let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
|
||||
new_args.push(minus_one);
|
||||
new_args.push(last_arg);
|
||||
args = new_args.into();
|
||||
},
|
||||
}
|
||||
"__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let last_arg = new_args.pop().expect("last arg");
|
||||
|
@ -180,54 +288,72 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
|
|||
new_args.push(minus_one);
|
||||
new_args.push(last_arg);
|
||||
args = new_args.into();
|
||||
},
|
||||
"__builtin_ia32_vpermi2vard512_mask" | "__builtin_ia32_vpermi2vard256_mask"
|
||||
| "__builtin_ia32_vpermi2vard128_mask" | "__builtin_ia32_vpermi2varq512_mask"
|
||||
| "__builtin_ia32_vpermi2varq256_mask" | "__builtin_ia32_vpermi2varq128_mask"
|
||||
| "__builtin_ia32_vpermi2varps512_mask" | "__builtin_ia32_vpermi2varps256_mask"
|
||||
| "__builtin_ia32_vpermi2varps128_mask" | "__builtin_ia32_vpermi2varpd512_mask"
|
||||
| "__builtin_ia32_vpermi2varpd256_mask" | "__builtin_ia32_vpermi2varpd128_mask" | "__builtin_ia32_vpmadd52huq512_mask"
|
||||
| "__builtin_ia32_vpmadd52luq512_mask" | "__builtin_ia32_vpmadd52huq256_mask" | "__builtin_ia32_vpmadd52luq256_mask"
|
||||
| "__builtin_ia32_vpmadd52huq128_mask"
|
||||
=> {
|
||||
}
|
||||
"__builtin_ia32_vpermi2vard512_mask"
|
||||
| "__builtin_ia32_vpermi2vard256_mask"
|
||||
| "__builtin_ia32_vpermi2vard128_mask"
|
||||
| "__builtin_ia32_vpermi2varq512_mask"
|
||||
| "__builtin_ia32_vpermi2varq256_mask"
|
||||
| "__builtin_ia32_vpermi2varq128_mask"
|
||||
| "__builtin_ia32_vpermi2varps512_mask"
|
||||
| "__builtin_ia32_vpermi2varps256_mask"
|
||||
| "__builtin_ia32_vpermi2varps128_mask"
|
||||
| "__builtin_ia32_vpermi2varpd512_mask"
|
||||
| "__builtin_ia32_vpermi2varpd256_mask"
|
||||
| "__builtin_ia32_vpermi2varpd128_mask"
|
||||
| "__builtin_ia32_vpmadd52huq512_mask"
|
||||
| "__builtin_ia32_vpmadd52luq512_mask"
|
||||
| "__builtin_ia32_vpmadd52huq256_mask"
|
||||
| "__builtin_ia32_vpmadd52luq256_mask"
|
||||
| "__builtin_ia32_vpmadd52huq128_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let arg4_type = gcc_func.get_param_type(3);
|
||||
let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
|
||||
new_args.push(minus_one);
|
||||
args = new_args.into();
|
||||
},
|
||||
"__builtin_ia32_cvtdq2ps512_mask" | "__builtin_ia32_cvtudq2ps512_mask"
|
||||
| "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => {
|
||||
}
|
||||
"__builtin_ia32_cvtdq2ps512_mask"
|
||||
| "__builtin_ia32_cvtudq2ps512_mask"
|
||||
| "__builtin_ia32_sqrtps512_mask"
|
||||
| "__builtin_ia32_sqrtpd512_mask" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let last_arg = new_args.pop().expect("last arg");
|
||||
let arg2_type = gcc_func.get_param_type(1);
|
||||
let undefined = builder.current_func().new_local(None, arg2_type, "undefined_for_intrinsic").to_rvalue();
|
||||
let undefined = builder
|
||||
.current_func()
|
||||
.new_local(None, arg2_type, "undefined_for_intrinsic")
|
||||
.to_rvalue();
|
||||
new_args.push(undefined);
|
||||
let arg3_type = gcc_func.get_param_type(2);
|
||||
let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1);
|
||||
new_args.push(minus_one);
|
||||
new_args.push(last_arg);
|
||||
args = new_args.into();
|
||||
},
|
||||
}
|
||||
"__builtin_ia32_stmxcsr" => {
|
||||
args = vec![].into();
|
||||
},
|
||||
"__builtin_ia32_addcarryx_u64" | "__builtin_ia32_sbb_u64" | "__builtin_ia32_addcarryx_u32" | "__builtin_ia32_sbb_u32" => {
|
||||
}
|
||||
"__builtin_ia32_addcarryx_u64"
|
||||
| "__builtin_ia32_sbb_u64"
|
||||
| "__builtin_ia32_addcarryx_u32"
|
||||
| "__builtin_ia32_sbb_u32" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let arg2_type = gcc_func.get_param_type(1);
|
||||
let variable = builder.current_func().new_local(None, arg2_type, "addcarryResult");
|
||||
new_args.push(variable.get_address(None));
|
||||
args = new_args.into();
|
||||
},
|
||||
"__builtin_ia32_vpermt2varqi512_mask" | "__builtin_ia32_vpermt2varqi256_mask"
|
||||
| "__builtin_ia32_vpermt2varqi128_mask" | "__builtin_ia32_vpermt2varhi512_mask"
|
||||
| "__builtin_ia32_vpermt2varhi256_mask" | "__builtin_ia32_vpermt2varhi128_mask"
|
||||
=> {
|
||||
}
|
||||
"__builtin_ia32_vpermt2varqi512_mask"
|
||||
| "__builtin_ia32_vpermt2varqi256_mask"
|
||||
| "__builtin_ia32_vpermt2varqi128_mask"
|
||||
| "__builtin_ia32_vpermt2varhi512_mask"
|
||||
| "__builtin_ia32_vpermt2varhi256_mask"
|
||||
| "__builtin_ia32_vpermt2varhi128_mask" => {
|
||||
let new_args = args.to_vec();
|
||||
let arg4_type = gcc_func.get_param_type(3);
|
||||
let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
|
||||
args = vec![new_args[1], new_args[0], new_args[2], minus_one].into();
|
||||
},
|
||||
}
|
||||
"__builtin_ia32_xrstor" | "__builtin_ia32_xsavec" => {
|
||||
let new_args = args.to_vec();
|
||||
let thirty_two = builder.context.new_rvalue_from_int(new_args[1].get_type(), 32);
|
||||
|
@ -235,22 +361,25 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
|
|||
let arg2_type = gcc_func.get_param_type(1);
|
||||
let arg2 = builder.context.new_cast(None, arg2, arg2_type);
|
||||
args = vec![new_args[0], arg2].into();
|
||||
},
|
||||
}
|
||||
// These builtins are sent one more argument than needed.
|
||||
"__builtin_prefetch" => {
|
||||
let mut new_args = args.to_vec();
|
||||
new_args.pop();
|
||||
args = new_args.into();
|
||||
},
|
||||
}
|
||||
// The GCC version returns one value of the tuple through a pointer.
|
||||
"__builtin_ia32_rdrand64_step" => {
|
||||
let arg = builder.current_func().new_local(None, builder.ulonglong_type, "return_rdrand_arg");
|
||||
let arg = builder.current_func().new_local(
|
||||
None,
|
||||
builder.ulonglong_type,
|
||||
"return_rdrand_arg",
|
||||
);
|
||||
args = vec![arg.get_address(None)].into();
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
match &*func_name {
|
||||
"__builtin_ia32_rndscaless_mask_round" | "__builtin_ia32_rndscalesd_mask_round" => {
|
||||
let new_args = args.to_vec();
|
||||
|
@ -259,7 +388,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
|
|||
let arg4_type = gcc_func.get_param_type(3);
|
||||
let arg4 = builder.context.new_bitcast(None, new_args[2], arg4_type);
|
||||
args = vec![new_args[0], new_args[1], arg3, arg4, new_args[3], new_args[5]].into();
|
||||
},
|
||||
}
|
||||
// NOTE: the LLVM intrinsic receives 3 floats, but the GCC builtin requires 3 vectors.
|
||||
// FIXME: the intrinsics like _mm_mask_fmadd_sd should probably directly call the GCC
|
||||
// intrinsic to avoid this.
|
||||
|
@ -272,7 +401,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
|
|||
let b = builder.context.new_rvalue_from_vector(None, arg2_type, &[new_args[1]; 4]);
|
||||
let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 4]);
|
||||
args = vec![a, b, c, new_args[3]].into();
|
||||
},
|
||||
}
|
||||
"__builtin_ia32_vfmaddsd3_round" => {
|
||||
let new_args = args.to_vec();
|
||||
let arg1_type = gcc_func.get_param_type(0);
|
||||
|
@ -282,25 +411,34 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
|
|||
let b = builder.context.new_rvalue_from_vector(None, arg2_type, &[new_args[1]; 2]);
|
||||
let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 2]);
|
||||
args = vec![a, b, c, new_args[3]].into();
|
||||
},
|
||||
"__builtin_ia32_vfmaddsubpd256" | "__builtin_ia32_vfmaddsubps" | "__builtin_ia32_vfmaddsubps256"
|
||||
| "__builtin_ia32_vfmaddsubpd" => {
|
||||
}
|
||||
"__builtin_ia32_vfmaddsubpd256"
|
||||
| "__builtin_ia32_vfmaddsubps"
|
||||
| "__builtin_ia32_vfmaddsubps256"
|
||||
| "__builtin_ia32_vfmaddsubpd" => {
|
||||
if let Some(original_function_name) = original_function_name {
|
||||
match &**original_function_name {
|
||||
"llvm.x86.fma.vfmsubadd.pd.256" | "llvm.x86.fma.vfmsubadd.ps" | "llvm.x86.fma.vfmsubadd.ps.256"
|
||||
| "llvm.x86.fma.vfmsubadd.pd" => {
|
||||
"llvm.x86.fma.vfmsubadd.pd.256"
|
||||
| "llvm.x86.fma.vfmsubadd.ps"
|
||||
| "llvm.x86.fma.vfmsubadd.ps.256"
|
||||
| "llvm.x86.fma.vfmsubadd.pd" => {
|
||||
// NOTE: since both llvm.x86.fma.vfmsubadd.ps and llvm.x86.fma.vfmaddsub.ps maps to
|
||||
// __builtin_ia32_vfmaddsubps, only add minus if this comes from a
|
||||
// subadd LLVM intrinsic, e.g. _mm256_fmsubadd_pd.
|
||||
let mut new_args = args.to_vec();
|
||||
let arg3 = &mut new_args[2];
|
||||
*arg3 = builder.context.new_unary_op(None, UnaryOp::Minus, arg3.get_type(), *arg3);
|
||||
*arg3 = builder.context.new_unary_op(
|
||||
None,
|
||||
UnaryOp::Minus,
|
||||
arg3.get_type(),
|
||||
*arg3,
|
||||
);
|
||||
args = new_args.into();
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
"__builtin_ia32_ldmxcsr" => {
|
||||
// The builtin __builtin_ia32_ldmxcsr takes an integer value while llvm.x86.sse.ldmxcsr takes a pointer,
|
||||
// so dereference the pointer.
|
||||
|
@ -309,23 +447,31 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
|
|||
let arg1 = builder.context.new_cast(None, args[0], uint_ptr_type);
|
||||
new_args[0] = arg1.dereference(None).to_rvalue();
|
||||
args = new_args.into();
|
||||
},
|
||||
"__builtin_ia32_rcp14sd_mask" | "__builtin_ia32_rcp14ss_mask" | "__builtin_ia32_rsqrt14sd_mask"
|
||||
| "__builtin_ia32_rsqrt14ss_mask" => {
|
||||
}
|
||||
"__builtin_ia32_rcp14sd_mask"
|
||||
| "__builtin_ia32_rcp14ss_mask"
|
||||
| "__builtin_ia32_rsqrt14sd_mask"
|
||||
| "__builtin_ia32_rsqrt14ss_mask" => {
|
||||
let new_args = args.to_vec();
|
||||
args = vec![new_args[1], new_args[0], new_args[2], new_args[3]].into();
|
||||
},
|
||||
}
|
||||
"__builtin_ia32_sqrtsd_mask_round" | "__builtin_ia32_sqrtss_mask_round" => {
|
||||
let new_args = args.to_vec();
|
||||
args = vec![new_args[1], new_args[0], new_args[2], new_args[3], new_args[4]].into();
|
||||
},
|
||||
"__builtin_ia32_vpshrdv_v8di" | "__builtin_ia32_vpshrdv_v4di" | "__builtin_ia32_vpshrdv_v2di" |
|
||||
"__builtin_ia32_vpshrdv_v16si" | "__builtin_ia32_vpshrdv_v8si" | "__builtin_ia32_vpshrdv_v4si" |
|
||||
"__builtin_ia32_vpshrdv_v32hi" | "__builtin_ia32_vpshrdv_v16hi" | "__builtin_ia32_vpshrdv_v8hi" => {
|
||||
}
|
||||
"__builtin_ia32_vpshrdv_v8di"
|
||||
| "__builtin_ia32_vpshrdv_v4di"
|
||||
| "__builtin_ia32_vpshrdv_v2di"
|
||||
| "__builtin_ia32_vpshrdv_v16si"
|
||||
| "__builtin_ia32_vpshrdv_v8si"
|
||||
| "__builtin_ia32_vpshrdv_v4si"
|
||||
| "__builtin_ia32_vpshrdv_v32hi"
|
||||
| "__builtin_ia32_vpshrdv_v16hi"
|
||||
| "__builtin_ia32_vpshrdv_v8hi" => {
|
||||
// The first two arguments are reversed, compared to LLVM.
|
||||
let new_args = args.to_vec();
|
||||
args = vec![new_args[1], new_args[0], new_args[2]].into();
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -333,16 +479,27 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
|
|||
args
|
||||
}
|
||||
|
||||
pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, 'tcx>, mut return_value: RValue<'gcc>, func_name: &str, args: &[RValue<'gcc>], args_adjusted: bool, orig_args: &[RValue<'gcc>]) -> RValue<'gcc> {
|
||||
pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
|
||||
builder: &Builder<'a, 'gcc, 'tcx>,
|
||||
mut return_value: RValue<'gcc>,
|
||||
func_name: &str,
|
||||
args: &[RValue<'gcc>],
|
||||
args_adjusted: bool,
|
||||
orig_args: &[RValue<'gcc>],
|
||||
) -> RValue<'gcc> {
|
||||
match func_name {
|
||||
"__builtin_ia32_vfmaddss3_round" | "__builtin_ia32_vfmaddsd3_round" => {
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
{
|
||||
let zero = builder.context.new_rvalue_zero(builder.int_type);
|
||||
return_value = builder.context.new_vector_access(None, return_value, zero).to_rvalue();
|
||||
return_value =
|
||||
builder.context.new_vector_access(None, return_value, zero).to_rvalue();
|
||||
}
|
||||
},
|
||||
"__builtin_ia32_addcarryx_u64" | "__builtin_ia32_sbb_u64" | "__builtin_ia32_addcarryx_u32" | "__builtin_ia32_sbb_u32" => {
|
||||
}
|
||||
"__builtin_ia32_addcarryx_u64"
|
||||
| "__builtin_ia32_sbb_u64"
|
||||
| "__builtin_ia32_addcarryx_u32"
|
||||
| "__builtin_ia32_sbb_u32" => {
|
||||
// Both llvm.x86.addcarry.32 and llvm.x86.addcarryx.u32 points to the same GCC builtin,
|
||||
// but only the former requires adjusting the return value.
|
||||
// Those 2 LLVM intrinsics differ by their argument count, that's why we check if the
|
||||
|
@ -351,10 +508,16 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc,
|
|||
let last_arg = args.last().expect("last arg");
|
||||
let field1 = builder.context.new_field(None, builder.u8_type, "carryFlag");
|
||||
let field2 = builder.context.new_field(None, args[1].get_type(), "carryResult");
|
||||
let struct_type = builder.context.new_struct_type(None, "addcarryResult", &[field1, field2]);
|
||||
return_value = builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[return_value, last_arg.dereference(None).to_rvalue()]);
|
||||
let struct_type =
|
||||
builder.context.new_struct_type(None, "addcarryResult", &[field1, field2]);
|
||||
return_value = builder.context.new_struct_constructor(
|
||||
None,
|
||||
struct_type.as_type(),
|
||||
None,
|
||||
&[return_value, last_arg.dereference(None).to_rvalue()],
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
"__builtin_ia32_stmxcsr" => {
|
||||
// The builtin __builtin_ia32_stmxcsr returns a value while llvm.x86.sse.stmxcsr writes
|
||||
// the result in its pointer argument.
|
||||
|
@ -366,20 +529,24 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc,
|
|||
// The return value was assigned to the result pointer above. In order to not call the
|
||||
// builtin twice, we overwrite the return value with a dummy value.
|
||||
return_value = builder.context.new_rvalue_zero(builder.int_type);
|
||||
},
|
||||
}
|
||||
"__builtin_ia32_rdrand64_step" => {
|
||||
let random_number = args[0].dereference(None).to_rvalue();
|
||||
let success_variable = builder.current_func().new_local(None, return_value.get_type(), "success");
|
||||
let success_variable =
|
||||
builder.current_func().new_local(None, return_value.get_type(), "success");
|
||||
builder.llbb().add_assignment(None, success_variable, return_value);
|
||||
|
||||
let field1 = builder.context.new_field(None, random_number.get_type(), "random_number");
|
||||
let field2 = builder.context.new_field(None, return_value.get_type(), "success");
|
||||
let struct_type = builder.context.new_struct_type(None, "rdrand_result", &[field1, field2]);
|
||||
return_value = builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[
|
||||
random_number,
|
||||
success_variable.to_rvalue(),
|
||||
]);
|
||||
},
|
||||
let struct_type =
|
||||
builder.context.new_struct_type(None, "rdrand_result", &[field1, field2]);
|
||||
return_value = builder.context.new_struct_constructor(
|
||||
None,
|
||||
struct_type.as_type(),
|
||||
None,
|
||||
&[random_number, success_variable.to_rvalue()],
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
@ -391,23 +558,33 @@ pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool {
|
|||
match func_name {
|
||||
// NOTE: these intrinsics have missing parameters before the last one, so ignore the
|
||||
// last argument type check.
|
||||
"__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask"
|
||||
| "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask" | "__builtin_ia32_sqrtps512_mask"
|
||||
| "__builtin_ia32_sqrtpd512_mask" | "__builtin_ia32_addps512_mask" | "__builtin_ia32_addpd512_mask"
|
||||
| "__builtin_ia32_subps512_mask" | "__builtin_ia32_subpd512_mask"
|
||||
| "__builtin_ia32_mulps512_mask" | "__builtin_ia32_mulpd512_mask"
|
||||
| "__builtin_ia32_divps512_mask" | "__builtin_ia32_divpd512_mask"
|
||||
| "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask"
|
||||
| "__builtin_ia32_cvtdq2ps512_mask" | "__builtin_ia32_cvtudq2ps512_mask" => {
|
||||
if index == args_len - 1 {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
"__builtin_ia32_maxps512_mask"
|
||||
| "__builtin_ia32_maxpd512_mask"
|
||||
| "__builtin_ia32_minps512_mask"
|
||||
| "__builtin_ia32_minpd512_mask"
|
||||
| "__builtin_ia32_sqrtps512_mask"
|
||||
| "__builtin_ia32_sqrtpd512_mask"
|
||||
| "__builtin_ia32_addps512_mask"
|
||||
| "__builtin_ia32_addpd512_mask"
|
||||
| "__builtin_ia32_subps512_mask"
|
||||
| "__builtin_ia32_subpd512_mask"
|
||||
| "__builtin_ia32_mulps512_mask"
|
||||
| "__builtin_ia32_mulpd512_mask"
|
||||
| "__builtin_ia32_divps512_mask"
|
||||
| "__builtin_ia32_divpd512_mask"
|
||||
| "__builtin_ia32_vfmaddsubps512_mask"
|
||||
| "__builtin_ia32_vfmaddsubpd512_mask"
|
||||
| "__builtin_ia32_cvtdq2ps512_mask"
|
||||
| "__builtin_ia32_cvtudq2ps512_mask" => {
|
||||
if index == args_len - 1 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
"__builtin_ia32_rndscaless_mask_round" | "__builtin_ia32_rndscalesd_mask_round" => {
|
||||
if index == 2 || index == 3 {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
}
|
||||
"__builtin_ia32_vfmaddps512_mask" | "__builtin_ia32_vfmaddpd512_mask" => {
|
||||
// Since there are two LLVM intrinsics that map to each of these GCC builtins and only
|
||||
// one of them has a missing parameter before the last one, we check the number of
|
||||
|
@ -415,49 +592,50 @@ pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool {
|
|||
if args_len == 4 && index == args_len - 1 {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
}
|
||||
// NOTE: the LLVM intrinsic receives 3 floats, but the GCC builtin requires 3 vectors.
|
||||
"__builtin_ia32_vfmaddss3_round" | "__builtin_ia32_vfmaddsd3_round" => return true,
|
||||
"__builtin_ia32_vplzcntd_512_mask" | "__builtin_ia32_vplzcntd_256_mask" | "__builtin_ia32_vplzcntd_128_mask"
|
||||
| "__builtin_ia32_vplzcntq_512_mask" | "__builtin_ia32_vplzcntq_256_mask" | "__builtin_ia32_vplzcntq_128_mask" => {
|
||||
"__builtin_ia32_vplzcntd_512_mask"
|
||||
| "__builtin_ia32_vplzcntd_256_mask"
|
||||
| "__builtin_ia32_vplzcntd_128_mask"
|
||||
| "__builtin_ia32_vplzcntq_512_mask"
|
||||
| "__builtin_ia32_vplzcntq_256_mask"
|
||||
| "__builtin_ia32_vplzcntq_128_mask" => {
|
||||
if index == args_len - 1 {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(not(feature="master"))]
|
||||
#[cfg(not(feature = "master"))]
|
||||
pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
|
||||
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 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")]
|
||||
#[cfg(feature = "master")]
|
||||
pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
|
||||
match name {
|
||||
"llvm.prefetch" => {
|
||||
let gcc_name = "__builtin_prefetch";
|
||||
let func = cx.context.get_builtin_function(gcc_name);
|
||||
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
|
||||
return func
|
||||
},
|
||||
return func;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
|
1088
src/intrinsic/mod.rs
1088
src/intrinsic/mod.rs
File diff suppressed because it is too large
Load diff
|
@ -21,10 +21,10 @@ use rustc_span::{sym, Span, Symbol};
|
|||
use rustc_target::abi::Align;
|
||||
|
||||
use crate::builder::Builder;
|
||||
#[cfg(feature = "master")]
|
||||
use crate::context::CodegenCx;
|
||||
#[cfg(not(feature = "master"))]
|
||||
use crate::common::SignType;
|
||||
#[cfg(feature = "master")]
|
||||
use crate::context::CodegenCx;
|
||||
|
||||
pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
||||
bx: &mut Builder<'a, 'gcc, 'tcx>,
|
||||
|
@ -176,7 +176,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
|
||||
#[cfg(not(feature = "master"))]
|
||||
let shuffled = {
|
||||
let new_elements: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _)
|
||||
let new_elements: Vec<_> = shuffle_indices
|
||||
.chunks_exact(elem_size_bytes as _)
|
||||
.flat_map(|x| x.iter().rev())
|
||||
.map(|&i| {
|
||||
let index = bx.context.new_rvalue_from_long(bx.u64_type, i as _);
|
||||
|
@ -188,7 +189,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
};
|
||||
#[cfg(feature = "master")]
|
||||
let shuffled = {
|
||||
let indices: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _)
|
||||
let indices: Vec<_> = shuffle_indices
|
||||
.chunks_exact(elem_size_bytes as _)
|
||||
.flat_map(|x| x.iter().rev())
|
||||
.map(|&i| bx.context.new_rvalue_from_int(bx.u8_type, i as _))
|
||||
.collect();
|
||||
|
@ -202,12 +204,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
if name == sym::simd_bswap || name == sym::simd_bitreverse {
|
||||
require!(
|
||||
bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
|
||||
InvalidMonomorphization::UnsupportedOperation {
|
||||
span,
|
||||
name,
|
||||
in_ty,
|
||||
in_elem,
|
||||
}
|
||||
InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -245,23 +242,27 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
.map(|x| bx.context.new_rvalue_from_int(bx.u8_type, x.reverse_bits() as _))
|
||||
.chain((16..byte_vector_type_size).map(|_| zero_byte))
|
||||
.collect();
|
||||
let hi_nibble = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &hi_nibble_elements);
|
||||
let hi_nibble =
|
||||
bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &hi_nibble_elements);
|
||||
|
||||
let lo_nibble_elements: Vec<_> = (0u8..16)
|
||||
.map(|x| bx.context.new_rvalue_from_int(bx.u8_type, (x.reverse_bits() >> 4) as _))
|
||||
.chain((16..byte_vector_type_size).map(|_| zero_byte))
|
||||
.collect();
|
||||
let lo_nibble = bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &lo_nibble_elements);
|
||||
let lo_nibble =
|
||||
bx.context.new_rvalue_from_vector(None, long_byte_vector_type, &lo_nibble_elements);
|
||||
|
||||
let mask = bx.context.new_rvalue_from_vector(
|
||||
None,
|
||||
long_byte_vector_type,
|
||||
&vec![bx.context.new_rvalue_from_int(bx.u8_type, 0x0f); byte_vector_type_size as _]);
|
||||
&vec![bx.context.new_rvalue_from_int(bx.u8_type, 0x0f); byte_vector_type_size as _],
|
||||
);
|
||||
|
||||
let four_vec = bx.context.new_rvalue_from_vector(
|
||||
None,
|
||||
long_byte_vector_type,
|
||||
&vec![bx.context.new_rvalue_from_int(bx.u8_type, 4); byte_vector_type_size as _]);
|
||||
&vec![bx.context.new_rvalue_from_int(bx.u8_type, 4); byte_vector_type_size as _],
|
||||
);
|
||||
|
||||
// Step 2: Byte-swap the input.
|
||||
let swapped = simd_bswap(bx, args[0].immediate());
|
||||
|
@ -294,7 +295,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
|
||||
// Step 5: Combine the results of the shuffle back together and cast back to the original type.
|
||||
let result = hi | lo;
|
||||
let cast_ty = bx.context.new_vector_type(elem_type, byte_vector_type_size / (elem_size_bytes as u64));
|
||||
let cast_ty =
|
||||
bx.context.new_vector_type(elem_type, byte_vector_type_size / (elem_size_bytes as u64));
|
||||
|
||||
// we might need to truncate if sizeof(v_type) < sizeof(cast_type)
|
||||
if type_size_bytes < byte_vector_type_size {
|
||||
|
@ -305,7 +307,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
bx.extract_element(cast_result, idx)
|
||||
})
|
||||
.collect();
|
||||
return Ok(bx.context.new_rvalue_from_vector(None, v_type, &elems))
|
||||
return Ok(bx.context.new_rvalue_from_vector(None, v_type, &elems));
|
||||
} else {
|
||||
// avoid the unnecessary truncation as an optimization.
|
||||
return Ok(bx.context.new_bitcast(None, result, v_type));
|
||||
|
@ -702,7 +704,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
invert: bool,
|
||||
) -> RValue<'gcc> {
|
||||
let vector_type = default.get_type();
|
||||
let elem_type = vector_type.unqualified().dyncast_vector().expect("vector type").get_element_type();
|
||||
let elem_type =
|
||||
vector_type.unqualified().dyncast_vector().expect("vector type").get_element_type();
|
||||
|
||||
let mut values = Vec::with_capacity(in_len as usize);
|
||||
for i in 0..in_len {
|
||||
|
@ -724,7 +727,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
mask_types.push(bx.context.new_field(None, bx.i32_type, "m"));
|
||||
let mask_value = bx.context.new_vector_access(None, mask, index).to_rvalue();
|
||||
let mask_value_cast = bx.context.new_cast(None, mask_value, bx.i32_type);
|
||||
let masked = bx.context.new_rvalue_from_int(bx.i32_type, in_len as i32) & mask_value_cast;
|
||||
let masked =
|
||||
bx.context.new_rvalue_from_int(bx.i32_type, in_len as i32) & mask_value_cast;
|
||||
let value = index + masked;
|
||||
mask_values.push(value);
|
||||
}
|
||||
|
@ -965,14 +969,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
let result = gather(
|
||||
args[0].immediate(),
|
||||
args[1].immediate(),
|
||||
args[2].immediate(),
|
||||
bx,
|
||||
in_len,
|
||||
true,
|
||||
);
|
||||
let result =
|
||||
gather(args[0].immediate(), args[1].immediate(), args[2].immediate(), bx, in_len, true);
|
||||
|
||||
let pointers = args[1].immediate();
|
||||
|
||||
|
|
234
src/lib.rs
234
src/lib.rs
|
@ -25,7 +25,7 @@
|
|||
hash_raw_entry
|
||||
)]
|
||||
#![allow(broken_intra_doc_links)]
|
||||
#![recursion_limit="256"]
|
||||
#![recursion_limit = "256"]
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![warn(unused_lifetimes)]
|
||||
#![deny(clippy::pattern_type_mismatch)]
|
||||
|
@ -40,7 +40,7 @@ extern crate rustc_fluent_macro;
|
|||
extern crate rustc_fs_util;
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_index;
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
extern crate rustc_interface;
|
||||
extern crate rustc_macros;
|
||||
extern crate rustc_metadata;
|
||||
|
@ -80,36 +80,40 @@ mod type_of;
|
|||
|
||||
use std::any::Any;
|
||||
use std::fmt::Debug;
|
||||
#[cfg(not(feature = "master"))]
|
||||
use std::sync::atomic::AtomicBool;
|
||||
#[cfg(not(feature = "master"))]
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
#[cfg(not(feature="master"))]
|
||||
use std::sync::atomic::AtomicBool;
|
||||
#[cfg(not(feature="master"))]
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use gccjit::{Context, OptimizationLevel};
|
||||
#[cfg(feature="master")]
|
||||
use gccjit::{TargetInfo, Version};
|
||||
#[cfg(not(feature="master"))]
|
||||
use gccjit::CType;
|
||||
use errors::LTONotSupported;
|
||||
#[cfg(not(feature = "master"))]
|
||||
use gccjit::CType;
|
||||
use gccjit::{Context, OptimizationLevel};
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::{TargetInfo, Version};
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
|
||||
use rustc_codegen_ssa::base::codegen_crate;
|
||||
use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn};
|
||||
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
|
||||
use rustc_codegen_ssa::back::write::{
|
||||
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn,
|
||||
};
|
||||
use rustc_codegen_ssa::base::codegen_crate;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods,
|
||||
};
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync::IntoDynSyncSend;
|
||||
use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods};
|
||||
use rustc_errors::{ErrorGuaranteed, DiagCtxt};
|
||||
use rustc_errors::{DiagCtxt, ErrorGuaranteed};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_session::config::{Lto, OptLevel, OutputFilenames};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::fatal_error::FatalError;
|
||||
use rustc_span::Symbol;
|
||||
use tempfile::TempDir;
|
||||
|
||||
use crate::back::lto::ModuleBuffer;
|
||||
|
@ -127,13 +131,13 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature="master"))]
|
||||
#[cfg(not(feature = "master"))]
|
||||
#[derive(Debug)]
|
||||
pub struct TargetInfo {
|
||||
supports_128bit_integers: AtomicBool,
|
||||
}
|
||||
|
||||
#[cfg(not(feature="master"))]
|
||||
#[cfg(not(feature = "master"))]
|
||||
impl TargetInfo {
|
||||
fn cpu_supports(&self, _feature: &str) -> bool {
|
||||
false
|
||||
|
@ -176,7 +180,7 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
}
|
||||
|
||||
fn init(&self, sess: &Session) {
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
{
|
||||
let target_cpu = target_cpu(sess);
|
||||
|
||||
|
@ -189,13 +193,13 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
**self.target_info.info.lock().expect("lock") = context.get_target_info();
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
gccjit::set_global_personality_function_name(b"rust_eh_personality\0");
|
||||
if sess.lto() == Lto::Thin {
|
||||
sess.dcx().emit_warn(LTONotSupported {});
|
||||
}
|
||||
|
||||
#[cfg(not(feature="master"))]
|
||||
#[cfg(not(feature = "master"))]
|
||||
{
|
||||
let temp_dir = TempDir::new().expect("cannot create temporary directory");
|
||||
let temp_file = temp_dir.into_path().join("result.asm");
|
||||
|
@ -203,39 +207,62 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
check_context.set_print_errors_to_stderr(false);
|
||||
let _int128_ty = check_context.new_c_type(CType::UInt128t);
|
||||
// NOTE: we cannot just call compile() as this would require other files than libgccjit.so.
|
||||
check_context.compile_to_file(gccjit::OutputKind::Assembler, temp_file.to_str().expect("path to str"));
|
||||
self.target_info.info.lock().expect("lock").supports_128bit_integers.store(check_context.get_last_error() == Ok(None), Ordering::SeqCst);
|
||||
check_context.compile_to_file(
|
||||
gccjit::OutputKind::Assembler,
|
||||
temp_file.to_str().expect("path to str"),
|
||||
);
|
||||
self.target_info
|
||||
.info
|
||||
.lock()
|
||||
.expect("lock")
|
||||
.supports_128bit_integers
|
||||
.store(check_context.get_last_error() == Ok(None), Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
fn provide(&self, providers: &mut Providers) {
|
||||
providers.global_backend_features =
|
||||
|tcx, ()| gcc_util::global_gcc_features(tcx.sess, true)
|
||||
providers.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true)
|
||||
}
|
||||
|
||||
fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool) -> Box<dyn Any> {
|
||||
fn codegen_crate<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any> {
|
||||
let target_cpu = target_cpu(tcx.sess);
|
||||
let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module);
|
||||
let res = codegen_crate(
|
||||
self.clone(),
|
||||
tcx,
|
||||
target_cpu.to_string(),
|
||||
metadata,
|
||||
need_metadata_module,
|
||||
);
|
||||
|
||||
Box::new(res)
|
||||
}
|
||||
|
||||
fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session, _outputs: &OutputFilenames) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
fn join_codegen(
|
||||
&self,
|
||||
ongoing_codegen: Box<dyn Any>,
|
||||
sess: &Session,
|
||||
_outputs: &OutputFilenames,
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
ongoing_codegen
|
||||
.downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<GccCodegenBackend>>()
|
||||
.expect("Expected GccCodegenBackend's OngoingCodegen, found Box<Any>")
|
||||
.join(sess)
|
||||
}
|
||||
|
||||
fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorGuaranteed> {
|
||||
fn link(
|
||||
&self,
|
||||
sess: &Session,
|
||||
codegen_results: CodegenResults,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
use rustc_codegen_ssa::back::link::link_binary;
|
||||
|
||||
link_binary(
|
||||
sess,
|
||||
&crate::archive::ArArchiveBuilderBuilder,
|
||||
&codegen_results,
|
||||
outputs,
|
||||
)
|
||||
link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs)
|
||||
}
|
||||
|
||||
fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
|
@ -248,14 +275,15 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> {
|
|||
if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" {
|
||||
context.add_command_line_option("-masm=intel");
|
||||
}
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
{
|
||||
context.set_allow_special_chars_in_func_names(true);
|
||||
let version = Version::get();
|
||||
let version = format!("{}.{}.{}", version.major, version.minor, version.patch);
|
||||
context.set_output_ident(&format!("rustc version {} with libgccjit {}",
|
||||
rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
|
||||
version,
|
||||
context.set_output_ident(&format!(
|
||||
"rustc version {} with libgccjit {}",
|
||||
rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
|
||||
version,
|
||||
));
|
||||
}
|
||||
// TODO(antoyo): check if this should only be added when using -Cforce-unwind-tables=n.
|
||||
|
@ -264,26 +292,41 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> {
|
|||
}
|
||||
|
||||
impl ExtraBackendMethods for GccCodegenBackend {
|
||||
fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module {
|
||||
fn codegen_allocator<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
module_name: &str,
|
||||
kind: AllocatorKind,
|
||||
alloc_error_handler_kind: AllocatorKind,
|
||||
) -> Self::Module {
|
||||
let mut mods = GccContext {
|
||||
context: new_context(tcx),
|
||||
should_combine_object_files: false,
|
||||
temp_dir: None,
|
||||
};
|
||||
|
||||
unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
|
||||
unsafe {
|
||||
allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind);
|
||||
}
|
||||
mods
|
||||
}
|
||||
|
||||
fn compile_codegen_unit(&self, tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
|
||||
fn compile_codegen_unit(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
cgu_name: Symbol,
|
||||
) -> (ModuleCodegen<Self::Module>, u64) {
|
||||
base::compile_codegen_unit(tcx, cgu_name, self.target_info.clone())
|
||||
}
|
||||
|
||||
fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel, _features: &[String]) -> TargetMachineFactoryFn<Self> {
|
||||
fn target_machine_factory(
|
||||
&self,
|
||||
_sess: &Session,
|
||||
_opt_level: OptLevel,
|
||||
_features: &[String],
|
||||
) -> TargetMachineFactoryFn<Self> {
|
||||
// TODO(antoyo): set opt level.
|
||||
Arc::new(|_| {
|
||||
Ok(())
|
||||
})
|
||||
Arc::new(|_| Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,11 +357,19 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||
type ThinData = ();
|
||||
type ThinBuffer = ThinBuffer;
|
||||
|
||||
fn run_fat_lto(cgcx: &CodegenContext<Self>, modules: Vec<FatLtoInput<Self>>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
|
||||
fn run_fat_lto(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
modules: Vec<FatLtoInput<Self>>,
|
||||
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
|
||||
) -> Result<LtoModuleCodegen<Self>, FatalError> {
|
||||
back::lto::run_fat(cgcx, modules, cached_modules)
|
||||
}
|
||||
|
||||
fn run_thin_lto(_cgcx: &CodegenContext<Self>, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
|
||||
fn run_thin_lto(
|
||||
_cgcx: &CodegenContext<Self>,
|
||||
_modules: Vec<(String, Self::ThinBuffer)>,
|
||||
_cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
|
||||
) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
|
@ -330,21 +381,37 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
unsafe fn optimize(_cgcx: &CodegenContext<Self>, _dcx: &DiagCtxt, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<(), FatalError> {
|
||||
unsafe fn optimize(
|
||||
_cgcx: &CodegenContext<Self>,
|
||||
_dcx: &DiagCtxt,
|
||||
module: &ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
) -> Result<(), FatalError> {
|
||||
module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn optimize_fat(_cgcx: &CodegenContext<Self>, _module: &mut ModuleCodegen<Self::Module>) -> Result<(), FatalError> {
|
||||
fn optimize_fat(
|
||||
_cgcx: &CodegenContext<Self>,
|
||||
_module: &mut ModuleCodegen<Self::Module>,
|
||||
) -> Result<(), FatalError> {
|
||||
// TODO(antoyo)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
|
||||
unsafe fn optimize_thin(
|
||||
_cgcx: &CodegenContext<Self>,
|
||||
_thin: ThinModule<Self>,
|
||||
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
unsafe fn codegen(cgcx: &CodegenContext<Self>, dcx: &DiagCtxt, module: ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
|
||||
unsafe fn codegen(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
dcx: &DiagCtxt,
|
||||
module: ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
) -> Result<CompiledModule, FatalError> {
|
||||
back::write::codegen(cgcx, dcx, module, config)
|
||||
}
|
||||
|
||||
|
@ -356,7 +423,11 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||
unimplemented!();
|
||||
}
|
||||
|
||||
fn run_link(cgcx: &CodegenContext<Self>, dcx: &DiagCtxt, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
|
||||
fn run_link(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
dcx: &DiagCtxt,
|
||||
modules: Vec<ModuleCodegen<Self::Module>>,
|
||||
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
|
||||
back::write::link(cgcx, dcx, modules)
|
||||
}
|
||||
}
|
||||
|
@ -364,55 +435,56 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||
/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
|
||||
#[no_mangle]
|
||||
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
let info = {
|
||||
// Check whether the target supports 128-bit integers.
|
||||
let context = Context::default();
|
||||
Arc::new(Mutex::new(IntoDynSyncSend(context.get_target_info())))
|
||||
};
|
||||
#[cfg(not(feature="master"))]
|
||||
#[cfg(not(feature = "master"))]
|
||||
let info = Arc::new(Mutex::new(IntoDynSyncSend(TargetInfo {
|
||||
supports_128bit_integers: AtomicBool::new(false),
|
||||
})));
|
||||
|
||||
Box::new(GccCodegenBackend {
|
||||
target_info: LockedTargetInfo { info },
|
||||
})
|
||||
Box::new(GccCodegenBackend { target_info: LockedTargetInfo { info } })
|
||||
}
|
||||
|
||||
fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
|
||||
match optlevel {
|
||||
None => OptimizationLevel::None,
|
||||
Some(level) => {
|
||||
match level {
|
||||
OptLevel::No => OptimizationLevel::None,
|
||||
OptLevel::Less => OptimizationLevel::Limited,
|
||||
OptLevel::Default => OptimizationLevel::Standard,
|
||||
OptLevel::Aggressive => OptimizationLevel::Aggressive,
|
||||
OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited,
|
||||
}
|
||||
Some(level) => match level {
|
||||
OptLevel::No => OptimizationLevel::None,
|
||||
OptLevel::Less => OptimizationLevel::Limited,
|
||||
OptLevel::Default => OptimizationLevel::Standard,
|
||||
OptLevel::Aggressive => OptimizationLevel::Aggressive,
|
||||
OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &LockedTargetInfo) -> Vec<Symbol> {
|
||||
sess
|
||||
.target
|
||||
pub fn target_features(
|
||||
sess: &Session,
|
||||
allow_unstable: bool,
|
||||
target_info: &LockedTargetInfo,
|
||||
) -> Vec<Symbol> {
|
||||
sess.target
|
||||
.supported_target_features()
|
||||
.iter()
|
||||
.filter_map(
|
||||
|&(feature, gate)| {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.is_stable() { Some(feature) } else { None }
|
||||
},
|
||||
)
|
||||
.filter_map(|&(feature, gate)| {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
|
||||
Some(feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|_feature| {
|
||||
target_info.cpu_supports(_feature)
|
||||
/*
|
||||
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
|
||||
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
|
||||
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
|
||||
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
|
||||
*/
|
||||
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
|
||||
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
|
||||
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
|
||||
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
|
||||
*/
|
||||
})
|
||||
.map(|feature| Symbol::intern(feature))
|
||||
.collect()
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#[cfg(feature="master")]
|
||||
use gccjit::{VarAttribute, FnAttribute};
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::{FnAttribute, VarAttribute};
|
||||
use rustc_codegen_ssa::traits::PreDefineMethods;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::mono::{Linkage, Visibility};
|
||||
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
||||
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
|
||||
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
||||
|
||||
use crate::attributes;
|
||||
use crate::base;
|
||||
|
@ -13,8 +13,14 @@ use crate::context::CodegenCx;
|
|||
use crate::type_of::LayoutGccExt;
|
||||
|
||||
impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
#[cfg_attr(not(feature="master"), allow(unused_variables))]
|
||||
fn predefine_static(&self, def_id: DefId, _linkage: Linkage, visibility: Visibility, symbol_name: &str) {
|
||||
#[cfg_attr(not(feature = "master"), allow(unused_variables))]
|
||||
fn predefine_static(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
_linkage: Linkage,
|
||||
visibility: Visibility,
|
||||
symbol_name: &str,
|
||||
) {
|
||||
let attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||
let instance = Instance::mono(self.tcx, def_id);
|
||||
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
|
||||
|
@ -22,15 +28,21 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
|
||||
let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
|
||||
let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section);
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
global.add_string_attribute(VarAttribute::Visibility(base::visibility_to_gcc(visibility)));
|
||||
|
||||
// TODO(antoyo): set linkage.
|
||||
self.instances.borrow_mut().insert(instance, global);
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature="master"), allow(unused_variables))]
|
||||
fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, visibility: Visibility, symbol_name: &str) {
|
||||
#[cfg_attr(not(feature = "master"), allow(unused_variables))]
|
||||
fn predefine_fn(
|
||||
&self,
|
||||
instance: Instance<'tcx>,
|
||||
linkage: Linkage,
|
||||
visibility: Visibility,
|
||||
symbol_name: &str,
|
||||
) {
|
||||
assert!(!instance.args.has_infer());
|
||||
|
||||
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
|
||||
|
@ -48,11 +60,10 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
&& linkage != Linkage::Private
|
||||
&& self.tcx.is_compiler_builtins(LOCAL_CRATE)
|
||||
{
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
decl.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
||||
}
|
||||
else {
|
||||
#[cfg(feature="master")]
|
||||
} else {
|
||||
#[cfg(feature = "master")]
|
||||
decl.add_attribute(FnAttribute::Visibility(base::visibility_to_gcc(visibility)));
|
||||
}
|
||||
|
||||
|
|
59
src/type_.rs
59
src/type_.rs
|
@ -1,8 +1,8 @@
|
|||
use gccjit::{RValue, Struct, Type};
|
||||
use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods};
|
||||
use rustc_codegen_ssa::common::TypeKind;
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_target::abi::{AddressSpace, Align, Integer, Size};
|
||||
|
||||
use crate::common::TypeReflection;
|
||||
|
@ -135,12 +135,16 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
if let Some(typ) = self.struct_types.borrow().get(fields) {
|
||||
return typ.clone();
|
||||
}
|
||||
let fields: Vec<_> = fields.iter().enumerate()
|
||||
.map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index)))
|
||||
let fields: Vec<_> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, field)| {
|
||||
self.context.new_field(None, *field, &format!("field{}_TODO", index))
|
||||
})
|
||||
.collect();
|
||||
let typ = self.context.new_struct_type(None, "struct", &fields).as_type();
|
||||
if packed {
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
typ.set_packed();
|
||||
}
|
||||
self.struct_types.borrow_mut().insert(types, typ);
|
||||
|
@ -150,17 +154,13 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
fn type_kind(&self, typ: Type<'gcc>) -> TypeKind {
|
||||
if self.is_int_type_or_bool(typ) {
|
||||
TypeKind::Integer
|
||||
}
|
||||
else if typ.is_compatible_with(self.float_type) {
|
||||
} else if typ.is_compatible_with(self.float_type) {
|
||||
TypeKind::Float
|
||||
}
|
||||
else if typ.is_compatible_with(self.double_type) {
|
||||
} else if typ.is_compatible_with(self.double_type) {
|
||||
TypeKind::Double
|
||||
}
|
||||
else if typ.is_vector() {
|
||||
} else if typ.is_vector() {
|
||||
TypeKind::Vector
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// TODO(antoyo): support other types.
|
||||
TypeKind::Void
|
||||
}
|
||||
|
@ -177,14 +177,11 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> {
|
||||
if let Some(typ) = ty.dyncast_array() {
|
||||
typ
|
||||
}
|
||||
else if let Some(vector_type) = ty.dyncast_vector() {
|
||||
} else if let Some(vector_type) = ty.dyncast_vector() {
|
||||
vector_type.get_element_type()
|
||||
}
|
||||
else if let Some(typ) = ty.get_pointee() {
|
||||
} else if let Some(typ) = ty.get_pointee() {
|
||||
typ
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
@ -198,11 +195,9 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
let f64 = self.context.new_type::<f64>();
|
||||
if typ.is_compatible_with(f32) {
|
||||
32
|
||||
}
|
||||
else if typ.is_compatible_with(f64) {
|
||||
} else if typ.is_compatible_with(f64) {
|
||||
64
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
panic!("Cannot get width of float type {:?}", typ);
|
||||
}
|
||||
// TODO(antoyo): support other sizes.
|
||||
|
@ -216,9 +211,9 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
value.get_type()
|
||||
}
|
||||
|
||||
#[cfg_attr(feature="master", allow(unused_mut))]
|
||||
#[cfg_attr(feature = "master", allow(unused_mut))]
|
||||
fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
|
||||
#[cfg(not(feature="master"))]
|
||||
#[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
|
||||
|
@ -242,12 +237,14 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], packed: bool) {
|
||||
let fields: Vec<_> = fields.iter().enumerate()
|
||||
let fields: Vec<_> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index)))
|
||||
.collect();
|
||||
typ.set_fields(None, &fields);
|
||||
if packed {
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
typ.as_type().set_packed();
|
||||
}
|
||||
}
|
||||
|
@ -257,7 +254,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec<Type<'gcc>>, bool) {
|
||||
pub fn struct_fields<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
) -> (Vec<Type<'gcc>>, bool) {
|
||||
let field_count = layout.fields.count();
|
||||
|
||||
let mut packed = false;
|
||||
|
@ -295,5 +295,4 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
|
|||
(result, packed)
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
}
|
||||
impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {}
|
||||
|
|
163
src/type_of.rs
163
src/type_of.rs
|
@ -1,13 +1,16 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use gccjit::{Struct, Type};
|
||||
use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods};
|
||||
use gccjit::{Struct, Type};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
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_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
|
||||
use rustc_target::abi::{
|
||||
self, Abi, Align, FieldsShape, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface,
|
||||
Variants, F32, F64,
|
||||
};
|
||||
|
||||
use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType};
|
||||
use crate::context::CodegenCx;
|
||||
|
@ -25,7 +28,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
pub fn type_int_from_ty(&self, t: ty::IntTy) -> Type<'gcc> {
|
||||
match t {
|
||||
ty::IntTy::Isize => self.type_isize(),
|
||||
|
@ -37,7 +40,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
pub fn type_uint_from_ty(&self, t: ty::UintTy) -> Type<'gcc> {
|
||||
match t {
|
||||
ty::UintTy::Usize => self.type_isize(),
|
||||
|
@ -56,7 +59,11 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> {
|
||||
fn uncached_gcc_type<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>,
|
||||
) -> Type<'gcc> {
|
||||
match layout.abi {
|
||||
Abi::Scalar(_) => bug!("handled elsewhere"),
|
||||
Abi::Vector { ref element, count } => {
|
||||
|
@ -70,7 +77,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
|
|||
element
|
||||
};
|
||||
return cx.context.new_vector_type(element, count);
|
||||
},
|
||||
}
|
||||
Abi::ScalarPair(..) => {
|
||||
return cx.type_struct(
|
||||
&[
|
||||
|
@ -87,7 +94,12 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
|
|||
// FIXME(eddyb) producing readable type names for trait objects can result
|
||||
// in problematically distinct types due to HRTB and subtyping (see #47638).
|
||||
// ty::Dynamic(..) |
|
||||
ty::Adt(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Foreign(..) | ty::Coroutine(..) | ty::Str
|
||||
ty::Adt(..)
|
||||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::Str
|
||||
if !cx.sess().fewer_names() =>
|
||||
{
|
||||
let mut name = with_no_trimmed_paths!(layout.ty.to_string());
|
||||
|
@ -125,22 +137,21 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
|
|||
let gcc_type = cx.type_named_struct(name);
|
||||
cx.set_struct_body(gcc_type, &[fill], packed);
|
||||
gcc_type.as_type()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).gcc_type(cx), count),
|
||||
FieldsShape::Arbitrary { .. } =>
|
||||
match name {
|
||||
None => {
|
||||
let (gcc_fields, packed) = struct_fields(cx, layout);
|
||||
cx.type_struct(&gcc_fields, packed)
|
||||
},
|
||||
Some(ref name) => {
|
||||
let gcc_type = cx.type_named_struct(name);
|
||||
*defer = Some((gcc_type, layout));
|
||||
gcc_type.as_type()
|
||||
},
|
||||
},
|
||||
FieldsShape::Arbitrary { .. } => match name {
|
||||
None => {
|
||||
let (gcc_fields, packed) = struct_fields(cx, layout);
|
||||
cx.type_struct(&gcc_fields, packed)
|
||||
}
|
||||
Some(ref name) => {
|
||||
let gcc_type = cx.type_named_struct(name);
|
||||
*defer = Some((gcc_type, layout));
|
||||
gcc_type.as_type()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,10 +160,23 @@ pub trait LayoutGccExt<'tcx> {
|
|||
fn is_gcc_scalar_pair(&self) -> bool;
|
||||
fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
|
||||
fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
|
||||
fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>;
|
||||
fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc>;
|
||||
fn scalar_gcc_type_at<'gcc>(
|
||||
&self,
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
scalar: &abi::Scalar,
|
||||
offset: Size,
|
||||
) -> Type<'gcc>;
|
||||
fn scalar_pair_element_gcc_type<'gcc>(
|
||||
&self,
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
index: usize,
|
||||
) -> Type<'gcc>;
|
||||
fn gcc_field_index(&self, index: usize) -> u64;
|
||||
fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option<PointeeInfo>;
|
||||
fn pointee_info_at<'gcc>(
|
||||
&self,
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
offset: Size,
|
||||
) -> Option<PointeeInfo>;
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
||||
|
@ -192,24 +216,24 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
|
||||
return ty;
|
||||
}
|
||||
let ty =
|
||||
match *self.ty.kind() {
|
||||
// NOTE: we cannot remove this match like in the LLVM codegen because the call
|
||||
// to fn_ptr_backend_type handle the on-stack attribute.
|
||||
// TODO(antoyo): find a less hackish way to hande the on-stack attribute.
|
||||
ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())),
|
||||
_ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),
|
||||
};
|
||||
let ty = match *self.ty.kind() {
|
||||
// NOTE: we cannot remove this match like in the LLVM codegen because the call
|
||||
// to fn_ptr_backend_type handle the on-stack attribute.
|
||||
// TODO(antoyo): find a less hackish way to hande the on-stack attribute.
|
||||
ty::FnPtr(sig) => {
|
||||
cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty()))
|
||||
}
|
||||
_ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),
|
||||
};
|
||||
cx.scalar_types.borrow_mut().insert(self.ty, ty);
|
||||
return ty;
|
||||
}
|
||||
|
||||
// Check the cache.
|
||||
let variant_index =
|
||||
match self.variants {
|
||||
Variants::Single { index } => Some(index),
|
||||
_ => None,
|
||||
};
|
||||
let variant_index = match self.variants {
|
||||
Variants::Single { index } => Some(index),
|
||||
_ => None,
|
||||
};
|
||||
let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned();
|
||||
if let Some(ty) = cached_type {
|
||||
return ty;
|
||||
|
@ -222,17 +246,15 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
let normal_ty = cx.tcx.erase_regions(self.ty);
|
||||
|
||||
let mut defer = None;
|
||||
let ty =
|
||||
if self.ty != normal_ty {
|
||||
let mut layout = cx.layout_of(normal_ty);
|
||||
if let Some(v) = variant_index {
|
||||
layout = layout.for_variant(cx, v);
|
||||
}
|
||||
layout.gcc_type(cx)
|
||||
let ty = if self.ty != normal_ty {
|
||||
let mut layout = cx.layout_of(normal_ty);
|
||||
if let Some(v) = variant_index {
|
||||
layout = layout.for_variant(cx, v);
|
||||
}
|
||||
else {
|
||||
uncached_gcc_type(cx, *self, &mut defer)
|
||||
};
|
||||
layout.gcc_type(cx)
|
||||
} else {
|
||||
uncached_gcc_type(cx, *self, &mut defer)
|
||||
};
|
||||
|
||||
cx.types.borrow_mut().insert((self.ty, variant_index), ty);
|
||||
|
||||
|
@ -253,7 +275,12 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
self.gcc_type(cx)
|
||||
}
|
||||
|
||||
fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc> {
|
||||
fn scalar_gcc_type_at<'gcc>(
|
||||
&self,
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
scalar: &abi::Scalar,
|
||||
offset: Size,
|
||||
) -> Type<'gcc> {
|
||||
match scalar.primitive() {
|
||||
Int(i, true) => cx.type_from_integer(i),
|
||||
Int(i, false) => cx.type_from_unsigned_integer(i),
|
||||
|
@ -261,19 +288,21 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
F64 => cx.type_f64(),
|
||||
Pointer(address_space) => {
|
||||
// If we know the alignment, pick something better than i8.
|
||||
let pointee =
|
||||
if let Some(pointee) = self.pointee_info_at(cx, offset) {
|
||||
cx.type_pointee_for_align(pointee.align)
|
||||
}
|
||||
else {
|
||||
cx.type_i8()
|
||||
};
|
||||
let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {
|
||||
cx.type_pointee_for_align(pointee.align)
|
||||
} else {
|
||||
cx.type_i8()
|
||||
};
|
||||
cx.type_ptr_to_ext(pointee, address_space)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc> {
|
||||
fn scalar_pair_element_gcc_type<'gcc>(
|
||||
&self,
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
index: usize,
|
||||
) -> Type<'gcc> {
|
||||
// This must produce the same result for `repr(transparent)` wrappers as for the inner type!
|
||||
// In other words, this should generally not look at the type at all, but only at the
|
||||
// layout.
|
||||
|
@ -294,13 +323,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
return cx.type_i1();
|
||||
}
|
||||
|
||||
let offset =
|
||||
if index == 0 {
|
||||
Size::ZERO
|
||||
}
|
||||
else {
|
||||
a.size(cx).align_to(b.align(cx).abi)
|
||||
};
|
||||
let offset = if index == 0 { Size::ZERO } else { a.size(cx).align_to(b.align(cx).abi) };
|
||||
self.scalar_gcc_type_at(cx, scalar, offset)
|
||||
}
|
||||
|
||||
|
@ -355,7 +378,12 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
layout.gcc_field_index(index)
|
||||
}
|
||||
|
||||
fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, _immediate: bool) -> Type<'gcc> {
|
||||
fn scalar_pair_element_backend_type(
|
||||
&self,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
index: usize,
|
||||
_immediate: bool,
|
||||
) -> Type<'gcc> {
|
||||
layout.scalar_pair_element_gcc_type(self, index)
|
||||
}
|
||||
|
||||
|
@ -373,12 +401,7 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
|
||||
fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
|
||||
// FIXME(antoyo): Should we do something with `FnAbiGcc::fn_attributes`?
|
||||
let FnAbiGcc {
|
||||
return_type,
|
||||
arguments_type,
|
||||
is_c_variadic,
|
||||
..
|
||||
} = fn_abi.gcc_type(self);
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ use std::{
|
|||
process::Command,
|
||||
};
|
||||
|
||||
use boml::Toml;
|
||||
use lang_tester::LangTester;
|
||||
use tempfile::TempDir;
|
||||
use boml::Toml;
|
||||
|
||||
/// Controls the compile options (e.g., optimization level) used to compile
|
||||
/// test code.
|
||||
|
@ -21,8 +21,7 @@ pub fn main_inner(profile: Profile) {
|
|||
let tempdir = TempDir::new().expect("temp dir");
|
||||
let current_dir = current_dir().expect("current dir");
|
||||
let current_dir = current_dir.to_str().expect("current dir").to_string();
|
||||
let toml = Toml::parse(include_str!("../config.toml"))
|
||||
.expect("Failed to parse `config.toml`");
|
||||
let toml = Toml::parse(include_str!("../config.toml")).expect("Failed to parse `config.toml`");
|
||||
let gcc_path = if let Ok(gcc_path) = toml.get_string("gcc-path") {
|
||||
PathBuf::from(gcc_path.to_string())
|
||||
} else {
|
||||
|
@ -42,12 +41,12 @@ pub fn main_inner(profile: Profile) {
|
|||
filename.extension().expect("extension").to_str().expect("to_str") == "rs"
|
||||
}
|
||||
|
||||
#[cfg(feature="master")]
|
||||
#[cfg(feature = "master")]
|
||||
fn filter(filename: &Path) -> bool {
|
||||
rust_filter(filename)
|
||||
}
|
||||
|
||||
#[cfg(not(feature="master"))]
|
||||
#[cfg(not(feature = "master"))]
|
||||
fn filter(filename: &Path) -> bool {
|
||||
if let Some(filename) = filename.to_str() {
|
||||
if filename.ends_with("gep.rs") {
|
||||
|
@ -61,13 +60,13 @@ pub fn main_inner(profile: Profile) {
|
|||
.test_dir("tests/run")
|
||||
.test_file_filter(filter)
|
||||
.test_extract(|source| {
|
||||
let lines =
|
||||
source.lines()
|
||||
.skip_while(|l| !l.starts_with("//"))
|
||||
.take_while(|l| l.starts_with("//"))
|
||||
.map(|l| &l[2..])
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
let lines = source
|
||||
.lines()
|
||||
.skip_while(|l| !l.starts_with("//"))
|
||||
.take_while(|l| l.starts_with("//"))
|
||||
.map(|l| &l[2..])
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
Some(lines)
|
||||
})
|
||||
.test_cmds(move |path| {
|
||||
|
@ -78,10 +77,13 @@ pub fn main_inner(profile: Profile) {
|
|||
let mut compiler = Command::new("rustc");
|
||||
compiler.args(&[
|
||||
&format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir),
|
||||
"--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir),
|
||||
"--sysroot",
|
||||
&format!("{}/build_sysroot/sysroot/", current_dir),
|
||||
"-Zno-parallel-llvm",
|
||||
"-C", "link-arg=-lc",
|
||||
"-o", exe.to_str().expect("to_str"),
|
||||
"-C",
|
||||
"link-arg=-lc",
|
||||
"-o",
|
||||
exe.to_str().expect("to_str"),
|
||||
path.to_str().expect("to_str"),
|
||||
]);
|
||||
|
||||
|
@ -105,10 +107,7 @@ pub fn main_inner(profile: Profile) {
|
|||
match profile {
|
||||
Profile::Debug => {}
|
||||
Profile::Release => {
|
||||
compiler.args(&[
|
||||
"-C", "opt-level=3",
|
||||
"-C", "lto=no",
|
||||
]);
|
||||
compiler.args(&["-C", "opt-level=3", "-C", "lto=no"]);
|
||||
}
|
||||
}
|
||||
// Test command 2: run `tempdir/x`.
|
||||
|
@ -130,18 +129,10 @@ pub fn main_inner(profile: Profile) {
|
|||
runtime.args(&["chroot", vm_dir, "qemu-m68k-static"]);
|
||||
runtime.arg(inside_vm_exe_path);
|
||||
runtime.current_dir(vm_parent_dir);
|
||||
vec![
|
||||
("Compiler", compiler),
|
||||
("Copy", copy),
|
||||
("Run-time", runtime),
|
||||
]
|
||||
}
|
||||
else {
|
||||
vec![("Compiler", compiler), ("Copy", copy), ("Run-time", runtime)]
|
||||
} else {
|
||||
let runtime = Command::new(exe);
|
||||
vec![
|
||||
("Compiler", compiler),
|
||||
("Run-time", runtime),
|
||||
]
|
||||
vec![("Compiler", compiler), ("Run-time", runtime)]
|
||||
}
|
||||
})
|
||||
.run();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue