Merge from rustc

This commit is contained in:
The Miri Conjob Bot 2023-11-02 05:22:49 +00:00
commit 869827fd86
747 changed files with 18672 additions and 10001 deletions

View file

@ -193,8 +193,9 @@ jobs:
os: ubuntu-20.04-8core-32gb
env: {}
- name: dist-aarch64-linux
env:
CODEGEN_BACKENDS: "llvm,cranelift"
os: ubuntu-20.04-8core-32gb
env: {}
- name: dist-android
os: ubuntu-20.04-8core-32gb
env: {}
@ -244,15 +245,18 @@ jobs:
os: ubuntu-20.04-8core-32gb
env: {}
- name: dist-x86_64-linux
env:
CODEGEN_BACKENDS: "llvm,cranelift"
os: ubuntu-20.04-16core-64gb
env: {}
- name: dist-x86_64-linux-alt
env:
IMAGE: dist-x86_64-linux
CODEGEN_BACKENDS: "llvm,cranelift"
os: ubuntu-20.04-16core-64gb
- name: dist-x86_64-musl
env:
CODEGEN_BACKENDS: "llvm,cranelift"
os: ubuntu-20.04-8core-32gb
env: {}
- name: dist-x86_64-netbsd
os: ubuntu-20.04-8core-32gb
env: {}
@ -316,6 +320,7 @@ jobs:
NO_DEBUG_ASSERTIONS: 1
NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
CODEGEN_BACKENDS: "llvm,cranelift"
os: macos-13
- name: dist-apple-various
env:
@ -377,6 +382,7 @@ jobs:
- name: x86_64-msvc-ext
env:
SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo && src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows
HOST_TARGET: x86_64-pc-windows-msvc
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-lld --save-toolstates=/tmp/toolstate/toolstates.json"
DEPLOY_TOOLSTATES_JSON: toolstates-windows.json
os: windows-2019-8core-32gb
@ -554,8 +560,9 @@ jobs:
matrix:
include:
- name: dist-x86_64-linux
env:
CODEGEN_BACKENDS: "llvm,cranelift"
os: ubuntu-20.04-16core-64gb
env: {}
timeout-minutes: 600
runs-on: "${{ matrix.os }}"
steps:

View file

@ -1011,6 +1011,17 @@ dependencies = [
"syn 2.0.29",
]
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive_builder"
version = "0.12.0"
@ -4054,7 +4065,6 @@ dependencies = [
"rustc_hir_analysis",
"rustc_hir_typeck",
"rustc_incremental",
"rustc_index",
"rustc_lint",
"rustc_macros",
"rustc_metadata",
@ -4413,7 +4423,6 @@ version = "0.0.0"
dependencies = [
"field-offset",
"measureme",
"memoffset",
"rustc-rayon-core",
"rustc_data_structures",
"rustc_errors",
@ -4669,6 +4678,7 @@ name = "rustc_type_ir"
version = "0.0.0"
dependencies = [
"bitflags 1.3.2",
"derivative",
"rustc_data_structures",
"rustc_index",
"rustc_macros",

View file

@ -4,16 +4,21 @@ version = "0.0.0"
edition = "2021"
[dependencies]
rustc_driver = { path = "../rustc_driver" }
rustc_driver_impl = { path = "../rustc_driver_impl" }
# tidy-alphabetical-start
# Make sure rustc_codegen_ssa ends up in the sysroot, because this
# crate is intended to be used by codegen backends, which may not be in-tree.
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
rustc_driver = { path = "../rustc_driver" }
rustc_driver_impl = { path = "../rustc_driver_impl" }
# Make sure rustc_smir ends up in the sysroot, because this
# crate is intended to be used by stable MIR consumers, which are not in-tree
# crate is intended to be used by stable MIR consumers, which are not in-tree.
rustc_smir = { path = "../rustc_smir" }
stable_mir = { path = "../stable_mir" }
# tidy-alphabetical-end
[dependencies.jemalloc-sys]
version = "0.5.0"
@ -21,7 +26,9 @@ optional = true
features = ['unprefixed_malloc_on_supported_platforms']
[features]
# tidy-alphabetical-start
jemalloc = ['jemalloc-sys']
llvm = ['rustc_driver_impl/llvm']
max_level_info = ['rustc_driver_impl/max_level_info']
rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler']
# tidy-alphabetical-end

View file

@ -4,18 +4,20 @@ version = "0.0.0"
edition = "2021"
[dependencies]
# tidy-alphabetical-start
bitflags = "1.2.1"
tracing = "0.1"
rand = { version = "0.8.4", default-features = false, optional = true }
rand_xoshiro = { version = "0.6.0", optional = true }
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
rustc_index = { path = "../rustc_index", default-features = false }
rustc_macros = { path = "../rustc_macros", optional = true }
rustc_serialize = { path = "../rustc_serialize", optional = true }
tracing = "0.1"
# tidy-alphabetical-end
[features]
# tidy-alphabetical-start
default = ["nightly", "randomize"]
randomize = ["rand", "rand_xoshiro", "nightly"]
# rust-analyzer depends on this crate and we therefore require it to built on a stable toolchain
# without depending on rustc_data_structures, rustc_macros and rustc_serialize
nightly = [
@ -24,3 +26,5 @@ nightly = [
"rustc_macros",
"rustc_serialize",
]
randomize = ["rand", "rand_xoshiro", "nightly"]
# tidy-alphabetical-end

View file

@ -539,6 +539,7 @@ pub trait LayoutCalculator {
// Align the maximum variant size to the largest alignment.
size = size.align_to(align.abi);
// FIXME(oli-obk): deduplicate and harden these checks
if size.bytes() >= dl.obj_size_bound() {
return None;
}
@ -1103,6 +1104,10 @@ fn univariant<
inverse_memory_index.into_iter().map(|it| it.index() as u32).collect()
};
let size = min_size.align_to(align.abi);
// FIXME(oli-obk): deduplicate and harden these checks
if size.bytes() >= dl.obj_size_bound() {
return None;
}
let mut layout_of_single_non_zst_field = None;
let mut abi = Abi::Aggregate { sized };
// Try to make this a Scalar/ScalarPair.

View file

@ -4,4 +4,6 @@ version = "0.0.0"
edition = "2021"
[dependencies]
# tidy-alphabetical-start
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
# tidy-alphabetical-end

View file

@ -3,9 +3,8 @@ name = "rustc_ast"
version = "0.0.0"
edition = "2021"
[lib]
[dependencies]
# tidy-alphabetical-start
bitflags = "1.2.1"
memchr = "2.5.0"
rustc_data_structures = { path = "../rustc_data_structures" }
@ -14,8 +13,9 @@ rustc_lexer = { path = "../rustc_lexer" }
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
# depends on Mutability and Movability, which could be uplifted into a common crate.
# For Mutability and Movability, which could be uplifted into a common crate.
rustc_type_ir = { path = "../rustc_type_ir" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2.12"
tracing = "0.1"
# tidy-alphabetical-end

View file

@ -1235,7 +1235,7 @@ impl Expr {
ExprKind::Closure(..) => ExprPrecedence::Closure,
ExprKind::Block(..) => ExprPrecedence::Block,
ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
ExprKind::Async(..) => ExprPrecedence::Async,
ExprKind::Gen(..) => ExprPrecedence::Gen,
ExprKind::Await(..) => ExprPrecedence::Await,
ExprKind::Assign(..) => ExprPrecedence::Assign,
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
@ -1405,11 +1405,9 @@ pub enum ExprKind {
Closure(Box<Closure>),
/// A block (`'label: { ... }`).
Block(P<Block>, Option<Label>),
/// An async block (`async move { ... }`).
///
/// The async block used to have a `NodeId`, which was removed in favor of
/// using the parent `NodeId` of the parent `Expr`.
Async(CaptureBy, P<Block>),
/// An `async` block (`async move { ... }`),
/// or a `gen` block (`gen move { ... }`)
Gen(CaptureBy, P<Block>, GenBlockKind),
/// An await expression (`my_future.await`). Span is of await keyword.
Await(P<Expr>, Span),
@ -1499,6 +1497,28 @@ pub enum ExprKind {
Err,
}
/// Used to differentiate between `async {}` blocks and `gen {}` blocks.
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
pub enum GenBlockKind {
Async,
Gen,
}
impl fmt::Display for GenBlockKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.modifier().fmt(f)
}
}
impl GenBlockKind {
pub fn modifier(&self) -> &'static str {
match self {
GenBlockKind::Async => "async",
GenBlockKind::Gen => "gen",
}
}
}
/// The explicit `Self` type in a "qualified path". The actual
/// path, including the trait and the associated item, is stored
/// separately. `position` represents the index of the associated
@ -2363,6 +2383,12 @@ pub enum Async {
No,
}
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
pub enum Gen {
Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
No,
}
impl Async {
pub fn is_async(self) -> bool {
matches!(self, Async::Yes { .. })

View file

@ -1418,7 +1418,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
vis.visit_block(blk);
visit_opt(label, |label| vis.visit_label(label));
}
ExprKind::Async(_capture_by, body) => {
ExprKind::Gen(_capture_by, body, _) => {
vis.visit_block(body);
}
ExprKind::Await(expr, await_kw_span) => {

View file

@ -197,6 +197,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
kw::Continue,
kw::False,
kw::For,
kw::Gen,
kw::If,
kw::Let,
kw::Loop,

View file

@ -46,7 +46,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
Closure(closure) => {
expr = &closure.body;
}
Async(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
Gen(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
| TryBlock(..) | While(..) => break Some(expr),
_ => break None,
}

View file

@ -285,7 +285,7 @@ pub enum ExprPrecedence {
Block,
TryBlock,
Struct,
Async,
Gen,
Await,
Err,
}
@ -351,7 +351,7 @@ impl ExprPrecedence {
| ExprPrecedence::ConstBlock
| ExprPrecedence::Block
| ExprPrecedence::TryBlock
| ExprPrecedence::Async
| ExprPrecedence::Gen
| ExprPrecedence::Struct
| ExprPrecedence::Err => PREC_PAREN,
}

View file

@ -872,7 +872,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block);
}
ExprKind::Async(_, body) => {
ExprKind::Gen(_, body, _) => {
visitor.visit_block(body);
}
ExprKind::Await(expr, _) => visitor.visit_expr(expr),

View file

@ -7,18 +7,20 @@ edition = "2021"
doctest = false
[dependencies]
# tidy-alphabetical-start
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_middle = { path = "../rustc_middle" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2.12"
tracing = "0.1"
# tidy-alphabetical-end

View file

@ -183,7 +183,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
hir::MatchSource::Normal,
),
ExprKind::Async(capture_clause, block) => self.make_async_expr(
ExprKind::Gen(capture_clause, block, GenBlockKind::Async) => self.make_async_expr(
*capture_clause,
e.id,
None,
@ -317,6 +317,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
rest,
)
}
ExprKind::Gen(capture_clause, block, GenBlockKind::Gen) => self.make_gen_expr(
*capture_clause,
e.id,
None,
e.span,
hir::CoroutineSource::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
),
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
ExprKind::Err => hir::ExprKind::Err(
self.tcx.sess.delay_span_bug(e.span, "lowered ExprKind::Err"),
@ -598,7 +606,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
closure_node_id: NodeId,
ret_ty: Option<hir::FnRetTy<'hir>>,
span: Span,
async_gen_kind: hir::CoroutineSource,
async_coroutine_source: hir::CoroutineSource,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::ExprKind<'hir> {
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
@ -637,7 +645,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let params = arena_vec![self; param];
let body = self.lower_body(move |this| {
this.coroutine_kind = Some(hir::CoroutineKind::Async(async_gen_kind));
this.coroutine_kind = Some(hir::CoroutineKind::Async(async_coroutine_source));
let old_ctx = this.task_context;
this.task_context = Some(task_context_hid);
@ -661,6 +669,57 @@ impl<'hir> LoweringContext<'_, 'hir> {
}))
}
/// Lower a `gen` construct to a generator that implements `Iterator`.
///
/// This results in:
///
/// ```text
/// static move? |()| -> () {
/// <body>
/// }
/// ```
pub(super) fn make_gen_expr(
&mut self,
capture_clause: CaptureBy,
closure_node_id: NodeId,
_yield_ty: Option<hir::FnRetTy<'hir>>,
span: Span,
coroutine_source: hir::CoroutineSource,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::ExprKind<'hir> {
let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
// The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
let fn_decl = self.arena.alloc(hir::FnDecl {
inputs: &[],
output,
c_variadic: false,
implicit_self: hir::ImplicitSelfKind::None,
lifetime_elision_allowed: false,
});
let body = self.lower_body(move |this| {
this.coroutine_kind = Some(hir::CoroutineKind::Gen(coroutine_source));
let res = body(this);
(&[], res)
});
// `static |()| -> () { body }`:
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
def_id: self.local_def_id(closure_node_id),
binder: hir::ClosureBinder::Default,
capture_clause,
bound_generic_params: &[],
fn_decl,
body,
fn_decl_span: self.lower_span(span),
fn_arg_span: None,
movability: Some(Movability::Movable),
constness: hir::Constness::NotConst,
}))
}
/// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
/// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
pub(super) fn maybe_forward_track_caller(
@ -712,7 +771,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let full_span = expr.span.to(await_kw_span);
match self.coroutine_kind {
Some(hir::CoroutineKind::Async(_)) => {}
Some(hir::CoroutineKind::Coroutine) | None => {
Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) | None => {
self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks {
await_kw_span,
item_span: self.current_item,
@ -936,8 +995,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
Some(movability)
}
Some(hir::CoroutineKind::Async(_)) => {
panic!("non-`async` closure body turned `async` during lowering");
Some(hir::CoroutineKind::Gen(_)) | Some(hir::CoroutineKind::Async(_)) => {
panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering");
}
None => {
if movability == Movability::Static {
@ -1445,11 +1504,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
match self.coroutine_kind {
Some(hir::CoroutineKind::Coroutine) => {}
Some(hir::CoroutineKind::Gen(_)) => {}
Some(hir::CoroutineKind::Async(_)) => {
self.tcx.sess.emit_err(AsyncCoroutinesNotSupported { span });
}
None => self.coroutine_kind = Some(hir::CoroutineKind::Coroutine),
Some(hir::CoroutineKind::Coroutine) | None => {
if !self.tcx.features().coroutines {
rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
sym::coroutines,
span,
"yield syntax is experimental",
)
.emit();
}
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine)
}
}
let expr =

View file

@ -988,12 +988,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>),
) -> hir::BodyId {
let prev_gen_kind = self.coroutine_kind.take();
let prev_coroutine_kind = self.coroutine_kind.take();
let task_context = self.task_context.take();
let (parameters, result) = f(self);
let body_id = self.record_body(parameters, result);
self.task_context = task_context;
self.coroutine_kind = prev_gen_kind;
self.coroutine_kind = prev_coroutine_kind;
body_id
}

View file

@ -1742,14 +1742,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
// Skip the `...` (`CVarArgs`) trailing arguments from the AST,
// as they are not explicit in HIR/Ty function signatures.
// (instead, the `c_variadic` flag is set to `true`)
let mut inputs = &decl.inputs[..];
if decl.c_variadic() {
inputs = &inputs[..inputs.len() - 1];
}
self.arena.alloc_from_iter(inputs.iter().map(|param| match param.pat.kind {
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
PatKind::Ident(_, ident, _) => self.lower_ident(ident),
_ => Ident::new(kw::Empty, self.lower_span(param.pat.span)),
}))

View file

@ -4,6 +4,7 @@ version = "0.0.0"
edition = "2021"
[dependencies]
# tidy-alphabetical-start
itertools = "0.10.1"
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
@ -11,11 +12,12 @@ rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_macros = { path = "../rustc_macros" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_macros = { path = "../rustc_macros" }
rustc_parse = { path = "../rustc_parse" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
thin-vec = "0.2.12"
tracing = "0.1"
# tidy-alphabetical-end

View file

@ -42,6 +42,10 @@ ast_passes_const_and_async = functions cannot be both `const` and `async`
.async = `async` because of this
.label = {""}
ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic
.const = `const` because of this
.variadic = C-variadic because of this
ast_passes_const_without_body =
free constant item without body
.suggestion = provide a definition for the constant

View file

@ -482,9 +482,36 @@ impl<'a> AstValidator<'a> {
}
}
/// Reject C-variadic type unless the function is foreign,
/// or free and `unsafe extern "C"` semantically.
/// Reject invalid C-variadic types.
///
/// C-variadics must be:
/// - Non-const
/// - Either foreign, or free and `unsafe extern "C"` semantically
fn check_c_variadic_type(&self, fk: FnKind<'a>) {
let variadic_spans: Vec<_> = fk
.decl()
.inputs
.iter()
.filter(|arg| matches!(arg.ty.kind, TyKind::CVarArgs))
.map(|arg| arg.span)
.collect();
if variadic_spans.is_empty() {
return;
}
if let Some(header) = fk.header() {
if let Const::Yes(const_span) = header.constness {
let mut spans = variadic_spans.clone();
spans.push(const_span);
self.err_handler().emit_err(errors::ConstAndCVariadic {
spans,
const_span,
variadic_spans: variadic_spans.clone(),
});
}
}
match (fk.ctxt(), fk.header()) {
(Some(FnCtxt::Foreign), _) => return,
(Some(FnCtxt::Free), Some(header)) => match header.ext {
@ -499,11 +526,7 @@ impl<'a> AstValidator<'a> {
_ => {}
};
for Param { ty, span, .. } in &fk.decl().inputs {
if let TyKind::CVarArgs = ty.kind {
self.err_handler().emit_err(errors::BadCVariadic { span: *span });
}
}
self.err_handler().emit_err(errors::BadCVariadic { span: variadic_spans });
}
fn check_item_named(&self, ident: Ident, kind: &str) {

View file

@ -271,7 +271,7 @@ pub struct ExternItemAscii {
#[diag(ast_passes_bad_c_variadic)]
pub struct BadCVariadic {
#[primary_span]
pub span: Span,
pub span: Vec<Span>,
}
#[derive(Diagnostic)]
@ -583,6 +583,17 @@ pub struct ConstAndAsync {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_const_and_c_variadic)]
pub struct ConstAndCVariadic {
#[primary_span]
pub spans: Vec<Span>,
#[label(ast_passes_const)]
pub const_span: Span,
#[label(ast_passes_variadic)]
pub variadic_spans: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_foreign, code = "E0130")]
pub struct PatternInForeign {

View file

@ -554,7 +554,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
"consider removing `for<...>`"
);
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
gate_all!(coroutines, "yield syntax is experimental");
for &span in spans.get(&sym::yield_expr).iter().copied().flatten() {
if !span.at_least_rust_2024() {
gate_feature_post!(&visitor, coroutines, span, "yield syntax is experimental");
}
}
gate_all!(gen_blocks, "gen blocks are experimental");
gate_all!(raw_ref_op, "raw address of syntax is experimental");
gate_all!(const_trait_impl, "const trait impls are experimental");
gate_all!(

View file

@ -3,9 +3,9 @@ name = "rustc_ast_pretty"
version = "0.0.0"
edition = "2021"
[lib]
[dependencies]
# tidy-alphabetical-start
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
thin-vec = "0.2.12"
# tidy-alphabetical-end

View file

@ -445,8 +445,8 @@ impl<'a> State<'a> {
self.ibox(0);
self.print_block_with_attrs(blk, attrs);
}
ast::ExprKind::Async(capture_clause, blk) => {
self.word_nbsp("async");
ast::ExprKind::Gen(capture_clause, blk, kind) => {
self.word_nbsp(kind.modifier());
self.print_capture_clause(*capture_clause);
// cbox/ibox in analogy to the `ExprKind::Block` arm above
self.cbox(0);

View file

@ -3,9 +3,8 @@ name = "rustc_attr"
version = "0.0.0"
edition = "2021"
[lib]
[dependencies]
# tidy-alphabetical-start
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
@ -17,3 +16,4 @@ rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
# tidy-alphabetical-end

View file

@ -10,10 +10,9 @@ use rustc_session::config::ExpectedValues;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::Session;
use rustc_session::{RustcVersion, Session};
use rustc_span::hygiene::Transparency;
use rustc_span::{symbol::sym, symbol::Symbol, Span};
use std::fmt::{self, Display};
use std::num::NonZeroU32;
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@ -24,8 +23,6 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
pub const CURRENT_RUSTC_VERSION: &str = env!("CFG_RELEASE");
pub fn is_builtin_attr(attr: &Attribute) -> bool {
attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
}
@ -142,7 +139,7 @@ pub enum StabilityLevel {
/// `#[stable]`
Stable {
/// Rust release which stabilized this feature.
since: Since,
since: StableSince,
/// Is this item allowed to be referred to on stable, despite being contained in unstable
/// modules?
allowed_through_unstable_modules: bool,
@ -152,8 +149,8 @@ pub enum StabilityLevel {
/// Rust release in which a feature is stabilized.
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
#[derive(HashStable_Generic)]
pub enum Since {
Version(Version),
pub enum StableSince {
Version(RustcVersion),
/// Stabilized in the upcoming version, whatever number that is.
Current,
/// Failed to parse a stabilization version.
@ -381,16 +378,16 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
let since = if let Some(since) = since {
if since.as_str() == VERSION_PLACEHOLDER {
Since::Current
} else if let Some(version) = parse_version(since.as_str(), false) {
Since::Version(version)
StableSince::Current
} else if let Some(version) = parse_version(since) {
StableSince::Version(version)
} else {
sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
Since::Err
StableSince::Err
}
} else {
sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
Since::Err
StableSince::Err
};
match feature {
@ -567,31 +564,20 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
}
}
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(HashStable_Generic)]
pub struct Version {
pub major: u16,
pub minor: u16,
pub patch: u16,
}
fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
let mut components = s.split('-');
/// Parse a rustc version number written inside string literal in an attribute,
/// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
/// not accepted in this position, unlike when parsing CFG_RELEASE.
fn parse_version(s: Symbol) -> Option<RustcVersion> {
let mut components = s.as_str().split('-');
let d = components.next()?;
if !allow_appendix && components.next().is_some() {
if components.next().is_some() {
return None;
}
let mut digits = d.splitn(3, '.');
let major = digits.next()?.parse().ok()?;
let minor = digits.next()?.parse().ok()?;
let patch = digits.next().unwrap_or("0").parse().ok()?;
Some(Version { major, minor, patch })
}
impl Display for Version {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
}
Some(RustcVersion { major, minor, patch })
}
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
@ -623,17 +609,16 @@ pub fn eval_condition(
return false;
}
};
let Some(min_version) = parse_version(min_version.as_str(), false) else {
let Some(min_version) = parse_version(*min_version) else {
sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
return false;
};
let rustc_version = parse_version(CURRENT_RUSTC_VERSION, true).unwrap();
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
if sess.assume_incomplete_release {
rustc_version > min_version
RustcVersion::CURRENT > min_version
} else {
rustc_version >= min_version
RustcVersion::CURRENT >= min_version
}
}
ast::MetaItemKind::List(mis) => {
@ -735,17 +720,49 @@ pub fn eval_condition(
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
pub struct Deprecation {
pub since: Option<Symbol>,
pub since: DeprecatedSince,
/// The note to issue a reason.
pub note: Option<Symbol>,
/// A text snippet used to completely replace any use of the deprecated item in an expression.
///
/// This is currently unstable.
pub suggestion: Option<Symbol>,
}
/// Whether to treat the since attribute as being a Rust version identifier
/// (rather than an opaque string).
pub is_since_rustc_version: bool,
/// Release in which an API is deprecated.
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
pub enum DeprecatedSince {
RustcVersion(RustcVersion),
/// Deprecated in the future ("to be determined").
Future,
/// `feature(staged_api)` is off. Deprecation versions outside the standard
/// library are allowed to be arbitrary strings, for better or worse.
NonStandard(Symbol),
/// Deprecation version is unspecified but optional.
Unspecified,
/// Failed to parse a deprecation version, or the deprecation version is
/// unspecified and required. An error has already been emitted.
Err,
}
impl Deprecation {
/// Whether an item marked with #[deprecated(since = "X")] is currently
/// deprecated (i.e., whether X is not greater than the current rustc
/// version).
pub fn is_in_effect(&self) -> bool {
match self.since {
DeprecatedSince::RustcVersion(since) => since <= RustcVersion::CURRENT,
DeprecatedSince::Future => false,
// The `since` field doesn't have semantic purpose without `#![staged_api]`.
DeprecatedSince::NonStandard(_) => true,
// Assume deprecation is in effect if "since" field is absent or invalid.
DeprecatedSince::Unspecified | DeprecatedSince::Err => true,
}
}
pub fn is_since_rustc_version(&self) -> bool {
matches!(self.since, DeprecatedSince::RustcVersion(_))
}
}
/// Finds the deprecation attribute. `None` if none exists.
@ -854,22 +871,30 @@ pub fn find_deprecation(
}
}
if is_rustc {
if since.is_none() {
sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
continue;
let since = if let Some(since) = since {
if since.as_str() == "TBD" {
DeprecatedSince::Future
} else if !is_rustc {
DeprecatedSince::NonStandard(since)
} else if let Some(version) = parse_version(since) {
DeprecatedSince::RustcVersion(version)
} else {
sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
DeprecatedSince::Err
}
} else if is_rustc {
sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
DeprecatedSince::Err
} else {
DeprecatedSince::Unspecified
};
if note.is_none() {
sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
continue;
}
if is_rustc && note.is_none() {
sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
continue;
}
depr = Some((
Deprecation { since, note, suggestion, is_since_rustc_version: is_rustc },
attr.span,
));
depr = Some((Deprecation { since, note, suggestion }, attr.span));
}
depr

View file

@ -27,6 +27,6 @@ pub use StabilityLevel::*;
pub use rustc_ast::attr::*;
pub(crate) use rustc_ast::HashStableContext;
pub(crate) use rustc_session::HashStableContext;
fluent_messages! { "../messages.ftl" }

View file

@ -4,11 +4,15 @@ version = "0.0.0"
edition = "2021"
[dependencies]
# tidy-alphabetical-start
icu_list = "1.2"
icu_locid = "1.2"
icu_provider = "1.2"
icu_provider_adapters = "1.2"
zerovec = "0.9.4"
# tidy-alphabetical-end
[features]
# tidy-alphabetical-start
rustc_use_parallel_compiler = ['icu_provider/sync']
# tidy-alphabetical-end

View file

@ -3,19 +3,16 @@ name = "rustc_borrowck"
version = "0.0.0"
edition = "2021"
[lib]
[dependencies]
# tidy-alphabetical-start
either = "1.5.0"
itertools = "0.10.1"
tracing = "0.1"
polonius-engine = "0.13.0"
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_lexer = { path = "../rustc_lexer" }
@ -24,7 +21,10 @@ rustc_middle = { path = "../rustc_middle" }
rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_traits = { path = "../rustc_traits" }
rustc_span = { path = "../rustc_span" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
tracing = "0.1"
# tidy-alphabetical-end

View file

@ -373,11 +373,12 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
span: Span,
yield_span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind;
let mut err = struct_span_err!(
self,
span,
E0626,
"borrow may still be in use when coroutine yields",
"borrow may still be in use when {coroutine_kind:#} yields",
);
err.span_label(yield_span, "possible yield occurs here");
err

View file

@ -2491,11 +2491,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
Ok(string) => {
if string.starts_with("async ") {
let pos = args_span.lo() + BytePos(6);
(args_span.with_lo(pos).with_hi(pos), "move ")
} else if string.starts_with("async|") {
let pos = args_span.lo() + BytePos(5);
let coro_prefix = if string.starts_with("async") {
// `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize` to `u32`
Some(5)
} else if string.starts_with("gen") {
// `gen` is 3 chars long
Some(3)
} else {
None
};
if let Some(n) = coro_prefix {
let pos = args_span.lo() + BytePos(n);
(args_span.with_lo(pos).with_hi(pos), " move")
} else {
(args_span.shrink_to_lo(), "move ")
@ -2505,6 +2511,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
};
let kind = match use_span.coroutine_kind() {
Some(coroutine_kind) => match coroutine_kind {
CoroutineKind::Gen(kind) => match kind {
CoroutineSource::Block => "gen block",
CoroutineSource::Closure => "gen closure",
_ => bug!("gen block/closure expected, but gen function found."),
},
CoroutineKind::Async(async_kind) => match async_kind {
CoroutineSource::Block => "async block",
CoroutineSource::Closure => "async closure",

View file

@ -698,6 +698,20 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
" of async function"
}
},
Some(hir::CoroutineKind::Gen(gen)) => match gen {
hir::CoroutineSource::Block => " of gen block",
hir::CoroutineSource::Closure => " of gen closure",
hir::CoroutineSource::Fn => {
let parent_item =
hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
let output = &parent_item
.fn_decl()
.expect("coroutine lowered from gen fn should be in fn")
.output;
span = output.span();
" of gen function"
}
},
Some(hir::CoroutineKind::Coroutine) => " of coroutine",
None => " of closure",
};

View file

@ -3,6 +3,7 @@ use rustc_data_structures::graph::WithSuccessors;
use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
use rustc_index::interval::IntervalSet;
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::for_liveness;
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
use rustc_middle::traits::query::DropckOutlivesResult;
use rustc_middle::ty::{RegionVid, Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
@ -601,34 +602,36 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
values::location_set_str(elements, live_at.iter()),
);
let tcx = typeck.tcx();
let borrowck_context = &mut typeck.borrowck_context;
// When using `-Zpolonius=next`, we want to record the loans that flow into this value's
// regions as being live at the given `live_at` points: this will be used to compute the
// location where a loan goes out of scope.
let num_loans = borrowck_context.borrow_set.len();
let mut value_loans = HybridBitSet::new_empty(num_loans);
let num_loans = typeck.borrowck_context.borrow_set.len();
let value_loans = &mut HybridBitSet::new_empty(num_loans);
tcx.for_each_free_region(&value, |live_region| {
let live_region_vid = borrowck_context.universal_regions.to_region_vid(live_region);
value.visit_with(&mut for_liveness::FreeRegionsVisitor {
tcx: typeck.tcx(),
param_env: typeck.param_env,
op: |r| {
let live_region_vid = typeck.borrowck_context.universal_regions.to_region_vid(r);
borrowck_context
.constraints
.liveness_constraints
.add_elements(live_region_vid, live_at);
typeck
.borrowck_context
.constraints
.liveness_constraints
.add_elements(live_region_vid, live_at);
// There can only be inflowing loans for this region when we are using
// `-Zpolonius=next`.
if let Some(inflowing) = inflowing_loans.row(live_region_vid) {
value_loans.union(inflowing);
}
// There can only be inflowing loans for this region when we are using
// `-Zpolonius=next`.
if let Some(inflowing) = inflowing_loans.row(live_region_vid) {
value_loans.union(inflowing);
}
},
});
// Record the loans reaching the value.
if !value_loans.is_empty() {
for point in live_at.iter() {
borrowck_context.live_loans.union_row(point, &value_loans);
typeck.borrowck_context.live_loans.union_row(point, value_loans);
}
}
}

View file

@ -188,11 +188,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
&mut borrowck_context,
);
// FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
// predefined opaques in the typeck root.
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
checker.register_predefined_opaques_in_new_solver();
}
checker.check_user_type_annotations();
let mut verifier = TypeVerifier::new(&mut checker, promoted);
verifier.visit_body(&body);
@ -1021,7 +1017,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
borrowck_context,
reported_errors: Default::default(),
};
checker.check_user_type_annotations();
// FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
// predefined opaques in the typeck root.
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
checker.register_predefined_opaques_in_new_solver();
}
checker
}
@ -1640,7 +1642,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
TerminatorKind::UnwindTerminate(_) => {
if !is_cleanup {
span_mirbug!(self, block_data, "abort on non-cleanup block!")
span_mirbug!(self, block_data, "terminate on non-cleanup block!")
}
}
TerminatorKind::Return => {

View file

@ -7,6 +7,7 @@ edition = "2021"
doctest = false
[dependencies]
# tidy-alphabetical-start
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
@ -14,16 +15,17 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_expand = { path = "../rustc_expand" }
rustc_feature = { path = "../rustc_feature" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_parse_format = { path = "../rustc_parse_format" }
rustc_parse = { path = "../rustc_parse" }
rustc_parse_format = { path = "../rustc_parse_format" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2.12"
tracing = "0.1"
# tidy-alphabetical-end

View file

@ -294,7 +294,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
// sync with the `rfc-2011-nicer-assert-messages/all-expr-kinds.rs` test.
ExprKind::Assign(_, _, _)
| ExprKind::AssignOp(_, _, _)
| ExprKind::Async(_, _)
| ExprKind::Gen(_, _, _)
| ExprKind::Await(_, _)
| ExprKind::Block(_, _)
| ExprKind::Break(_, _)

View file

@ -45,18 +45,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift-bforest"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1512c3bb6b13018e7109fc3ac964bc87b329eaf3a77825d337558d0c7f6f1be"
checksum = "f773437307980ac0f424bf9b9a5d0cd21a0f17248c6860c9a65bec8b5975f3fe"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16cb8fb9220a6ea7a226705a273ab905309ee546267bdf34948d57932d7f0396"
checksum = "443c2ac50e97fb7de1a0f862753fce3f27215558811a6fcee508eb0c3747fa79"
dependencies = [
"bumpalo",
"cranelift-bforest",
@ -75,39 +75,39 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab3a8d3b0d4745b183da5ea0792b13d79f5c23d6e69ac04761728e2532b56649"
checksum = "c5b174c411480c79ce0793c55042fa51bec27e486381d103a53cab3b480cb2db"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524141c8e68f2abc2043de4c2b31f6d9dd42432738c246431d0572a1422a4a84"
checksum = "73fa0151a528066a369de6debeea4d4b23a32aba68b5add8c46d3dc8091ff434"
[[package]]
name = "cranelift-control"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97513b57c961c713789a03886a57b43e14ebcd204cbaa8ae50ca6c70a8e716b3"
checksum = "b8adf1e6398493c9bea1190e37d28a0eb0eca5fddbc80e01e506cda34db92b1f"
dependencies = [
"arbitrary",
]
[[package]]
name = "cranelift-entity"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3f23d3cf3afa7e45f239702612c76d87964f652a55e28d13ed6d7e20f3479dd"
checksum = "4917e2ed3bb5fe87d0ed88395ca6d644018d119a034faedd1f3e1f2c33cd52b2"
[[package]]
name = "cranelift-frontend"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "554cd4947ec9209b58bf9ae5bf83581b5ddf9128bd967208e334b504a57db54e"
checksum = "9aaadf1e7cf28886bbf046eaf7ef538997bc8a7e020e578ea4957b39da87d5a1"
dependencies = [
"cranelift-codegen",
"log",
@ -117,15 +117,15 @@ dependencies = [
[[package]]
name = "cranelift-isle"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c1892a439696b6413cb54083806f5fd9fc431768b8de74864b3d9e8b93b124f"
checksum = "a67fda31b9d69eaa1c49a2081939454c45857596a9d45af6744680541c628b4c"
[[package]]
name = "cranelift-jit"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32209252fb38acaf1662ccd0397907bbe0e92bdb13b6ddbfd2f74e437f83e685"
checksum = "d6bf32710628e7ff298739f1ed80a0bfdafc0c6a3e284c4540b23f18e8889d4b"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -143,9 +143,9 @@ dependencies = [
[[package]]
name = "cranelift-module"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf42656f5f6df7bfafc4dd7b63a1888b0627c07b43b2cb9aa54e13843fed39eb"
checksum = "4d693e93a0fbf56b4bc93cffe6b107c2e52f070e1111950505fc8c83ac440b9d"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -154,9 +154,9 @@ dependencies = [
[[package]]
name = "cranelift-native"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0c2d3badd4b9690865f5bb68a71fa94de592fa2df3f3d11a5a062c60c0a107a"
checksum = "76fb52ba71be98312f35e798d9e98e45ab2586f27584231bf7c644fa9501e8af"
dependencies = [
"cranelift-codegen",
"libc",
@ -165,9 +165,9 @@ dependencies = [
[[package]]
name = "cranelift-object"
version = "0.101.1"
version = "0.101.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88eca54bbecea3170035168357306e9c779d4a63d8bf036c9e16bd21fdaa69b5"
checksum = "2551b2e185022b89e9efa5e04c0f17f679b86ef73d9f7feabc48b608ff23120d"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -362,9 +362,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "target-lexicon"
version = "0.12.5"
version = "0.12.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d"
checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
[[package]]
name = "version_check"
@ -374,9 +374,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasmtime-jit-icache-coherence"
version = "14.0.1"
version = "14.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aaf2fa8fd2d6b65abae9b92edfe69254cc5d6b166e342364036c3e347de8da9"
checksum = "0980a96b16abbdaf829858d2389697b1d6cfc6a903873fd74b7e47a6b1045584"
dependencies = [
"cfg-if",
"libc",

View file

@ -8,12 +8,12 @@ crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
cranelift-codegen = { version = "0.101.1", features = ["unwind", "all-arch"] }
cranelift-frontend = { version = "0.101.1" }
cranelift-module = { version = "0.101.1" }
cranelift-native = { version = "0.101.1" }
cranelift-jit = { version = "0.101.1", optional = true }
cranelift-object = { version = "0.101.1" }
cranelift-codegen = { version = "0.101.2", default-features = false, features = ["std", "unwind", "all-arch"] }
cranelift-frontend = { version = "0.101.2" }
cranelift-module = { version = "0.101.2" }
cranelift-native = { version = "0.101.2" }
cranelift-jit = { version = "0.101.2", optional = true }
cranelift-object = { version = "0.101.2" }
target-lexicon = "0.12.0"
gimli = { version = "0.28", default-features = false, features = ["write"]}
object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
@ -35,9 +35,9 @@ smallvec = "1.8.1"
[features]
# Enable features not ready to be enabled when compiling as part of rustc
unstable-features = ["jit", "inline_asm"]
unstable-features = ["jit", "inline_asm_sym"]
jit = ["cranelift-jit", "libloading"]
inline_asm = []
inline_asm_sym = []
[package.metadata.rust-analyzer]
rustc_private = true

View file

@ -40,22 +40,6 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9"
[[package]]
name = "auxv"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e50430f9beb8effb02399fa81c76eeaa26b05e4f03b09285cad8d079c1af5a3d"
dependencies = [
"byteorder",
"gcc",
]
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.79"
@ -388,7 +372,6 @@ dependencies = [
name = "std_detect"
version = "0.1.5"
dependencies = [
"auxv",
"cfg-if",
"compiler_builtins",
"cupid",

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-10-21"
channel = "nightly-2023-10-29"
components = ["rust-src", "rustc-dev", "llvm-tools"]

View file

@ -4,7 +4,9 @@ set -e
# Compiletest expects all standard library paths to start with /rustc/FAKE_PREFIX.
# CG_CLIF_STDLIB_REMAP_PATH_PREFIX will cause cg_clif's build system to pass
# --remap-path-prefix to handle this.
CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build
# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we
# the LLVM backend isn't compiled in here.
CG_CLIF_FORCE_GNU_AS=1 CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build
echo "[SETUP] Rust fork"
git clone https://github.com/rust-lang/rust.git || true

View file

@ -11,5 +11,7 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src}
cp ../Cargo.* compiler/rustc_codegen_cranelift/
cp -r ../src compiler/rustc_codegen_cranelift/src
./x.py build --stage 1 library/std
# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we
# the LLVM backend isn't compiled in here.
CG_CLIF_FORCE_GNU_AS=1 ./x.py build --stage 1 library/std
popd

View file

@ -766,7 +766,7 @@ fn codegen_stmt<'tcx>(
NullOp::SizeOf => layout.size.bytes(),
NullOp::AlignOf => layout.align.abi.bytes(),
NullOp::OffsetOf(fields) => {
layout.offset_of_subfield(fx, fields.iter().map(|f| f.index())).bytes()
layout.offset_of_subfield(fx, fields.iter()).bytes()
}
};
let val = CValue::by_val(

View file

@ -430,47 +430,11 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
}
}
// Note: must be kept in sync with get_caller_location from cg_ssa
pub(crate) fn get_caller_location(&mut self, mut source_info: mir::SourceInfo) -> CValue<'tcx> {
let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span| {
use rustc_session::RemapFileNameExt;
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = fx.tcx.sess.source_map().lookup_char_pos(topmost.lo());
let const_loc = fx.tcx.const_caller_location((
rustc_span::symbol::Symbol::intern(
&caller.file.name.for_codegen(&fx.tcx.sess).to_string_lossy(),
),
caller.line as u32,
caller.col_display as u32 + 1,
));
crate::constant::codegen_const_value(fx, const_loc, fx.tcx.caller_location_ty())
};
// Walk up the `SourceScope`s, in case some of them are from MIR inlining.
// If so, the starting `source_info.span` is in the innermost inlined
// function, and will be replaced with outer callsite spans as long
// as the inlined functions were `#[track_caller]`.
loop {
let scope_data = &self.mir.source_scopes[source_info.scope];
if let Some((callee, callsite_span)) = scope_data.inlined {
// Stop inside the most nested non-`#[track_caller]` function,
// before ever reaching its caller (which is irrelevant).
if !callee.def.requires_caller_location(self.tcx) {
return span_to_caller_location(self, source_info.span);
}
source_info.span = callsite_span;
}
// Skip past all of the parents with `inlined: None`.
match scope_data.inlined_parent_scope {
Some(parent) => source_info.scope = parent,
None => break,
}
}
// No inlined `SourceScope`s, or all of them were `#[track_caller]`.
self.caller_location.unwrap_or_else(|| span_to_caller_location(self, source_info.span))
pub(crate) fn get_caller_location(&mut self, source_info: mir::SourceInfo) -> CValue<'tcx> {
self.mir.caller_location_span(source_info, self.caller_location, self.tcx, |span| {
let const_loc = self.tcx.span_as_caller_location(span);
crate::constant::codegen_const_value(self, const_loc, self.tcx.caller_location_ty())
})
}
pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value {

View file

@ -46,6 +46,13 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
global_asm.push_str(&string);
}
InlineAsmOperand::SymFn { anon_const } => {
if cfg!(not(feature = "inline_asm_sym")) {
tcx.sess.span_err(
item.span,
"asm! and global_asm! sym operands are not yet supported",
);
}
let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
let instance = match ty.kind() {
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
@ -57,6 +64,13 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
global_asm.push_str(symbol.name);
}
InlineAsmOperand::SymStatic { path: _, def_id } => {
if cfg!(not(feature = "inline_asm_sym")) {
tcx.sess.span_err(
item.span,
"asm! and global_asm! sym operands are not yet supported",
);
}
let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
let symbol = tcx.symbol_name(instance);
global_asm.push_str(symbol.name);
@ -81,22 +95,23 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
}
}
pub(crate) fn asm_supported(tcx: TyCtxt<'_>) -> bool {
cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows
}
#[derive(Debug)]
pub(crate) struct GlobalAsmConfig {
asm_enabled: bool,
assembler: PathBuf,
target: String,
pub(crate) output_filenames: Arc<OutputFilenames>,
}
impl GlobalAsmConfig {
pub(crate) fn new(tcx: TyCtxt<'_>) -> Self {
GlobalAsmConfig {
asm_enabled: asm_supported(tcx),
assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"),
target: match &tcx.sess.opts.target_triple {
rustc_target::spec::TargetTriple::TargetTriple(triple) => triple.clone(),
rustc_target::spec::TargetTriple::TargetJson { path_for_rustdoc, .. } => {
path_for_rustdoc.to_str().unwrap().to_owned()
}
},
output_filenames: tcx.output_filenames(()).clone(),
}
}
@ -111,21 +126,6 @@ pub(crate) fn compile_global_asm(
return Ok(None);
}
if !config.asm_enabled {
if global_asm.contains("__rust_probestack") {
return Ok(None);
}
if cfg!(not(feature = "inline_asm")) {
return Err(
"asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift"
.to_owned(),
);
} else {
return Err("asm! and global_asm! are not yet supported on Windows".to_owned());
}
}
// Remove all LLVM style comments
let mut global_asm = global_asm
.lines()
@ -134,20 +134,67 @@ pub(crate) fn compile_global_asm(
.join("\n");
global_asm.push('\n');
let output_object_file = config.output_filenames.temp_path(OutputType::Object, Some(cgu_name));
let global_asm_object_file = add_file_stem_postfix(
config.output_filenames.temp_path(OutputType::Object, Some(cgu_name)),
".asm",
);
// Assemble `global_asm`
let global_asm_object_file = add_file_stem_postfix(output_object_file, ".asm");
let mut child = Command::new(&config.assembler)
.arg("-o")
.arg(&global_asm_object_file)
.stdin(Stdio::piped())
.spawn()
.expect("Failed to spawn `as`.");
child.stdin.take().unwrap().write_all(global_asm.as_bytes()).unwrap();
let status = child.wait().expect("Failed to wait for `as`.");
if !status.success() {
return Err(format!("Failed to assemble `{}`", global_asm));
if option_env!("CG_CLIF_FORCE_GNU_AS").is_some() {
let mut child = Command::new(&config.assembler)
.arg("-o")
.arg(&global_asm_object_file)
.stdin(Stdio::piped())
.spawn()
.expect("Failed to spawn `as`.");
child.stdin.take().unwrap().write_all(global_asm.as_bytes()).unwrap();
let status = child.wait().expect("Failed to wait for `as`.");
if !status.success() {
return Err(format!("Failed to assemble `{}`", global_asm));
}
} else {
let mut child = Command::new(std::env::current_exe().unwrap())
.arg("--target")
.arg(&config.target)
.arg("--crate-type")
.arg("staticlib")
.arg("--emit")
.arg("obj")
.arg("-o")
.arg(&global_asm_object_file)
.arg("-")
.arg("-Abad_asm_style")
.arg("-Zcodegen-backend=llvm")
.stdin(Stdio::piped())
.spawn()
.expect("Failed to spawn `as`.");
let mut stdin = child.stdin.take().unwrap();
stdin
.write_all(
br####"
#![feature(decl_macro, no_core, rustc_attrs)]
#![allow(internal_features)]
#![no_core]
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
macro global_asm() { /* compiler built-in */ }
global_asm!(r###"
"####,
)
.unwrap();
stdin.write_all(global_asm.as_bytes()).unwrap();
stdin
.write_all(
br####"
"###);
"####,
)
.unwrap();
std::mem::drop(stdin);
let status = child.wait().expect("Failed to wait for `as`.");
if !status.success() {
return Err(format!("Failed to assemble `{}`", global_asm));
}
}
Ok(Some(global_asm_object_file))

View file

@ -8,7 +8,6 @@ use rustc_span::sym;
use rustc_target::asm::*;
use target_lexicon::BinaryFormat;
use crate::global_asm::asm_supported;
use crate::prelude::*;
enum CInlineAsmOperand<'tcx> {
@ -45,208 +44,11 @@ pub(crate) fn codegen_inline_asm<'tcx>(
) {
// FIXME add .eh_frame unwind info directives
if !asm_supported(fx.tcx) {
if template.is_empty() {
let destination_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(destination_block, &[]);
return;
}
// Used by panic_abort
if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
fx.bcx.ins().trap(TrapCode::User(1));
return;
}
// Used by stdarch
if template[0] == InlineAsmTemplatePiece::String("mov ".to_string())
&& matches!(
template[1],
InlineAsmTemplatePiece::Placeholder {
operand_idx: 0,
modifier: Some('r'),
span: _
}
)
&& template[2] == InlineAsmTemplatePiece::String(", rbx".to_string())
&& template[3] == InlineAsmTemplatePiece::String("\n".to_string())
&& template[4] == InlineAsmTemplatePiece::String("cpuid".to_string())
&& template[5] == InlineAsmTemplatePiece::String("\n".to_string())
&& template[6] == InlineAsmTemplatePiece::String("xchg ".to_string())
&& matches!(
template[7],
InlineAsmTemplatePiece::Placeholder {
operand_idx: 0,
modifier: Some('r'),
span: _
}
)
&& template[8] == InlineAsmTemplatePiece::String(", rbx".to_string())
{
assert_eq!(operands.len(), 4);
let (leaf, eax_place) = match operands[1] {
InlineAsmOperand::InOut {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
late: _,
ref in_value,
out_place: Some(out_place),
} => (
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
crate::base::codegen_place(fx, out_place),
),
_ => unreachable!(),
};
let ebx_place = match operands[0] {
InlineAsmOperand::Out {
reg:
InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
X86InlineAsmRegClass::reg,
)),
late: _,
place: Some(place),
} => crate::base::codegen_place(fx, place),
_ => unreachable!(),
};
let (sub_leaf, ecx_place) = match operands[2] {
InlineAsmOperand::InOut {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)),
late: _,
ref in_value,
out_place: Some(out_place),
} => (
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
crate::base::codegen_place(fx, out_place),
),
_ => unreachable!(),
};
let edx_place = match operands[3] {
InlineAsmOperand::Out {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
late: _,
place: Some(place),
} => crate::base::codegen_place(fx, place),
_ => unreachable!(),
};
let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
let destination_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(destination_block, &[]);
return;
}
// Used by compiler-builtins
if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
// ___chkstk, ___chkstk_ms and __alloca are only used on Windows
crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
return;
} else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
crate::trap::trap_unimplemented(fx, "Alloca is not supported");
return;
}
// Used by core::hint::spin_loop()
if template[0]
== InlineAsmTemplatePiece::String(".insn i 0x0F, 0, x0, x0, 0x010".to_string())
&& template.len() == 1
{
let destination_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(destination_block, &[]);
return;
}
// Used by measureme
if template[0] == InlineAsmTemplatePiece::String("xor %eax, %eax".to_string())
&& template[1] == InlineAsmTemplatePiece::String("\n".to_string())
&& template[2] == InlineAsmTemplatePiece::String("mov %rbx, ".to_string())
&& matches!(
template[3],
InlineAsmTemplatePiece::Placeholder {
operand_idx: 0,
modifier: Some('r'),
span: _
}
)
&& template[4] == InlineAsmTemplatePiece::String("\n".to_string())
&& template[5] == InlineAsmTemplatePiece::String("cpuid".to_string())
&& template[6] == InlineAsmTemplatePiece::String("\n".to_string())
&& template[7] == InlineAsmTemplatePiece::String("mov ".to_string())
&& matches!(
template[8],
InlineAsmTemplatePiece::Placeholder {
operand_idx: 0,
modifier: Some('r'),
span: _
}
)
&& template[9] == InlineAsmTemplatePiece::String(", %rbx".to_string())
{
let destination_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(destination_block, &[]);
return;
} else if template[0] == InlineAsmTemplatePiece::String("rdpmc".to_string()) {
// Return zero dummy values for all performance counters
match operands[0] {
InlineAsmOperand::In {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)),
value: _,
} => {}
_ => unreachable!(),
};
let lo = match operands[1] {
InlineAsmOperand::Out {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
late: true,
place: Some(place),
} => crate::base::codegen_place(fx, place),
_ => unreachable!(),
};
let hi = match operands[2] {
InlineAsmOperand::Out {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
late: true,
place: Some(place),
} => crate::base::codegen_place(fx, place),
_ => unreachable!(),
};
let u32_layout = fx.layout_of(fx.tcx.types.u32);
let zero = fx.bcx.ins().iconst(types::I32, 0);
lo.write_cvalue(fx, CValue::by_val(zero, u32_layout));
hi.write_cvalue(fx, CValue::by_val(zero, u32_layout));
let destination_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(destination_block, &[]);
return;
} else if template[0] == InlineAsmTemplatePiece::String("lock xadd ".to_string())
&& matches!(
template[1],
InlineAsmTemplatePiece::Placeholder { operand_idx: 1, modifier: None, span: _ }
)
&& template[2] == InlineAsmTemplatePiece::String(", (".to_string())
&& matches!(
template[3],
InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: None, span: _ }
)
&& template[4] == InlineAsmTemplatePiece::String(")".to_string())
{
let destination_block = fx.get_block(destination.unwrap());
fx.bcx.ins().jump(destination_block, &[]);
return;
}
if cfg!(not(feature = "inline_asm")) {
fx.tcx.sess.span_err(
span,
"asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift",
);
} else {
fx.tcx.sess.span_err(span, "asm! and global_asm! are not yet supported on Windows");
}
// Used by panic_abort on Windows, but uses a syntax which only happens to work with
// asm!() by accident and breaks with the GNU assembler as well as global_asm!() for
// the LLVM backend.
if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
fx.bcx.ins().trap(TrapCode::User(1));
return;
}
@ -280,6 +82,12 @@ pub(crate) fn codegen_inline_asm<'tcx>(
CInlineAsmOperand::Const { value }
}
InlineAsmOperand::SymFn { ref value } => {
if cfg!(not(feature = "inline_asm_sym")) {
fx.tcx
.sess
.span_err(span, "asm! and global_asm! sym operands are not yet supported");
}
let const_ = fx.monomorphize(value.const_);
if let ty::FnDef(def_id, args) = *const_.ty().kind() {
let instance = ty::Instance::resolve_for_fn_ptr(

View file

@ -1,74 +0,0 @@
//! Emulation of a subset of the cpuid x86 instruction.
use crate::prelude::*;
/// Emulates a subset of the cpuid x86 instruction.
///
/// This emulates an intel cpu with sse and sse2 support, but which doesn't support anything else.
pub(crate) fn codegen_cpuid_call<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
leaf: Value,
_sub_leaf: Value,
) -> (Value, Value, Value, Value) {
let leaf_0 = fx.bcx.create_block();
let leaf_1 = fx.bcx.create_block();
let leaf_7 = fx.bcx.create_block();
let leaf_8000_0000 = fx.bcx.create_block();
let leaf_8000_0001 = fx.bcx.create_block();
let unsupported_leaf = fx.bcx.create_block();
let dest = fx.bcx.create_block();
let eax = fx.bcx.append_block_param(dest, types::I32);
let ebx = fx.bcx.append_block_param(dest, types::I32);
let ecx = fx.bcx.append_block_param(dest, types::I32);
let edx = fx.bcx.append_block_param(dest, types::I32);
let mut switch = cranelift_frontend::Switch::new();
switch.set_entry(0, leaf_0);
switch.set_entry(1, leaf_1);
switch.set_entry(7, leaf_7);
switch.set_entry(0x8000_0000, leaf_8000_0000);
switch.set_entry(0x8000_0001, leaf_8000_0001);
switch.emit(&mut fx.bcx, leaf, unsupported_leaf);
fx.bcx.switch_to_block(leaf_0);
let max_basic_leaf = fx.bcx.ins().iconst(types::I32, 1);
let vend0 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"Genu")));
let vend2 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"ineI")));
let vend1 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"ntel")));
fx.bcx.ins().jump(dest, &[max_basic_leaf, vend0, vend1, vend2]);
fx.bcx.switch_to_block(leaf_1);
let cpu_signature = fx.bcx.ins().iconst(types::I32, 0);
let additional_information = fx.bcx.ins().iconst(types::I32, 0);
let ecx_features = fx.bcx.ins().iconst(types::I32, 0);
let edx_features = fx.bcx.ins().iconst(types::I32, 1 << 25 /* sse */ | 1 << 26 /* sse2 */);
fx.bcx.ins().jump(dest, &[cpu_signature, additional_information, ecx_features, edx_features]);
fx.bcx.switch_to_block(leaf_7);
// This leaf technically has subleaves, but we just return zero for all subleaves.
let zero = fx.bcx.ins().iconst(types::I32, 0);
fx.bcx.ins().jump(dest, &[zero, zero, zero, zero]);
fx.bcx.switch_to_block(leaf_8000_0000);
let extended_max_basic_leaf = fx.bcx.ins().iconst(types::I32, 0);
let zero = fx.bcx.ins().iconst(types::I32, 0);
fx.bcx.ins().jump(dest, &[extended_max_basic_leaf, zero, zero, zero]);
fx.bcx.switch_to_block(leaf_8000_0001);
let zero = fx.bcx.ins().iconst(types::I32, 0);
let proc_info_ecx = fx.bcx.ins().iconst(types::I32, 0);
let proc_info_edx = fx.bcx.ins().iconst(types::I32, 0);
fx.bcx.ins().jump(dest, &[zero, zero, proc_info_ecx, proc_info_edx]);
fx.bcx.switch_to_block(unsupported_leaf);
crate::trap::trap_unimplemented(
fx,
"__cpuid_count arch intrinsic doesn't yet support specified leaf",
);
fx.bcx.switch_to_block(dest);
fx.bcx.ins().nop();
(eax, ebx, ecx, edx)
}

View file

@ -32,41 +32,6 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
ret.write_cvalue(fx, CValue::by_val(res, fx.layout_of(fx.tcx.types.i64)));
}
// Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
"llvm.x86.sse2.pmovmskb.128"
| "llvm.x86.avx2.pmovmskb"
| "llvm.x86.sse.movmsk.ps"
| "llvm.x86.sse2.movmsk.pd" => {
intrinsic_args!(fx, args => (a); intrinsic);
let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
let lane_ty = fx.clif_type(lane_ty).unwrap();
assert!(lane_count <= 32);
let mut res = fx.bcx.ins().iconst(types::I32, 0);
for lane in (0..lane_count).rev() {
let a_lane = a.value_lane(fx, lane).load_scalar(fx);
// cast float to int
let a_lane = match lane_ty {
types::F32 => codegen_bitcast(fx, types::I32, a_lane),
types::F64 => codegen_bitcast(fx, types::I64, a_lane),
_ => a_lane,
};
// extract sign bit of an int
let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1));
// shift sign bit into result
let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false);
res = fx.bcx.ins().ishl_imm(res, 1);
res = fx.bcx.ins().bor(res, a_lane_sign);
}
let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
ret.write_cvalue(fx, res);
}
"llvm.x86.sse.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
let (x, y, kind) = match args {
[x, y, kind] => (x, y, kind),

View file

@ -12,7 +12,6 @@ macro_rules! intrinsic_args {
}
}
mod cpuid;
mod llvm;
mod llvm_aarch64;
mod llvm_x86;
@ -25,7 +24,6 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::GenericArgsRef;
use rustc_span::symbol::{kw, sym, Symbol};
pub(crate) use self::cpuid::codegen_cpuid_call;
pub(crate) use self::llvm::codegen_llvm_intrinsic_call;
use crate::prelude::*;

View file

@ -19,9 +19,8 @@ jobs:
fail-fast: false
matrix:
libgccjit_version:
- { gcc: "libgccjit.so", extra: "", env_extra: "", artifacts_branch: "master" }
- { gcc: "libgccjit_without_int128.so", extra: "", env_extra: "", artifacts_branch: "master-without-128bit-integers" }
- { gcc: "libgccjit12.so", extra: "--no-default-features", env_extra: "TEST_FLAGS='-Cpanic=abort -Zpanic-abort-tests'", artifacts_branch: "gcc12" }
- { gcc: "libgccjit.so", artifacts_branch: "master" }
- { gcc: "libgccjit_without_int128.so", artifacts_branch: "master-without-128bit-integers" }
commands: [
"--mini-tests",
"--std-tests",
@ -33,27 +32,16 @@ jobs:
"--extended-regex-tests",
"--test-successful-rustc --nb-parts 2 --current-part 0",
"--test-successful-rustc --nb-parts 2 --current-part 1",
"--test-failing-rustc",
]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3
with:
repository: llvm/llvm-project
path: llvm
- name: Install packages
# `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 libgccjit12
if: matrix.libgccjit_version.gcc == 'libgccjit12.so'
run: sudo apt-get install libgccjit-12-dev
- name: Download artifact
if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
uses: dawidd6/action-download-artifact@v2
with:
workflow: main.yml
@ -65,11 +53,6 @@ jobs:
search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts.
- name: Setup path to libgccjit
if: matrix.libgccjit_version.gcc == 'libgccjit12.so'
run: echo /usr/lib/gcc/x86_64-linux-gnu/12 > gcc_path
- name: Setup path to libgccjit
if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
run: |
sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb
echo /usr/lib/ > gcc_path
@ -80,9 +63,6 @@ jobs:
echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
- name: Set RUST_COMPILER_RT_ROOT
run: echo "RUST_COMPILER_RT_ROOT="${{ env.workspace }}/llvm/compiler-rt >> $GITHUB_ENV
- name: Cache cargo installed crates
uses: actions/cache@v3
with:
@ -119,8 +99,8 @@ jobs:
- name: Build
run: |
./y.sh prepare --only-libcore
${{ matrix.libgccjit_version.env_extra }} ./y.sh build ${{ matrix.libgccjit_version.extra }}
${{ matrix.libgccjit_version.env_extra }} cargo test ${{ matrix.libgccjit_version.extra }}
./y.sh build
cargo test
./clean_all.sh
- name: Prepare dependencies
@ -136,16 +116,12 @@ jobs:
command: build
args: --release
- name: Add more failing tests for GCC 12
if: ${{ matrix.libgccjit_version.gcc == 'libgccjit12.so' }}
run: cat failing-ui-tests12.txt >> failing-ui-tests.txt
- name: Add more failing tests because the sysroot is not compiled with LTO
run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt
- name: Run tests
run: |
${{ matrix.libgccjit_version.env_extra }} ./test.sh --release --clean --build-sysroot ${{ matrix.commands }} ${{ matrix.libgccjit_version.extra }}
./test.sh --release --clean --build-sysroot ${{ matrix.commands }}
duplicates:
runs-on: ubuntu-latest

View file

@ -0,0 +1,129 @@
# TODO: refactor to avoid duplication with the ci.yml file.
name: Failures
on:
- pull_request
permissions:
contents: read
env:
# Enable backtraces for easier debugging
RUST_BACKTRACE: 1
jobs:
build:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
libgccjit_version:
- gcc: "libgccjit.so"
artifacts_branch: "master"
- gcc: "libgccjit_without_int128.so"
artifacts_branch: "master-without-128bit-integers"
- gcc: "libgccjit12.so"
artifacts_branch: "gcc12"
extra: "--no-default-features"
# FIXME(antoyo): we need to set GCC_EXEC_PREFIX so that the linker can find the linker plugin.
# Not sure why it's not found otherwise.
env_extra: "TEST_FLAGS='-Cpanic=abort -Zpanic-abort-tests' GCC_EXEC_PREFIX=/usr/lib/gcc/"
steps:
- uses: actions/checkout@v3
- name: Install packages
run: sudo apt-get install ninja-build ripgrep
- name: Install libgccjit12
if: matrix.libgccjit_version.gcc == 'libgccjit12.so'
run: sudo apt-get install libgccjit-12-dev
- name: Setup path to libgccjit
if: matrix.libgccjit_version.gcc == 'libgccjit12.so'
run: echo /usr/lib/gcc/x86_64-linux-gnu/12 > gcc_path
- name: Download artifact
if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
uses: dawidd6/action-download-artifact@v2
with:
workflow: main.yml
name: gcc-13
path: gcc-13
repo: antoyo/gcc
branch: ${{ matrix.libgccjit_version.artifacts_branch }}
event: push
search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts.
- name: Setup path to libgccjit
if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
run: |
sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb
echo /usr/lib/ > gcc_path
- name: Set env
run: |
echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
- name: Cache cargo installed crates
uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: cargo-installed-crates2-ubuntu-latest
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
uses: actions/cache@v3
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }}
#- name: Cache rust repository
#uses: actions/cache@v3
#id: cache-rust-repository
#with:
#path: rust
#key: ${{ runner.os }}-packages-${{ hashFiles('rust/.git/HEAD') }}
- name: Git config
run: |
git config --global user.email "user@example.com"
git config --global user.name "User"
- name: Prepare dependencies
if: matrix.libgccjit_version.gcc == 'libgccjit12.so'
run: ./y.sh prepare --libgccjit12-patches
- name: Prepare dependencies
if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
run: ./y.sh prepare
# Compile is a separate step, as the actions-rs/cargo action supports error annotations
- name: Compile
uses: actions-rs/cargo@v1.0.3
with:
command: build
args: --release
- name: Add more failing tests because the sysroot is not compiled with LTO
run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt
- name: Run tests
id: tests
run: |
${{ matrix.libgccjit_version.env_extra }} ./test.sh --release --clean --build-sysroot --test-failing-rustc ${{ matrix.libgccjit_version.extra }} | tee output_log
rg --text "test result" output_log >> $GITHUB_STEP_SUMMARY

View file

@ -0,0 +1,115 @@
name: CI libgccjit 12
on:
- push
- pull_request
permissions:
contents: read
env:
# Enable backtraces for easier debugging
RUST_BACKTRACE: 1
TEST_FLAGS: "-Cpanic=abort -Zpanic-abort-tests"
# FIXME(antoyo): we need to set GCC_EXEC_PREFIX so that the linker can find the linker plugin.
# Not sure why it's not found otherwise.
GCC_EXEC_PREFIX: /usr/lib/gcc/
jobs:
build:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
commands: [
"--mini-tests",
"--std-tests",
# FIXME: re-enable asm tests when GCC can emit in the right syntax.
# "--asm-tests",
"--test-libcore",
"--extended-rand-tests",
"--extended-regex-example-tests",
"--extended-regex-tests",
"--test-successful-rustc --nb-parts 2 --current-part 0",
"--test-successful-rustc --nb-parts 2 --current-part 1",
]
steps:
- uses: actions/checkout@v3
- name: Install packages
# `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 libgccjit-12-dev
- name: Setup path to libgccjit
run: echo /usr/lib/gcc/x86_64-linux-gnu/12 > gcc_path
- name: Set env
run: |
echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
- name: Cache cargo installed crates
uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: cargo-installed-crates2-ubuntu-latest
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
uses: actions/cache@v3
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }}
#- name: Cache rust repository
## We only clone the rust repository for rustc tests
#if: ${{ contains(matrix.commands, 'rustc') }}
#uses: actions/cache@v3
#id: cache-rust-repository
#with:
#path: rust
#key: ${{ runner.os }}-packages-${{ hashFiles('rust/.git/HEAD') }}
- name: Build
run: |
./y.sh prepare --only-libcore --libgccjit12-patches
./y.sh build --no-default-features --sysroot-panic-abort
cargo test --no-default-features
./clean_all.sh
- name: Prepare dependencies
run: |
git config --global user.email "user@example.com"
git config --global user.name "User"
./y.sh prepare --libgccjit12-patches
# Compile is a separate step, as the actions-rs/cargo action supports error annotations
- name: Compile
uses: actions-rs/cargo@v1.0.3
with:
command: build
args: --release
- name: Add more failing tests for GCC 12
run: cat failing-ui-tests12.txt >> failing-ui-tests.txt
- name: Add more failing tests because the sysroot is not compiled with LTO
run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt
- name: Run tests
run: |
./test.sh --release --clean --build-sysroot ${{ matrix.commands }} --no-default-features

View file

@ -0,0 +1,139 @@
# TODO: check if qemu-user-static-binfmt is needed (perhaps to run some tests since it probably calls exec).
name: m68k CI
on:
- push
- pull_request
permissions:
contents: read
env:
# Enable backtraces for easier debugging
RUST_BACKTRACE: 1
# TODO: remove when confish.sh is removed.
OVERWRITE_TARGET_TRIPLE: m68k-unknown-linux-gnu
jobs:
build:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
commands: [
"--mini-tests",
"--std-tests",
# TODO(antoyo): fix those on m68k.
#"--test-libcore",
#"--extended-rand-tests",
#"--extended-regex-example-tests",
#"--extended-regex-tests",
#"--test-successful-rustc --nb-parts 2 --current-part 0",
#"--test-successful-rustc --nb-parts 2 --current-part 1",
#"--test-failing-rustc",
]
steps:
- name: Install packages
run: |
sudo apt-get update
sudo apt-get install qemu qemu-user-static
- uses: actions/checkout@v3
- name: Download GCC artifact
uses: dawidd6/action-download-artifact@v2
with:
workflow: m68k.yml
name: gcc-m68k-13
repo: cross-cg-gcc-tools/cross-gcc
branch: master
event: push
- name: Download VM artifact
uses: dawidd6/action-download-artifact@v2
with:
workflow: m68k.yml
name: debian-m68k
repo: cross-cg-gcc-tools/vms
branch: master
event: push
- name: Setup path to libgccjit
run: |
sudo dpkg -i gcc-m68k-13.deb
echo /usr/lib/ > gcc_path
- name: Set env
run: |
echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
- name: Cache cargo installed crates
uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: cargo-installed-crates2-ubuntu-latest
#- name: Cache cargo registry
#uses: actions/cache@v3
#with:
#path: ~/.cargo/registry
#key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }}
#- name: Cache cargo index
#uses: actions/cache@v3
#with:
#path: ~/.cargo/git
#key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }}
#- name: Cache rust repository
## We only clone the rust repository for rustc tests
#if: ${{ contains(matrix.commands, 'rustc') }}
#uses: actions/cache@v3
#id: cache-rust-repository
#with:
#path: rust
#key: ${{ runner.os }}-packages-${{ hashFiles('rust/.git/HEAD') }}
- name: Prepare VM
run: |
mkdir vm
sudo mount debian-m68k.img vm
sudo cp $(which qemu-m68k-static) vm/usr/bin/
- name: Build
run: |
./y.sh prepare --only-libcore --cross
./y.sh build --target-triple m68k-unknown-linux-gnu
CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test
./clean_all.sh
- name: Prepare dependencies
run: |
git config --global user.email "user@example.com"
git config --global user.name "User"
./y.sh prepare --cross
# Compile is a separate step, as the actions-rs/cargo action supports error annotations
- name: Compile
uses: actions-rs/cargo@v1.0.3
with:
command: build
args: --release
- name: Add more failing tests because the sysroot is not compiled with LTO
run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt
- name: Run tests
run: |
./test.sh --release --clean --build-sysroot ${{ matrix.commands }}

View file

@ -26,11 +26,6 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3
with:
repository: llvm/llvm-project
path: llvm
- name: Install packages
run: sudo apt-get install ninja-build ripgrep
@ -56,9 +51,6 @@ jobs:
echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
- name: Set RUST_COMPILER_RT_ROOT
run: echo "RUST_COMPILER_RT_ROOT="${{ env.workspace }}/llvm/compiler-rt >> $GITHUB_ENV
- name: Cache cargo installed crates
uses: actions/cache@v3
with:

View file

@ -26,11 +26,6 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3
with:
repository: llvm/llvm-project
path: llvm
- name: Install packages
run: sudo apt-get install ninja-build ripgrep
@ -70,9 +65,6 @@ jobs:
echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
- name: Set RUST_COMPILER_RT_ROOT
run: echo "RUST_COMPILER_RT_ROOT="${{ env.workspace }}/llvm/compiler-rt >> $GITHUB_ENV
- name: Cache cargo installed crates
uses: actions/cache@v3
with:

View file

@ -0,0 +1,10 @@
!/build_sysroot/sysroot_src
!/simple-raytracer
!/regex
!/rand
!/test-backend
!/gcc_path
!/benchmarks
!*gimple*
!*asm*
!.github

View file

@ -74,7 +74,7 @@ dependencies = [
[[package]]
name = "gccjit"
version = "1.0.0"
source = "git+https://github.com/antoyo/gccjit.rs#0b158c68bf7e46732869d90550a98e886dee8858"
source = "git+https://github.com/antoyo/gccjit.rs#c52a218f5529321285b4489e5562a00e5428e033"
dependencies = [
"gccjit_sys",
]
@ -82,7 +82,7 @@ dependencies = [
[[package]]
name = "gccjit_sys"
version = "0.0.1"
source = "git+https://github.com/antoyo/gccjit.rs#0b158c68bf7e46732869d90550a98e886dee8858"
source = "git+https://github.com/antoyo/gccjit.rs#c52a218f5529321285b4489e5562a00e5428e033"
dependencies = [
"libc",
]

View file

@ -55,13 +55,6 @@ $ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=jit.dg/test-asm.cc"
$ dirname $(readlink -f `find . -name libgccjit.so`) > gcc_path
```
You also need to set RUST_COMPILER_RT_ROOT:
```bash
$ git clone https://github.com/llvm/llvm-project llvm --depth 1 --single-branch
$ export RUST_COMPILER_RT_ROOT="$PWD/llvm/compiler-rt"
```
Then you can run commands like this:
```bash
@ -91,9 +84,17 @@ $ CHANNEL="release" $CG_GCCJIT_DIR/cargo.sh run
If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./test.sh`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely.
### LTO
To use LTO, you need to set the variable `FAT_LTO=1` and `EMBED_LTO_BITCODE=1` in addition to setting `lto = "fat"` in the `Cargo.toml`.
Don't set `FAT_LTO` when compiling the sysroot, though: only set `EMBED_LTO_BITCODE=1`.
Failing to set `EMBED_LTO_BITCODE` will give you the following error:
```
error: failed to copy bitcode to object file: No such file or directory (os error 2)
```
### Rustc
> You should prefer using the Cargo method.
@ -286,6 +287,16 @@ git checkout sync_branch_name
git merge master
```
To send the changes to the rust repo:
```bash
cd ../rust
git pull origin master
git checkout -b subtree-update_cg_gcc_YYYY-MM-DD
PATH="$HOME/bin:$PATH" ~/bin/git-subtree pull --prefix=compiler/rustc_codegen_gcc/ https://github.com/rust-lang/rustc_codegen_gcc.git master
git push
```
TODO: write a script that does the above.
https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.20madness/near/258877725
@ -303,16 +314,25 @@ generate it in [gimple.md](./doc/gimple.md).
#### Building libgccjit
* Follow these instructions: https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/ with the following changes:
* Configure gcc with `../gcc/configure --enable-host-shared --disable-multilib --enable-languages=c,jit,c++ --disable-bootstrap --enable-checking=release --prefix=/opt/m68k-gcc/ --target=m68k-linux --without-headers`.
* Some shells, like fish, don't define the environment variable `$MACHTYPE`.
* Add `CFLAGS="-Wno-error=attributes -g -O2"` at the end of the configure command for building glibc (`CFLAGS="-Wno-error=attributes -Wno-error=array-parameter -Wno-error=stringop-overflow -Wno-error=array-bounds -g -O2"` for glibc 2.31, which is useful for Debian).
* Follow the instructions on [this repo](https://github.com/cross-cg-gcc-tools/cross-gcc).
#### Configuring rustc_codegen_gcc
* Set `TARGET_TRIPLE="m68k-unknown-linux-gnu"` in config.sh.
* Since rustc doesn't support this architecture yet, set it back to `TARGET_TRIPLE="mips-unknown-linux-gnu"` (or another target having the same attributes). Alternatively, create a [target specification file](https://book.avr-rust.com/005.1-the-target-specification-json-file.html) (note that the `arch` specified in this file must be supported by the rust compiler).
* Set `linker='-Clinker=m68k-linux-gcc'`.
* Run `./y.sh prepare --cross` so that the sysroot is patched for the cross-compiling case.
* Set the path to the cross-compiling libgccjit in `gcc_path`.
* Comment the line: `context.add_command_line_option("-masm=intel");` in src/base.rs.
* (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?): Remove dylib from build_sysroot/sysroot_src/library/std/Cargo.toml.
* Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. Currently, the linker name is hardcoded as being `$TARGET-gcc`. Specify the target when building the sysroot: `./y.sh build --target-triple m68k-unknown-linux-gnu`.
* Build your project by specifying the target: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../cargo.sh build --target m68k-unknown-linux-gnu`.
If the target is not yet supported by the Rust compiler, create a [target specification file](https://docs.rust-embedded.org/embedonomicon/custom-target.html) (note that the `arch` specified in this file must be supported by the rust compiler).
Then, you can use it the following way:
* Add the target specification file using `--target` as an **absolute** path to build the sysroot: `./y.sh build --target-triple m68k-unknown-linux-gnu --target $(pwd)/m68k-unknown-linux-gnu.json`
* Build your project by specifying the target specification file: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../cargo.sh build --target path/to/m68k-unknown-linux-gnu.json`.
If you get the following error:
```
/usr/bin/ld: unrecognised emulation mode: m68kelf
```
Make sure you set `gcc_path` to the install directory.

View file

@ -22,7 +22,7 @@ if [[ "$1" == "--release" ]]; then
RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target $TARGET_TRIPLE --release
else
sysroot_channel='debug'
cargo build --target $TARGET_TRIPLE --features compiler_builtins/c
cargo build --target $TARGET_TRIPLE
fi
# Copy files to sysroot

View file

@ -1,6 +1,6 @@
use crate::config::set_config;
use crate::config::{set_config, ConfigInfo};
use crate::utils::{
get_gcc_path, run_command, run_command_with_env, run_command_with_output_and_env, walk_dir,
get_gcc_path, run_command, run_command_with_output_and_env, walk_dir,
};
use std::collections::HashMap;
use std::ffi::OsStr;
@ -11,7 +11,8 @@ use std::path::Path;
struct BuildArg {
codegen_release_channel: bool,
sysroot_release_channel: bool,
features: Vec<String>,
sysroot_panic_abort: bool,
flags: Vec<String>,
gcc_path: String,
}
@ -30,12 +31,15 @@ impl BuildArg {
"--release" => build_arg.codegen_release_channel = true,
"--release-sysroot" => build_arg.sysroot_release_channel = true,
"--no-default-features" => {
build_arg.features.push("--no-default-features".to_string());
build_arg.flags.push("--no-default-features".to_string());
}
"--sysroot-panic-abort" => {
build_arg.sysroot_panic_abort = true;
},
"--features" => {
if let Some(arg) = args.next() {
build_arg.features.push("--features".to_string());
build_arg.features.push(arg.as_str().into());
build_arg.flags.push("--features".to_string());
build_arg.flags.push(arg.as_str().into());
} else {
return Err(
"Expected a value after `--features`, found nothing".to_string()
@ -46,6 +50,24 @@ impl BuildArg {
Self::usage();
return Ok(None);
}
"--target-triple" => {
if args.next().is_some() {
// Handled in config.rs.
} else {
return Err(
"Expected a value after `--target-triple`, found nothing".to_string()
);
}
}
"--target" => {
if args.next().is_some() {
// Handled in config.rs.
} else {
return Err(
"Expected a value after `--target`, found nothing".to_string()
);
}
}
arg => return Err(format!("Unknown argument `{}`", arg)),
}
}
@ -59,8 +81,10 @@ impl BuildArg {
--release : Build codegen in release mode
--release-sysroot : Build sysroot in release mode
--sysroot-panic-abort : Build the sysroot without unwinding support.
--no-default-features : Add `--no-default-features` flag
--features [arg] : Add a new feature [arg]
--target-triple [arg] : Set the target triple to [arg]
--help : Show this help
"#
)
@ -69,8 +93,8 @@ impl BuildArg {
fn build_sysroot(
env: &mut HashMap<String, String>,
release_mode: bool,
target_triple: &str,
args: &BuildArg,
config: &ConfigInfo,
) -> Result<(), String> {
std::env::set_current_dir("build_sysroot")
.map_err(|error| format!("Failed to go to `build_sysroot` directory: {:?}", error))?;
@ -119,21 +143,24 @@ fn build_sysroot(
let _ = fs::remove_dir_all("sysroot");
// Builds libs
let channel = if release_mode {
let rustflags = env
.get("RUSTFLAGS")
.cloned()
.unwrap_or_default();
env.insert(
"RUSTFLAGS".to_string(),
format!("{} -Zmir-opt-level=3", rustflags),
);
let mut rustflags = env
.get("RUSTFLAGS")
.cloned()
.unwrap_or_default();
if args.sysroot_panic_abort {
rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests");
}
env.insert(
"RUSTFLAGS".to_string(),
format!("{} -Zmir-opt-level=3", rustflags),
);
let channel = if args.sysroot_release_channel {
run_command_with_output_and_env(
&[
&"cargo",
&"build",
&"--target",
&target_triple,
&config.target,
&"--release",
],
None,
@ -146,9 +173,7 @@ fn build_sysroot(
&"cargo",
&"build",
&"--target",
&target_triple,
&"--features",
&"compiler_builtins/c",
&config.target,
],
None,
Some(env),
@ -157,14 +182,14 @@ fn build_sysroot(
};
// Copy files to sysroot
let sysroot_path = format!("sysroot/lib/rustlib/{}/lib/", target_triple);
let sysroot_path = format!("sysroot/lib/rustlib/{}/lib/", config.target_triple);
fs::create_dir_all(&sysroot_path)
.map_err(|error| format!("Failed to create directory `{}`: {:?}", sysroot_path, error))?;
let copier = |dir_to_copy: &Path| {
run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ())
};
walk_dir(
&format!("target/{}/{}/deps", target_triple, channel),
&format!("target/{}/{}/deps", config.target_triple, channel),
copier,
copier,
)?;
@ -175,16 +200,6 @@ fn build_sysroot(
fn build_codegen(args: &BuildArg) -> Result<(), String> {
let mut env = HashMap::new();
let current_dir =
std::env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?;
if let Ok(rt_root) = std::env::var("RUST_COMPILER_RT_ROOT") {
env.insert("RUST_COMPILER_RT_ROOT".to_string(), rt_root);
} else {
env.insert(
"RUST_COMPILER_RT_ROOT".to_string(),
format!("{}", current_dir.join("llvm/compiler-rt").display()),
);
}
env.insert("LD_LIBRARY_PATH".to_string(), args.gcc_path.clone());
env.insert("LIBRARY_PATH".to_string(), args.gcc_path.clone());
@ -196,11 +211,11 @@ fn build_codegen(args: &BuildArg) -> Result<(), String> {
} else {
env.insert("CHANNEL".to_string(), "debug".to_string());
}
let ref_features = args.features.iter().map(|s| s.as_str()).collect::<Vec<_>>();
for feature in &ref_features {
command.push(feature);
let flags = args.flags.iter().map(|s| s.as_str()).collect::<Vec<_>>();
for flag in &flags {
command.push(flag);
}
run_command_with_env(&command, None, Some(&env))?;
run_command_with_output_and_env(&command, None, Some(&env))?;
let config = set_config(&mut env, &[], Some(&args.gcc_path))?;
@ -217,8 +232,8 @@ fn build_codegen(args: &BuildArg) -> Result<(), String> {
println!("[BUILD] sysroot");
build_sysroot(
&mut env,
args.sysroot_release_channel,
&config.target_triple,
args,
&config,
)?;
Ok(())
}

View file

@ -3,9 +3,9 @@ use std::collections::HashMap;
use std::env as std_env;
pub struct ConfigInfo {
pub target: String,
pub target_triple: String,
pub rustc_command: Vec<String>,
pub run_wrapper: Option<&'static str>,
}
// Returns the beginning for the command line of rustc.
@ -30,22 +30,46 @@ pub fn set_config(
};
let host_triple = get_rustc_host_triple()?;
let mut linker = None;
let mut target_triple = host_triple.as_str();
let mut run_wrapper = None;
// FIXME: handle this with a command line flag?
// let mut target_triple = "m68k-unknown-linux-gnu";
let mut target_triple = host_triple.clone();
let mut target = target_triple.clone();
// We skip binary name and the command.
let mut args = std::env::args().skip(2);
let mut set_target_triple = false;
let mut set_target = false;
while let Some(arg) = args.next() {
match arg.as_str() {
"--target-triple" => {
if let Some(arg) = args.next() {
target_triple = arg;
set_target_triple = true;
} else {
return Err(
"Expected a value after `--target-triple`, found nothing".to_string()
);
}
},
"--target" => {
if let Some(arg) = args.next() {
target = arg;
set_target = true;
} else {
return Err(
"Expected a value after `--target`, found nothing".to_string()
);
}
},
_ => (),
}
}
if set_target_triple && !set_target {
target = target_triple.clone();
}
if host_triple != target_triple {
if target_triple == "m68k-unknown-linux-gnu" {
target_triple = "mips-unknown-linux-gnu";
linker = Some("-Clinker=m68k-linux-gcc");
} else if target_triple == "aarch64-unknown-linux-gnu" {
// We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
linker = Some("-Clinker=aarch64-linux-gnu-gcc");
run_wrapper = Some("qemu-aarch64 -L /usr/aarch64-linux-gnu");
} else {
return Err(format!("unknown non-native platform `{}`", target_triple));
}
linker = Some(format!("-Clinker={}-gcc", target_triple));
}
let current_dir =
std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?;
@ -118,8 +142,8 @@ pub fn set_config(
"target/out".to_string(),
]);
Ok(ConfigInfo {
target_triple: target_triple.to_string(),
target,
target_triple,
rustc_command,
run_wrapper,
})
}

View file

@ -5,6 +5,7 @@ mod build;
mod config;
mod prepare;
mod rustc_info;
mod test;
mod utils;
macro_rules! arg_error {
@ -23,6 +24,7 @@ Available commands for build_system:
prepare : Run prepare command
build : Run build command
test : Run test command
--help : Show this message"
);
}
@ -30,6 +32,7 @@ Available commands for build_system:
pub enum Command {
Prepare,
Build,
Test,
}
fn main() {
@ -40,6 +43,7 @@ fn main() {
let command = match env::args().nth(1).as_deref() {
Some("prepare") => Command::Prepare,
Some("build") => Command::Build,
Some("test") => Command::Test,
Some("--help") => {
usage();
process::exit(0);
@ -55,6 +59,7 @@ fn main() {
if let Err(e) = match command {
Command::Prepare => prepare::run(),
Command::Build => build::run(),
Command::Test => test::run(),
} {
eprintln!("Command failed to run: {e:?}");
process::exit(1);

View file

@ -4,7 +4,7 @@ use crate::utils::{cargo_install, git_clone, run_command, run_command_with_outpu
use std::fs;
use std::path::Path;
fn prepare_libcore(sysroot_path: &Path) -> Result<(), String> {
fn prepare_libcore(sysroot_path: &Path, libgccjit12_patches: bool, cross_compile: bool) -> Result<(), String> {
let rustc_path = match get_rustc_path() {
Some(path) => path,
None => return Err("`rustc` path not found".to_string()),
@ -87,6 +87,22 @@ fn prepare_libcore(sysroot_path: &Path) -> Result<(), String> {
Ok(())
},
)?;
if cross_compile {
walk_dir("cross_patches", |_| Ok(()), |file_path: &Path| {
patches.push(file_path.to_path_buf());
Ok(())
})?;
}
if libgccjit12_patches {
walk_dir(
"patches/libgccjit12",
|_| Ok(()),
|file_path: &Path| {
patches.push(file_path.to_path_buf());
Ok(())
},
)?;
}
patches.sort();
for file_path in patches {
println!("[GIT] apply `{}`", file_path.display());
@ -156,16 +172,22 @@ where
}
struct PrepareArg {
cross_compile: bool,
only_libcore: bool,
libgccjit12_patches: bool,
}
impl PrepareArg {
fn new() -> Result<Option<Self>, String> {
let mut only_libcore = false;
let mut cross_compile = false;
let mut libgccjit12_patches = false;
for arg in std::env::args().skip(2) {
match arg.as_str() {
"--only-libcore" => only_libcore = true,
"--cross" => cross_compile = true,
"--libgccjit12-patches" => libgccjit12_patches = true,
"--help" => {
Self::usage();
return Ok(None);
@ -173,7 +195,11 @@ impl PrepareArg {
a => return Err(format!("Unknown argument `{a}`")),
}
}
Ok(Some(Self { only_libcore }))
Ok(Some(Self {
cross_compile,
only_libcore,
libgccjit12_patches,
}))
}
fn usage() {
@ -181,8 +207,10 @@ impl PrepareArg {
r#"
`prepare` command help:
--only-libcore : Only setup libcore and don't clone other repositories
--help : Show this help
--only-libcore : Only setup libcore and don't clone other repositories
--cross : Apply the patches needed to do cross-compilation
--libgccjit12-patches : Apply patches needed for libgccjit12
--help : Show this help
"#
)
}
@ -194,7 +222,7 @@ pub fn run() -> Result<(), String> {
None => return Ok(()),
};
let sysroot_path = Path::new("build_sysroot");
prepare_libcore(sysroot_path)?;
prepare_libcore(sysroot_path, args.libgccjit12_patches, args.cross_compile)?;
if !args.only_libcore {
cargo_install("hyperfine")?;

View file

@ -0,0 +1,15 @@
use crate::utils::run_command_with_output;
fn get_args<'a>(args: &mut Vec<&'a dyn AsRef<std::ffi::OsStr>>, extra_args: &'a Vec<String>) {
for extra_arg in extra_args {
args.push(extra_arg);
}
}
pub fn run() -> Result<(), String> {
let mut args: Vec<&dyn AsRef<std::ffi::OsStr>> = vec![&"bash", &"test.sh"];
let extra_args = std::env::args().skip(2).collect::<Vec<_>>();
get_args(&mut args, &extra_args);
let current_dir = std::env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?;
run_command_with_output(args.as_slice(), Some(&current_dir))
}

View file

@ -12,7 +12,7 @@ TOOLCHAIN=$(cat rust-toolchain | grep channel | sed 's/channel = "\(.*\)"/\1/')
popd >/dev/null
if [[ $(rustc -V) != $(rustc +${TOOLCHAIN} -V) ]]; then
if [[ $(${RUSTC} -V) != $(${RUSTC} +${TOOLCHAIN} -V) ]]; then
echo "rustc_codegen_gcc is build for $(rustc +${TOOLCHAIN} -V) but the default rustc version is $(rustc -V)."
echo "Using $(rustc +${TOOLCHAIN} -V)."
fi

View file

@ -4,38 +4,43 @@ export CARGO_INCREMENTAL=0
if [ -f ./gcc_path ]; then
export GCC_PATH=$(cat gcc_path)
elif (( $use_system_gcc == 1 )); then
echo 'Using system GCC'
else
echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
exit 1
fi
if [[ -z "$RUSTC" ]]; then
export RUSTC="rustc"
fi
unamestr=`uname`
if [[ "$unamestr" == 'Linux' ]]; then
dylib_ext='so'
dylib_ext='so'
elif [[ "$unamestr" == 'Darwin' ]]; then
dylib_ext='dylib'
dylib_ext='dylib'
else
echo "Unsupported os"
exit 1
echo "Unsupported os"
exit 1
fi
HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
TARGET_TRIPLE=$HOST_TRIPLE
#TARGET_TRIPLE="m68k-unknown-linux-gnu"
# TODO: remove $OVERWRITE_TARGET_TRIPLE when config.sh is removed.
TARGET_TRIPLE="${OVERWRITE_TARGET_TRIPLE:-$HOST_TRIPLE}"
linker=''
RUN_WRAPPER=''
if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
if [[ "$TARGET_TRIPLE" == "m68k-unknown-linux-gnu" ]]; then
TARGET_TRIPLE="mips-unknown-linux-gnu"
linker='-Clinker=m68k-linux-gcc'
elif [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
# We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
linker='-Clinker=aarch64-linux-gnu-gcc'
RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
else
echo "Unknown non-native platform"
fi
RUN_WRAPPER=run_in_vm
if [[ "$TARGET_TRIPLE" == "m68k-unknown-linux-gnu" ]]; then
linker='-Clinker=m68k-unknown-linux-gnu-gcc'
elif [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
# We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
linker='-Clinker=aarch64-linux-gnu-gcc'
else
echo "Unknown non-native platform"
fi
fi
# Since we don't support ThinLTO, disable LTO completely when not trying to do LTO.
@ -45,19 +50,32 @@ if [[ ! -v FAT_LTO ]]; then
disable_lto_flags='-Clto=off'
fi
export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 $disable_lto_flags -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot $TEST_FLAGS"
if [[ -z "$BUILTIN_BACKEND" ]]; then
export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 $disable_lto_flags -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot $TEST_FLAGS"
else
export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 $disable_lto_flags -Zcodegen-backend=gcc $TEST_FLAGS -Cpanic=abort"
fi
# FIXME(antoyo): remove once the atomic shim is gone
if [[ unamestr == 'Darwin' ]]; then
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
fi
RUSTC="rustc $RUSTFLAGS -L crate=target/out --out-dir target/out"
if [[ -z "$cargo_target_dir" ]]; then
RUST_CMD="$RUSTC $RUSTFLAGS -L crate=target/out --out-dir target/out"
cargo_target_dir="target/out"
else
RUST_CMD="$RUSTC $RUSTFLAGS -L crate=$cargo_target_dir --out-dir $cargo_target_dir"
fi
export RUSTC_LOG=warn # display metadata load errors
export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib:$GCC_PATH"
export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib"
if [[ ! -z "$:$GCC_PATH" ]]; then
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$GCC_PATH"
fi
export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
# NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc.
# To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH.
# Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc
export PATH="/opt/gcc/bin:$PATH"
export PATH="/opt/gcc/bin:/opt/m68k-unknown-linux-gnu/bin:$PATH"

View file

@ -0,0 +1,39 @@
From 966beefe08be6045bfcca26079b76a7a80413080 Mon Sep 17 00:00:00 2001
From: None <none@example.com>
Date: Thu, 28 Sep 2023 17:37:38 -0400
Subject: [PATCH] Disable libstd and libtest dylib
---
library/std/Cargo.toml | 2 +-
library/test/Cargo.toml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 5b21355..cb0c49b 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -9,7 +9,7 @@ description = "The Rust Standard Library"
edition = "2021"
[lib]
-crate-type = ["dylib", "rlib"]
+crate-type = ["rlib"]
[dependencies]
alloc = { path = "../alloc", public = true }
diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml
index 91a1abd..a58c160 100644
--- a/library/test/Cargo.toml
+++ b/library/test/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
edition = "2021"
[lib]
-crate-type = ["dylib", "rlib"]
+crate-type = ["rlib"]
[dependencies]
getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] }
--
2.42.0

View file

@ -0,0 +1,5 @@
# Tests
## Show the rustc command for UI tests
Add ` --test-args "--verbose"` to `./x.py test`.

View file

@ -9,6 +9,7 @@
// add fast paths for low alignment values.
#[cfg(any(target_arch = "x86",
target_arch = "arm",
target_arch = "m68k",
target_arch = "mips",
target_arch = "mips32r6",
target_arch = "powerpc",

View file

@ -152,7 +152,8 @@ fn main() {
let slice = &[0, 1] as &[i32];
let slice_ptr = slice as *const [i32] as *const i32;
assert_eq!(slice_ptr as usize % 4, 0);
let align = intrinsics::min_align_of::<*const i32>();
assert_eq!(slice_ptr as usize % align, 0);
//return;
@ -186,7 +187,10 @@ fn main() {
let a: &dyn SomeTrait = &"abc\0";
a.object_safe();
#[cfg(target_arch="x86_64")]
assert_eq!(intrinsics::size_of_val(a) as u8, 16);
#[cfg(target_arch="m68k")]
assert_eq!(intrinsics::size_of_val(a) as u8, 8);
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);

View file

@ -1,6 +1,7 @@
#![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted)]
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
use std::arch::x86_64::*;
use std::io::Write;
use std::ops::Coroutine;
@ -95,6 +96,7 @@ fn main() {
println!("{:?}", std::intrinsics::caller_location());
#[cfg(target_arch="x86_64")]
#[cfg(feature="master")]
unsafe {
test_simd();
@ -108,6 +110,7 @@ fn main() {
}
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
#[target_feature(enable = "sse2")]
unsafe fn test_simd() {
let x = _mm_setzero_si128();
@ -136,6 +139,7 @@ unsafe fn test_simd() {
}
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_slli_si128() {
#[rustfmt::skip]
@ -164,6 +168,7 @@ unsafe fn test_mm_slli_si128() {
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_movemask_epi8() {
#[rustfmt::skip]
@ -178,6 +183,7 @@ unsafe fn test_mm_movemask_epi8() {
}
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
#[target_feature(enable = "avx2")]
unsafe fn test_mm256_movemask_epi8() {
let a = _mm256_set1_epi8(-1);
@ -187,6 +193,7 @@ unsafe fn test_mm256_movemask_epi8() {
}
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_add_epi8() {
let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
@ -203,6 +210,7 @@ unsafe fn test_mm_add_epi8() {
}
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_add_pd() {
let a = _mm_setr_pd(1.0, 2.0);
@ -212,6 +220,7 @@ unsafe fn test_mm_add_pd() {
}
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) {
unsafe {
assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y));
@ -219,6 +228,7 @@ fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i)
}
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
#[target_feature(enable = "sse2")]
pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
@ -227,6 +237,7 @@ pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
}
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
#[target_feature(enable = "sse2")]
unsafe fn test_mm_cvtsi128_si64() {
let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0]));
@ -234,6 +245,7 @@ unsafe fn test_mm_cvtsi128_si64() {
}
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
#[target_feature(enable = "sse4.1")]
unsafe fn test_mm_cvtepi8_epi16() {
let a = _mm_set1_epi8(10);
@ -247,6 +259,7 @@ unsafe fn test_mm_cvtepi8_epi16() {
}
#[cfg(feature="master")]
#[cfg(target_arch="x86_64")]
#[target_feature(enable = "sse4.1")]
unsafe fn test_mm_extract_epi8() {
#[rustfmt::skip]

View file

@ -5,7 +5,7 @@ tests/ui/lto/lto-many-codegen-units.rs
tests/ui/lto/issue-100772.rs
tests/ui/lto/lto-rustc-loads-linker-plugin.rs
tests/ui/panic-runtime/lto-unwind.rs
tests/ui/sanitize/issue-111184-generator-witness.rs
tests/ui/sanitize/issue-111184-coroutine-witness.rs
tests/ui/sepcomp/sepcomp-lib-lto.rs
tests/ui/lto/lto-opt-level-s.rs
tests/ui/lto/lto-opt-level-z.rs

View file

@ -21,8 +21,8 @@ tests/ui/cfg/cfg-panic-abort.rs
tests/ui/drop/dynamic-drop-async.rs
tests/ui/drop/repeat-drop.rs
tests/ui/fmt/format-args-capture.rs
tests/ui/generator/panic-drops-resume.rs
tests/ui/generator/panic-drops.rs
tests/ui/coroutine/panic-drops-resume.rs
tests/ui/coroutine/panic-drops.rs
tests/ui/intrinsics/panic-uninitialized-zeroed.rs
tests/ui/iterators/iter-sum-overflow-debug.rs
tests/ui/iterators/iter-sum-overflow-overflow-checks.rs
@ -53,7 +53,7 @@ tests/ui/simd/issue-89193.rs
tests/ui/statics/issue-91050-1.rs
tests/ui/statics/issue-91050-2.rs
tests/ui/alloc-error/default-alloc-error-hook.rs
tests/ui/generator/panic-safe.rs
tests/ui/coroutine/panic-safe.rs
tests/ui/issues/issue-14875.rs
tests/ui/issues/issue-29948.rs
tests/ui/panics/nested_panic_caught.rs
@ -70,4 +70,5 @@ tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs
tests/ui/lto/all-crates.rs
tests/ui/async-await/deep-futures-are-freeze.rs
tests/ui/closures/capture-unsized-by-ref.rs
tests/ui/generator/resume-after-return.rs
tests/ui/coroutine/resume-after-return.rs
tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs

View file

@ -19,22 +19,22 @@ tests/ui/simd/intrinsic/generic-reduction-pass.rs
tests/ui/simd/intrinsic/generic-select-pass.rs
tests/ui/simd/intrinsic/inlining-issue67557-ice.rs
tests/ui/simd/intrinsic/inlining-issue67557.rs
tests/ui/simd/monomorphize-shuffle-index.rs
tests/ui/simd/shuffle.rs
tests/ui/simd/simd-bitmask.rs
tests/ui/generator/resume-after-return.rs
tests/ui/iterators/iter-step-overflow-debug.rs
tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs
tests/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
tests/ui/privacy/reachable-unnameable-items.rs
tests/ui/rfc-1937-termination-trait/termination-trait-in-test.rs
tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test.rs
tests/ui/async-await/async-fn-size-moved-locals.rs
tests/ui/async-await/async-fn-size-uninit-locals.rs
tests/ui/cfg/cfg-panic.rs
tests/ui/generator/size-moved-locals.rs
tests/ui/coroutine/size-moved-locals.rs
tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs
tests/ui/simd/intrinsic/generic-gather-pass.rs
tests/ui/simd/issue-85915-simd-ptrs.rs
tests/ui/issues/issue-68010-large-zst-consts.rs
tests/ui/rust-2018/proc-macro-crate-in-paths.rs
tests/ui/target-feature/missing-plusminus.rs
tests/ui/sse2.rs
tests/ui/codegen/issue-79865-llvm-miscompile.rs
tests/ui/intrinsics/intrinsics-integer.rs

View file

@ -0,0 +1,32 @@
From 7bcd24ec6d4a96121874cb1ae5a23ea274aeff34 Mon Sep 17 00:00:00 2001
From: None <none@example.com>
Date: Thu, 19 Oct 2023 13:12:51 -0400
Subject: [PATCH] [core] Disable portable-simd test
---
library/core/tests/lib.rs | 2 --
1 file changed, 2 deletions(-)
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 5814ed4..194ad4c 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -90,7 +90,6 @@
#![feature(unwrap_infallible)]
#![feature(pointer_byte_offsets)]
#![feature(pointer_is_aligned)]
-#![feature(portable_simd)]
#![feature(ptr_metadata)]
#![feature(lazy_cell)]
#![feature(unsized_tuple_coercion)]
@@ -157,7 +156,6 @@ mod pin;
mod pin_macro;
mod ptr;
mod result;
-mod simd;
mod slice;
mod str;
mod str_lossy;
--
2.42.0

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-10-08"
channel = "nightly-2023-10-21"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View file

@ -1,3 +1,5 @@
#[cfg(feature = "master")]
use gccjit::FnAttribute;
use gccjit::{ToLValue, ToRValue, Type};
use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods};
use rustc_data_structures::fx::FxHashSet;
@ -96,14 +98,23 @@ impl GccType for Reg {
}
}
pub struct FnAbiGcc<'gcc> {
pub return_type: Type<'gcc>,
pub arguments_type: Vec<Type<'gcc>>,
pub is_c_variadic: bool,
pub on_stack_param_indices: FxHashSet<usize>,
#[cfg(feature = "master")]
pub fn_attributes: Vec<FnAttribute<'gcc>>,
}
pub trait FnAbiGccExt<'gcc, 'tcx> {
// TODO(antoyo): return a function pointer type instead?
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>);
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> FnAbiGcc<'gcc>;
fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
}
impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool, FxHashSet<usize>) {
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> FnAbiGcc<'gcc> {
let mut on_stack_param_indices = FxHashSet::default();
// This capacity calculation is approximate.
@ -111,7 +122,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
self.args.len() + if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 }
);
let return_ty =
let return_type =
match self.ret.mode {
PassMode::Ignore => cx.type_void(),
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
@ -121,19 +132,24 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
cx.type_void()
}
};
#[cfg(feature = "master")]
let mut non_null_args = Vec::new();
#[cfg(feature = "master")]
let apply_attrs = |ty: Type<'gcc>, attrs: &ArgAttributes| {
if cx.sess().opts.optimize != config::OptLevel::No
&& attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NoAlias)
{
ty.make_restrict()
} else {
ty
let mut apply_attrs = |mut ty: Type<'gcc>, attrs: &ArgAttributes, arg_index: usize| {
if cx.sess().opts.optimize == config::OptLevel::No {
return ty;
}
if attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NoAlias) {
ty = ty.make_restrict()
}
if attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NonNull) {
non_null_args.push(arg_index as i32 + 1);
}
ty
};
#[cfg(not(feature = "master"))]
let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes| {
let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes, _arg_index: usize| {
ty
};
@ -141,8 +157,9 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
let arg_ty = match arg.mode {
PassMode::Ignore => continue,
PassMode::Pair(a, b) => {
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 0), &a));
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 1), &b));
let arg_pos = argument_tys.len();
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 0), &a, arg_pos));
argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 1), &b, arg_pos + 1));
continue;
}
PassMode::Cast { ref cast, pad_i32 } => {
@ -151,31 +168,53 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
argument_tys.push(Reg::i32().gcc_type(cx));
}
let ty = cast.gcc_type(cx);
apply_attrs(ty, &cast.attrs)
apply_attrs(ty, &cast.attrs, argument_tys.len())
}
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: true } => {
// This is a "byval" argument, so we don't apply the `restrict` attribute on it.
on_stack_param_indices.insert(argument_tys.len());
arg.memory_ty(cx)
},
PassMode::Direct(attrs) => apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs),
PassMode::Direct(attrs) => apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs, argument_tys.len()),
PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs)
apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len())
}
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
assert!(!on_stack);
apply_attrs(apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs), &meta_attrs)
let ty = apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs, argument_tys.len());
apply_attrs(ty, &meta_attrs, argument_tys.len())
}
};
argument_tys.push(arg_ty);
}
(return_ty, argument_tys, self.c_variadic, on_stack_param_indices)
#[cfg(feature = "master")]
let fn_attrs = if non_null_args.is_empty() {
Vec::new()
} else {
vec![FnAttribute::NonNull(non_null_args)]
};
FnAbiGcc {
return_type,
arguments_type: argument_tys,
is_c_variadic: self.c_variadic,
on_stack_param_indices,
#[cfg(feature = "master")]
fn_attributes: fn_attrs,
}
}
fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
let (return_type, params, variadic, on_stack_param_indices) = self.gcc_type(cx);
let pointer_type = cx.context.new_function_pointer_type(None, return_type, &params, variadic);
// FIXME(antoyo): Should we do something with `FnAbiGcc::fn_attributes`?
let FnAbiGcc {
return_type,
arguments_type,
is_c_variadic,
on_stack_param_indices,
..
} = self.gcc_type(cx);
let pointer_type = cx.context.new_function_pointer_type(None, return_type, &arguments_type, is_c_variadic);
cx.on_stack_params.borrow_mut().insert(pointer_type.dyncast_function_ptr_type().expect("function ptr type"), on_stack_param_indices);
pointer_type
}

View file

@ -53,6 +53,9 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
codegen_fn_attrs.inline
};
if let Some(attr) = inline_attr(cx, inline) {
if let FnAttribute::AlwaysInline = attr {
func.add_attribute(FnAttribute::Inline);
}
func.add_attribute(attr);
}

View file

@ -98,10 +98,11 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock
.map(|string| &string[1..])
.collect();
// TODO(antoyo): only set on x86 platforms.
context.add_command_line_option("-masm=intel");
if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" {
context.add_command_line_option("-masm=intel");
}
if !disabled_features.contains("avx") {
if !disabled_features.contains("avx") && tcx.sess.target.arch == "x86_64" {
// NOTE: we always enable AVX because the equivalent of llvm.x86.sse2.cmp.pd in GCC for
// SSE2 is multiple builtins, so we use the AVX __builtin_ia32_cmppd instead.
// FIXME(antoyo): use the proper builtins for llvm.x86.sse2.cmp.pd and similar.

View file

@ -751,9 +751,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
loaded_value.to_rvalue()
}
fn volatile_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
// TODO(antoyo): use ty.
let ptr = self.context.new_cast(None, ptr, ptr.get_type().make_volatile());
fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
let ptr = self.context.new_cast(None, ptr, ty.make_volatile().make_pointer());
ptr.dereference(None).to_rvalue()
}

View file

@ -424,35 +424,35 @@ impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
}
fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.i8_type
self.is_compatible_with(cx.i8_type)
}
fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.u8_type
self.is_compatible_with(cx.u8_type)
}
fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.i16_type
self.is_compatible_with(cx.i16_type)
}
fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.u16_type
self.is_compatible_with(cx.u16_type)
}
fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.i32_type
self.is_compatible_with(cx.i32_type)
}
fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.u32_type
self.is_compatible_with(cx.u32_type)
}
fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.i64_type
self.is_compatible_with(cx.i64_type)
}
fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
self.unqualified() == cx.u64_type
self.is_compatible_with(cx.u64_type)
}
fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {

View file

@ -20,6 +20,7 @@ use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDat
use rustc_target::spec::{HasTargetSpec, Target, TlsModel};
use crate::callee::get_fn;
use crate::common::SignType;
#[derive(Clone)]
pub struct FuncSig<'gcc> {
@ -129,29 +130,57 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, tcx: TyCtxt<'tcx>, supports_128bit_integers: bool) -> Self {
let check_overflow = tcx.sess.overflow_checks();
let i8_type = context.new_c_type(CType::Int8t);
let i16_type = context.new_c_type(CType::Int16t);
let i32_type = context.new_c_type(CType::Int32t);
let i64_type = context.new_c_type(CType::Int64t);
let u8_type = context.new_c_type(CType::UInt8t);
let u16_type = context.new_c_type(CType::UInt16t);
let u32_type = context.new_c_type(CType::UInt32t);
let u64_type = context.new_c_type(CType::UInt64t);
let create_type = |ctype, rust_type| {
let layout = tcx.layout_of(ParamEnv::reveal_all().and(rust_type)).unwrap();
let align = layout.align.abi.bytes();
#[cfg(feature="master")]
{
context.new_c_type(ctype).get_aligned(align)
}
#[cfg(not(feature="master"))]
{
// Since libgccjit 12 doesn't contain the fix to compare aligned integer types,
// only align u128 and i128.
if layout.ty.int_size_and_signed(tcx).0.bytes() == 16 {
context.new_c_type(ctype).get_aligned(align)
}
else {
context.new_c_type(ctype)
}
}
};
let i8_type = create_type(CType::Int8t, tcx.types.i8);
let i16_type = create_type(CType::Int16t, tcx.types.i16);
let i32_type = create_type(CType::Int32t, tcx.types.i32);
let i64_type = create_type(CType::Int64t, tcx.types.i64);
let u8_type = create_type(CType::UInt8t, tcx.types.u8);
let u16_type = create_type(CType::UInt16t, tcx.types.u16);
let u32_type = create_type(CType::UInt32t, tcx.types.u32);
let u64_type = create_type(CType::UInt64t, tcx.types.u64);
let (i128_type, u128_type) =
if supports_128bit_integers {
let i128_type = context.new_c_type(CType::Int128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?;
let u128_type = context.new_c_type(CType::UInt128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?;
let i128_type = create_type(CType::Int128t, tcx.types.i128);
let u128_type = create_type(CType::UInt128t, tcx.types.u128);
(i128_type, u128_type)
}
else {
let i128_type = context.new_array_type(None, i64_type, 2);
let u128_type = context.new_array_type(None, u64_type, 2);
/*let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.i128)).unwrap();
let i128_align = layout.align.abi.bytes();
let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.u128)).unwrap();
let u128_align = layout.align.abi.bytes();*/
// TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in
// gcc_jit_context_new_array_constructor (it should not use reinterpret_cast).
let i128_type = context.new_array_type(None, i64_type, 2)/*.get_aligned(i128_align)*/;
let u128_type = context.new_array_type(None, u64_type, 2)/*.get_aligned(u128_align)*/;
(i128_type, u128_type)
};
let tls_model = to_gcc_tls_mode(tcx.sess.tls_model());
// TODO(antoyo): set alignment on those types as well.
let float_type = context.new_type::<f32>();
let double_type = context.new_type::<f64>();
@ -167,14 +196,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
let ulonglong_type = context.new_c_type(CType::ULongLong);
let sizet_type = context.new_c_type(CType::SizeT);
let isize_type = context.new_c_type(CType::LongLong);
let usize_type = context.new_c_type(CType::ULongLong);
let usize_type = sizet_type;
let isize_type = usize_type;
let bool_type = context.new_type::<bool>();
// TODO(antoyo): only have those assertions on x86_64.
assert_eq!(isize_type.get_size(), i64_type.get_size());
assert_eq!(usize_type.get_size(), u64_type.get_size());
let mut functions = FxHashMap::default();
let builtins = [
"__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow",
@ -192,7 +217,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
functions.insert(builtin.to_string(), context.get_builtin_function(builtin));
}
Self {
let mut cx = Self {
check_overflow,
codegen_unit,
context,
@ -254,7 +279,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
pointee_infos: Default::default(),
structs_as_pointer: Default::default(),
cleanup_blocks: Default::default(),
}
};
// TODO(antoyo): instead of doing this, add SsizeT to libgccjit.
cx.isize_type = usize_type.to_signed(&cx);
cx
}
pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {

View file

@ -6,7 +6,7 @@ use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::abi::call::FnAbi;
use crate::abi::FnAbiGccExt;
use crate::abi::{FnAbiGcc, FnAbiGccExt};
use crate::context::CodegenCx;
use crate::intrinsic::llvm;
@ -80,9 +80,20 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
}
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> {
let (return_type, params, variadic, on_stack_param_indices) = fn_abi.gcc_type(self);
let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &params, variadic);
let FnAbiGcc {
return_type,
arguments_type,
is_c_variadic,
on_stack_param_indices,
#[cfg(feature="master")]
fn_attributes,
} = fn_abi.gcc_type(self);
let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &arguments_type, is_c_variadic);
self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices);
#[cfg(feature="master")]
for fn_attr in fn_attributes {
func.add_attribute(fn_attr);
}
func
}

View file

@ -198,9 +198,16 @@ pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) ->
None
}
fn arch_to_gcc(name: &str) -> &str {
match name {
"M68020" => "68020",
_ => name,
}
}
fn handle_native(name: &str) -> &str {
if name != "native" {
return name;
return arch_to_gcc(name);
}
#[cfg(feature="master")]

View file

@ -7,7 +7,9 @@ use std::convert::TryFrom;
use gccjit::{ComparisonOp, FunctionType, RValue, ToRValue, Type, UnaryOp, BinaryOp};
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp};
use rustc_middle::ty::Ty;
use rustc_middle::ty::{ParamEnv, Ty};
use rustc_target::abi::{Endian, call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}};
use rustc_target::spec;
use crate::builder::ToGccComp;
use crate::{builder::Builder, common::{SignType, TypeReflection}, context::CodegenCx};
@ -37,11 +39,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
}
else {
let element_type = typ.dyncast_array().expect("element type");
let values = [
self.from_low_high_rvalues(typ,
self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.low(a)),
self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.high(a)),
];
self.cx.context.new_array_constructor(None, typ, &values)
)
}
}
@ -100,7 +101,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero);
self.llbb().end_with_conditional(None, condition, then_block, else_block);
// TODO(antoyo): take endianness into account.
let shift_value = self.gcc_sub(b, sixty_four);
let high = self.high(a);
let sign =
@ -110,11 +110,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
else {
zero
};
let values = [
high >> shift_value,
sign,
];
let array_value = self.context.new_array_constructor(None, a_type, &values);
let array_value = self.from_low_high_rvalues(a_type, high >> shift_value, sign);
then_block.add_assignment(None, result, array_value);
then_block.end_with_jump(None, after_block);
@ -130,11 +126,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let casted_low = self.context.new_cast(None, self.low(a), unsigned_type);
let shifted_low = casted_low >> self.context.new_cast(None, b, unsigned_type);
let shifted_low = self.context.new_cast(None, shifted_low, native_int_type);
let values = [
let array_value = self.from_low_high_rvalues(a_type,
(high << shift_value) | shifted_low,
high >> b,
];
let array_value = self.context.new_array_constructor(None, a_type, &values);
);
actual_else_block.add_assignment(None, result, array_value);
actual_else_block.end_with_jump(None, after_block);
@ -314,18 +309,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
_ => unreachable!(),
},
};
let a_type = lhs.get_type();
let b_type = rhs.get_type();
let param_a = self.context.new_parameter(None, a_type, "a");
let param_b = self.context.new_parameter(None, b_type, "b");
let result_field = self.context.new_field(None, a_type, "result");
let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
let result = self.context.new_call(None, func, &[lhs, rhs]);
let overflow = result.access_field(None, overflow_field);
let int_result = result.access_field(None, result_field);
return (int_result, overflow);
return self.operation_with_overflow(func_name, lhs, rhs);
},
_ => {
match oop {
@ -350,6 +334,54 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
(res.dereference(None).to_rvalue(), overflow)
}
pub fn operation_with_overflow(&self, func_name: &str, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
let a_type = lhs.get_type();
let b_type = rhs.get_type();
let param_a = self.context.new_parameter(None, a_type, "a");
let param_b = self.context.new_parameter(None, b_type, "b");
let result_field = self.context.new_field(None, a_type, "result");
let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
let ret_ty = Ty::new_tup(self.tcx, &[self.tcx.types.i128, self.tcx.types.bool]);
let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ret_ty)).unwrap();
let arg_abi = ArgAbi {
layout,
mode: PassMode::Direct(ArgAttributes::new()),
};
let mut fn_abi = FnAbi {
args: vec![arg_abi.clone(), arg_abi.clone()].into_boxed_slice(),
ret: arg_abi,
c_variadic: false,
fixed_count: 2,
conv: Conv::C,
can_unwind: false,
};
fn_abi.adjust_for_foreign_abi(self.cx, spec::abi::Abi::C {
unwind: false,
}).unwrap();
let indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
let result =
if indirect {
let return_value = self.current_func().new_local(None, return_type.as_type(), "return_value");
let return_param_type = return_type.as_type().make_pointer();
let return_param = self.context.new_parameter(None, return_param_type, "return_value");
let func = self.context.new_function(None, FunctionType::Extern, self.type_void(), &[return_param, param_a, param_b], func_name, false);
self.llbb().add_eval(None, self.context.new_call(None, func, &[return_value.get_address(None), lhs, rhs]));
return_value.to_rvalue()
}
else {
let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
self.context.new_call(None, func, &[lhs, rhs])
};
let overflow = result.access_field(None, overflow_field);
let int_result = result.access_field(None, result_field);
return (int_result, overflow);
}
pub fn gcc_icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> {
let a_type = lhs.get_type();
let b_type = rhs.get_type();
@ -415,6 +447,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
IntPredicate::IntNE => {
return self.context.new_comparison(None, ComparisonOp::NotEquals, cmp, self.context.new_rvalue_one(self.int_type));
},
// TODO(antoyo): cast to u128 for unsigned comparison. See below.
IntPredicate::IntUGT => (ComparisonOp::Equals, 2),
IntPredicate::IntUGE => (ComparisonOp::GreaterThanEquals, 1),
IntPredicate::IntULT => (ComparisonOp::Equals, 0),
@ -444,6 +477,18 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
rhs = self.context.new_cast(None, rhs, a_type);
}
}
match op {
IntPredicate::IntUGT | IntPredicate::IntUGE | IntPredicate::IntULT | IntPredicate::IntULE => {
if !a_type.is_vector() {
let unsigned_type = a_type.to_unsigned(&self.cx);
lhs = self.context.new_cast(None, lhs, unsigned_type);
rhs = self.context.new_cast(None, rhs, unsigned_type);
}
},
// TODO(antoyo): we probably need to handle signed comparison for unsigned
// integers.
_ => (),
}
self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
}
}
@ -455,11 +500,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
a ^ b
}
else {
let values = [
self.from_low_high_rvalues(a_type,
self.low(a) ^ self.low(b),
self.high(a) ^ self.high(b),
];
self.context.new_array_constructor(None, a_type, &values)
)
}
}
@ -505,12 +549,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero);
self.llbb().end_with_conditional(None, condition, then_block, else_block);
// TODO(antoyo): take endianness into account.
let values = [
let array_value = self.from_low_high_rvalues(a_type,
zero,
self.low(a) << (b - sixty_four),
];
let array_value = self.context.new_array_constructor(None, a_type, &values);
);
then_block.add_assignment(None, result, array_value);
then_block.end_with_jump(None, after_block);
@ -521,16 +563,16 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
b0_block.end_with_jump(None, after_block);
// NOTE: cast low to its unsigned type in order to perform a logical right shift.
// TODO(antoyo): adjust this ^ comment.
let unsigned_type = native_int_type.to_unsigned(&self.cx);
let casted_low = self.context.new_cast(None, self.low(a), unsigned_type);
let shift_value = self.context.new_cast(None, sixty_four - b, unsigned_type);
let high_low = self.context.new_cast(None, casted_low >> shift_value, native_int_type);
let values = [
let array_value = self.from_low_high_rvalues(a_type,
self.low(a) << b,
(self.high(a) << b) | high_low,
];
let array_value = self.context.new_array_constructor(None, a_type, &values);
);
actual_else_block.add_assignment(None, result, array_value);
actual_else_block.end_with_jump(None, after_block);
@ -546,16 +588,16 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let arg_type = arg.get_type();
if !self.is_native_int_type(arg_type) {
let native_int_type = arg_type.dyncast_array().expect("get element type");
let lsb = self.context.new_array_access(None, arg, self.context.new_rvalue_from_int(self.int_type, 0)).to_rvalue();
let lsb = self.low(arg);
let swapped_lsb = self.gcc_bswap(lsb, width / 2);
let swapped_lsb = self.context.new_cast(None, swapped_lsb, native_int_type);
let msb = self.context.new_array_access(None, arg, self.context.new_rvalue_from_int(self.int_type, 1)).to_rvalue();
let msb = self.high(arg);
let swapped_msb = self.gcc_bswap(msb, width / 2);
let swapped_msb = self.context.new_cast(None, swapped_msb, native_int_type);
// NOTE: we also need to swap the two elements here, in addition to swapping inside
// the elements themselves like done above.
return self.context.new_array_constructor(None, arg_type, &[swapped_msb, swapped_lsb]);
return self.from_low_high_rvalues(arg_type, swapped_msb, swapped_lsb);
}
// TODO(antoyo): check if it's faster to use string literals and a
@ -659,11 +701,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
else {
assert!(!a_native && !b_native, "both types should either be native or non-native for or operation");
let native_int_type = a_type.dyncast_array().expect("get element type");
let values = [
self.from_low_high_rvalues(a_type,
self.context.new_binary_op(None, operation, native_int_type, self.low(a), self.low(b)),
self.context.new_binary_op(None, operation, native_int_type, self.high(a), self.high(b)),
];
self.context.new_array_constructor(None, a_type, &values)
)
}
}
@ -687,11 +728,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
let zero = self.context.new_rvalue_zero(value_type);
let is_negative = self.context.new_comparison(None, ComparisonOp::LessThan, value, zero);
let is_negative = self.gcc_int_cast(is_negative, dest_element_type);
let values = [
self.from_low_high_rvalues(dest_typ,
self.context.new_cast(None, value, dest_element_type),
self.context.new_unary_op(None, UnaryOp::Minus, dest_element_type, is_negative),
];
self.context.new_array_constructor(None, dest_typ, &values)
)
}
else {
// Since u128 and i128 are the only types that can be unsupported, we know the type of
@ -769,20 +809,47 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
}
fn high(&self, value: RValue<'gcc>) -> RValue<'gcc> {
self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, 1))
let index =
match self.sess().target.options.endian {
Endian::Little => 1,
Endian::Big => 0,
};
self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, index))
.to_rvalue()
}
fn low(&self, value: RValue<'gcc>) -> RValue<'gcc> {
self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, 0))
let index =
match self.sess().target.options.endian {
Endian::Little => 0,
Endian::Big => 1,
};
self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, index))
.to_rvalue()
}
fn from_low_high_rvalues(&self, typ: Type<'gcc>, low: RValue<'gcc>, high: RValue<'gcc>) -> RValue<'gcc> {
let (first, last) =
match self.sess().target.options.endian {
Endian::Little => (low, high),
Endian::Big => (high, low),
};
let values = [first, last];
self.context.new_array_constructor(None, typ, &values)
}
fn from_low_high(&self, typ: Type<'gcc>, low: i64, high: i64) -> RValue<'gcc> {
let (first, last) =
match self.sess().target.options.endian {
Endian::Little => (low, high),
Endian::Big => (high, low),
};
let native_int_type = typ.dyncast_array().expect("get element type");
let values = [
self.context.new_rvalue_from_long(native_int_type, low),
self.context.new_rvalue_from_long(native_int_type, high),
self.context.new_rvalue_from_long(native_int_type, first),
self.context.new_rvalue_from_long(native_int_type, last),
];
self.context.new_array_constructor(None, typ, &values)
}

File diff suppressed because it is too large Load diff

View file

@ -432,15 +432,21 @@ pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool {
#[cfg(not(feature="master"))]
pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
match name {
"llvm.x86.xgetbv" | "llvm.x86.sse2.pause" => {
let gcc_name = "__builtin_trap";
let func = cx.context.get_builtin_function(gcc_name);
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
return func;
},
_ => unimplemented!("unsupported LLVM intrinsic {}", name),
}
let gcc_name =
match name {
"llvm.x86.sse2.pause" => {
// NOTE: pause is only a hint, so we use a dummy built-in because target built-ins
// are not supported in libgccjit 12.
"__builtin_inff"
},
"llvm.x86.xgetbv" => {
"__builtin_trap"
},
_ => unimplemented!("unsupported LLVM intrinsic {}", name),
};
let func = cx.context.get_builtin_function(gcc_name);
cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
return func;
}
#[cfg(feature="master")]

View file

@ -4,7 +4,9 @@ mod simd;
#[cfg(feature="master")]
use std::iter;
use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp, FunctionType};
#[cfg(feature="master")]
use gccjit::FunctionType;
use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp};
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::base::wants_msvc_seh;
use rustc_codegen_ssa::common::IntPredicate;
@ -143,11 +145,15 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = fn_args.type_at(0);
let mut ptr = args[0].immediate();
if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode {
ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
}
let load = self.volatile_load(ptr.get_type(), ptr);
let ptr = args[0].immediate();
let load =
if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode {
let gcc_ty = ty.gcc_type(self);
self.volatile_load(gcc_ty, ptr)
}
else {
self.volatile_load(self.layout_of(tp_ty).gcc_type(self), ptr)
};
// TODO(antoyo): set alignment.
self.to_immediate(load, self.layout_of(tp_ty))
}
@ -819,75 +825,58 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
value
};
if value_type.is_u128(&self.cx) {
// TODO(antoyo): implement in the normal algorithm below to have a more efficient
// implementation (that does not require a call to __popcountdi2).
let popcount = self.context.get_builtin_function("__builtin_popcountll");
// only break apart 128-bit ints if they're not natively supported
// TODO(antoyo): remove this if/when native 128-bit integers land in libgccjit
if value_type.is_u128(&self.cx) && !self.cx.supports_128bit_integers {
let sixty_four = self.gcc_int(value_type, 64);
let right_shift = self.gcc_lshr(value, sixty_four);
let high = self.gcc_int_cast(right_shift, self.cx.ulonglong_type);
let high = self.context.new_call(None, popcount, &[high]);
let high = self.pop_count(high);
let low = self.gcc_int_cast(value, self.cx.ulonglong_type);
let low = self.context.new_call(None, popcount, &[low]);
let low = self.pop_count(low);
let res = high + low;
return self.gcc_int_cast(res, result_type);
}
// First step.
let mask = self.context.new_rvalue_from_long(value_type, 0x5555555555555555);
let left = value & mask;
let shifted = value >> self.context.new_rvalue_from_int(value_type, 1);
let right = shifted & mask;
let value = left + right;
// Use Wenger's algorithm for population count, gcc's seems to play better with it
// for (int counter = 0; value != 0; counter++) {
// value &= value - 1;
// }
let func = self.current_func.borrow().expect("func");
let loop_head = func.new_block("head");
let loop_body = func.new_block("body");
let loop_tail = func.new_block("tail");
// Second step.
let mask = self.context.new_rvalue_from_long(value_type, 0x3333333333333333);
let left = value & mask;
let shifted = value >> self.context.new_rvalue_from_int(value_type, 2);
let right = shifted & mask;
let value = left + right;
let counter_type = self.int_type;
let counter = self.current_func().new_local(None, counter_type, "popcount_counter");
let val = self.current_func().new_local(None, value_type, "popcount_value");
let zero = self.gcc_zero(counter_type);
self.llbb().add_assignment(None, counter, zero);
self.llbb().add_assignment(None, val, value);
self.br(loop_head);
// Third step.
let mask = self.context.new_rvalue_from_long(value_type, 0x0F0F0F0F0F0F0F0F);
let left = value & mask;
let shifted = value >> self.context.new_rvalue_from_int(value_type, 4);
let right = shifted & mask;
let value = left + right;
// check if value isn't zero
self.switch_to_block(loop_head);
let zero = self.gcc_zero(value_type);
let cond = self.gcc_icmp(IntPredicate::IntNE, val.to_rvalue(), zero);
self.cond_br(cond, loop_body, loop_tail);
if value_type.is_u8(&self.cx) {
return self.context.new_cast(None, value, result_type);
}
// val &= val - 1;
self.switch_to_block(loop_body);
let one = self.gcc_int(value_type, 1);
let sub = self.gcc_sub(val.to_rvalue(), one);
let op = self.gcc_and(val.to_rvalue(), sub);
loop_body.add_assignment(None, val, op);
// Fourth step.
let mask = self.context.new_rvalue_from_long(value_type, 0x00FF00FF00FF00FF);
let left = value & mask;
let shifted = value >> self.context.new_rvalue_from_int(value_type, 8);
let right = shifted & mask;
let value = left + right;
// counter += 1
let one = self.gcc_int(counter_type, 1);
let op = self.gcc_add(counter.to_rvalue(), one);
loop_body.add_assignment(None, counter, op);
self.br(loop_head);
if value_type.is_u16(&self.cx) {
return self.context.new_cast(None, value, result_type);
}
// Fifth step.
let mask = self.context.new_rvalue_from_long(value_type, 0x0000FFFF0000FFFF);
let left = value & mask;
let shifted = value >> self.context.new_rvalue_from_int(value_type, 16);
let right = shifted & mask;
let value = left + right;
if value_type.is_u32(&self.cx) {
return self.context.new_cast(None, value, result_type);
}
// Sixth step.
let mask = self.context.new_rvalue_from_long(value_type, 0x00000000FFFFFFFF);
let left = value & mask;
let shifted = value >> self.context.new_rvalue_from_int(value_type, 32);
let right = shifted & mask;
let value = left + right;
self.context.new_cast(None, value, result_type)
// end of loop
self.switch_to_block(loop_tail);
self.gcc_int_cast(counter.to_rvalue(), result_type)
}
// Algorithm from: https://blog.regehr.org/archives/1063
@ -947,15 +936,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
128 => "__rust_i128_addo",
_ => unreachable!(),
};
let param_a = self.context.new_parameter(None, result_type, "a");
let param_b = self.context.new_parameter(None, result_type, "b");
let result_field = self.context.new_field(None, result_type, "result");
let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
let result = self.context.new_call(None, func, &[lhs, rhs]);
let overflow = result.access_field(None, overflow_field);
let int_result = result.access_field(None, result_field);
let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs);
self.llbb().add_assignment(None, res, int_result);
overflow
};
@ -1017,15 +998,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
128 => "__rust_i128_subo",
_ => unreachable!(),
};
let param_a = self.context.new_parameter(None, result_type, "a");
let param_b = self.context.new_parameter(None, result_type, "b");
let result_field = self.context.new_field(None, result_type, "result");
let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
let result = self.context.new_call(None, func, &[lhs, rhs]);
let overflow = result.access_field(None, overflow_field);
let int_result = result.access_field(None, result_field);
let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs);
self.llbb().add_assignment(None, res, int_result);
overflow
};
@ -1197,7 +1170,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, codegen: &mut
#[cfg(feature="master")]
fn gen_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, name: &str, rust_fn_sig: ty::PolyFnSig<'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) {
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
let (typ, _, _, _) = fn_abi.gcc_type(cx);
let return_type = fn_abi.gcc_type(cx).return_type;
// FIXME(eddyb) find a nicer way to do this.
cx.linkage.set(FunctionType::Internal);
let func = cx.declare_fn(name, fn_abi);
@ -1207,5 +1180,5 @@ fn gen_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, name: &str, rust_fn_sig
let block = Builder::append_block(cx, func_val, "entry-block");
let bx = Builder::build(cx, block);
codegen(bx);
(typ, func)
(return_type, func)
}

View file

@ -12,6 +12,7 @@
* TODO(antoyo): remove the patches.
*/
#![cfg_attr(not(bootstrap), allow(internal_features))]
#![cfg_attr(not(bootstrap), doc(rust_logo))]
#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
#![feature(
@ -251,8 +252,9 @@ impl ExtraBackendMethods for GccCodegenBackend {
temp_dir: None,
};
// TODO(antoyo): only set for x86.
mods.context.add_command_line_option("-masm=intel");
if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" {
mods.context.add_command_line_option("-masm=intel");
}
unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
mods
}

View file

@ -119,11 +119,11 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}
fn type_f32(&self) -> Type<'gcc> {
self.context.new_type::<f32>()
self.float_type
}
fn type_f64(&self) -> Type<'gcc> {
self.context.new_type::<f64>()
self.double_type
}
fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> {
@ -216,17 +216,17 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
value.get_type()
}
fn type_array(&self, ty: Type<'gcc>, len: u64) -> Type<'gcc> {
// TODO: remove this as well?
/*if let Some(struct_type) = ty.is_struct() {
#[cfg_attr(feature="master", allow(unused_mut))]
fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
#[cfg(not(feature="master"))]
if let Some(struct_type) = ty.is_struct() {
if struct_type.get_field_count() == 0 {
// NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
// size of usize::MAX in test_binary_search, we workaround this by setting the size to
// zero for ZSTs.
// FIXME(antoyo): fix gccjit API.
len = 0;
}
}*/
}
self.context.new_array_type(None, ty, len)
}

View file

@ -9,7 +9,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_target::abi::{self, Abi, Align, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants};
use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
use crate::abi::{FnAbiGccExt, GccType};
use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType};
use crate::context::CodegenCx;
use crate::type_::struct_fields;
@ -372,7 +372,13 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
}
fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
let (return_type, param_types, variadic, _) = fn_abi.gcc_type(self);
self.context.new_function_pointer_type(None, return_type, &param_types, variadic)
// FIXME(antoyo): Should we do something with `FnAbiGcc::fn_attributes`?
let FnAbiGcc {
return_type,
arguments_type,
is_c_variadic,
..
} = fn_abi.gcc_type(self);
self.context.new_function_pointer_type(None, return_type, &arguments_type, is_c_variadic)
}
}

View file

@ -5,16 +5,6 @@
set -e
#set -x
if [ -f ./gcc_path ]; then
export GCC_PATH=$(cat gcc_path)
else
echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
exit 1
fi
export LD_LIBRARY_PATH="$GCC_PATH"
export LIBRARY_PATH="$GCC_PATH"
flags=
gcc_master_branch=1
channel="debug"
@ -22,12 +12,18 @@ funcs=()
build_only=0
nb_parts=0
current_part=0
use_system_gcc=0
use_backend=0
cargo_target_dir=""
export CHANNEL='debug'
while [[ $# -gt 0 ]]; do
case $1 in
--release)
codegen_channel=release
channel="release"
export CHANNEL='release'
shift
;;
--release-sysroot)
@ -111,6 +107,22 @@ while [[ $# -gt 0 ]]; do
build_only=1
shift
;;
"--use-system-gcc")
use_system_gcc=1
shift
;;
"--use-backend")
use_backend=1
shift
export BUILTIN_BACKEND=$1
shift
;;
"--out-dir")
shift
export CARGO_TARGET_DIR=$1
cargo_target_dir=$1
shift
;;
"--nb-parts")
shift
nb_parts=$1
@ -128,13 +140,25 @@ while [[ $# -gt 0 ]]; do
esac
done
if [[ $channel == "release" ]]; then
export CHANNEL='release'
CARGO_INCREMENTAL=1 cargo rustc --release $flags
if [ -f ./gcc_path ]; then
export GCC_PATH=$(cat gcc_path)
elif (( $use_system_gcc == 1 )); then
echo 'Using system GCC'
else
echo $LD_LIBRARY_PATH
export CHANNEL='debug'
cargo rustc $flags
echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
exit 1
fi
export LD_LIBRARY_PATH="$GCC_PATH"
export LIBRARY_PATH="$GCC_PATH"
if [[ $use_backend == 0 ]]; then
if [[ $channel == "release" ]]; then
CARGO_INCREMENTAL=1 cargo rustc --release $flags
else
echo $LD_LIBRARY_PATH
cargo rustc $flags
fi
fi
if (( $build_only == 1 )); then
@ -145,20 +169,26 @@ fi
source config.sh
function clean() {
rm -r target/out || true
mkdir -p target/out/gccjit
rm -r $cargo_target_dir || true
mkdir -p $cargo_target_dir/gccjit
}
function mini_tests() {
echo "[BUILD] mini_core"
$RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target $TARGET_TRIPLE
crate_types="lib,dylib"
if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
crate_types="lib"
fi
$RUST_CMD example/mini_core.rs --crate-name mini_core --crate-type $crate_types --target $TARGET_TRIPLE
echo "[BUILD] example"
$RUSTC example/example.rs --crate-type lib --target $TARGET_TRIPLE
$RUST_CMD example/example.rs --crate-type lib --target $TARGET_TRIPLE
echo "[AOT] mini_core_hello_world"
$RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target $TARGET_TRIPLE
$RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd
$RUST_CMD example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target $TARGET_TRIPLE
$RUN_WRAPPER $cargo_target_dir/mini_core_hello_world abc bcd
}
function build_sysroot() {
@ -166,41 +196,61 @@ function build_sysroot() {
time ./build_sysroot/build_sysroot.sh $sysroot_channel
}
# TODO(GuillaumeGomez): when rewriting in Rust, refactor with the code in tests/lang_tests_common.rs if possible.
function run_in_vm() {
vm_parent_dir=${CG_GCC_VM_DIR:-$(pwd)}
vm_dir=vm
exe=$1
exe_filename=$(basename $exe)
vm_home_dir=$vm_parent_dir/$vm_dir/home
vm_exe_path=$vm_home_dir/$exe_filename
inside_vm_exe_path=/home/$exe_filename
sudo cp $exe $vm_exe_path
shift
pushd $vm_parent_dir
sudo chroot $vm_dir qemu-m68k-static $inside_vm_exe_path $@
popd
}
function std_tests() {
echo "[AOT] arbitrary_self_types_pointers_and_wrappers"
$RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target $TARGET_TRIPLE
$RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers
$RUST_CMD example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target $TARGET_TRIPLE
$RUN_WRAPPER $cargo_target_dir/arbitrary_self_types_pointers_and_wrappers
echo "[AOT] alloc_system"
$RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE"
$RUST_CMD example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE"
echo "[AOT] alloc_example"
$RUSTC example/alloc_example.rs --crate-type bin --target $TARGET_TRIPLE
$RUN_WRAPPER ./target/out/alloc_example
# FIXME: doesn't work on m68k.
if [[ "$HOST_TRIPLE" == "$TARGET_TRIPLE" ]]; then
echo "[AOT] alloc_example"
$RUST_CMD example/alloc_example.rs --crate-type bin --target $TARGET_TRIPLE
$RUN_WRAPPER $cargo_target_dir/alloc_example
fi
echo "[AOT] dst_field_align"
# FIXME(antoyo): Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed.
$RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target $TARGET_TRIPLE
$RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false)
$RUST_CMD example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target $TARGET_TRIPLE
$RUN_WRAPPER $cargo_target_dir/dst_field_align || (echo $?; false)
echo "[AOT] std_example"
std_flags="--cfg feature=\"master\""
if (( $gcc_master_branch == 0 )); then
std_flags=""
fi
$RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE $std_flags
$RUN_WRAPPER ./target/out/std_example --target $TARGET_TRIPLE
$RUST_CMD example/std_example.rs --crate-type bin --target $TARGET_TRIPLE $std_flags
$RUN_WRAPPER $cargo_target_dir/std_example --target $TARGET_TRIPLE
echo "[AOT] subslice-patterns-const-eval"
$RUSTC example/subslice-patterns-const-eval.rs --crate-type bin $TEST_FLAGS --target $TARGET_TRIPLE
$RUN_WRAPPER ./target/out/subslice-patterns-const-eval
$RUST_CMD example/subslice-patterns-const-eval.rs --crate-type bin $TEST_FLAGS --target $TARGET_TRIPLE
$RUN_WRAPPER $cargo_target_dir/subslice-patterns-const-eval
echo "[AOT] track-caller-attribute"
$RUSTC example/track-caller-attribute.rs --crate-type bin $TEST_FLAGS --target $TARGET_TRIPLE
$RUN_WRAPPER ./target/out/track-caller-attribute
$RUST_CMD example/track-caller-attribute.rs --crate-type bin $TEST_FLAGS --target $TARGET_TRIPLE
$RUN_WRAPPER $cargo_target_dir/track-caller-attribute
echo "[BUILD] mod_bench"
$RUSTC example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE
$RUST_CMD example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE
}
function setup_rustc() {
@ -209,7 +259,7 @@ function setup_rustc() {
git clone https://github.com/rust-lang/rust.git || true
cd rust
git fetch
git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(')
git checkout $($RUSTC -V | cut -d' ' -f3 | tr -d '(')
export RUSTFLAGS=
rm config.toml || true
@ -225,7 +275,7 @@ verbose-tests = true
[build]
cargo = "$(rustup which cargo)"
local-rebuild = true
rustc = "$HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE/bin/rustc"
rustc = "$HOME/.rustup/toolchains/$rust_toolchain-$HOST_TRIPLE/bin/rustc"
[target.x86_64-unknown-linux-gnu]
llvm-filecheck = "`which FileCheck-10 || which FileCheck-11 || which FileCheck-12 || which FileCheck-13 || which FileCheck-14`"
@ -234,8 +284,8 @@ llvm-filecheck = "`which FileCheck-10 || which FileCheck-11 || which FileCheck-1
download-ci-llvm = false
EOF
rustc -V | cut -d' ' -f3 | tr -d '('
git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') tests
$RUSTC -V | cut -d' ' -f3 | tr -d '('
git checkout $($RUSTC -V | cut -d' ' -f3 | tr -d '(') tests
}
function asm_tests() {
@ -262,17 +312,17 @@ function test_libcore() {
#echo "[BENCH COMPILE] mod_bench"
#COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline"
#COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o target/out/mod_bench_llvm_0 -Cpanic=abort"
#COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o target/out/mod_bench_llvm_1 -Cpanic=abort"
#COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o target/out/mod_bench_llvm_2 -Cpanic=abort"
#COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o target/out/mod_bench_llvm_3 -Cpanic=abort"
#COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o $cargo_target_dir/mod_bench_llvm_0 -Cpanic=abort"
#COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o $cargo_target_dir/mod_bench_llvm_1 -Cpanic=abort"
#COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o $cargo_target_dir/mod_bench_llvm_2 -Cpanic=abort"
#COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o $cargo_target_dir/mod_bench_llvm_3 -Cpanic=abort"
## Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow
#hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3"
#echo
#echo "[BENCH RUN] mod_bench"
#hyperfine --runs ${RUN_RUNS:-10} ./target/out/mod_bench{,_inline} ./target/out/mod_bench_llvm_*
#hyperfine --runs ${RUN_RUNS:-10} $cargo_target_dir/mod_bench{,_inline} $cargo_target_dir/mod_bench_llvm_*
function extended_rand_tests() {
if (( $gcc_master_branch == 0 )); then
@ -347,10 +397,10 @@ function test_rustc() {
git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
rm -r tests/ui/{abi*,extern/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,chalkify/bugs/,test*,consts/const-float-bits-reject-conv.rs,consts/issue-miri-1910.rs} || true
rm -r tests/ui/{abi*,extern/,unsized-locals/,proc-macro/,threads-sendsync/,borrowck/,test*,consts/issue-miri-1910.rs} || true
rm tests/ui/mir/mir_heavy_promoted.rs # this test is oom-killed in the CI.
# Tests generating errors.
rm tests/ui/consts/const-eval/nonnull_as_ref_ub.rs tests/ui/consts/issue-94675.rs
rm tests/ui/consts/issue-94675.rs
for test in $(rg --files-with-matches "thread" tests/ui); do
rm $test
done
@ -393,7 +443,7 @@ function test_rustc() {
fi
echo "[TEST] rustc test suite"
COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 tests/ui/ --rustc-args "$RUSTC_ARGS"
COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 tests/ui/ --rustc-args "$RUSTC_ARGS" # --target $TARGET_TRIPLE
}
function test_failing_rustc() {

View file

@ -1,7 +1,7 @@
//! The common code for `tests/lang_tests_*.rs`
use std::{
env::{self, current_dir},
path::PathBuf,
path::{Path, PathBuf},
process::Command,
};
@ -23,9 +23,29 @@ pub fn main_inner(profile: Profile) {
let gcc_path = include_str!("../gcc_path");
let gcc_path = gcc_path.trim();
env::set_var("LD_LIBRARY_PATH", gcc_path);
fn rust_filter(filename: &Path) -> bool {
filename.extension().expect("extension").to_str().expect("to_str") == "rs"
}
#[cfg(feature="master")]
fn filter(filename: &Path) -> bool {
rust_filter(filename)
}
#[cfg(not(feature="master"))]
fn filter(filename: &Path) -> bool {
if let Some(filename) = filename.to_str() {
if filename.ends_with("gep.rs") {
return false;
}
}
rust_filter(filename)
}
LangTester::new()
.test_dir("tests/run")
.test_file_filter(|path| path.extension().expect("extension").to_str().expect("to_str") == "rs")
.test_file_filter(filter)
.test_extract(|source| {
let lines =
source.lines()
@ -50,6 +70,19 @@ pub fn main_inner(profile: Profile) {
"-o", exe.to_str().expect("to_str"),
path.to_str().expect("to_str"),
]);
// TODO(antoyo): find a way to send this via a cli argument.
let test_target = std::env::var("CG_GCC_TEST_TARGET");
if let Ok(ref target) = test_target {
compiler.args(&["--target", &target]);
let linker = format!("{}-gcc", target);
compiler.args(&[format!("-Clinker={}", linker)]);
let mut env_path = std::env::var("PATH").unwrap_or_default();
// TODO(antoyo): find a better way to add the PATH necessary locally.
env_path = format!("/opt/m68k-unknown-linux-gnu/bin:{}", env_path);
compiler.env("PATH", env_path);
}
if let Some(flags) = option_env!("TEST_FLAGS") {
for flag in flags.split_whitespace() {
compiler.arg(&flag);
@ -65,8 +98,37 @@ pub fn main_inner(profile: Profile) {
}
}
// Test command 2: run `tempdir/x`.
let runtime = Command::new(exe);
vec![("Compiler", compiler), ("Run-time", runtime)]
if test_target.is_ok() {
let vm_parent_dir = std::env::var("CG_GCC_VM_DIR")
.map(|dir| PathBuf::from(dir))
.unwrap_or_else(|_| std::env::current_dir().unwrap());
let vm_dir = "vm";
let exe_filename = exe.file_name().unwrap();
let vm_home_dir = vm_parent_dir.join(vm_dir).join("home");
let vm_exe_path = vm_home_dir.join(exe_filename);
// FIXME(antoyo): panicking here makes the test pass.
let inside_vm_exe_path = PathBuf::from("/home").join(&exe_filename);
let mut copy = Command::new("sudo");
copy.arg("cp");
copy.args(&[&exe, &vm_exe_path]);
let mut runtime = Command::new("sudo");
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 {
let runtime = Command::new(exe);
vec![
("Compiler", compiler),
("Run-time", runtime),
]
}
})
.run();
}

View file

@ -5,8 +5,10 @@
#![feature(asm_const)]
#[cfg(target_arch="x86_64")]
use std::arch::{asm, global_asm};
#[cfg(target_arch="x86_64")]
global_asm!(
"
.global add_asm
@ -20,6 +22,7 @@ extern "C" {
fn add_asm(a: i64, b: i64) -> i64;
}
#[cfg(target_arch="x86_64")]
pub unsafe fn mem_cpy(dst: *mut u8, src: *const u8, len: usize) {
asm!(
"rep movsb",
@ -30,7 +33,8 @@ pub unsafe fn mem_cpy(dst: *mut u8, src: *const u8, len: usize) {
);
}
fn main() {
#[cfg(target_arch="x86_64")]
fn asm() {
unsafe {
asm!("nop");
}
@ -173,3 +177,11 @@ fn main() {
}
assert_eq!(array1, array2);
}
#[cfg(not(target_arch="x86_64"))]
fn asm() {
}
fn main() {
asm();
}

View file

@ -35,6 +35,6 @@ pub(crate) unsafe auto trait Freeze {}
*/
#[start]
fn main(mut argc: isize, _argv: *const *const u8) -> isize {
fn main(_argc: isize, _argv: *const *const u8) -> isize {
0
}

View file

@ -4,138 +4,20 @@
// stdout: Success
// status: signal
#![allow(internal_features, unused_attributes)]
#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
fn main() {
std::panic::set_hook(Box::new(|_| {
println!("Success");
std::process::abort();
}));
#![no_std]
#![no_core]
/*
* Core
*/
// Because we don't have core yet.
#[lang = "sized"]
pub trait Sized {}
#[lang = "copy"]
trait Copy {
}
impl Copy for isize {}
impl Copy for *mut i32 {}
impl Copy for usize {}
impl Copy for i32 {}
impl Copy for u8 {}
impl Copy for i8 {}
#[lang = "receiver"]
trait Receiver {
}
#[lang = "freeze"]
pub(crate) unsafe auto trait Freeze {}
#[lang = "panic_location"]
struct PanicLocation {
file: &'static str,
line: u32,
column: u32,
}
mod libc {
#[link(name = "c")]
extern "C" {
pub fn puts(s: *const u8) -> i32;
pub fn fflush(stream: *mut i32) -> i32;
pub static stdout: *mut i32;
}
}
mod intrinsics {
extern "rust-intrinsic" {
#[rustc_safe_intrinsic]
pub fn abort() -> !;
}
}
#[lang = "panic"]
#[track_caller]
#[no_mangle]
pub fn panic(_msg: &'static str) -> ! {
unsafe {
// Panicking is expected iff overflow checking is enabled.
#[cfg(debug_assertions)]
libc::puts("Success\0" as *const str as *const u8);
libc::fflush(libc::stdout);
intrinsics::abort();
}
}
#[lang = "add"]
trait Add<RHS = Self> {
type Output;
fn add(self, rhs: RHS) -> Self::Output;
}
impl Add for u8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for i32 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for usize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for isize {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
/*
* Code
*/
#[start]
fn main(mut argc: isize, _argv: *const *const u8) -> isize {
let int = 9223372036854775807isize;
let int = int + argc; // overflow
let arg_count = std::env::args().count();
let int = isize::MAX;
let _int = int + arg_count as isize; // overflow
// If overflow checking is disabled, we should reach here.
#[cfg(not(debug_assertions))]
unsafe {
libc::puts("Success\0" as *const str as *const u8);
libc::fflush(libc::stdout);
intrinsics::abort();
println!("Success");
std::process::abort();
}
int
}

View file

@ -0,0 +1,26 @@
// Compiler:
//
// Run-time:
// status: 0
use std::mem::MaybeUninit;
#[derive(Debug)]
struct Struct {
pointer: *const (),
func: unsafe fn(*const ()),
}
fn func(ptr: *const ()) {
}
fn main() {
let mut x = MaybeUninit::<&Struct>::uninit();
x.write(&Struct {
pointer: std::ptr::null(),
func,
});
let x = unsafe { x.assume_init() };
let value = unsafe { (x as *const Struct).read_volatile() };
println!("{:?}", value);
}

View file

@ -7,18 +7,15 @@ edition = "2021"
test = false
[dependencies]
# tidy-alphabetical-start
bitflags = "1.0"
cstr = "0.2"
itertools = "0.10.5"
libc = "0.2"
measureme = "10.0.0"
object = { version = "0.32.0", default-features = false, features = [
"std",
"read",
] }
tracing = "0.1"
rustc_middle = { path = "../rustc_middle" }
object = { version = "0.32.0", default-features = false, features = ["std", "read"] }
rustc-demangle = "0.1.21"
rustc_ast = { path = "../rustc_ast" }
rustc_attr = { path = "../rustc_attr" }
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
rustc_data_structures = { path = "../rustc_data_structures" }
@ -30,12 +27,14 @@ rustc_index = { path = "../rustc_index" }
rustc_llvm = { path = "../rustc_llvm" }
rustc_macros = { path = "../rustc_macros" }
rustc_metadata = { path = "../rustc_metadata" }
rustc_middle = { path = "../rustc_middle" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
serde = { version = "1", features = [ "derive" ]}
serde_json = "1"
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
tracing = "0.1"
# tidy-alphabetical-end

View file

@ -102,7 +102,7 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
// have zero as both of their operands, and will therefore always have
// a value of zero. Other expressions that refer to these as operands
// can have those operands replaced with `CovTerm::Zero`.
let mut zero_expressions = FxIndexSet::default();
let mut zero_expressions = ZeroExpressions::default();
// Simplify a copy of each expression based on lower-numbered expressions,
// and then update the set of always-zero expressions if necessary.
@ -131,16 +131,16 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
)
};
// If an operand refers to an expression that is always zero, then
// that operand can be replaced with `CovTerm::Zero`.
let maybe_set_operand_to_zero = |operand: &mut CovTerm| match *operand {
CovTerm::Expression(id) => {
// If an operand refers to a counter or expression that is always
// zero, then that operand can be replaced with `CovTerm::Zero`.
let maybe_set_operand_to_zero = |operand: &mut CovTerm| {
if let CovTerm::Expression(id) = *operand {
assert_operand_expression_is_lower(id);
if zero_expressions.contains(&id) {
*operand = CovTerm::Zero;
}
}
_ => (),
if is_zero_term(&self.counters_seen, &zero_expressions, *operand) {
*operand = CovTerm::Zero;
}
};
maybe_set_operand_to_zero(&mut lhs);
maybe_set_operand_to_zero(&mut rhs);
@ -159,7 +159,7 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
}
}
ZeroExpressions(zero_expressions)
zero_expressions
}
pub(crate) fn into_finished(self) -> FunctionCoverage<'tcx> {
@ -205,19 +205,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
// thing on the Rust side unless we're confident we can do much better.
// (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
let counter_from_operand = |operand: CovTerm| match operand {
CovTerm::Expression(id) if self.zero_expressions.contains(id) => Counter::ZERO,
_ => Counter::from_term(operand),
};
self.function_coverage_info.expressions.iter().map(move |&Expression { lhs, op, rhs }| {
CounterExpression {
lhs: counter_from_operand(lhs),
lhs: self.counter_for_term(lhs),
kind: match op {
Op::Add => ExprKind::Add,
Op::Subtract => ExprKind::Subtract,
},
rhs: counter_from_operand(rhs),
rhs: self.counter_for_term(rhs),
}
})
}
@ -227,34 +222,49 @@ impl<'tcx> FunctionCoverage<'tcx> {
pub(crate) fn counter_regions(
&self,
) -> impl Iterator<Item = (Counter, &CodeRegion)> + ExactSizeIterator {
// Historically, mappings were stored directly in counter/expression
// statements in MIR, and MIR optimizations would sometimes remove them.
// That's mostly no longer true, so now we detect cases where that would
// have happened, and zero out the corresponding mappings here instead.
let counter_for_term = move |term: CovTerm| {
let force_to_zero = match term {
CovTerm::Counter(id) => !self.counters_seen.contains(id),
CovTerm::Expression(id) => self.zero_expressions.contains(id),
CovTerm::Zero => false,
};
if force_to_zero { Counter::ZERO } else { Counter::from_term(term) }
};
self.function_coverage_info.mappings.iter().map(move |mapping| {
let &Mapping { term, ref code_region } = mapping;
let counter = counter_for_term(term);
let counter = self.counter_for_term(term);
(counter, code_region)
})
}
fn counter_for_term(&self, term: CovTerm) -> Counter {
if is_zero_term(&self.counters_seen, &self.zero_expressions, term) {
Counter::ZERO
} else {
Counter::from_term(term)
}
}
}
/// Set of expression IDs that are known to always evaluate to zero.
/// Any mapping or expression operand that refers to these expressions can have
/// that reference replaced with a constant zero value.
#[derive(Default)]
struct ZeroExpressions(FxIndexSet<ExpressionId>);
impl ZeroExpressions {
fn insert(&mut self, id: ExpressionId) {
self.0.insert(id);
}
fn contains(&self, id: ExpressionId) -> bool {
self.0.contains(&id)
}
}
/// Returns `true` if the given term is known to have a value of zero, taking
/// into account knowledge of which counters are unused and which expressions
/// are always zero.
fn is_zero_term(
counters_seen: &BitSet<CounterId>,
zero_expressions: &ZeroExpressions,
term: CovTerm,
) -> bool {
match term {
CovTerm::Zero => true,
CovTerm::Counter(id) => !counters_seen.contains(id),
CovTerm::Expression(id) => zero_expressions.contains(id),
}
}

View file

@ -935,9 +935,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
macro_rules! require_simd {
($ty: expr, $diag: expr) => {
require!($ty.is_simd(), $diag)
};
($ty: expr, $variant:ident) => {{
require!($ty.is_simd(), InvalidMonomorphization::$variant { span, name, ty: $ty });
$ty.simd_size_and_type(bx.tcx())
}};
}
let tcx = bx.tcx();
@ -946,12 +947,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let arg_tys = sig.inputs();
if name == sym::simd_select_bitmask {
require_simd!(
arg_tys[1],
InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
);
let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
let (len, _) = require_simd!(arg_tys[1], SimdArgument);
let expected_int_bits = (len.max(8) - 1).next_power_of_two();
let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
@ -988,7 +984,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
// every intrinsic below takes a SIMD vector as its first argument
require_simd!(arg_tys[0], InvalidMonomorphization::SimdInput { span, name, ty: arg_tys[0] });
let (in_len, in_elem) = require_simd!(arg_tys[0], SimdInput);
let in_ty = arg_tys[0];
let comparison = match name {
@ -1001,11 +997,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
_ => None,
};
let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
if let Some(cmp_op) = comparison {
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn);
require!(
in_len == out_len,
@ -1041,8 +1034,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
.unwrap_branch();
let n = idx.len() as u64;
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn);
require!(
out_len == n,
InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
@ -1099,8 +1091,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}),
};
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn);
require!(
out_len == n,
InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
@ -1179,11 +1170,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
if name == sym::simd_select {
let m_elem_ty = in_elem;
let m_len = in_len;
require_simd!(
arg_tys[1],
InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
);
let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
let (v_len, _) = require_simd!(arg_tys[1], SimdArgument);
require!(
m_len == v_len,
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
@ -1401,20 +1388,16 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
// * M: any integer width is supported, will be truncated to i1
// All types must be simd vector types
require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
require_simd!(
arg_tys[1],
InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
);
require_simd!(
arg_tys[2],
InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
);
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
// The second argument must be a simd vector with an element type that's a pointer
// to the element type of the first argument
let (_, element_ty0) = require_simd!(in_ty, SimdFirst);
let (out_len, element_ty1) = require_simd!(arg_tys[1], SimdSecond);
// The element type of the third argument must be a signed integer type of any width:
let (out_len2, element_ty2) = require_simd!(arg_tys[2], SimdThird);
require_simd!(ret_ty, SimdReturn);
// Of the same length:
let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
require!(
in_len == out_len,
InvalidMonomorphization::SecondArgumentLength {
@ -1444,11 +1427,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty }
);
// The second argument must be a simd vector with an element type that's a pointer
// to the element type of the first argument
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
require!(
matches!(
element_ty1.kind(),
@ -1465,20 +1443,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
);
// The element type of the third argument must be a signed integer type of any width:
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
match element_ty2.kind() {
ty::Int(_) => (),
_ => {
require!(
false,
InvalidMonomorphization::ThirdArgElementType {
span,
name,
expected_element: element_ty2,
third_arg: arg_tys[2]
}
);
return_error!(InvalidMonomorphization::ThirdArgElementType {
span,
name,
expected_element: element_ty2,
third_arg: arg_tys[2]
});
}
}
@ -1527,19 +1500,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
// * M: any integer width is supported, will be truncated to i1
// All types must be simd vector types
require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
require_simd!(
arg_tys[1],
InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
);
require_simd!(
arg_tys[2],
InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
);
// The second argument must be a simd vector with an element type that's a pointer
// to the element type of the first argument
let (_, element_ty0) = require_simd!(in_ty, SimdFirst);
let (element_len1, element_ty1) = require_simd!(arg_tys[1], SimdSecond);
let (element_len2, element_ty2) = require_simd!(arg_tys[2], SimdThird);
// Of the same length:
let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
require!(
in_len == element_len1,
InvalidMonomorphization::SecondArgumentLength {
@ -1563,12 +1530,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
);
// The second argument must be a simd vector with an element type that's a pointer
// to the element type of the first argument
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
require!(
matches!(
element_ty1.kind(),
@ -1590,15 +1551,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
match element_ty2.kind() {
ty::Int(_) => (),
_ => {
require!(
false,
InvalidMonomorphization::ThirdArgElementType {
span,
name,
expected_element: element_ty2,
third_arg: arg_tys[2]
}
);
return_error!(InvalidMonomorphization::ThirdArgElementType {
span,
name,
expected_element: element_ty2,
third_arg: arg_tys[2]
});
}
}
@ -1794,8 +1752,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
bitwise_red!(simd_reduce_any: vector_reduce_or, true);
if name == sym::simd_cast_ptr {
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
require!(
in_len == out_len,
InvalidMonomorphization::ReturnLengthInputType {
@ -1843,8 +1800,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
if name == sym::simd_expose_addr {
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
require!(
in_len == out_len,
InvalidMonomorphization::ReturnLengthInputType {
@ -1872,8 +1828,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
if name == sym::simd_from_exposed_addr {
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
require!(
in_len == out_len,
InvalidMonomorphization::ReturnLengthInputType {
@ -1901,8 +1856,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
if name == sym::simd_cast || name == sym::simd_as {
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
require!(
in_len == out_len,
InvalidMonomorphization::ReturnLengthInputType {
@ -1989,17 +1943,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}
_ => { /* Unsupported. Fallthrough. */ }
}
require!(
false,
InvalidMonomorphization::UnsupportedCast {
span,
name,
in_ty,
in_elem,
ret_ty,
out_elem
}
);
return_error!(InvalidMonomorphization::UnsupportedCast {
span,
name,
in_ty,
in_elem,
ret_ty,
out_elem
});
}
macro_rules! arith_binary {
($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
@ -2010,8 +1961,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
})*
_ => {},
}
require!(
false,
return_error!(
InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
);
})*
@ -2041,8 +1991,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
})*
_ => {},
}
require!(
false,
return_error!(
InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
);
})*

Some files were not shown because too many files have changed in this diff Show more