Merge pull request #4120 from rust-lang/rustup-2025-01-03
Automatic Rustup
This commit is contained in:
commit
26f09b571b
571 changed files with 351710 additions and 1377 deletions
4
.gitmodules
vendored
4
.gitmodules
vendored
|
|
@ -22,10 +22,6 @@
|
|||
path = library/stdarch
|
||||
url = https://github.com/rust-lang/stdarch.git
|
||||
shallow = true
|
||||
[submodule "src/doc/rustc-dev-guide"]
|
||||
path = src/doc/rustc-dev-guide
|
||||
url = https://github.com/rust-lang/rustc-dev-guide.git
|
||||
shallow = true
|
||||
[submodule "src/doc/edition-guide"]
|
||||
path = src/doc/edition-guide
|
||||
url = https://github.com/rust-lang/edition-guide.git
|
||||
|
|
|
|||
53
.mailmap
53
.mailmap
|
|
@ -48,6 +48,7 @@ Andrew Poelstra <asp11@sfu.ca> <apoelstra@wpsoftware.net>
|
|||
Anhad Singh <andypythonappdeveloper@gmail.com>
|
||||
Antoine Plaskowski <antoine.plaskowski@epitech.eu>
|
||||
Anton Löfgren <anton.lofgren@gmail.com> <alofgren@op5.com>
|
||||
apiraino <apiraino@users.noreply.github.com> <apiraino@protonmail.com>
|
||||
Araam Borhanian <avborhanian@gmail.com>
|
||||
Araam Borhanian <avborhanian@gmail.com> <dobbybabee@gmail.com>
|
||||
Areski Belaid <areski@gmail.com> areski <areski@gmail.com>
|
||||
|
|
@ -62,7 +63,10 @@ Austin Seipp <mad.one@gmail.com> <as@hacks.yi.org>
|
|||
Ayaz Hafiz <ayaz.hafiz.1@gmail.com>
|
||||
Aydin Kim <ladinjin@hanmail.net> aydin.kim <aydin.kim@samsung.com>
|
||||
Ayush Mishra <ayushmishra2005@gmail.com>
|
||||
Ashley Mannix <kodraus@hey.com> <ashleymannix@live.com.au>
|
||||
asrar <aszenz@gmail.com>
|
||||
b-naber <bn263@gmx.de>
|
||||
b-naber <bn263@gmx.de> <b_naber@gmx.de>
|
||||
BaoshanPang <pangbw@gmail.com>
|
||||
Barosl Lee <vcs@barosl.com> Barosl LEE <github@barosl.com>
|
||||
Bastian Kersting <bastian@cmbt.de>
|
||||
|
|
@ -98,6 +102,8 @@ Caleb Cartwright <caleb.cartwright@outlook.com>
|
|||
Caleb Jones <code@calebjones.net>
|
||||
Noah Lev <camelidcamel@gmail.com>
|
||||
Noah Lev <camelidcamel@gmail.com> <37223377+camelid@users.noreply.github.com>
|
||||
Catherine <catherine3.flores@gmail.com>
|
||||
Catherine <catherine3.flores@gmail.com> <catherine.3.flores@gmail.com>
|
||||
cameron1024 <cameron.studdstreet@gmail.com>
|
||||
Camille Gillot <gillot.camille@gmail.com>
|
||||
Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com>
|
||||
|
|
@ -133,11 +139,13 @@ Clement Miao <clementmiao@gmail.com>
|
|||
Clément Renault <renault.cle@gmail.com>
|
||||
Cliff Dyer <jcd@sdf.org>
|
||||
Clinton Ryan <clint.ryan3@gmail.com>
|
||||
Taylor Cramer <cramertaylorj@gmail.com> <cramertj@google.com>
|
||||
ember arlynx <ember@lunar.town> <corey@octayn.net>
|
||||
Crazycolorz5 <Crazycolorz5@gmail.com>
|
||||
csmoe <35686186+csmoe@users.noreply.github.com>
|
||||
Cyryl Płotnicki <cyplo@cyplo.net>
|
||||
Damien Schoof <damien.schoof@gmail.com>
|
||||
Dan Gohman <dev@sunfishcode.online> <sunfish@mozilla.com>
|
||||
Dan Robertson <danlrobertson89@gmail.com>
|
||||
Daniel Campoverde <alx741@riseup.net>
|
||||
Daniel J Rollins <drollins@financialforce.com>
|
||||
|
|
@ -179,10 +187,17 @@ Eduardo Bautista <me@eduardobautista.com> <=>
|
|||
Eduardo Bautista <me@eduardobautista.com> <mail@eduardobautista.com>
|
||||
Eduardo Broto <ebroto@tutanota.com>
|
||||
Edward Shen <code@eddie.sh> <xes@meta.com>
|
||||
Jacob Finkelman <eh2406@wayne.edu>
|
||||
Jacob Finkelman <eh2406@wayne.edu> <YeomanYaacov@gmail.com>
|
||||
Jacob Finkelman <eh2406@wayne.edu> <jfinkelm@amazon.com>
|
||||
Jacob Finkelman <eh2406@wayne.edu> <finkelman@semcog.org>
|
||||
Jacob Finkelman <eh2406@wayne.edu> <Eh2406@users.noreply.github.com>
|
||||
Elliott Slaughter <elliottslaughter@gmail.com> <eslaughter@mozilla.com>
|
||||
Elly Fong-Jones <elly@leptoquark.net>
|
||||
Eric Holk <eric.holk@gmail.com> <eholk@cs.indiana.edu>
|
||||
Eric Holk <eric.holk@gmail.com> <eholk@mozilla.com>
|
||||
Eric Holk <eric.holk@gmail.com> <eric@theincredibleholk.org>
|
||||
Eric Holk <eric.holk@gmail.com> <ericholk@microsoft.com>
|
||||
Eric Holmes <eric@ejholmes.net>
|
||||
Eric Reed <ecreed@cs.washington.edu> <ereed@mozilla.com>
|
||||
Erick Tryzelaar <erick.tryzelaar@gmail.com> <etryzelaar@iqt.org>
|
||||
|
|
@ -206,6 +221,7 @@ Felix S. Klock II <pnkfelix@pnkfx.org> <pnkfelix@mozilla.com>
|
|||
Félix Saparelli <felix@passcod.name>
|
||||
Flaper Fesp <flaper87@gmail.com>
|
||||
Florian Berger <fbergr@gmail.com>
|
||||
Florian Gilcher <florian.gilcher@asquera.de> <flo@andersground.net>
|
||||
Florian Wilkens <mrfloya_github@outlook.com> Florian Wilkens <floya@live.de>
|
||||
François Mockers <mockersf@gmail.com>
|
||||
Frank Steffahn <fdsteffahn@gmail.com> <frank.steffahn@stu.uni-kiel.de>
|
||||
|
|
@ -240,6 +256,8 @@ Herman J. Radtke III <herman@hermanradtke.com> Herman J. Radtke III <hermanradtk
|
|||
Hirochika Matsumoto <git@hkmatsumoto.com> <matsujika@gmail.com>
|
||||
Hrvoje Nikšić <hniksic@gmail.com>
|
||||
Hsiang-Cheng Yang <rick68@users.noreply.github.com>
|
||||
Huon Wilson <dbau.pp@gmail.com>
|
||||
Huon Wilson <dbau.pp@gmail.com> <wilson.huon@gmail.com>
|
||||
Ian Jackson <ijackson@chiark.greenend.org.uk> <ian.jackson@citrix.com>
|
||||
Ian Jackson <ijackson@chiark.greenend.org.uk> <ijackson+github@slimy.greenend.org.uk>
|
||||
Ian Jackson <ijackson@chiark.greenend.org.uk> <iwj@xenproject.org>
|
||||
|
|
@ -252,9 +270,13 @@ ivan tkachenko <me@ratijas.tk>
|
|||
J. J. Weber <jjweber@gmail.com>
|
||||
Jack Huey <jack.huey@umassmed.edu> <jackh726@gmail.com>
|
||||
Jacob <jacob.macritchie@gmail.com>
|
||||
Jacob Hoffman-Andrews <rust@hoffman-andrews.com> <github@hoffman-andrews.com>
|
||||
Jacob Greenfield <xales@naveria.com>
|
||||
Jacob Pratt <jacob@jhpratt.dev> <the.z.cuber@gmail.com>
|
||||
Jacob Pratt <jacob@jhpratt.dev> <jacopratt@tesla.com>
|
||||
Jake Goulding <jake.goulding@integer32.com>
|
||||
Jake Goulding <jake.goulding@integer32.com> <jake.goulding@gmail.com>
|
||||
Jake Goulding <jake.goulding@integer32.com> <shepmaster@mac.com>
|
||||
Jake Vossen <jake@vossen.dev>
|
||||
Jakob Degen <jakob.e.degen@gmail.com> <jakob@degen.com>
|
||||
Jakob Lautrup Nysom <jako3047@gmail.com>
|
||||
|
|
@ -287,6 +309,7 @@ Jerry Hardee <hardeejj9@gmail.com>
|
|||
Jesús Rubio <jesusprubio@gmail.com>
|
||||
Jethro Beekman <github@jbeekman.nl>
|
||||
Jian Zeng <knight42@mail.ustc.edu.cn>
|
||||
Jieyou Xu <jieyouxu@outlook.com>
|
||||
Jieyou Xu <jieyouxu@outlook.com> <39484203+jieyouxu@users.noreply.github.com>
|
||||
Jihyun Yu <j.yu@navercorp.com> <yjh0502@gmail.com>
|
||||
Jihyun Yu <j.yu@navercorp.com> jihyun <jihyun@nablecomm.com>
|
||||
|
|
@ -322,9 +345,12 @@ Josh Holmer <jholmer.in@gmail.com>
|
|||
Josh Stone <cuviper@gmail.com> <jistone@redhat.com>
|
||||
Josh Stone <cuviper@gmail.com> <jistone@fedoraproject.org>
|
||||
Julia Ryan <juliaryan3.14@gmail.com> <josephryan3.14@gmail.com>
|
||||
Jubilee Young <workingjubilee@gmail.com> <46493976+workingjubilee@users.noreply.github.com>
|
||||
Jubilee Young <workingjubilee@gmail.com>
|
||||
Julian Knodt <julianknodt@gmail.com>
|
||||
jumbatm <jumbatm@gmail.com> <30644300+jumbatm@users.noreply.github.com>
|
||||
Junyoung Cho <june0.cho@samsung.com>
|
||||
Jynn Nelson <github@jyn.dev> <rust@jyn.dev>
|
||||
Jynn Nelson <github@jyn.dev> <jyn514@gmail.com>
|
||||
Jynn Nelson <github@jyn.dev> <joshua@yottadb.com>
|
||||
Jynn Nelson <github@jyn.dev> <jyn.nelson@redjack.com>
|
||||
|
|
@ -385,12 +411,14 @@ Marcell Pardavi <marcell.pardavi@gmail.com>
|
|||
Marcus Klaas de Vries <mail@marcusklaas.nl>
|
||||
Margaret Meyerhofer <mmeyerho@andrew.cmu.edu> <mmeyerho@andrew>
|
||||
Mark Mansi <markm@cs.wisc.edu>
|
||||
Mark Mansi <markm@cs.wisc.edu> <m.mim95@gmail.com>
|
||||
Mark Rousskov <mark.simulacrum@gmail.com>
|
||||
Mark Sinclair <mark.edward.x@gmail.com>
|
||||
Mark Sinclair <mark.edward.x@gmail.com> =Mark Sinclair <=125axel125@gmail.com>
|
||||
Markus Legner <markus@legner.ch>
|
||||
Markus Westerlind <marwes91@gmail.com> Markus <marwes91@gmail.com>
|
||||
Martin Carton <cartonmartin+git@gmail.com>
|
||||
Martin Carton <cartonmartin+git@gmail.com> <cartonmartin@gmail.com>
|
||||
Martin Habovštiak <martin.habovstiak@gmail.com>
|
||||
Martin Hafskjold Thoresen <martinhath@gmail.com>
|
||||
Martin Nordholts <martin.nordholts@codetale.se> <enselic@gmail.com>
|
||||
|
|
@ -415,6 +443,7 @@ Melody Horn <melody@boringcactus.com> <mathphreak@gmail.com>
|
|||
Mendes <pedro.mendes.26@gmail.com>
|
||||
mental <m3nta1@yahoo.com>
|
||||
mibac138 <5672750+mibac138@users.noreply.github.com>
|
||||
Michael Howell <michael@notriddle.com> <notriddle+rust-mod@protonmail.com>
|
||||
Michael Williams <m.t.williams@live.com>
|
||||
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@gmail>
|
||||
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@gmail.com>
|
||||
|
|
@ -431,6 +460,7 @@ Ms2ger <ms2ger@gmail.com> <Ms2ger@gmail.com>
|
|||
msizanoen1 <qtmlabs@protonmail.com>
|
||||
Mukilan Thiagarajan <mukilanthiagarajan@gmail.com>
|
||||
Nadrieril Feneanar <Nadrieril@users.noreply.github.com>
|
||||
Nadrieril Feneanar <Nadrieril@users.noreply.github.com> <nadrieril+rust@gmail.com>
|
||||
Nadrieril Feneanar <Nadrieril@users.noreply.github.com> <nadrieril+git@gmail.com>
|
||||
NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> <makoto.nksm@gmail.com>
|
||||
NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> <makoto.nksm+github@gmail.com>
|
||||
|
|
@ -447,15 +477,23 @@ Nicholas Bishop <nbishop@nbishop.net> <nicholasbishop@gmail.com>
|
|||
Nicholas Bishop <nbishop@nbishop.net> <nicholasbishop@google.com>
|
||||
Nicholas Nethercote <n.nethercote@gmail.com> <nnethercote@apple.com>
|
||||
Nicholas Nethercote <n.nethercote@gmail.com> <nnethercote@mozilla.com>
|
||||
Nick Cameron <nrc@ncameron.org> <ncameron@mozilla.com>
|
||||
Nick Fitzgerald <fitzgen@gmail.com> <nfitzgerald@mozilla.com>
|
||||
Nick Platt <platt.nicholas@gmail.com>
|
||||
Niclas Schwarzlose <15schnic@gmail.com>
|
||||
Nicolas Abram <abramlujan@gmail.com>
|
||||
Nicole Mazzuca <npmazzuca@gmail.com>
|
||||
Niko Matsakis <rust@nikomatsakis.com>
|
||||
Niko Matsakis <rust@nikomatsakis.com> <niko@alum.mit.edu>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <48135649+Nilstrieb@users.noreply.github.com>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nilstrieb@gmail.com>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <rust@noratrieb.dev>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nora@noratrieb.dev>
|
||||
Nif Ward <nif.ward@gmail.com>
|
||||
Nika Layzell <nika@thelayzells.com> <michael@thelayzells.com>
|
||||
Nikita Popov <nikita.ppv@gmail.com>
|
||||
Nikita Popov <nikita.ppv@gmail.com> <npopov@redhat.com>
|
||||
NODA Kai <nodakai@gmail.com>
|
||||
Oğuz Ağcayazı <oguz.agcayazi@gmail.com> <oguz.agcayazi@gmail.com>
|
||||
Oğuz Ağcayazı <oguz.agcayazi@gmail.com> <ouz.agz@gmail.com>
|
||||
|
|
@ -516,6 +554,7 @@ Ricky Hosfelt <ricky@hosfelt.io>
|
|||
Ritiek Malhotra <ritiekmalhotra123@gmail.com>
|
||||
Rob Arnold <robarnold@cs.cmu.edu>
|
||||
Rob Arnold <robarnold@cs.cmu.edu> Rob Arnold <robarnold@68-26-94-7.pools.spcsdns.net>
|
||||
Robert Collins <robertc@robertcollins.net> <robertc+rust@robertcollins.net>
|
||||
Robert Foss <dev@robertfoss.se> robertfoss <dev@robertfoss.se>
|
||||
Robert Gawdzik <rgawdzik@hotmail.com> Robert Gawdzik ☢ <rgawdzik@hotmail.com>
|
||||
Robert Habermeier <rphmeier@gmail.com>
|
||||
|
|
@ -553,7 +592,15 @@ Simon Sapin <simon@exyr.org> <simon.sapin@exyr.org>
|
|||
Simonas Kazlauskas <git@kazlauskas.me> Simonas Kazlauskas <github@kazlauskas.me>
|
||||
Simonas Kazlauskas <git@kazlauskas.me> <simonas+t-compiler@kazlauskas.me>
|
||||
Siva Prasad <sivaauturic@gmail.com>
|
||||
Skgland <3877590+Skgland@users.noreply.github.com>
|
||||
Skgland <3877590+Skgland@users.noreply.github.com> <bb-github@t-online.de>
|
||||
Skgland <3877590+Skgland@users.noreply.github.com> <bennet.blessmann+github@googlemail.com>
|
||||
Smittyvb <me@smitop.com>
|
||||
Sophia June Turner <547158+sophiajt@users.noreply.github.com>
|
||||
Sophia June Turner <547158+sophiajt@users.noreply.github.com> <547158+jntrnr@users.noreply.github.com>
|
||||
Sophia June Turner <547158+sophiajt@users.noreply.github.com> <jonathandturner@users.noreply.github.com>
|
||||
Sophia June Turner <547158+sophiajt@users.noreply.github.com> <jturner@mozilla.com>
|
||||
Sophia June Turner <547158+sophiajt@users.noreply.github.com> <jonathan.d.turner@gmail.com>
|
||||
Srinivas Reddy Thatiparthy <thatiparthysreenivas@gmail.com>
|
||||
Stanislav Tkach <stanislav.tkach@gmail.com>
|
||||
startling <tdixon51793@gmail.com>
|
||||
|
|
@ -586,8 +633,10 @@ Tim Diekmann <t.diekmann.3dv@gmail.com>
|
|||
Tim Hutt <tdhutt@gmail.com>
|
||||
Tim JIANG <p90eri@gmail.com>
|
||||
Tim Joseph Dumol <tim@timdumol.com>
|
||||
Tim Neumann <mail@timnn.me> <timnn@google.com>
|
||||
Timothy Maloney <tmaloney@pdx.edu>
|
||||
Tomas Koutsky <tomas@stepnivlk.net>
|
||||
Tomasz Miąsko <tomasz.miasko@gmail.com>
|
||||
Torsten Weber <TorstenWeber12@gmail.com>
|
||||
Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com>
|
||||
Trevor Gross <tmgross@umich.edu> <t.gross35@gmail.com>
|
||||
|
|
@ -607,7 +656,9 @@ Valerii Lashmanov <vflashm@gmail.com>
|
|||
Vitali Haravy <HumaneProgrammer@gmail.com> Vitali Haravy <humaneprogrammer@gmail.com>
|
||||
Vitaly Shukela <vi0oss@gmail.com>
|
||||
Waffle Lapkin <waffle.lapkin@gmail.com>
|
||||
Waffle Lapkin <waffle.lapkin@tasking.com>
|
||||
Waffle Lapkin <waffle.lapkin@gmail.com> <waffle.lapkin@tasking.com>
|
||||
Weihang Lo <me@weihanglo.tw>
|
||||
Weihang Lo <me@weihanglo.tw> <weihanglo@users.noreply.github.com>
|
||||
Wesley Wiser <wwiser@gmail.com> <wesleywiser@microsoft.com>
|
||||
whitequark <whitequark@whitequark.org>
|
||||
William Ting <io@williamting.com> <william.h.ting@gmail.com>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,38 @@
|
|||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
/*! ABI handling for rustc
|
||||
|
||||
## What is an "ABI"?
|
||||
|
||||
Literally, "application binary interface", which means it is everything about how code interacts,
|
||||
at the machine level, with other code. This means it technically covers all of the following:
|
||||
- object binary format for e.g. relocations or offset tables
|
||||
- in-memory layout of types
|
||||
- procedure calling conventions
|
||||
|
||||
When we discuss "ABI" in the context of rustc, we are probably discussing calling conventions.
|
||||
To describe those `rustc_abi` also covers type layout, as it must for values passed on the stack.
|
||||
Despite `rustc_abi` being about calling conventions, it is good to remember these usages exist.
|
||||
You will encounter all of them and more if you study target-specific codegen enough!
|
||||
Even in general conversation, when someone says "the Rust ABI is unstable", it may allude to
|
||||
either or both of
|
||||
- `repr(Rust)` types have a mostly-unspecified layout
|
||||
- `extern "Rust" fn(A) -> R` has an unspecified calling convention
|
||||
|
||||
## Crate Goal
|
||||
|
||||
ABI is a foundational concept, so the `rustc_abi` crate serves as an equally foundational crate.
|
||||
It cannot carry all details relevant to an ABI: those permeate code generation and linkage.
|
||||
Instead, `rustc_abi` is intended to provide the interface for reasoning about the binary interface.
|
||||
It should contain traits and types that other crates then use in their implementation.
|
||||
For example, a platform's `extern "C" fn` calling convention will be implemented in `rustc_target`
|
||||
but `rustc_abi` contains the types for calculating layout and describing register-passing.
|
||||
This makes it easier to describe things in the same way across targets, codegen backends, and
|
||||
even other Rust compilers, such as rust-analyzer!
|
||||
|
||||
*/
|
||||
|
||||
use std::fmt;
|
||||
#[cfg(feature = "nightly")]
|
||||
use std::iter::Step;
|
||||
|
|
|
|||
|
|
@ -241,15 +241,15 @@ impl AngleBracketedArg {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<P<GenericArgs>> for AngleBracketedArgs {
|
||||
fn into(self) -> P<GenericArgs> {
|
||||
P(GenericArgs::AngleBracketed(self))
|
||||
impl From<AngleBracketedArgs> for P<GenericArgs> {
|
||||
fn from(val: AngleBracketedArgs) -> Self {
|
||||
P(GenericArgs::AngleBracketed(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<P<GenericArgs>> for ParenthesizedArgs {
|
||||
fn into(self) -> P<GenericArgs> {
|
||||
P(GenericArgs::Parenthesized(self))
|
||||
impl From<ParenthesizedArgs> for P<GenericArgs> {
|
||||
fn from(val: ParenthesizedArgs) -> Self {
|
||||
P(GenericArgs::Parenthesized(val))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
use std::fmt::{self, Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::expand::typetree::TypeTree;
|
||||
use crate::expand::{Decodable, Encodable, HashStable_Generic};
|
||||
use crate::ptr::P;
|
||||
use crate::{Ty, TyKind};
|
||||
|
|
@ -79,10 +78,6 @@ pub struct AutoDiffItem {
|
|||
/// The name of the function being generated
|
||||
pub target: String,
|
||||
pub attrs: AutoDiffAttrs,
|
||||
/// Describe the memory layout of input types
|
||||
pub inputs: Vec<TypeTree>,
|
||||
/// Describe the memory layout of the output type
|
||||
pub output: TypeTree,
|
||||
}
|
||||
#[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct AutoDiffAttrs {
|
||||
|
|
@ -262,22 +257,14 @@ impl AutoDiffAttrs {
|
|||
!matches!(self.mode, DiffMode::Error | DiffMode::Source)
|
||||
}
|
||||
|
||||
pub fn into_item(
|
||||
self,
|
||||
source: String,
|
||||
target: String,
|
||||
inputs: Vec<TypeTree>,
|
||||
output: TypeTree,
|
||||
) -> AutoDiffItem {
|
||||
AutoDiffItem { source, target, inputs, output, attrs: self }
|
||||
pub fn into_item(self, source: String, target: String) -> AutoDiffItem {
|
||||
AutoDiffItem { source, target, attrs: self }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for AutoDiffItem {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Differentiating {} -> {}", self.source, self.target)?;
|
||||
write!(f, " with attributes: {:?}", self.attrs)?;
|
||||
write!(f, " with inputs: {:?}", self.inputs)?;
|
||||
write!(f, " with output: {:?}", self.output)
|
||||
write!(f, " with attributes: {:?}", self.attrs)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use rustc_span::{Ident, Span, Symbol};
|
|||
|
||||
use crate::Expr;
|
||||
use crate::ptr::P;
|
||||
use crate::token::LitKind;
|
||||
|
||||
// Definitions:
|
||||
//
|
||||
|
|
@ -45,6 +46,10 @@ pub struct FormatArgs {
|
|||
pub span: Span,
|
||||
pub template: Vec<FormatArgsPiece>,
|
||||
pub arguments: FormatArguments,
|
||||
/// The raw, un-split format string literal, with no escaping or processing.
|
||||
///
|
||||
/// Generally only useful for lints that care about the raw bytes the user wrote.
|
||||
pub uncooked_fmt_str: (LitKind, Symbol),
|
||||
}
|
||||
|
||||
/// A piece of a format template string.
|
||||
|
|
|
|||
|
|
@ -1596,7 +1596,7 @@ fn walk_inline_asm_sym<T: MutVisitor>(
|
|||
|
||||
fn walk_format_args<T: MutVisitor>(vis: &mut T, fmt: &mut FormatArgs) {
|
||||
// FIXME: visit the template exhaustively.
|
||||
let FormatArgs { span, template: _, arguments } = fmt;
|
||||
let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt;
|
||||
for FormatArgument { kind, expr } in arguments.all_args_mut() {
|
||||
match kind {
|
||||
FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {
|
||||
|
|
|
|||
|
|
@ -158,9 +158,9 @@ impl<T> From<Vec<T>> for P<[T]> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Into<Vec<T>> for P<[T]> {
|
||||
fn into(self) -> Vec<T> {
|
||||
self.into_vec()
|
||||
impl<T> From<P<[T]>> for Vec<T> {
|
||||
fn from(val: P<[T]>) -> Self {
|
||||
val.into_vec()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1061,7 +1061,7 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(
|
|||
}
|
||||
|
||||
pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) -> V::Result {
|
||||
let FormatArgs { span: _, template: _, arguments } = fmt;
|
||||
let FormatArgs { span: _, template: _, arguments, uncooked_fmt_str: _ } = fmt;
|
||||
for FormatArgument { kind, expr } in arguments.all_args() {
|
||||
match kind {
|
||||
FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {
|
||||
|
|
|
|||
|
|
@ -1845,11 +1845,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
GenericParamKind::Lifetime => {
|
||||
// AST resolution emitted an error on those parameters, so we lower them using
|
||||
// `ParamName::Error`.
|
||||
let ident = self.lower_ident(param.ident);
|
||||
let param_name =
|
||||
if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
|
||||
ParamName::Error
|
||||
ParamName::Error(ident)
|
||||
} else {
|
||||
let ident = self.lower_ident(param.ident);
|
||||
ParamName::Plain(ident)
|
||||
};
|
||||
let kind =
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{CaptureBy, ExprKind, HirId, Node};
|
||||
use rustc_hir::{self as hir, CaptureBy, ExprKind, HirId, Node};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
|
@ -683,48 +684,126 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn add_move_error_suggestions(&self, err: &mut Diag<'_>, binds_to: &[Local]) {
|
||||
let mut suggestions: Vec<(Span, String, String)> = Vec::new();
|
||||
/// A HIR visitor to associate each binding with a `&` or `&mut` that could be removed to
|
||||
/// make it bind by reference instead (if possible)
|
||||
struct BindingFinder<'tcx> {
|
||||
typeck_results: &'tcx ty::TypeckResults<'tcx>,
|
||||
hir: rustc_middle::hir::map::Map<'tcx>,
|
||||
/// Input: the span of the pattern we're finding bindings in
|
||||
pat_span: Span,
|
||||
/// Input: the spans of the bindings we're providing suggestions for
|
||||
binding_spans: Vec<Span>,
|
||||
/// Internal state: have we reached the pattern we're finding bindings in?
|
||||
found_pat: bool,
|
||||
/// Internal state: the innermost `&` or `&mut` "above" the visitor
|
||||
ref_pat: Option<&'tcx hir::Pat<'tcx>>,
|
||||
/// Internal state: could removing a `&` give bindings unexpected types?
|
||||
has_adjustments: bool,
|
||||
/// Output: for each input binding, the `&` or `&mut` to remove to make it by-ref
|
||||
ref_pat_for_binding: Vec<(Span, Option<&'tcx hir::Pat<'tcx>>)>,
|
||||
/// Output: ref patterns that can't be removed straightforwardly
|
||||
cannot_remove: FxHashSet<HirId>,
|
||||
}
|
||||
impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> {
|
||||
type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.hir
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {
|
||||
// Don't walk into const patterns or anything else that might confuse this
|
||||
if !self.found_pat {
|
||||
hir::intravisit::walk_expr(self, ex)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
|
||||
if p.span == self.pat_span {
|
||||
self.found_pat = true;
|
||||
}
|
||||
|
||||
let parent_has_adjustments = self.has_adjustments;
|
||||
self.has_adjustments |=
|
||||
self.typeck_results.pat_adjustments().contains_key(p.hir_id);
|
||||
|
||||
// Track the innermost `&` or `&mut` enclosing bindings, to suggest removing it.
|
||||
let parent_ref_pat = self.ref_pat;
|
||||
if let hir::PatKind::Ref(..) = p.kind {
|
||||
self.ref_pat = Some(p);
|
||||
// To avoid edition-dependent logic to figure out how many refs this `&` can
|
||||
// peel off, simply don't remove the "parent" `&`.
|
||||
self.cannot_remove.extend(parent_ref_pat.map(|r| r.hir_id));
|
||||
if self.has_adjustments {
|
||||
// Removing this `&` could give child bindings unexpected types, so don't.
|
||||
self.cannot_remove.insert(p.hir_id);
|
||||
// As long the `&` stays, child patterns' types should be as expected.
|
||||
self.has_adjustments = false;
|
||||
}
|
||||
}
|
||||
|
||||
if let hir::PatKind::Binding(_, _, ident, _) = p.kind {
|
||||
// the spans in `binding_spans` encompass both the ident and binding mode
|
||||
if let Some(&bind_sp) =
|
||||
self.binding_spans.iter().find(|bind_sp| bind_sp.contains(ident.span))
|
||||
{
|
||||
self.ref_pat_for_binding.push((bind_sp, self.ref_pat));
|
||||
} else {
|
||||
// we've encountered a binding that we're not reporting a move error for.
|
||||
// we don't want to change its type, so don't remove the surrounding `&`.
|
||||
if let Some(ref_pat) = self.ref_pat {
|
||||
self.cannot_remove.insert(ref_pat.hir_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hir::intravisit::walk_pat(self, p);
|
||||
self.ref_pat = parent_ref_pat;
|
||||
self.has_adjustments = parent_has_adjustments;
|
||||
}
|
||||
}
|
||||
let mut pat_span = None;
|
||||
let mut binding_spans = Vec::new();
|
||||
for local in binds_to {
|
||||
let bind_to = &self.body.local_decls[*local];
|
||||
if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span, .. })) =
|
||||
if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span: pat_sp, .. })) =
|
||||
*bind_to.local_info()
|
||||
{
|
||||
let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let Some(stripped) = pat_snippet.strip_prefix('&') else {
|
||||
suggestions.push((
|
||||
bind_to.source_info.span.shrink_to_lo(),
|
||||
"consider borrowing the pattern binding".to_string(),
|
||||
"ref ".to_string(),
|
||||
));
|
||||
continue;
|
||||
};
|
||||
let inner_pat_snippet = stripped.trim_start();
|
||||
let (pat_span, suggestion, to_remove) = if inner_pat_snippet.starts_with("mut")
|
||||
&& inner_pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
|
||||
{
|
||||
let inner_pat_snippet = inner_pat_snippet["mut".len()..].trim_start();
|
||||
let pat_span = pat_span.with_hi(
|
||||
pat_span.lo()
|
||||
+ BytePos((pat_snippet.len() - inner_pat_snippet.len()) as u32),
|
||||
);
|
||||
(pat_span, String::new(), "mutable borrow")
|
||||
} else {
|
||||
let pat_span = pat_span.with_hi(
|
||||
pat_span.lo()
|
||||
+ BytePos(
|
||||
(pat_snippet.len() - inner_pat_snippet.trim_start().len()) as u32,
|
||||
),
|
||||
);
|
||||
(pat_span, String::new(), "borrow")
|
||||
};
|
||||
suggestions.push((
|
||||
pat_span,
|
||||
format!("consider removing the {to_remove}"),
|
||||
suggestion,
|
||||
));
|
||||
pat_span = Some(pat_sp);
|
||||
binding_spans.push(bind_to.source_info.span);
|
||||
}
|
||||
}
|
||||
let Some(pat_span) = pat_span else { return };
|
||||
|
||||
let hir = self.infcx.tcx.hir();
|
||||
let Some(body) = hir.maybe_body_owned_by(self.mir_def_id()) else { return };
|
||||
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
|
||||
let mut finder = BindingFinder {
|
||||
typeck_results,
|
||||
hir,
|
||||
pat_span,
|
||||
binding_spans,
|
||||
found_pat: false,
|
||||
ref_pat: None,
|
||||
has_adjustments: false,
|
||||
ref_pat_for_binding: Vec::new(),
|
||||
cannot_remove: FxHashSet::default(),
|
||||
};
|
||||
finder.visit_body(body);
|
||||
|
||||
let mut suggestions = Vec::new();
|
||||
for (binding_span, opt_ref_pat) in finder.ref_pat_for_binding {
|
||||
if let Some(ref_pat) = opt_ref_pat
|
||||
&& !finder.cannot_remove.contains(&ref_pat.hir_id)
|
||||
&& let hir::PatKind::Ref(subpat, mutbl) = ref_pat.kind
|
||||
&& let Some(ref_span) = ref_pat.span.trim_end(subpat.span)
|
||||
{
|
||||
let mutable_str = if mutbl.is_mut() { "mutable " } else { "" };
|
||||
let msg = format!("consider removing the {mutable_str}borrow");
|
||||
suggestions.push((ref_span, msg, "".to_string()));
|
||||
} else {
|
||||
let msg = "consider borrowing the pattern binding".to_string();
|
||||
suggestions.push((binding_span.shrink_to_lo(), msg, "ref ".to_string()));
|
||||
}
|
||||
}
|
||||
suggestions.sort_unstable_by_key(|&(span, _, _)| span);
|
||||
|
|
|
|||
|
|
@ -575,7 +575,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// ---------- place
|
||||
self.err.multipart_suggestions(
|
||||
format!(
|
||||
"to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API",
|
||||
"use `.insert()` to insert a value into a `{}`, `.get_mut()` \
|
||||
to modify it, or the entry API for more flexibility",
|
||||
self.ty,
|
||||
),
|
||||
vec![
|
||||
|
|
@ -592,16 +593,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
(rv.span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
vec![
|
||||
// val.get_mut(index).map(|v| { *v = rv; });
|
||||
// if let Some(v) = val.get_mut(index) { *v = rv; }
|
||||
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
|
||||
(
|
||||
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
||||
".get_mut(".to_string(),
|
||||
),
|
||||
(
|
||||
index.span.shrink_to_hi().with_hi(place.span.hi()),
|
||||
").map(|val| { *val".to_string(),
|
||||
") { *val".to_string(),
|
||||
),
|
||||
(rv.span.shrink_to_hi(), "; })".to_string()),
|
||||
(rv.span.shrink_to_hi(), "; }".to_string()),
|
||||
],
|
||||
vec![
|
||||
// let x = val.entry(index).or_insert(rv);
|
||||
|
|
@ -622,21 +624,22 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.suggested = true;
|
||||
} else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
|
||||
&& let hir::ExprKind::Index(val, index, _) = receiver.kind
|
||||
&& expr.span == self.assign_span
|
||||
&& receiver.span == self.assign_span
|
||||
{
|
||||
// val[index].path(args..);
|
||||
self.err.multipart_suggestion(
|
||||
format!("to modify a `{}` use `.get_mut()`", self.ty),
|
||||
vec![
|
||||
(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
|
||||
(
|
||||
val.span.shrink_to_hi().with_hi(index.span.lo()),
|
||||
".get_mut(".to_string(),
|
||||
),
|
||||
(
|
||||
index.span.shrink_to_hi().with_hi(receiver.span.hi()),
|
||||
").map(|val| val".to_string(),
|
||||
") { val".to_string(),
|
||||
),
|
||||
(sp.shrink_to_hi(), ")".to_string()),
|
||||
(sp.shrink_to_hi(), "; }".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -197,6 +197,8 @@ builtin_macros_format_redundant_args = redundant {$n ->
|
|||
|
||||
builtin_macros_format_remove_raw_ident = remove the `r#`
|
||||
|
||||
builtin_macros_format_reorder_format_parameter = did you mean `{$replacement}`?
|
||||
|
||||
builtin_macros_format_requires_string = requires at least a format string argument
|
||||
|
||||
builtin_macros_format_string_invalid = invalid format string: {$desc}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use smallvec::smallvec;
|
|||
use {rustc_ast as ast, rustc_parse_format as parse};
|
||||
|
||||
use crate::errors;
|
||||
use crate::util::expr_to_spanned_string;
|
||||
use crate::util::{ExprToSpannedString, expr_to_spanned_string};
|
||||
|
||||
pub struct AsmArgs {
|
||||
pub templates: Vec<P<ast::Expr>>,
|
||||
|
|
@ -527,7 +527,12 @@ fn expand_preparsed_asm(
|
|||
let msg = "asm template must be a string literal";
|
||||
let template_sp = template_expr.span;
|
||||
let template_is_mac_call = matches!(template_expr.kind, ast::ExprKind::MacCall(_));
|
||||
let (template_str, template_style, template_span) = {
|
||||
let ExprToSpannedString {
|
||||
symbol: template_str,
|
||||
style: template_style,
|
||||
span: template_span,
|
||||
..
|
||||
} = {
|
||||
let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else {
|
||||
return ExpandResult::Retry(());
|
||||
};
|
||||
|
|
|
|||
|
|
@ -618,6 +618,17 @@ pub(crate) enum InvalidFormatStringSuggestion {
|
|||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
builtin_macros_format_reorder_format_parameter,
|
||||
code = "{replacement}",
|
||||
style = "verbose",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
ReorderFormatParameter {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
replacement: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use rustc_parse_format as parse;
|
|||
use rustc_span::{BytePos, ErrorGuaranteed, Ident, InnerSpan, Span, Symbol};
|
||||
|
||||
use crate::errors;
|
||||
use crate::util::expr_to_spanned_string;
|
||||
use crate::util::{ExprToSpannedString, expr_to_spanned_string};
|
||||
|
||||
// The format_args!() macro is expanded in three steps:
|
||||
// 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
|
||||
|
|
@ -166,13 +166,18 @@ fn make_format_args(
|
|||
|
||||
let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input;
|
||||
|
||||
let (fmt_str, fmt_style, fmt_span) = {
|
||||
let ExprToSpannedString {
|
||||
symbol: fmt_str,
|
||||
span: fmt_span,
|
||||
style: fmt_style,
|
||||
uncooked_symbol: uncooked_fmt_str,
|
||||
} = {
|
||||
let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else {
|
||||
return ExpandResult::Retry(());
|
||||
};
|
||||
match mac {
|
||||
Ok(mut fmt) if append_newline => {
|
||||
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
|
||||
fmt.symbol = Symbol::intern(&format!("{}\n", fmt.symbol));
|
||||
fmt
|
||||
}
|
||||
Ok(fmt) => fmt,
|
||||
|
|
@ -316,6 +321,13 @@ fn make_format_args(
|
|||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span })
|
||||
}
|
||||
}
|
||||
parse::Suggestion::ReorderFormatParameter(span, replacement) => {
|
||||
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
|
||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::ReorderFormatParameter {
|
||||
span,
|
||||
replacement,
|
||||
});
|
||||
}
|
||||
}
|
||||
let guar = ecx.dcx().emit_err(e);
|
||||
return ExpandResult::Ready(Err(guar));
|
||||
|
|
@ -584,7 +596,12 @@ fn make_format_args(
|
|||
}
|
||||
}
|
||||
|
||||
ExpandResult::Ready(Ok(FormatArgs { span: fmt_span, template, arguments: args }))
|
||||
ExpandResult::Ready(Ok(FormatArgs {
|
||||
span: fmt_span,
|
||||
template,
|
||||
arguments: args,
|
||||
uncooked_fmt_str,
|
||||
}))
|
||||
}
|
||||
|
||||
fn invalid_placeholder_type_error(
|
||||
|
|
|
|||
|
|
@ -57,7 +57,17 @@ pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable,
|
|||
|
||||
/// `Ok` represents successfully retrieving the string literal at the correct
|
||||
/// position, e.g., `println("abc")`.
|
||||
type ExprToSpannedStringResult<'a> = Result<(Symbol, ast::StrStyle, Span), UnexpectedExprKind<'a>>;
|
||||
pub(crate) type ExprToSpannedStringResult<'a> = Result<ExprToSpannedString, UnexpectedExprKind<'a>>;
|
||||
|
||||
pub(crate) struct ExprToSpannedString {
|
||||
pub symbol: Symbol,
|
||||
pub style: ast::StrStyle,
|
||||
pub span: Span,
|
||||
/// The raw string literal, with no escaping or processing.
|
||||
///
|
||||
/// Generally only useful for lints that care about the raw bytes the user wrote.
|
||||
pub uncooked_symbol: (ast::token::LitKind, Symbol),
|
||||
}
|
||||
|
||||
/// - `Ok` is returned when the conversion to a string literal is unsuccessful,
|
||||
/// but another type of expression is obtained instead.
|
||||
|
|
@ -90,7 +100,12 @@ pub(crate) fn expr_to_spanned_string<'a>(
|
|||
ExpandResult::Ready(Err(match expr.kind {
|
||||
ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
|
||||
Ok(ast::LitKind::Str(s, style)) => {
|
||||
return ExpandResult::Ready(Ok((s, style, expr.span)));
|
||||
return ExpandResult::Ready(Ok(ExprToSpannedString {
|
||||
symbol: s,
|
||||
style,
|
||||
span: expr.span,
|
||||
uncooked_symbol: (token_lit.kind, token_lit.symbol),
|
||||
}));
|
||||
}
|
||||
Ok(ast::LitKind::ByteStr(..)) => {
|
||||
let mut err = cx.dcx().struct_span_err(expr.span, err_msg);
|
||||
|
|
@ -128,7 +143,7 @@ pub(crate) fn expr_to_string(
|
|||
Ok((err, _)) => err.emit(),
|
||||
Err(guar) => guar,
|
||||
})
|
||||
.map(|(symbol, style, _)| (symbol, style))
|
||||
.map(|ExprToSpannedString { symbol, style, .. }| (symbol, style))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -183,7 +198,7 @@ pub(crate) fn get_single_str_spanned_from_tts(
|
|||
Ok((err, _)) => err.emit(),
|
||||
Err(guar) => guar,
|
||||
})
|
||||
.map(|(symbol, _style, span)| (symbol, span))
|
||||
.map(|ExprToSpannedString { symbol, span, .. }| (symbol, span))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ use gccjit::{CType, Context, OptimizationLevel};
|
|||
#[cfg(feature = "master")]
|
||||
use gccjit::{TargetInfo, Version};
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
|
||||
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
|
||||
use rustc_codegen_ssa::back::write::{
|
||||
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn,
|
||||
|
|
@ -439,6 +440,15 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
|
||||
back::write::link(cgcx, dcx, modules)
|
||||
}
|
||||
fn autodiff(
|
||||
_cgcx: &CodegenContext<Self>,
|
||||
_tcx: TyCtxt<'_>,
|
||||
_module: &ModuleCodegen<Self::Module>,
|
||||
_diff_fncs: Vec<AutoDiffItem>,
|
||||
_config: &ModuleConfig,
|
||||
) -> Result<(), FatalError> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
codegen_llvm_autodiff_without_lto = using the autodiff feature requires using fat-lto
|
||||
|
||||
codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
|
||||
|
||||
codegen_llvm_dynamic_linking_with_lto =
|
||||
|
|
@ -47,6 +49,8 @@ codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO modul
|
|||
codegen_llvm_parse_target_machine_config =
|
||||
failed to parse target machine config to target machine: {$error}
|
||||
|
||||
codegen_llvm_prepare_autodiff = failed to prepare autodiff: src: {$src}, target: {$target}, {$error}
|
||||
codegen_llvm_prepare_autodiff_with_llvm_err = failed to prepare autodiff: {$llvm_err}, src: {$src}, target: {$target}, {$error}
|
||||
codegen_llvm_prepare_thin_lto_context = failed to prepare thin LTO context
|
||||
codegen_llvm_prepare_thin_lto_context_with_llvm_err = failed to prepare thin LTO context: {$llvm_err}
|
||||
|
||||
|
|
|
|||
|
|
@ -604,7 +604,14 @@ pub(crate) fn run_pass_manager(
|
|||
debug!("running the pass manager");
|
||||
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
|
||||
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
|
||||
unsafe { write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) }?;
|
||||
|
||||
// If this rustc version was build with enzyme/autodiff enabled, and if users applied the
|
||||
// `#[autodiff]` macro at least once, then we will later call llvm_optimize a second time.
|
||||
let first_run = true;
|
||||
debug!("running llvm pm opt pipeline");
|
||||
unsafe {
|
||||
write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage, first_run)?;
|
||||
}
|
||||
debug!("lto done");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ impl OwnedTargetMachine {
|
|||
model: llvm::CodeModel,
|
||||
reloc: llvm::RelocModel,
|
||||
level: llvm::CodeGenOptLevel,
|
||||
use_soft_fp: bool,
|
||||
float_abi: llvm::FloatAbi,
|
||||
function_sections: bool,
|
||||
data_sections: bool,
|
||||
unique_section_names: bool,
|
||||
|
|
@ -57,7 +57,7 @@ impl OwnedTargetMachine {
|
|||
model,
|
||||
reloc,
|
||||
level,
|
||||
use_soft_fp,
|
||||
float_abi,
|
||||
function_sections,
|
||||
data_sections,
|
||||
unique_section_names,
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ use rustc_session::config::{
|
|||
self, Lto, OutputType, Passes, RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath,
|
||||
};
|
||||
use rustc_span::{BytePos, InnerSpan, Pos, SpanData, SyntaxContext, sym};
|
||||
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
|
||||
use tracing::debug;
|
||||
use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::back::lto::ThinBuffer;
|
||||
use crate::back::owned_target_machine::OwnedTargetMachine;
|
||||
|
|
@ -181,6 +181,14 @@ pub(crate) fn to_llvm_code_model(code_model: Option<CodeModel>) -> llvm::CodeMod
|
|||
}
|
||||
}
|
||||
|
||||
fn to_llvm_float_abi(float_abi: Option<FloatAbi>) -> llvm::FloatAbi {
|
||||
match float_abi {
|
||||
None => llvm::FloatAbi::Default,
|
||||
Some(FloatAbi::Soft) => llvm::FloatAbi::Soft,
|
||||
Some(FloatAbi::Hard) => llvm::FloatAbi::Hard,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn target_machine_factory(
|
||||
sess: &Session,
|
||||
optlvl: config::OptLevel,
|
||||
|
|
@ -189,12 +197,12 @@ pub(crate) fn target_machine_factory(
|
|||
let reloc_model = to_llvm_relocation_model(sess.relocation_model());
|
||||
|
||||
let (opt_level, _) = to_llvm_opt_settings(optlvl);
|
||||
let use_softfp = if sess.target.arch == "arm" {
|
||||
sess.opts.cg.soft_float
|
||||
let float_abi = if sess.target.arch == "arm" && sess.opts.cg.soft_float {
|
||||
llvm::FloatAbi::Soft
|
||||
} else {
|
||||
// `validate_commandline_args_with_session_available` has already warned about this being
|
||||
// ignored. Let's make sure LLVM doesn't suddenly start using this flag on more targets.
|
||||
false
|
||||
to_llvm_float_abi(sess.target.llvm_floatabi)
|
||||
};
|
||||
|
||||
let ffunction_sections =
|
||||
|
|
@ -290,7 +298,7 @@ pub(crate) fn target_machine_factory(
|
|||
code_model,
|
||||
reloc_model,
|
||||
opt_level,
|
||||
use_softfp,
|
||||
float_abi,
|
||||
ffunction_sections,
|
||||
fdata_sections,
|
||||
funique_section_names,
|
||||
|
|
@ -529,9 +537,35 @@ pub(crate) unsafe fn llvm_optimize(
|
|||
config: &ModuleConfig,
|
||||
opt_level: config::OptLevel,
|
||||
opt_stage: llvm::OptStage,
|
||||
skip_size_increasing_opts: bool,
|
||||
) -> Result<(), FatalError> {
|
||||
let unroll_loops =
|
||||
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
|
||||
// Enzyme:
|
||||
// The whole point of compiler based AD is to differentiate optimized IR instead of unoptimized
|
||||
// source code. However, benchmarks show that optimizations increasing the code size
|
||||
// tend to reduce AD performance. Therefore deactivate them before AD, then differentiate the code
|
||||
// and finally re-optimize the module, now with all optimizations available.
|
||||
// FIXME(ZuseZ4): In a future update we could figure out how to only optimize individual functions getting
|
||||
// differentiated.
|
||||
|
||||
let unroll_loops;
|
||||
let vectorize_slp;
|
||||
let vectorize_loop;
|
||||
|
||||
// When we build rustc with enzyme/autodiff support, we want to postpone size-increasing
|
||||
// optimizations until after differentiation. FIXME(ZuseZ4): Before shipping on nightly,
|
||||
// we should make this more granular, or at least check that the user has at least one autodiff
|
||||
// call in their code, to justify altering the compilation pipeline.
|
||||
if skip_size_increasing_opts && cfg!(llvm_enzyme) {
|
||||
unroll_loops = false;
|
||||
vectorize_slp = false;
|
||||
vectorize_loop = false;
|
||||
} else {
|
||||
unroll_loops =
|
||||
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
|
||||
vectorize_slp = config.vectorize_slp;
|
||||
vectorize_loop = config.vectorize_loop;
|
||||
}
|
||||
trace!(?unroll_loops, ?vectorize_slp, ?vectorize_loop);
|
||||
let using_thin_buffers = opt_stage == llvm::OptStage::PreLinkThinLTO || config.bitcode_needed();
|
||||
let pgo_gen_path = get_pgo_gen_path(config);
|
||||
let pgo_use_path = get_pgo_use_path(config);
|
||||
|
|
@ -595,8 +629,8 @@ pub(crate) unsafe fn llvm_optimize(
|
|||
using_thin_buffers,
|
||||
config.merge_functions,
|
||||
unroll_loops,
|
||||
config.vectorize_slp,
|
||||
config.vectorize_loop,
|
||||
vectorize_slp,
|
||||
vectorize_loop,
|
||||
config.no_builtins,
|
||||
config.emit_lifetime_markers,
|
||||
sanitizer_options.as_ref(),
|
||||
|
|
@ -640,6 +674,8 @@ pub(crate) unsafe fn optimize(
|
|||
unsafe { llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()) };
|
||||
}
|
||||
|
||||
// FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts
|
||||
|
||||
if let Some(opt_level) = config.opt_level {
|
||||
let opt_stage = match cgcx.lto {
|
||||
Lto::Fat => llvm::OptStage::PreLinkFatLTO,
|
||||
|
|
@ -647,7 +683,20 @@ pub(crate) unsafe fn optimize(
|
|||
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
|
||||
_ => llvm::OptStage::PreLinkNoLTO,
|
||||
};
|
||||
return unsafe { llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) };
|
||||
|
||||
// If we know that we will later run AD, then we disable vectorization and loop unrolling
|
||||
let skip_size_increasing_opts = cfg!(llvm_enzyme);
|
||||
return unsafe {
|
||||
llvm_optimize(
|
||||
cgcx,
|
||||
dcx,
|
||||
module,
|
||||
config,
|
||||
opt_level,
|
||||
opt_stage,
|
||||
skip_size_increasing_opts,
|
||||
)
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use std::borrow::Cow;
|
|||
use std::ops::Deref;
|
||||
use std::{iter, ptr};
|
||||
|
||||
pub(crate) mod autodiff;
|
||||
|
||||
use libc::{c_char, c_uint};
|
||||
use rustc_abi as abi;
|
||||
use rustc_abi::{Align, Size, WrappingRange};
|
||||
|
|
@ -608,14 +610,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn range_metadata(&mut self, load: &'ll Value, range: WrappingRange) {
|
||||
if self.sess().target.arch == "amdgpu" {
|
||||
// amdgpu/LLVM does something weird and thinks an i64 value is
|
||||
// split into a v2i32, halving the bitwidth LLVM expects,
|
||||
// tripping an assertion. So, for now, just disable this
|
||||
// optimization.
|
||||
return;
|
||||
}
|
||||
|
||||
if self.cx.sess().opts.optimize == OptLevel::No {
|
||||
// Don't emit metadata we're not going to use
|
||||
return;
|
||||
|
|
|
|||
344
compiler/rustc_codegen_llvm/src/builder/autodiff.rs
Normal file
344
compiler/rustc_codegen_llvm/src/builder/autodiff.rs
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
use std::ptr;
|
||||
|
||||
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode};
|
||||
use rustc_codegen_ssa::ModuleCodegen;
|
||||
use rustc_codegen_ssa::back::write::ModuleConfig;
|
||||
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
|
||||
use rustc_errors::FatalError;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::Lto;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::back::write::{llvm_err, llvm_optimize};
|
||||
use crate::builder::Builder;
|
||||
use crate::declare::declare_raw_fn;
|
||||
use crate::errors::LlvmError;
|
||||
use crate::llvm::AttributePlace::Function;
|
||||
use crate::llvm::{Metadata, True};
|
||||
use crate::value::Value;
|
||||
use crate::{CodegenContext, LlvmCodegenBackend, ModuleLlvm, attributes, context, llvm};
|
||||
|
||||
fn get_params(fnc: &Value) -> Vec<&Value> {
|
||||
unsafe {
|
||||
let param_num = llvm::LLVMCountParams(fnc) as usize;
|
||||
let mut fnc_args: Vec<&Value> = vec![];
|
||||
fnc_args.reserve(param_num);
|
||||
llvm::LLVMGetParams(fnc, fnc_args.as_mut_ptr());
|
||||
fnc_args.set_len(param_num);
|
||||
fnc_args
|
||||
}
|
||||
}
|
||||
|
||||
/// When differentiating `fn_to_diff`, take a `outer_fn` and generate another
|
||||
/// function with expected naming and calling conventions[^1] which will be
|
||||
/// discovered by the enzyme LLVM pass and its body populated with the differentiated
|
||||
/// `fn_to_diff`. `outer_fn` is then modified to have a call to the generated
|
||||
/// function and handle the differences between the Rust calling convention and
|
||||
/// Enzyme.
|
||||
/// [^1]: <https://enzyme.mit.edu/getting_started/CallingConvention/>
|
||||
// FIXME(ZuseZ4): `outer_fn` should include upstream safety checks to
|
||||
// cover some assumptions of enzyme/autodiff, which could lead to UB otherwise.
|
||||
fn generate_enzyme_call<'ll, 'tcx>(
|
||||
cx: &context::CodegenCx<'ll, 'tcx>,
|
||||
fn_to_diff: &'ll Value,
|
||||
outer_fn: &'ll Value,
|
||||
attrs: AutoDiffAttrs,
|
||||
) {
|
||||
let inputs = attrs.input_activity;
|
||||
let output = attrs.ret_activity;
|
||||
|
||||
// We have to pick the name depending on whether we want forward or reverse mode autodiff.
|
||||
// FIXME(ZuseZ4): The new pass based approach should not need the {Forward/Reverse}First method anymore, since
|
||||
// it will handle higher-order derivatives correctly automatically (in theory). Currently
|
||||
// higher-order derivatives fail, so we should debug that before adjusting this code.
|
||||
let mut ad_name: String = match attrs.mode {
|
||||
DiffMode::Forward => "__enzyme_fwddiff",
|
||||
DiffMode::Reverse => "__enzyme_autodiff",
|
||||
DiffMode::ForwardFirst => "__enzyme_fwddiff",
|
||||
DiffMode::ReverseFirst => "__enzyme_autodiff",
|
||||
_ => panic!("logic bug in autodiff, unrecognized mode"),
|
||||
}
|
||||
.to_string();
|
||||
|
||||
// add outer_fn name to ad_name to make it unique, in case users apply autodiff to multiple
|
||||
// functions. Unwrap will only panic, if LLVM gave us an invalid string.
|
||||
let name = llvm::get_value_name(outer_fn);
|
||||
let outer_fn_name = std::ffi::CStr::from_bytes_with_nul(name).unwrap().to_str().unwrap();
|
||||
ad_name.push_str(outer_fn_name.to_string().as_str());
|
||||
|
||||
// Let us assume the user wrote the following function square:
|
||||
//
|
||||
// ```llvm
|
||||
// define double @square(double %x) {
|
||||
// entry:
|
||||
// %0 = fmul double %x, %x
|
||||
// ret double %0
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// The user now applies autodiff to the function square, in which case fn_to_diff will be `square`.
|
||||
// Our macro generates the following placeholder code (slightly simplified):
|
||||
//
|
||||
// ```llvm
|
||||
// define double @dsquare(double %x) {
|
||||
// ; placeholder code
|
||||
// return 0.0;
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// so our `outer_fn` will be `dsquare`. The unsafe code section below now removes the placeholder
|
||||
// code and inserts an autodiff call. We also add a declaration for the __enzyme_autodiff call.
|
||||
// Again, the arguments to all functions are slightly simplified.
|
||||
// ```llvm
|
||||
// declare double @__enzyme_autodiff_square(...)
|
||||
//
|
||||
// define double @dsquare(double %x) {
|
||||
// entry:
|
||||
// %0 = tail call double (...) @__enzyme_autodiff_square(double (double)* nonnull @square, double %x)
|
||||
// ret double %0
|
||||
// }
|
||||
// ```
|
||||
unsafe {
|
||||
// On LLVM-IR, we can luckily declare __enzyme_ functions without specifying the input
|
||||
// arguments. We do however need to declare them with their correct return type.
|
||||
// We already figured the correct return type out in our frontend, when generating the outer_fn,
|
||||
// so we can now just go ahead and use that. FIXME(ZuseZ4): This doesn't handle sret yet.
|
||||
let fn_ty = llvm::LLVMGlobalGetValueType(outer_fn);
|
||||
let ret_ty = llvm::LLVMGetReturnType(fn_ty);
|
||||
|
||||
// LLVM can figure out the input types on it's own, so we take a shortcut here.
|
||||
let enzyme_ty = llvm::LLVMFunctionType(ret_ty, ptr::null(), 0, True);
|
||||
|
||||
//FIXME(ZuseZ4): the CC/Addr/Vis values are best effort guesses, we should look at tests and
|
||||
// think a bit more about what should go here.
|
||||
let cc = llvm::LLVMGetFunctionCallConv(outer_fn);
|
||||
let ad_fn = declare_raw_fn(
|
||||
cx,
|
||||
&ad_name,
|
||||
llvm::CallConv::try_from(cc).expect("invalid callconv"),
|
||||
llvm::UnnamedAddr::No,
|
||||
llvm::Visibility::Default,
|
||||
enzyme_ty,
|
||||
);
|
||||
|
||||
// Otherwise LLVM might inline our temporary code before the enzyme pass has a chance to
|
||||
// do it's work.
|
||||
let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx);
|
||||
attributes::apply_to_llfn(ad_fn, Function, &[attr]);
|
||||
|
||||
// first, remove all calls from fnc
|
||||
let entry = llvm::LLVMGetFirstBasicBlock(outer_fn);
|
||||
let br = llvm::LLVMRustGetTerminator(entry);
|
||||
llvm::LLVMRustEraseInstFromParent(br);
|
||||
|
||||
let last_inst = llvm::LLVMRustGetLastInstruction(entry).unwrap();
|
||||
let mut builder = Builder::build(cx, entry);
|
||||
|
||||
let num_args = llvm::LLVMCountParams(&fn_to_diff);
|
||||
let mut args = Vec::with_capacity(num_args as usize + 1);
|
||||
args.push(fn_to_diff);
|
||||
|
||||
let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap();
|
||||
let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap();
|
||||
let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap();
|
||||
let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap();
|
||||
let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap();
|
||||
|
||||
match output {
|
||||
DiffActivity::Dual => {
|
||||
args.push(cx.get_metadata_value(enzyme_primal_ret));
|
||||
}
|
||||
DiffActivity::Active => {
|
||||
args.push(cx.get_metadata_value(enzyme_primal_ret));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
trace!("matching autodiff arguments");
|
||||
// We now handle the issue that Rust level arguments not always match the llvm-ir level
|
||||
// arguments. A slice, `&[f32]`, for example, is represented as a pointer and a length on
|
||||
// llvm-ir level. The number of activities matches the number of Rust level arguments, so we
|
||||
// need to match those.
|
||||
// FIXME(ZuseZ4): This logic is a bit more complicated than it should be, can we simplify it
|
||||
// using iterators and peek()?
|
||||
let mut outer_pos: usize = 0;
|
||||
let mut activity_pos = 0;
|
||||
let outer_args: Vec<&llvm::Value> = get_params(outer_fn);
|
||||
while activity_pos < inputs.len() {
|
||||
let activity = inputs[activity_pos as usize];
|
||||
// Duplicated arguments received a shadow argument, into which enzyme will write the
|
||||
// gradient.
|
||||
let (activity, duplicated): (&Metadata, bool) = match activity {
|
||||
DiffActivity::None => panic!("not a valid input activity"),
|
||||
DiffActivity::Const => (enzyme_const, false),
|
||||
DiffActivity::Active => (enzyme_out, false),
|
||||
DiffActivity::ActiveOnly => (enzyme_out, false),
|
||||
DiffActivity::Dual => (enzyme_dup, true),
|
||||
DiffActivity::DualOnly => (enzyme_dupnoneed, true),
|
||||
DiffActivity::Duplicated => (enzyme_dup, true),
|
||||
DiffActivity::DuplicatedOnly => (enzyme_dupnoneed, true),
|
||||
DiffActivity::FakeActivitySize => (enzyme_const, false),
|
||||
};
|
||||
let outer_arg = outer_args[outer_pos];
|
||||
args.push(cx.get_metadata_value(activity));
|
||||
args.push(outer_arg);
|
||||
if duplicated {
|
||||
// We know that duplicated args by construction have a following argument,
|
||||
// so this can not be out of bounds.
|
||||
let next_outer_arg = outer_args[outer_pos + 1];
|
||||
let next_outer_ty = cx.val_ty(next_outer_arg);
|
||||
// FIXME(ZuseZ4): We should add support for Vec here too, but it's less urgent since
|
||||
// vectors behind references (&Vec<T>) are already supported. Users can not pass a
|
||||
// Vec by value for reverse mode, so this would only help forward mode autodiff.
|
||||
let slice = {
|
||||
if activity_pos + 1 >= inputs.len() {
|
||||
// If there is no arg following our ptr, it also can't be a slice,
|
||||
// since that would lead to a ptr, int pair.
|
||||
false
|
||||
} else {
|
||||
let next_activity = inputs[activity_pos + 1];
|
||||
// We analyze the MIR types and add this dummy activity if we visit a slice.
|
||||
next_activity == DiffActivity::FakeActivitySize
|
||||
}
|
||||
};
|
||||
if slice {
|
||||
// A duplicated slice will have the following two outer_fn arguments:
|
||||
// (..., ptr1, int1, ptr2, int2, ...). We add the following llvm-ir to our __enzyme call:
|
||||
// (..., metadata! enzyme_dup, ptr, ptr, int1, ...).
|
||||
// FIXME(ZuseZ4): We will upstream a safety check later which asserts that
|
||||
// int2 >= int1, which means the shadow vector is large enough to store the gradient.
|
||||
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Integer);
|
||||
let next_outer_arg2 = outer_args[outer_pos + 2];
|
||||
let next_outer_ty2 = cx.val_ty(next_outer_arg2);
|
||||
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty2) == llvm::TypeKind::Pointer);
|
||||
let next_outer_arg3 = outer_args[outer_pos + 3];
|
||||
let next_outer_ty3 = cx.val_ty(next_outer_arg3);
|
||||
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty3) == llvm::TypeKind::Integer);
|
||||
args.push(next_outer_arg2);
|
||||
args.push(cx.get_metadata_value(enzyme_const));
|
||||
args.push(next_outer_arg);
|
||||
outer_pos += 4;
|
||||
activity_pos += 2;
|
||||
} else {
|
||||
// A duplicated pointer will have the following two outer_fn arguments:
|
||||
// (..., ptr, ptr, ...). We add the following llvm-ir to our __enzyme call:
|
||||
// (..., metadata! enzyme_dup, ptr, ptr, ...).
|
||||
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Pointer);
|
||||
args.push(next_outer_arg);
|
||||
outer_pos += 2;
|
||||
activity_pos += 1;
|
||||
}
|
||||
} else {
|
||||
// We do not differentiate with resprect to this argument.
|
||||
// We already added the metadata and argument above, so just increase the counters.
|
||||
outer_pos += 1;
|
||||
activity_pos += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
|
||||
|
||||
// This part is a bit iffy. LLVM requires that a call to an inlineable function has some
|
||||
// metadata attachted to it, but we just created this code oota. Given that the
|
||||
// differentiated function already has partly confusing metadata, and given that this
|
||||
// affects nothing but the auttodiff IR, we take a shortcut and just steal metadata from the
|
||||
// dummy code which we inserted at a higher level.
|
||||
// FIXME(ZuseZ4): Work with Enzyme core devs to clarify what debug metadata issues we have,
|
||||
// and how to best improve it for enzyme core and rust-enzyme.
|
||||
let md_ty = cx.get_md_kind_id("dbg");
|
||||
if llvm::LLVMRustHasMetadata(last_inst, md_ty) {
|
||||
let md = llvm::LLVMRustDIGetInstMetadata(last_inst)
|
||||
.expect("failed to get instruction metadata");
|
||||
let md_todiff = cx.get_metadata_value(md);
|
||||
llvm::LLVMSetMetadata(call, md_ty, md_todiff);
|
||||
} else {
|
||||
// We don't panic, since depending on whether we are in debug or release mode, we might
|
||||
// have no debug info to copy, which would then be ok.
|
||||
trace!("no dbg info");
|
||||
}
|
||||
// Now that we copied the metadata, get rid of dummy code.
|
||||
llvm::LLVMRustEraseInstBefore(entry, last_inst);
|
||||
llvm::LLVMRustEraseInstFromParent(last_inst);
|
||||
|
||||
if cx.val_ty(outer_fn) != cx.type_void() {
|
||||
builder.ret(call);
|
||||
} else {
|
||||
builder.ret_void();
|
||||
}
|
||||
|
||||
// Let's crash in case that we messed something up above and generated invalid IR.
|
||||
llvm::LLVMRustVerifyFunction(
|
||||
outer_fn,
|
||||
llvm::LLVMRustVerifierFailureAction::LLVMAbortProcessAction,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn differentiate<'ll, 'tcx>(
|
||||
module: &'ll ModuleCodegen<ModuleLlvm>,
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
diff_items: Vec<AutoDiffItem>,
|
||||
config: &ModuleConfig,
|
||||
) -> Result<(), FatalError> {
|
||||
for item in &diff_items {
|
||||
trace!("{}", item);
|
||||
}
|
||||
|
||||
let diag_handler = cgcx.create_dcx();
|
||||
let (_, cgus) = tcx.collect_and_partition_mono_items(());
|
||||
let cx = context::CodegenCx::new(tcx, &cgus.first().unwrap(), &module.module_llvm);
|
||||
|
||||
// Before dumping the module, we want all the TypeTrees to become part of the module.
|
||||
for item in diff_items.iter() {
|
||||
let name = item.source.clone();
|
||||
let fn_def: Option<&llvm::Value> = cx.get_function(&name);
|
||||
let Some(fn_def) = fn_def else {
|
||||
return Err(llvm_err(diag_handler.handle(), LlvmError::PrepareAutoDiff {
|
||||
src: item.source.clone(),
|
||||
target: item.target.clone(),
|
||||
error: "could not find source function".to_owned(),
|
||||
}));
|
||||
};
|
||||
debug!(?item.target);
|
||||
let fn_target: Option<&llvm::Value> = cx.get_function(&item.target);
|
||||
let Some(fn_target) = fn_target else {
|
||||
return Err(llvm_err(diag_handler.handle(), LlvmError::PrepareAutoDiff {
|
||||
src: item.source.clone(),
|
||||
target: item.target.clone(),
|
||||
error: "could not find target function".to_owned(),
|
||||
}));
|
||||
};
|
||||
|
||||
generate_enzyme_call(&cx, fn_def, fn_target, item.attrs.clone());
|
||||
}
|
||||
|
||||
// FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts
|
||||
|
||||
if let Some(opt_level) = config.opt_level {
|
||||
let opt_stage = match cgcx.lto {
|
||||
Lto::Fat => llvm::OptStage::PreLinkFatLTO,
|
||||
Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
|
||||
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
|
||||
_ => llvm::OptStage::PreLinkNoLTO,
|
||||
};
|
||||
// This is our second opt call, so now we run all opts,
|
||||
// to make sure we get the best performance.
|
||||
let skip_size_increasing_opts = false;
|
||||
trace!("running Module Optimization after differentiation");
|
||||
unsafe {
|
||||
llvm_optimize(
|
||||
cgcx,
|
||||
diag_handler.handle(),
|
||||
module,
|
||||
config,
|
||||
opt_level,
|
||||
opt_stage,
|
||||
skip_size_increasing_opts,
|
||||
)?
|
||||
};
|
||||
}
|
||||
trace!("done with differentiate()");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::ffi::{CStr, c_uint};
|
||||
use std::ffi::{CStr, c_char, c_uint};
|
||||
use std::str;
|
||||
|
||||
use rustc_abi::{HasDataLayout, TargetDataLayout, VariantIdx};
|
||||
|
|
@ -600,6 +600,31 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
llvm::set_section(g, c"llvm.metadata");
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value {
|
||||
unsafe { llvm::LLVMMetadataAsValue(self.llcx, metadata) }
|
||||
}
|
||||
|
||||
pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> {
|
||||
let name = SmallCStr::new(name);
|
||||
unsafe { llvm::LLVMGetNamedFunction(self.llmod, name.as_ptr()) }
|
||||
}
|
||||
|
||||
pub(crate) fn get_md_kind_id(&self, name: &str) -> u32 {
|
||||
unsafe {
|
||||
llvm::LLVMGetMDKindIDInContext(
|
||||
self.llcx,
|
||||
name.as_ptr() as *const c_char,
|
||||
name.len() as c_uint,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> {
|
||||
Some(unsafe {
|
||||
llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ use crate::{attributes, llvm};
|
|||
///
|
||||
/// If there’s a value with the same name already declared, the function will
|
||||
/// update the declaration and return existing Value instead.
|
||||
fn declare_raw_fn<'ll>(
|
||||
pub(crate) fn declare_raw_fn<'ll>(
|
||||
cx: &CodegenCx<'ll, '_>,
|
||||
name: &str,
|
||||
callconv: llvm::CallConv,
|
||||
|
|
|
|||
|
|
@ -89,6 +89,11 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_autodiff_without_lto)]
|
||||
#[note]
|
||||
pub(crate) struct AutoDiffWithoutLTO;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_lto_disallowed)]
|
||||
pub(crate) struct LtoDisallowed;
|
||||
|
|
@ -131,6 +136,8 @@ pub enum LlvmError<'a> {
|
|||
PrepareThinLtoModule,
|
||||
#[diag(codegen_llvm_parse_bitcode)]
|
||||
ParseBitcode,
|
||||
#[diag(codegen_llvm_prepare_autodiff)]
|
||||
PrepareAutoDiff { src: String, target: String, error: String },
|
||||
}
|
||||
|
||||
pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String);
|
||||
|
|
@ -152,6 +159,7 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for WithLlvmError<'_> {
|
|||
}
|
||||
PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err,
|
||||
ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err,
|
||||
PrepareAutoDiff { .. } => fluent::codegen_llvm_prepare_autodiff_with_llvm_err,
|
||||
};
|
||||
self.0
|
||||
.into_diag(dcx, level)
|
||||
|
|
|
|||
|
|
@ -28,9 +28,10 @@ use std::mem::ManuallyDrop;
|
|||
|
||||
use back::owned_target_machine::OwnedTargetMachine;
|
||||
use back::write::{create_informational_target_machine, create_target_machine};
|
||||
use errors::ParseTargetMachineConfig;
|
||||
use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig};
|
||||
pub use llvm_util::target_features_cfg;
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
|
||||
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
|
||||
use rustc_codegen_ssa::back::write::{
|
||||
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
|
||||
|
|
@ -44,7 +45,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest};
|
||||
use rustc_session::config::{Lto, OptLevel, OutputFilenames, PrintKind, PrintRequest};
|
||||
use rustc_span::Symbol;
|
||||
|
||||
mod back {
|
||||
|
|
@ -233,6 +234,20 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
|
||||
(module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
|
||||
}
|
||||
/// Generate autodiff rules
|
||||
fn autodiff(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
tcx: TyCtxt<'_>,
|
||||
module: &ModuleCodegen<Self::Module>,
|
||||
diff_fncs: Vec<AutoDiffItem>,
|
||||
config: &ModuleConfig,
|
||||
) -> Result<(), FatalError> {
|
||||
if cgcx.lto != Lto::Fat {
|
||||
let dcx = cgcx.create_dcx();
|
||||
return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO));
|
||||
}
|
||||
builder::autodiff::differentiate(module, cgcx, tcx, diff_fncs, config)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
|
||||
|
|
|
|||
29
compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
Normal file
29
compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#![allow(non_camel_case_types)]
|
||||
|
||||
use libc::{c_char, c_uint};
|
||||
|
||||
use super::ffi::{BasicBlock, Metadata, Module, Type, Value};
|
||||
use crate::llvm::Bool;
|
||||
extern "C" {
|
||||
// Enzyme
|
||||
pub fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool;
|
||||
pub fn LLVMRustEraseInstBefore(BB: &BasicBlock, I: &Value);
|
||||
pub fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>;
|
||||
pub fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
|
||||
pub fn LLVMRustEraseInstFromParent(V: &Value);
|
||||
pub fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value;
|
||||
pub fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
|
||||
|
||||
pub fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
|
||||
pub fn LLVMGetReturnType(T: &Type) -> &Type;
|
||||
pub fn LLVMGetParams(Fnc: &Value, parms: *mut &Value);
|
||||
pub fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum LLVMRustVerifierFailureAction {
|
||||
LLVMAbortProcessAction = 0,
|
||||
LLVMPrintMessageAction = 1,
|
||||
LLVMReturnStatusAction = 2,
|
||||
}
|
||||
|
|
@ -99,7 +99,7 @@ pub enum ModuleFlagMergeBehavior {
|
|||
/// LLVM CallingConv::ID. Should we wrap this?
|
||||
///
|
||||
/// See <https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/CallingConv.h>
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug, TryFromU32)]
|
||||
#[repr(C)]
|
||||
pub enum CallConv {
|
||||
CCallConv = 0,
|
||||
|
|
@ -526,7 +526,7 @@ pub struct SanitizerOptions {
|
|||
pub sanitize_kernel_address_recover: bool,
|
||||
}
|
||||
|
||||
/// LLVMRelocMode
|
||||
/// LLVMRustRelocModel
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub enum RelocModel {
|
||||
|
|
@ -538,6 +538,15 @@ pub enum RelocModel {
|
|||
ROPI_RWPI,
|
||||
}
|
||||
|
||||
/// LLVMRustFloatABI
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub enum FloatAbi {
|
||||
Default,
|
||||
Soft,
|
||||
Hard,
|
||||
}
|
||||
|
||||
/// LLVMRustCodeModel
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
|
|
@ -2192,7 +2201,7 @@ unsafe extern "C" {
|
|||
Model: CodeModel,
|
||||
Reloc: RelocModel,
|
||||
Level: CodeGenOptLevel,
|
||||
UseSoftFP: bool,
|
||||
FloatABIType: FloatAbi,
|
||||
FunctionSections: bool,
|
||||
DataSections: bool,
|
||||
UniqueSectionNames: bool,
|
||||
|
|
|
|||
|
|
@ -22,8 +22,11 @@ use crate::common::AsCCharPtr;
|
|||
|
||||
pub mod archive_ro;
|
||||
pub mod diagnostic;
|
||||
pub mod enzyme_ffi;
|
||||
mod ffi;
|
||||
|
||||
pub use self::enzyme_ffi::*;
|
||||
|
||||
impl LLVMRustResult {
|
||||
pub fn into_result(self) -> Result<(), ()> {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
use std::ffi::CString;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_errors::FatalError;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use super::write::CodegenContext;
|
||||
use crate::ModuleCodegen;
|
||||
use crate::back::write::ModuleConfig;
|
||||
use crate::traits::*;
|
||||
|
||||
pub struct ThinModule<B: WriteBackendMethods> {
|
||||
|
|
@ -81,6 +84,24 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
|
|||
LtoModuleCodegen::Thin(ref m) => m.cost(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Run autodiff on Fat LTO module
|
||||
pub unsafe fn autodiff(
|
||||
self,
|
||||
cgcx: &CodegenContext<B>,
|
||||
tcx: TyCtxt<'_>,
|
||||
diff_fncs: Vec<AutoDiffItem>,
|
||||
config: &ModuleConfig,
|
||||
) -> Result<LtoModuleCodegen<B>, FatalError> {
|
||||
match &self {
|
||||
LtoModuleCodegen::Fat(module) => {
|
||||
B::autodiff(cgcx, tcx, &module, diff_fncs, config)?;
|
||||
}
|
||||
_ => panic!("autodiff called with non-fat LTO module"),
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SerializedModule<M: ModuleBufferMethods> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
|
||||
use rustc_errors::{DiagCtxtHandle, FatalError};
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
|
||||
use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig};
|
||||
|
|
@ -61,6 +63,13 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
|
|||
want_summary: bool,
|
||||
) -> (String, Self::ThinBuffer);
|
||||
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
|
||||
fn autodiff(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
tcx: TyCtxt<'_>,
|
||||
module: &ModuleCodegen<Self::Module>,
|
||||
diff_fncs: Vec<AutoDiffItem>,
|
||||
config: &ModuleConfig,
|
||||
) -> Result<(), FatalError>;
|
||||
}
|
||||
|
||||
pub trait ThinBufferMethods: Send + Sync {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
//! Primarily used to extract a backtrace from stack overflow
|
||||
|
||||
use std::alloc::{Layout, alloc};
|
||||
use std::{fmt, mem, ptr};
|
||||
use std::{fmt, mem, ptr, slice};
|
||||
|
||||
use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE};
|
||||
|
||||
|
|
@ -35,20 +35,22 @@ macro raw_errln($tokens:tt) {
|
|||
}
|
||||
|
||||
/// Signal handler installed for SIGSEGV
|
||||
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
|
||||
#[allow(static_mut_refs)]
|
||||
extern "C" fn print_stack_trace(_: libc::c_int) {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Caller must ensure that this function is not re-entered.
|
||||
unsafe extern "C" fn print_stack_trace(_: libc::c_int) {
|
||||
const MAX_FRAMES: usize = 256;
|
||||
// Reserve data segment so we don't have to malloc in a signal handler, which might fail
|
||||
// in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking
|
||||
static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES];
|
||||
let stack = unsafe {
|
||||
// Reserve data segment so we don't have to malloc in a signal handler, which might fail
|
||||
// in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking
|
||||
static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES];
|
||||
// Collect return addresses
|
||||
let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32);
|
||||
let depth = libc::backtrace(&raw mut STACK_TRACE as _, MAX_FRAMES as i32);
|
||||
if depth == 0 {
|
||||
return;
|
||||
}
|
||||
&STACK_TRACE.as_slice()[0..(depth as _)]
|
||||
slice::from_raw_parts(&raw const STACK_TRACE as _, depth as _)
|
||||
};
|
||||
|
||||
// Just a stack trace is cryptic. Explain what we're doing.
|
||||
|
|
|
|||
|
|
@ -357,9 +357,9 @@ impl From<Cow<'static, str>> for DiagMessage {
|
|||
/// subdiagnostic derive refers to typed identifiers that are `DiagMessage`s, so need to be
|
||||
/// able to convert between these, as much as they'll be converted back into `DiagMessage`
|
||||
/// using `with_subdiagnostic_message` eventually. Don't use this other than for the derive.
|
||||
impl Into<SubdiagMessage> for DiagMessage {
|
||||
fn into(self) -> SubdiagMessage {
|
||||
match self {
|
||||
impl From<DiagMessage> for SubdiagMessage {
|
||||
fn from(val: DiagMessage) -> Self {
|
||||
match val {
|
||||
DiagMessage::Str(s) => SubdiagMessage::Str(s),
|
||||
DiagMessage::Translated(s) => SubdiagMessage::Translated(s),
|
||||
DiagMessage::FluentIdentifier(id, None) => SubdiagMessage::FluentIdentifier(id),
|
||||
|
|
|
|||
|
|
@ -156,9 +156,9 @@ impl IntoDiagArg for DiagArgValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<FluentValue<'static>> for DiagArgValue {
|
||||
fn into(self) -> FluentValue<'static> {
|
||||
match self {
|
||||
impl From<DiagArgValue> for FluentValue<'static> {
|
||||
fn from(val: DiagArgValue) -> Self {
|
||||
match val {
|
||||
DiagArgValue::Str(s) => From::from(s),
|
||||
DiagArgValue::Number(n) => From::from(n),
|
||||
DiagArgValue::StrListSepByAnd(l) => fluent_value_from_str_list_sep_by_and(l),
|
||||
|
|
|
|||
|
|
@ -52,6 +52,13 @@ pub enum ParamName {
|
|||
/// Some user-given name like `T` or `'x`.
|
||||
Plain(Ident),
|
||||
|
||||
/// Indicates an illegal name was given and an error has been
|
||||
/// reported (so we should squelch other derived errors).
|
||||
///
|
||||
/// Occurs when, e.g., `'_` is used in the wrong place, or a
|
||||
/// lifetime name is duplicated.
|
||||
Error(Ident),
|
||||
|
||||
/// Synthetic name generated when user elided a lifetime in an impl header.
|
||||
///
|
||||
/// E.g., the lifetimes in cases like these:
|
||||
|
|
@ -67,18 +74,13 @@ pub enum ParamName {
|
|||
/// where `'f` is something like `Fresh(0)`. The indices are
|
||||
/// unique per impl, but not necessarily continuous.
|
||||
Fresh,
|
||||
|
||||
/// Indicates an illegal name was given and an error has been
|
||||
/// reported (so we should squelch other derived errors). Occurs
|
||||
/// when, e.g., `'_` is used in the wrong place.
|
||||
Error,
|
||||
}
|
||||
|
||||
impl ParamName {
|
||||
pub fn ident(&self) -> Ident {
|
||||
match *self {
|
||||
ParamName::Plain(ident) => ident,
|
||||
ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
|
||||
ParamName::Plain(ident) | ParamName::Error(ident) => ident,
|
||||
ParamName::Fresh => Ident::with_dummy_span(kw::UnderscoreLifetime),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4072,33 +4074,33 @@ impl<'hir> OwnerNode<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'hir> Into<OwnerNode<'hir>> for &'hir Item<'hir> {
|
||||
fn into(self) -> OwnerNode<'hir> {
|
||||
OwnerNode::Item(self)
|
||||
impl<'hir> From<&'hir Item<'hir>> for OwnerNode<'hir> {
|
||||
fn from(val: &'hir Item<'hir>) -> Self {
|
||||
OwnerNode::Item(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Into<OwnerNode<'hir>> for &'hir ForeignItem<'hir> {
|
||||
fn into(self) -> OwnerNode<'hir> {
|
||||
OwnerNode::ForeignItem(self)
|
||||
impl<'hir> From<&'hir ForeignItem<'hir>> for OwnerNode<'hir> {
|
||||
fn from(val: &'hir ForeignItem<'hir>) -> Self {
|
||||
OwnerNode::ForeignItem(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Into<OwnerNode<'hir>> for &'hir ImplItem<'hir> {
|
||||
fn into(self) -> OwnerNode<'hir> {
|
||||
OwnerNode::ImplItem(self)
|
||||
impl<'hir> From<&'hir ImplItem<'hir>> for OwnerNode<'hir> {
|
||||
fn from(val: &'hir ImplItem<'hir>) -> Self {
|
||||
OwnerNode::ImplItem(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Into<OwnerNode<'hir>> for &'hir TraitItem<'hir> {
|
||||
fn into(self) -> OwnerNode<'hir> {
|
||||
OwnerNode::TraitItem(self)
|
||||
impl<'hir> From<&'hir TraitItem<'hir>> for OwnerNode<'hir> {
|
||||
fn from(val: &'hir TraitItem<'hir>) -> Self {
|
||||
OwnerNode::TraitItem(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Into<Node<'hir>> for OwnerNode<'hir> {
|
||||
fn into(self) -> Node<'hir> {
|
||||
match self {
|
||||
impl<'hir> From<OwnerNode<'hir>> for Node<'hir> {
|
||||
fn from(val: OwnerNode<'hir>) -> Self {
|
||||
match val {
|
||||
OwnerNode::Item(n) => Node::Item(n),
|
||||
OwnerNode::ForeignItem(n) => Node::ForeignItem(n),
|
||||
OwnerNode::ImplItem(n) => Node::ImplItem(n),
|
||||
|
|
|
|||
|
|
@ -928,8 +928,8 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
|
|||
) -> V::Result {
|
||||
try_visit!(visitor.visit_id(param.hir_id));
|
||||
match param.name {
|
||||
ParamName::Plain(ident) => try_visit!(visitor.visit_ident(ident)),
|
||||
ParamName::Error | ParamName::Fresh => {}
|
||||
ParamName::Plain(ident) | ParamName::Error(ident) => try_visit!(visitor.visit_ident(ident)),
|
||||
ParamName::Fresh => {}
|
||||
}
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {}
|
||||
|
|
|
|||
|
|
@ -2007,7 +2007,10 @@ fn check_variances_for_type_defn<'tcx>(
|
|||
}
|
||||
|
||||
match hir_param.name {
|
||||
hir::ParamName::Error => {}
|
||||
hir::ParamName::Error(_) => {
|
||||
// Don't report a bivariance error for a lifetime that isn't
|
||||
// even valid to name.
|
||||
}
|
||||
_ => {
|
||||
let has_explicit_bounds = explicitly_bounded_params.contains(¶meter);
|
||||
report_bivariance(tcx, hir_param, has_explicit_bounds, item);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::{self as hir, HirId, LangItem};
|
||||
use rustc_hir_analysis::autoderef::Autoderef;
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::traits::{self, Obligation, ObligationCause, ObligationCauseCode};
|
||||
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::adjustment::{
|
||||
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
|
||||
};
|
||||
|
|
@ -512,7 +512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.register_bound(
|
||||
ty,
|
||||
self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)),
|
||||
traits::ObligationCause::new(sp, self.body_id, ObligationCauseCode::RustCall),
|
||||
self.cause(sp, ObligationCauseCode::RustCall),
|
||||
);
|
||||
self.require_type_is_sized(ty, sp, ObligationCauseCode::RustCall);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -580,11 +580,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
let mut selcx = traits::SelectionContext::new(self);
|
||||
|
||||
// Create an obligation for `Source: CoerceUnsized<Target>`.
|
||||
let cause =
|
||||
ObligationCause::new(self.cause.span, self.body_id, ObligationCauseCode::Coercion {
|
||||
source,
|
||||
target,
|
||||
});
|
||||
let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target });
|
||||
|
||||
// Use a FIFO queue for this custom fulfillment procedure.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ use rustc_hir::{ExprKind, HirId, QPath};
|
|||
use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _};
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
|
|
@ -1174,9 +1173,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
for err in errors {
|
||||
let cause = &mut err.obligation.cause;
|
||||
if let ObligationCauseCode::OpaqueReturnType(None) = cause.code() {
|
||||
let new_cause = ObligationCause::new(
|
||||
let new_cause = self.cause(
|
||||
cause.span,
|
||||
cause.body_id,
|
||||
ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, hir_id))),
|
||||
);
|
||||
*cause = new_cause;
|
||||
|
|
@ -3856,7 +3854,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Enums are anyway always sized. But just to safeguard against future
|
||||
// language extensions, let's double-check.
|
||||
self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc);
|
||||
self.require_type_is_sized(
|
||||
field_ty,
|
||||
expr.span,
|
||||
ObligationCauseCode::FieldSized {
|
||||
adt_kind: AdtKind::Enum,
|
||||
span: self.tcx.def_span(field.did),
|
||||
last: false,
|
||||
},
|
||||
);
|
||||
|
||||
if field.vis.is_accessible_from(sub_def_scope, self.tcx) {
|
||||
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
|
||||
|
|
@ -3884,11 +3890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let field_ty = self.field_ty(expr.span, field, args);
|
||||
|
||||
if self.tcx.features().offset_of_slice() {
|
||||
self.require_type_has_static_alignment(
|
||||
field_ty,
|
||||
expr.span,
|
||||
ObligationCauseCode::Misc,
|
||||
);
|
||||
self.require_type_has_static_alignment(field_ty, expr.span);
|
||||
} else {
|
||||
self.require_type_is_sized(
|
||||
field_ty,
|
||||
|
|
@ -3917,11 +3919,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
if let Some(&field_ty) = tys.get(index) {
|
||||
if self.tcx.features().offset_of_slice() {
|
||||
self.require_type_has_static_alignment(
|
||||
field_ty,
|
||||
expr.span,
|
||||
ObligationCauseCode::Misc,
|
||||
);
|
||||
self.require_type_has_static_alignment(field_ty, expr.span);
|
||||
} else {
|
||||
self.require_type_is_sized(
|
||||
field_ty,
|
||||
|
|
|
|||
|
|
@ -384,7 +384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
code: traits::ObligationCauseCode<'tcx>,
|
||||
def_id: DefId,
|
||||
) {
|
||||
self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code));
|
||||
self.register_bound(ty, def_id, self.cause(span, code));
|
||||
}
|
||||
|
||||
pub(crate) fn require_type_is_sized(
|
||||
|
|
@ -410,12 +410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn require_type_has_static_alignment(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
code: traits::ObligationCauseCode<'tcx>,
|
||||
) {
|
||||
pub(crate) fn require_type_has_static_alignment(&self, ty: Ty<'tcx>, span: Span) {
|
||||
if !ty.references_error() {
|
||||
let tail = self.tcx.struct_tail_raw(
|
||||
ty,
|
||||
|
|
@ -434,7 +429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
// We can't be sure, let's required full `Sized`.
|
||||
let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
|
||||
self.require_type_meets(ty, span, code, lang_item);
|
||||
self.require_type_meets(ty, span, ObligationCauseCode::Misc, lang_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -572,7 +567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
code: traits::ObligationCauseCode<'tcx>,
|
||||
) {
|
||||
// WF obligations never themselves fail, so no real need to give a detailed cause:
|
||||
let cause = traits::ObligationCause::new(span, self.body_id, code);
|
||||
let cause = self.cause(span, code);
|
||||
self.register_predicate(traits::Obligation::new(
|
||||
self.tcx,
|
||||
cause,
|
||||
|
|
@ -1426,9 +1421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let bounds = self.instantiate_bounds(span, def_id, args);
|
||||
|
||||
for obligation in traits::predicates_for_generics(
|
||||
|idx, predicate_span| {
|
||||
traits::ObligationCause::new(span, self.body_id, code(idx, predicate_span))
|
||||
},
|
||||
|idx, predicate_span| self.cause(span, code(idx, predicate_span)),
|
||||
param_env,
|
||||
bounds,
|
||||
) {
|
||||
|
|
@ -1561,7 +1554,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
|
||||
) -> InferResult<'tcx, Ty<'tcx>> {
|
||||
self.instantiate_query_response_and_region_obligations(
|
||||
&traits::ObligationCause::misc(span, self.body_id),
|
||||
&self.misc(span),
|
||||
self.param_env,
|
||||
original_values,
|
||||
query_result,
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.register_wf_obligation(
|
||||
fn_input_ty.into(),
|
||||
arg_expr.span,
|
||||
ObligationCauseCode::Misc,
|
||||
ObligationCauseCode::WellFormed(None),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -601,7 +601,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
self.call_expr.hir_id,
|
||||
idx,
|
||||
);
|
||||
traits::ObligationCause::new(self.span, self.body_id, code)
|
||||
self.cause(self.span, code)
|
||||
},
|
||||
self.param_env,
|
||||
method_predicates,
|
||||
|
|
|
|||
|
|
@ -1739,8 +1739,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
&self,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> {
|
||||
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
||||
let obligation = traits::Obligation::new(self.tcx, cause, self.param_env, trait_ref);
|
||||
let obligation =
|
||||
traits::Obligation::new(self.tcx, self.misc(self.span), self.param_env, trait_ref);
|
||||
traits::SelectionContext::new(self).select(&obligation)
|
||||
}
|
||||
|
||||
|
|
@ -1841,7 +1841,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
self.scope_expr_id,
|
||||
idx,
|
||||
);
|
||||
ObligationCause::new(self.span, self.body_id, code)
|
||||
self.cause(self.span, code)
|
||||
},
|
||||
self.param_env,
|
||||
impl_bounds,
|
||||
|
|
|
|||
|
|
@ -105,8 +105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return false;
|
||||
};
|
||||
let trait_ref = ty::TraitRef::new(self.tcx, into_iterator_trait, [ty]);
|
||||
let cause = ObligationCause::new(span, self.body_id, ObligationCauseCode::Misc);
|
||||
let obligation = Obligation::new(self.tcx, cause, self.param_env, trait_ref);
|
||||
let obligation = Obligation::new(self.tcx, self.misc(span), self.param_env, trait_ref);
|
||||
if !self.predicate_must_hold_modulo_regions(&obligation) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3489,7 +3488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let pred = ty::TraitRef::new(self.tcx, unpin_trait, [*rcvr_ty]);
|
||||
let unpin = self.predicate_must_hold_considering_regions(&Obligation::new(
|
||||
self.tcx,
|
||||
ObligationCause::misc(rcvr.span, self.body_id),
|
||||
self.misc(rcvr.span),
|
||||
self.param_env,
|
||||
pred,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Diag;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::{declare_lint, impl_lint_pass};
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use crate::{LateContext, LateLintPass};
|
||||
|
|
@ -149,13 +151,16 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
|
|||
let hir_id = cx.tcx.local_def_id_to_hir_id(local);
|
||||
let hir::Node::Item(item) = cx.tcx.hir_node(hir_id) else { return };
|
||||
cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, item.span, |diag| {
|
||||
mk_lint(diag, orig_fields, fields);
|
||||
mk_lint(cx.tcx, diag, type_def_id, parent, orig_fields, fields);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn mk_lint(
|
||||
tcx: TyCtxt<'_>,
|
||||
diag: &mut Diag<'_, ()>,
|
||||
type_def_id: DefId,
|
||||
impl_def_id: DefId,
|
||||
orig_fields: FxHashMap<Symbol, &hir::FieldDef<'_>>,
|
||||
fields: &[hir::ExprField<'_>],
|
||||
) {
|
||||
|
|
@ -175,11 +180,24 @@ fn mk_lint(
|
|||
}
|
||||
}
|
||||
|
||||
diag.help(if removed_all_fields {
|
||||
"to avoid divergence in behavior between `Struct { .. }` and \
|
||||
`<Struct as Default>::default()`, derive the `Default`"
|
||||
if removed_all_fields {
|
||||
let msg = "to avoid divergence in behavior between `Struct { .. }` and \
|
||||
`<Struct as Default>::default()`, derive the `Default`";
|
||||
if let Some(hir::Node::Item(impl_)) = tcx.hir().get_if_local(impl_def_id) {
|
||||
diag.multipart_suggestion_verbose(
|
||||
msg,
|
||||
vec![
|
||||
(tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()),
|
||||
(impl_.span, String::new()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
diag.help(msg);
|
||||
}
|
||||
} else {
|
||||
"use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them \
|
||||
diverging over time"
|
||||
});
|
||||
let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \
|
||||
avoid them diverging over time";
|
||||
diag.help(msg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,36 @@ impl HiddenUnicodeCodepoints {
|
|||
sub,
|
||||
});
|
||||
}
|
||||
|
||||
fn check_literal(
|
||||
&mut self,
|
||||
cx: &EarlyContext<'_>,
|
||||
text: Symbol,
|
||||
lit_kind: ast::token::LitKind,
|
||||
span: Span,
|
||||
label: &'static str,
|
||||
) {
|
||||
if !contains_text_flow_control_chars(text.as_str()) {
|
||||
return;
|
||||
}
|
||||
let (padding, point_at_inner_spans) = match lit_kind {
|
||||
// account for `"` or `'`
|
||||
ast::token::LitKind::Str | ast::token::LitKind::Char => (1, true),
|
||||
// account for `c"`
|
||||
ast::token::LitKind::CStr => (2, true),
|
||||
// account for `r###"`
|
||||
ast::token::LitKind::StrRaw(n) => (n as u32 + 2, true),
|
||||
// account for `cr###"`
|
||||
ast::token::LitKind::CStrRaw(n) => (n as u32 + 3, true),
|
||||
// suppress bad literals.
|
||||
ast::token::LitKind::Err(_) => return,
|
||||
// Be conservative just in case new literals do support these.
|
||||
_ => (0, false),
|
||||
};
|
||||
self.lint_text_direction_codepoint(cx, text, span, padding, point_at_inner_spans, label);
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintPass for HiddenUnicodeCodepoints {
|
||||
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
|
||||
if let ast::AttrKind::DocComment(_, comment) = attr.kind {
|
||||
|
|
@ -97,18 +126,11 @@ impl EarlyLintPass for HiddenUnicodeCodepoints {
|
|||
// byte strings are already handled well enough by `EscapeError::NonAsciiCharInByteString`
|
||||
match &expr.kind {
|
||||
ast::ExprKind::Lit(token_lit) => {
|
||||
let text = token_lit.symbol;
|
||||
if !contains_text_flow_control_chars(text.as_str()) {
|
||||
return;
|
||||
}
|
||||
let padding = match token_lit.kind {
|
||||
// account for `"` or `'`
|
||||
ast::token::LitKind::Str | ast::token::LitKind::Char => 1,
|
||||
// account for `r###"`
|
||||
ast::token::LitKind::StrRaw(n) => n as u32 + 2,
|
||||
_ => return,
|
||||
};
|
||||
self.lint_text_direction_codepoint(cx, text, expr.span, padding, true, "literal");
|
||||
self.check_literal(cx, token_lit.symbol, token_lit.kind, expr.span, "literal");
|
||||
}
|
||||
ast::ExprKind::FormatArgs(args) => {
|
||||
let (lit_kind, text) = args.uncooked_fmt_str;
|
||||
self.check_literal(cx, text, lit_kind, args.span, "format string");
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -308,6 +308,24 @@ static Reloc::Model fromRust(LLVMRustRelocModel RustReloc) {
|
|||
report_fatal_error("Bad RelocModel.");
|
||||
}
|
||||
|
||||
enum class LLVMRustFloatABI {
|
||||
Default,
|
||||
Soft,
|
||||
Hard,
|
||||
};
|
||||
|
||||
static FloatABI::ABIType fromRust(LLVMRustFloatABI RustFloatAbi) {
|
||||
switch (RustFloatAbi) {
|
||||
case LLVMRustFloatABI::Default:
|
||||
return FloatABI::Default;
|
||||
case LLVMRustFloatABI::Soft:
|
||||
return FloatABI::Soft;
|
||||
case LLVMRustFloatABI::Hard:
|
||||
return FloatABI::Hard;
|
||||
}
|
||||
report_fatal_error("Bad FloatABI.");
|
||||
}
|
||||
|
||||
/// getLongestEntryLength - Return the length of the longest entry in the table.
|
||||
template <typename KV> static size_t getLongestEntryLength(ArrayRef<KV> Table) {
|
||||
size_t MaxLen = 0;
|
||||
|
|
@ -358,7 +376,7 @@ extern "C" const char *LLVMRustGetHostCPUName(size_t *OutLen) {
|
|||
extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
|
||||
const char *TripleStr, const char *CPU, const char *Feature,
|
||||
const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocModel RustReloc,
|
||||
LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
|
||||
LLVMRustCodeGenOptLevel RustOptLevel, LLVMRustFloatABI RustFloatABIType,
|
||||
bool FunctionSections, bool DataSections, bool UniqueSectionNames,
|
||||
bool TrapUnreachable, bool Singlethread, bool VerboseAsm,
|
||||
bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray,
|
||||
|
|
@ -369,6 +387,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
|
|||
auto OptLevel = fromRust(RustOptLevel);
|
||||
auto RM = fromRust(RustReloc);
|
||||
auto CM = fromRust(RustCM);
|
||||
auto FloatABIType = fromRust(RustFloatABIType);
|
||||
|
||||
std::string Error;
|
||||
auto Trip = Triple(Triple::normalize(TripleStr));
|
||||
|
|
@ -381,10 +400,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
|
|||
|
||||
TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Trip);
|
||||
|
||||
Options.FloatABIType = FloatABI::Default;
|
||||
if (UseSoftFloat) {
|
||||
Options.FloatABIType = FloatABI::Soft;
|
||||
}
|
||||
Options.FloatABIType = FloatABIType;
|
||||
Options.DataSections = DataSections;
|
||||
Options.FunctionSections = FunctionSections;
|
||||
Options.UniqueSectionNames = UniqueSectionNames;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "LLVMWrapper.h"
|
||||
|
||||
#include "llvm-c/Analysis.h"
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
|
@ -165,6 +166,30 @@ extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, const char *Name,
|
|||
return wrap(unwrap(M)->getNamedValue(StringRef(Name, NameLen)));
|
||||
}
|
||||
|
||||
enum class LLVMRustVerifierFailureAction {
|
||||
AbortProcessAction = 0,
|
||||
PrintMessageAction = 1,
|
||||
ReturnStatusAction = 2,
|
||||
};
|
||||
|
||||
static LLVMVerifierFailureAction
|
||||
fromRust(LLVMRustVerifierFailureAction Action) {
|
||||
switch (Action) {
|
||||
case LLVMRustVerifierFailureAction::AbortProcessAction:
|
||||
return LLVMAbortProcessAction;
|
||||
case LLVMRustVerifierFailureAction::PrintMessageAction:
|
||||
return LLVMPrintMessageAction;
|
||||
case LLVMRustVerifierFailureAction::ReturnStatusAction:
|
||||
return LLVMReturnStatusAction;
|
||||
}
|
||||
report_fatal_error("Invalid LLVMVerifierFailureAction value!");
|
||||
}
|
||||
|
||||
extern "C" LLVMBool
|
||||
LLVMRustVerifyFunction(LLVMValueRef Fn, LLVMRustVerifierFailureAction Action) {
|
||||
return LLVMVerifyFunction(Fn, fromRust(Action));
|
||||
}
|
||||
|
||||
enum class LLVMRustTailCallKind {
|
||||
None,
|
||||
Tail,
|
||||
|
|
@ -388,6 +413,17 @@ extern "C" void LLVMRustAddCallSiteAttributes(LLVMValueRef Instr,
|
|||
AddAttributes(Call, Index, Attrs, AttrsLen);
|
||||
}
|
||||
|
||||
extern "C" LLVMValueRef LLVMRustGetTerminator(LLVMBasicBlockRef BB) {
|
||||
Instruction *ret = unwrap(BB)->getTerminator();
|
||||
return wrap(ret);
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) {
|
||||
if (auto I = dyn_cast<Instruction>(unwrap<Value>(Instr))) {
|
||||
I->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" LLVMAttributeRef
|
||||
LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
|
||||
return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
|
||||
|
|
@ -954,6 +990,47 @@ extern "C" void LLVMRustAddModuleFlagString(
|
|||
MDString::get(unwrap(M)->getContext(), StringRef(Value, ValueLen)));
|
||||
}
|
||||
|
||||
extern "C" LLVMValueRef LLVMRustGetLastInstruction(LLVMBasicBlockRef BB) {
|
||||
auto Point = unwrap(BB)->rbegin();
|
||||
if (Point != unwrap(BB)->rend())
|
||||
return wrap(&*Point);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustEraseInstBefore(LLVMBasicBlockRef bb, LLVMValueRef I) {
|
||||
auto &BB = *unwrap(bb);
|
||||
auto &Inst = *unwrap<Instruction>(I);
|
||||
auto It = BB.begin();
|
||||
while (&*It != &Inst)
|
||||
++It;
|
||||
// Make sure we found the Instruction.
|
||||
assert(It != BB.end());
|
||||
// We don't want to erase the instruction itself.
|
||||
It--;
|
||||
// Delete in rev order to ensure no dangling references.
|
||||
while (It != BB.begin()) {
|
||||
auto Prev = std::prev(It);
|
||||
It->eraseFromParent();
|
||||
It = Prev;
|
||||
}
|
||||
It->eraseFromParent();
|
||||
}
|
||||
|
||||
extern "C" bool LLVMRustHasMetadata(LLVMValueRef inst, unsigned kindID) {
|
||||
if (auto *I = dyn_cast<Instruction>(unwrap<Value>(inst))) {
|
||||
return I->hasMetadata(kindID);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIGetInstMetadata(LLVMValueRef x) {
|
||||
if (auto *I = dyn_cast<Instruction>(unwrap<Value>(x))) {
|
||||
auto *MD = I->getDebugLoc().getAsMDNode();
|
||||
return wrap(MD);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
|
||||
LLVMMetadataRef MD) {
|
||||
unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));
|
||||
|
|
|
|||
|
|
@ -303,9 +303,9 @@ pub(crate) struct RawDefId {
|
|||
index: u32,
|
||||
}
|
||||
|
||||
impl Into<RawDefId> for DefId {
|
||||
fn into(self) -> RawDefId {
|
||||
RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() }
|
||||
impl From<DefId> for RawDefId {
|
||||
fn from(val: DefId) -> Self {
|
||||
RawDefId { krate: val.krate.as_u32(), index: val.index.as_u32() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,10 +88,10 @@ impl ReportedErrorInfo {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<ErrorGuaranteed> for ReportedErrorInfo {
|
||||
impl From<ReportedErrorInfo> for ErrorGuaranteed {
|
||||
#[inline]
|
||||
fn into(self) -> ErrorGuaranteed {
|
||||
self.error
|
||||
fn from(val: ReportedErrorInfo) -> Self {
|
||||
val.error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ use crate::ty::{self, GenericArgs, TyCtxt};
|
|||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
|
||||
/// that can't take any generic arguments like const items or enum discriminants. If a
|
||||
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
|
||||
/// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
|
||||
// In some situations def_id will have generic parameters within scope, but they aren't allowed
|
||||
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
|
||||
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
|
||||
// into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are
|
||||
// encountered.
|
||||
let args = GenericArgs::identity_for_item(self, def_id);
|
||||
let instance = ty::Instance::new(def_id, args);
|
||||
|
|
@ -32,12 +32,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
|
||||
/// that can't take any generic arguments like const items or enum discriminants. If a
|
||||
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
|
||||
/// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn const_eval_poly_to_alloc(self, def_id: DefId) -> EvalToAllocationRawResult<'tcx> {
|
||||
// In some situations def_id will have generic parameters within scope, but they aren't allowed
|
||||
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
|
||||
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
|
||||
// into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are
|
||||
// encountered.
|
||||
let args = GenericArgs::identity_for_item(self, def_id);
|
||||
let instance = ty::Instance::new(def_id, args);
|
||||
|
|
@ -201,12 +201,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
impl<'tcx> TyCtxtEnsure<'tcx> {
|
||||
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
|
||||
/// that can't take any generic arguments like const items or enum discriminants. If a
|
||||
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
|
||||
/// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn const_eval_poly(self, def_id: DefId) {
|
||||
// In some situations def_id will have generic parameters within scope, but they aren't allowed
|
||||
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
|
||||
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
|
||||
// into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are
|
||||
// encountered.
|
||||
let args = GenericArgs::identity_for_item(self.tcx, def_id);
|
||||
let instance = ty::Instance::new(def_id, self.tcx.erase_regions(args));
|
||||
|
|
|
|||
|
|
@ -249,9 +249,9 @@ pub enum AdtKind {
|
|||
Enum,
|
||||
}
|
||||
|
||||
impl Into<DataTypeKind> for AdtKind {
|
||||
fn into(self) -> DataTypeKind {
|
||||
match self {
|
||||
impl From<AdtKind> for DataTypeKind {
|
||||
fn from(val: AdtKind) -> Self {
|
||||
match val {
|
||||
AdtKind::Struct => DataTypeKind::Struct,
|
||||
AdtKind::Union => DataTypeKind::Union,
|
||||
AdtKind::Enum => DataTypeKind::Enum,
|
||||
|
|
|
|||
|
|
@ -221,6 +221,11 @@ pub enum Suggestion {
|
|||
/// Remove `r#` from identifier:
|
||||
/// `format!("{r#foo}")` -> `format!("{foo}")`
|
||||
RemoveRawIdent(InnerSpan),
|
||||
/// Reorder format parameter:
|
||||
/// `format!("{foo:?#}")` -> `format!("{foo:#?}")`
|
||||
/// `format!("{foo:?x}")` -> `format!("{foo:x?}")`
|
||||
/// `format!("{foo:?X}")` -> `format!("{foo:X?}")`
|
||||
ReorderFormatParameter(InnerSpan, string::String),
|
||||
}
|
||||
|
||||
/// The parser structure for interpreting the input format string. This is
|
||||
|
|
@ -731,6 +736,12 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
} else if self.consume('?') {
|
||||
spec.ty = "?";
|
||||
if let Some(&(_, maybe)) = self.cur.peek() {
|
||||
match maybe {
|
||||
'#' | 'x' | 'X' => self.suggest_format_parameter(maybe),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
spec.ty = self.word();
|
||||
if !spec.ty.is_empty() {
|
||||
|
|
@ -932,6 +943,30 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_format_parameter(&mut self, c: char) {
|
||||
let replacement = match c {
|
||||
'#' => "#?",
|
||||
'x' => "x?",
|
||||
'X' => "X?",
|
||||
_ => return,
|
||||
};
|
||||
let Some(pos) = self.consume_pos(c) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let span = self.span(pos - 1, pos + 1);
|
||||
let pos = self.to_span_index(pos);
|
||||
|
||||
self.errors.insert(0, ParseError {
|
||||
description: format!("expected `}}`, found `{c}`"),
|
||||
note: None,
|
||||
label: "expected `'}'`".into(),
|
||||
span: pos.to(pos),
|
||||
secondary_label: None,
|
||||
suggestion: Suggestion::ReorderFormatParameter(span, format!("{replacement}")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the indices of all characters that have been processed and differ between the actual
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use std::borrow::Cow;
|
|||
use std::env;
|
||||
|
||||
use crate::spec::{
|
||||
Cc, DebuginfoKind, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, StaticCow,
|
||||
TargetOptions, cvs,
|
||||
Cc, DebuginfoKind, FloatAbi, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType,
|
||||
StaticCow, TargetOptions, cvs,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -105,6 +105,7 @@ pub(crate) fn base(
|
|||
) -> (TargetOptions, StaticCow<str>, StaticCow<str>) {
|
||||
let opts = TargetOptions {
|
||||
abi: abi.target_abi().into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
os: os.into(),
|
||||
cpu: arch.target_cpu(abi).into(),
|
||||
link_env_remove: link_env_remove(os),
|
||||
|
|
|
|||
|
|
@ -116,6 +116,18 @@ impl Target {
|
|||
Some(Ok(()))
|
||||
})).unwrap_or(Ok(()))
|
||||
} );
|
||||
($key_name:ident, FloatAbi) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||
match s.parse::<super::FloatAbi>() {
|
||||
Ok(float_abi) => base.$key_name = Some(float_abi),
|
||||
_ => return Some(Err(format!("'{}' is not a valid value for \
|
||||
llvm-floatabi. Use 'soft' or 'hard'.",
|
||||
s))),
|
||||
}
|
||||
Some(Ok(()))
|
||||
})).unwrap_or(Ok(()))
|
||||
} );
|
||||
($key_name:ident, RelocModel) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||
|
|
@ -598,6 +610,7 @@ impl Target {
|
|||
key!(mcount = "target-mcount");
|
||||
key!(llvm_mcount_intrinsic, optional);
|
||||
key!(llvm_abiname);
|
||||
key!(llvm_floatabi, FloatAbi)?;
|
||||
key!(relax_elf_relocations, bool);
|
||||
key!(llvm_args, list);
|
||||
key!(use_ctors_section, bool);
|
||||
|
|
@ -772,6 +785,7 @@ impl ToJson for Target {
|
|||
target_option_val!(mcount, "target-mcount");
|
||||
target_option_val!(llvm_mcount_intrinsic);
|
||||
target_option_val!(llvm_abiname);
|
||||
target_option_val!(llvm_floatabi);
|
||||
target_option_val!(relax_elf_relocations);
|
||||
target_option_val!(llvm_args);
|
||||
target_option_val!(use_ctors_section);
|
||||
|
|
|
|||
|
|
@ -1085,6 +1085,35 @@ impl ToJson for CodeModel {
|
|||
}
|
||||
}
|
||||
|
||||
/// The float ABI setting to be configured in the LLVM target machine.
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||
pub enum FloatAbi {
|
||||
Soft,
|
||||
Hard,
|
||||
}
|
||||
|
||||
impl FromStr for FloatAbi {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<FloatAbi, ()> {
|
||||
Ok(match s {
|
||||
"soft" => FloatAbi::Soft,
|
||||
"hard" => FloatAbi::Hard,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for FloatAbi {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
FloatAbi::Soft => "soft",
|
||||
FloatAbi::Hard => "hard",
|
||||
}
|
||||
.to_json()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||
pub enum TlsModel {
|
||||
GeneralDynamic,
|
||||
|
|
@ -2150,6 +2179,8 @@ pub struct TargetOptions {
|
|||
pub env: StaticCow<str>,
|
||||
/// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, `"eabi"`
|
||||
/// or `"eabihf"`. Defaults to "".
|
||||
/// This field is *not* forwarded directly to LLVM; its primary purpose is `cfg(target_abi)`.
|
||||
/// However, parts of the backend do check this field for specific values to enable special behavior.
|
||||
pub abi: StaticCow<str>,
|
||||
/// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown".
|
||||
pub vendor: StaticCow<str>,
|
||||
|
|
@ -2446,8 +2477,17 @@ pub struct TargetOptions {
|
|||
pub llvm_mcount_intrinsic: Option<StaticCow<str>>,
|
||||
|
||||
/// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers
|
||||
/// and the `-target-abi` flag in llc. In the LLVM API this is `MCOptions.ABIName`.
|
||||
pub llvm_abiname: StaticCow<str>,
|
||||
|
||||
/// Control the float ABI to use, for architectures that support it. The only architecture we
|
||||
/// currently use this for is ARM. Corresponds to the `-float-abi` flag in llc. In the LLVM API
|
||||
/// this is `FloatABIType`. (clang's `-mfloat-abi` is similar but more complicated since it
|
||||
/// can also affect the `soft-float` target feature.)
|
||||
///
|
||||
/// If not provided, LLVM will infer the float ABI from the target triple (`llvm_target`).
|
||||
pub llvm_floatabi: Option<FloatAbi>,
|
||||
|
||||
/// Whether or not RelaxElfRelocation flag will be passed to the linker
|
||||
pub relax_elf_relocations: bool,
|
||||
|
||||
|
|
@ -2719,6 +2759,7 @@ impl Default for TargetOptions {
|
|||
mcount: "mcount".into(),
|
||||
llvm_mcount_intrinsic: None,
|
||||
llvm_abiname: "".into(),
|
||||
llvm_floatabi: None,
|
||||
relax_elf_relocations: false,
|
||||
llvm_args: cvs![],
|
||||
use_ctors_section: false,
|
||||
|
|
@ -3153,7 +3194,8 @@ impl Target {
|
|||
);
|
||||
}
|
||||
|
||||
// Check that RISC-V targets always specify which ABI they use.
|
||||
// Check that RISC-V targets always specify which ABI they use,
|
||||
// and that ARM targets specify their float ABI.
|
||||
match &*self.arch {
|
||||
"riscv32" => {
|
||||
check_matches!(
|
||||
|
|
@ -3170,6 +3212,9 @@ impl Target {
|
|||
"invalid RISC-V ABI name"
|
||||
);
|
||||
}
|
||||
"arm" => {
|
||||
check!(self.llvm_floatabi.is_some(), "ARM targets must specify their float ABI",)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{SanitizerSet, Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, SanitizerSet, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
// https://developer.android.com/ndk/guides/abis.html#armeabi
|
||||
features: "+strict-align,+v5te".into(),
|
||||
supported_sanitizers: SanitizerSet::ADDRESS,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+strict-align,+v6".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "\u{1}__gnu_mcount_nc".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
features: "+strict-align,+v6,+vfp2,-d32".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "\u{1}__gnu_mcount_nc".into(),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
// It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
|
||||
// to determine the calling convention and float ABI, and it doesn't
|
||||
// support the "musleabi" value.
|
||||
llvm_target: "arm-unknown-linux-gnueabi".into(),
|
||||
llvm_target: "arm-unknown-linux-musleabi".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("Armv6 Linux with musl 1.2.3".into()),
|
||||
tier: Some(2),
|
||||
|
|
@ -17,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
// Most of these settings are copied from the arm_unknown_linux_gnueabi
|
||||
// target.
|
||||
features: "+strict-align,+v6".into(),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
|
||||
// uses it to determine the calling convention and float ABI, and it
|
||||
// doesn't support the "musleabihf" value.
|
||||
llvm_target: "arm-unknown-linux-gnueabihf".into(),
|
||||
llvm_target: "arm-unknown-linux-musleabihf".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("Armv6 Linux with musl 1.2.3, hardfloat".into()),
|
||||
tier: Some(2),
|
||||
|
|
@ -17,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
// Most of these settings are copied from the arm_unknown_linux_gnueabihf
|
||||
// target.
|
||||
features: "+strict-align,+v6,+vfp2,-d32".into(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::abi::Endian;
|
||||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -15,6 +15,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+strict-align,+v8,+crc".into(),
|
||||
endian: Endian::Big,
|
||||
max_atomic_width: Some(64),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
// Targets the Big endian Cortex-R4/R5 processor (ARMv7-R)
|
||||
|
||||
use crate::abi::Endian;
|
||||
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
use crate::spec::{
|
||||
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
endian: Endian::Big,
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
// Targets the Cortex-R4F/R5F processor (ARMv7-R)
|
||||
|
||||
use crate::abi::Endian;
|
||||
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
use crate::spec::{
|
||||
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
endian: Endian::Big,
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
//! The default link script is very likely wrong, so you should use
|
||||
//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
|
||||
|
||||
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs};
|
||||
use crate::spec::{
|
||||
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -34,6 +36,7 @@ pub(crate) fn target() -> Target {
|
|||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",],
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+soft-float,+strict-align".into(),
|
||||
// Atomic operations provided by compiler-builtins
|
||||
max_atomic_width: Some(32),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Targets the ARMv5TE, with code as `a32` code by default.
|
||||
|
||||
use crate::spec::{FramePointer, Target, TargetOptions, base, cvs};
|
||||
use crate::spec::{FloatAbi, FramePointer, Target, TargetOptions, base, cvs};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -26,6 +26,7 @@ pub(crate) fn target() -> Target {
|
|||
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
// extra args passed to the external assembler (assuming `arm-none-eabi-as`):
|
||||
// * activate t32/a32 interworking
|
||||
// * use arch ARMv5TE
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+soft-float,+strict-align".into(),
|
||||
// Atomic operations provided by compiler-builtins
|
||||
max_atomic_width: Some(32),
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
// FIXME: this comment below does not seem applicable?
|
||||
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
|
||||
// uses it to determine the calling convention and float ABI, and LLVM
|
||||
// doesn't support the "musleabihf" value.
|
||||
llvm_target: "armv5te-unknown-linux-gnueabi".into(),
|
||||
llvm_target: "armv5te-unknown-linux-musleabi".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("Armv5TE Linux with musl 1.2.3".into()),
|
||||
tier: Some(2),
|
||||
|
|
@ -18,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+soft-float,+strict-align".into(),
|
||||
// Atomic operations provided by compiler-builtins
|
||||
max_atomic_width: Some(32),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+soft-float,+strict-align".into(),
|
||||
// Atomic operations provided by compiler-builtins
|
||||
max_atomic_width: Some(32),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
features: "+v6,+vfp2,-d32".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "\u{1}__gnu_mcount_nc".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
features: "+v6,+vfp2,-d32".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "__mcount".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
|
||||
use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
|
||||
|
||||
/// A base target for Nintendo 3DS devices using the devkitARM toolchain.
|
||||
///
|
||||
|
|
@ -28,8 +28,9 @@ pub(crate) fn target() -> Target {
|
|||
os: "horizon".into(),
|
||||
env: "newlib".into(),
|
||||
vendor: "nintendo".into(),
|
||||
abi: "eabihf".into(),
|
||||
cpu: "mpcore".into(),
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
families: cvs!["unix"],
|
||||
linker: Some("arm-none-eabi-gcc".into()),
|
||||
relocation_model: RelocModel::Static,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions, base};
|
||||
use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions, base};
|
||||
|
||||
// This target if is for the baseline of the Android v7a ABI
|
||||
// in thumb mode. It's named armv7-* instead of thumbv7-*
|
||||
|
|
@ -24,6 +24,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".into(),
|
||||
supported_sanitizers: SanitizerSet::ADDRESS,
|
||||
max_atomic_width: Some(64),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs};
|
||||
use crate::spec::{
|
||||
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
|
|||
os: "rtems".into(),
|
||||
families: cvs!["unix"],
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
|
||||
linker: None,
|
||||
relocation_model: RelocModel::Static,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::abi::Endian;
|
||||
use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
|
||||
use crate::spec::{Cc, FloatAbi, LinkerFlavor, Lld, RelocModel, Target, TargetOptions, cvs};
|
||||
|
||||
/// A base target for PlayStation Vita devices using the VITASDK toolchain (using newlib).
|
||||
///
|
||||
|
|
@ -32,6 +32,7 @@ pub(crate) fn target() -> Target {
|
|||
env: "newlib".into(),
|
||||
vendor: "sony".into(),
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
|
||||
no_default_libraries: false,
|
||||
cpu: "cortex-a9".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "\u{1}__gnu_mcount_nc".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
// This target is for glibc Linux on ARMv7 without thumb-mode, NEON or
|
||||
// hardfloat.
|
||||
|
|
@ -17,6 +17,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+v7,+thumb2,+soft-float,-neon".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "\u{1}__gnu_mcount_nc".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
// This target is for glibc Linux on ARMv7 without NEON or
|
||||
// thumb-mode. See the thumbv7neon variant for enabling both.
|
||||
|
|
@ -17,6 +17,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
// Info about features at https://wiki.debian.org/ArmHardFloatPort
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
|
||||
max_atomic_width: Some(64),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
// This target is for musl Linux on ARMv7 without thumb-mode, NEON or
|
||||
// hardfloat.
|
||||
|
|
@ -7,10 +7,7 @@ pub(crate) fn target() -> Target {
|
|||
// Most of these settings are copied from the armv7_unknown_linux_gnueabi
|
||||
// target.
|
||||
Target {
|
||||
// It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
|
||||
// to determine the calling convention and float ABI, and it doesn't
|
||||
// support the "musleabi" value.
|
||||
llvm_target: "armv7-unknown-linux-gnueabi".into(),
|
||||
llvm_target: "armv7-unknown-linux-musleabi".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("Armv7-A Linux with musl 1.2.3".into()),
|
||||
tier: Some(2),
|
||||
|
|
@ -23,6 +20,7 @@ pub(crate) fn target() -> Target {
|
|||
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+v7,+thumb2,+soft-float,-neon".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "\u{1}mcount".into(),
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
// This target is for musl Linux on ARMv7 without thumb-mode or NEON.
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
|
||||
// uses it to determine the calling convention and float ABI, and LLVM
|
||||
// doesn't support the "musleabihf" value.
|
||||
llvm_target: "armv7-unknown-linux-gnueabihf".into(),
|
||||
llvm_target: "armv7-unknown-linux-musleabihf".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("Armv7-A Linux with musl 1.2.3, hardfloat".into()),
|
||||
tier: Some(2),
|
||||
|
|
@ -22,6 +19,7 @@ pub(crate) fn target() -> Target {
|
|||
// target.
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "\u{1}mcount".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
// This target is for OpenHarmony on ARMv7 Linux with thumb-mode, but no NEON or
|
||||
// hardfloat.
|
||||
|
|
@ -20,6 +20,7 @@ pub(crate) fn target() -> Target {
|
|||
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+v7,+thumb2,+soft-float,-neon".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "\u{1}mcount".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
// This target is for uclibc Linux on ARMv7 without NEON,
|
||||
// thumb-mode or hardfloat.
|
||||
|
|
@ -18,11 +18,12 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+v7,+thumb2,+soft-float,-neon".into(),
|
||||
cpu: "generic".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "_mcount".into(),
|
||||
abi: "eabi".into(),
|
||||
..base
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
// This target is for uclibc Linux on ARMv7 without NEON or
|
||||
// thumb-mode. See the thumbv7neon variant for enabling both.
|
||||
|
|
@ -24,6 +24,7 @@ pub(crate) fn target() -> Target {
|
|||
max_atomic_width: Some(64),
|
||||
mcount: "_mcount".into(),
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
..base
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "__mcount".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use crate::spec::{LinkSelfContainedDefault, PanicStrategy, RelroLevel, Target, TargetOptions};
|
||||
use crate::spec::{
|
||||
FloatAbi, LinkSelfContainedDefault, PanicStrategy, RelroLevel, Target, TargetOptions,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
features: "+v7,+thumb2,+soft-float,-neon".into(),
|
||||
max_atomic_width: Some(64),
|
||||
mcount: "\u{1}mcount".into(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
// Info about features at https://wiki.debian.org/ArmHardFloatPort
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
|
||||
max_atomic_width: Some(64),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{RelocModel, Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, RelocModel, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let base = base::solid::opts("asp3");
|
||||
|
|
@ -15,6 +15,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
linker: Some("arm-kmc-eabi-gcc".into()),
|
||||
features: "+v7,+soft-float,+thumb2,-neon".into(),
|
||||
relocation_model: RelocModel::Static,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{RelocModel, Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, RelocModel, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let base = base::solid::opts("asp3");
|
||||
|
|
@ -15,6 +15,7 @@ pub(crate) fn target() -> Target {
|
|||
arch: "arm".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
linker: Some("arm-kmc-eabi-gcc".into()),
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".into(),
|
||||
relocation_model: RelocModel::Static,
|
||||
|
|
|
|||
|
|
@ -14,11 +14,14 @@
|
|||
// - `relocation-model` set to `static`; also no PIE, no relro and no dynamic
|
||||
// linking. rationale: matches `thumb` targets
|
||||
|
||||
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
use crate::spec::{
|
||||
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let opts = TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(),
|
||||
|
|
|
|||
|
|
@ -5,11 +5,14 @@
|
|||
// changes (list in `armv7a_none_eabi.rs`) to bring it closer to the bare-metal
|
||||
// `thumb` & `aarch64` targets.
|
||||
|
||||
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
use crate::spec::{
|
||||
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let opts = TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".into(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
|
||||
|
||||
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
use crate::spec::{
|
||||
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
|
|||
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
relocation_model: RelocModel::Static,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
|
||||
|
||||
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
use crate::spec::{
|
||||
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
|
|||
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
relocation_model: RelocModel::Static,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Targets the Little-endian Cortex-R52 processor (ARMv8-R)
|
||||
|
||||
use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
use crate::spec::{
|
||||
Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -17,6 +19,7 @@ pub(crate) fn target() -> Target {
|
|||
|
||||
options: TargetOptions {
|
||||
abi: "eabihf".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Hard),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
relocation_model: RelocModel::Static,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
//! The default link script is very likely wrong, so you should use
|
||||
//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
|
||||
|
||||
use crate::spec::{FramePointer, PanicStrategy, RelocModel, Target, TargetOptions, base, cvs};
|
||||
use crate::spec::{
|
||||
FloatAbi, FramePointer, PanicStrategy, RelocModel, Target, TargetOptions, base, cvs,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -34,6 +36,7 @@ pub(crate) fn target() -> Target {
|
|||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
|
||||
// extra args passed to the external assembler (assuming `arm-none-eabi-as`):
|
||||
// * activate t32/a32 interworking
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Targets the ARMv5TE, with code as `t32` code by default.
|
||||
|
||||
use crate::spec::{FramePointer, Target, TargetOptions, base, cvs};
|
||||
use crate::spec::{FloatAbi, FramePointer, Target, TargetOptions, base, cvs};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -26,6 +26,7 @@ pub(crate) fn target() -> Target {
|
|||
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
// extra args passed to the external assembler (assuming `arm-none-eabi-as`):
|
||||
// * activate t32/a32 interworking
|
||||
// * use arch ARMv5TE
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture)
|
||||
|
||||
use crate::spec::{Target, TargetOptions, base};
|
||||
use crate::spec::{FloatAbi, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
|
|
@ -17,6 +17,7 @@ pub(crate) fn target() -> Target {
|
|||
|
||||
options: TargetOptions {
|
||||
abi: "eabi".into(),
|
||||
llvm_floatabi: Some(FloatAbi::Soft),
|
||||
// The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
|
||||
// with +strict-align.
|
||||
// Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue