Add support for specifying multiple clobber_abi in asm!
Allow multiple clobber_abi in asm Update docs Fix aarch64 test Combine abis Emit duplicate ABI error, empty ABI list error multiple clobber_abi
This commit is contained in:
parent
214cd1f228
commit
b233d3b5da
14 changed files with 370 additions and 147 deletions
|
@ -2,6 +2,7 @@ use super::LoweringContext;
|
|||
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_set::FxHashSet;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_session::parse::feature_err;
|
||||
|
@ -49,22 +50,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
.emit();
|
||||
}
|
||||
|
||||
let mut clobber_abi = None;
|
||||
let mut clobber_abis = FxHashMap::default();
|
||||
if let Some(asm_arch) = asm_arch {
|
||||
if let Some((abi_name, abi_span)) = asm.clobber_abi {
|
||||
match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) {
|
||||
Ok(abi) => clobber_abi = Some((abi, abi_span)),
|
||||
for (abi_name, abi_span) in &asm.clobber_abis {
|
||||
match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
|
||||
Ok(abi) => {
|
||||
// If the abi was already in the list, emit an error
|
||||
match clobber_abis.get(&abi) {
|
||||
Some((prev_name, prev_sp)) => {
|
||||
let mut err = self.sess.struct_span_err(
|
||||
*abi_span,
|
||||
&format!("`{}` ABI specified multiple times", prev_name),
|
||||
);
|
||||
err.span_label(*prev_sp, "previously specified here");
|
||||
|
||||
// Multiple different abi names may actually be the same ABI
|
||||
// If the specified ABIs are not the same name, alert the user that they resolve to the same ABI
|
||||
let source_map = self.sess.source_map();
|
||||
if source_map.span_to_snippet(*prev_sp)
|
||||
!= source_map.span_to_snippet(*abi_span)
|
||||
{
|
||||
err.note("these ABIs are equivalent on the current target");
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
None => {
|
||||
clobber_abis.insert(abi, (abi_name, *abi_span));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(&[]) => {
|
||||
self.sess
|
||||
.struct_span_err(
|
||||
abi_span,
|
||||
*abi_span,
|
||||
"`clobber_abi` is not supported on this target",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
Err(supported_abis) => {
|
||||
let mut err =
|
||||
self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`");
|
||||
self.sess.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`");
|
||||
let mut abis = format!("`{}`", supported_abis[0]);
|
||||
for m in &supported_abis[1..] {
|
||||
let _ = write!(abis, ", `{}`", m);
|
||||
|
@ -348,8 +374,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
// If a clobber_abi is specified, add the necessary clobbers to the
|
||||
// operands list.
|
||||
if let Some((abi, abi_span)) = clobber_abi {
|
||||
let mut clobbered = FxHashSet::default();
|
||||
for (abi, (_, abi_span)) in clobber_abis {
|
||||
for &clobber in abi.clobbered_regs() {
|
||||
// Don't emit a clobber for a register already clobbered
|
||||
if clobbered.contains(&clobber) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut output_used = false;
|
||||
clobber.overlapping_regs(|reg| {
|
||||
if used_output_regs.contains_key(®) {
|
||||
|
@ -366,6 +398,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
},
|
||||
self.lower_span(abi_span),
|
||||
));
|
||||
clobbered.insert(clobber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue