Always lower asm! to valid HIR
This commit is contained in:
parent
56f74c52c1
commit
fa3694fada
@ -1331,84 +1331,83 @@ fn with_loop_condition_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T
|
||||
}
|
||||
|
||||
fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> {
|
||||
if self.sess.asm_arch.is_none() {
|
||||
// Rustdoc needs to support asm! from foriegn architectures: don't try
|
||||
// lowering the register contraints in this case.
|
||||
let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch };
|
||||
if asm_arch.is_none() && !self.sess.opts.actually_rustdoc {
|
||||
struct_span_err!(self.sess, sp, E0472, "asm! is unsupported on this target").emit();
|
||||
}
|
||||
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
|
||||
&& !matches!(
|
||||
self.sess.asm_arch,
|
||||
Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64)
|
||||
)
|
||||
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
|
||||
&& !self.sess.opts.actually_rustdoc
|
||||
{
|
||||
self.sess
|
||||
.struct_span_err(sp, "the `att_syntax` option is only supported on x86")
|
||||
.emit();
|
||||
}
|
||||
|
||||
// Lower operands to HIR, filter_map skips any operands with invalid
|
||||
// register classes.
|
||||
// Lower operands to HIR. We use dummy register classes if an error
|
||||
// occurs during lowering because we still need to be able to produce a
|
||||
// valid HIR.
|
||||
let sess = self.sess;
|
||||
let operands: Vec<_> = asm
|
||||
.operands
|
||||
.iter()
|
||||
.filter_map(|(op, op_sp)| {
|
||||
let lower_reg = |reg| {
|
||||
Some(match reg {
|
||||
InlineAsmRegOrRegClass::Reg(s) => asm::InlineAsmRegOrRegClass::Reg(
|
||||
.map(|(op, op_sp)| {
|
||||
let lower_reg = |reg| match reg {
|
||||
InlineAsmRegOrRegClass::Reg(s) => {
|
||||
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
|
||||
asm::InlineAsmReg::parse(
|
||||
sess.asm_arch?,
|
||||
asm_arch,
|
||||
|feature| sess.target_features.contains(&Symbol::intern(feature)),
|
||||
&sess.target,
|
||||
s,
|
||||
)
|
||||
.map_err(|e| {
|
||||
.unwrap_or_else(|e| {
|
||||
let msg = format!("invalid register `{}`: {}", s.as_str(), e);
|
||||
sess.struct_span_err(*op_sp, &msg).emit();
|
||||
asm::InlineAsmReg::Err
|
||||
})
|
||||
.ok()?,
|
||||
),
|
||||
InlineAsmRegOrRegClass::RegClass(s) => {
|
||||
asm::InlineAsmRegOrRegClass::RegClass(
|
||||
asm::InlineAsmRegClass::parse(sess.asm_arch?, s)
|
||||
.map_err(|e| {
|
||||
let msg = format!(
|
||||
"invalid register class `{}`: {}",
|
||||
s.as_str(),
|
||||
e
|
||||
);
|
||||
sess.struct_span_err(*op_sp, &msg).emit();
|
||||
})
|
||||
.ok()?,
|
||||
)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
asm::InlineAsmReg::Err
|
||||
})
|
||||
}
|
||||
InlineAsmRegOrRegClass::RegClass(s) => {
|
||||
asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch {
|
||||
asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| {
|
||||
let msg = format!("invalid register class `{}`: {}", s.as_str(), e);
|
||||
sess.struct_span_err(*op_sp, &msg).emit();
|
||||
asm::InlineAsmRegClass::Err
|
||||
})
|
||||
} else {
|
||||
asm::InlineAsmRegClass::Err
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// lower_reg is executed last because we need to lower all
|
||||
// sub-expressions even if we throw them away later.
|
||||
let op = match *op {
|
||||
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
|
||||
reg: lower_reg(reg),
|
||||
expr: self.lower_expr_mut(expr),
|
||||
reg: lower_reg(reg)?,
|
||||
},
|
||||
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
|
||||
reg: lower_reg(reg),
|
||||
late,
|
||||
expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
reg: lower_reg(reg)?,
|
||||
},
|
||||
InlineAsmOperand::InOut { reg, late, ref expr } => {
|
||||
hir::InlineAsmOperand::InOut {
|
||||
reg: lower_reg(reg),
|
||||
late,
|
||||
expr: self.lower_expr_mut(expr),
|
||||
reg: lower_reg(reg)?,
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
|
||||
hir::InlineAsmOperand::SplitInOut {
|
||||
reg: lower_reg(reg),
|
||||
late,
|
||||
in_expr: self.lower_expr_mut(in_expr),
|
||||
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
reg: lower_reg(reg)?,
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Const { ref expr } => {
|
||||
@ -1418,17 +1417,11 @@ fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> {
|
||||
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
|
||||
}
|
||||
};
|
||||
Some((op, *op_sp))
|
||||
(op, *op_sp)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Stop if there were any errors when lowering the register classes
|
||||
if operands.len() != asm.operands.len() || sess.asm_arch.is_none() {
|
||||
return hir::ExprKind::Err;
|
||||
}
|
||||
|
||||
// Validate template modifiers against the register classes for the operands
|
||||
let asm_arch = sess.asm_arch.unwrap();
|
||||
for p in &asm.template {
|
||||
if let InlineAsmTemplatePiece::Placeholder {
|
||||
operand_idx,
|
||||
@ -1443,7 +1436,10 @@ fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> {
|
||||
| hir::InlineAsmOperand::InOut { reg, .. }
|
||||
| hir::InlineAsmOperand::SplitInOut { reg, .. } => {
|
||||
let class = reg.reg_class();
|
||||
let valid_modifiers = class.valid_modifiers(asm_arch);
|
||||
if class == asm::InlineAsmRegClass::Err {
|
||||
continue;
|
||||
}
|
||||
let valid_modifiers = class.valid_modifiers(asm_arch.unwrap());
|
||||
if !valid_modifiers.contains(&modifier) {
|
||||
let mut err = sess.struct_span_err(
|
||||
placeholder_span,
|
||||
@ -1506,7 +1502,10 @@ fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> {
|
||||
// features. We check that at least one type is available for
|
||||
// the current target.
|
||||
let reg_class = reg.reg_class();
|
||||
for &(_, feature) in reg_class.supported_types(asm_arch) {
|
||||
if reg_class == asm::InlineAsmRegClass::Err {
|
||||
continue;
|
||||
}
|
||||
for &(_, feature) in reg_class.supported_types(asm_arch.unwrap()) {
|
||||
if let Some(feature) = feature {
|
||||
if self.sess.target_features.contains(&Symbol::intern(feature)) {
|
||||
required_features.clear();
|
||||
|
@ -528,6 +528,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
}
|
||||
InlineAsmRegClass::Err => unreachable!(),
|
||||
}
|
||||
.to_string(),
|
||||
}
|
||||
@ -594,6 +595,7 @@ fn modifier_to_llvm(
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
}
|
||||
InlineAsmRegClass::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,6 +639,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
}
|
||||
InlineAsmRegClass::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,6 +229,8 @@ pub enum InlineAsmReg {
|
||||
Mips(MipsInlineAsmReg),
|
||||
SpirV(SpirVInlineAsmReg),
|
||||
Wasm(WasmInlineAsmReg),
|
||||
// Placeholder for invalid register constraints for the current target
|
||||
Err,
|
||||
}
|
||||
|
||||
impl InlineAsmReg {
|
||||
@ -240,6 +242,7 @@ pub fn name(self) -> &'static str {
|
||||
Self::RiscV(r) => r.name(),
|
||||
Self::Hexagon(r) => r.name(),
|
||||
Self::Mips(r) => r.name(),
|
||||
Self::Err => "<reg>",
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,6 +254,7 @@ pub fn reg_class(self) -> InlineAsmRegClass {
|
||||
Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
|
||||
Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
|
||||
Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
|
||||
Self::Err => InlineAsmRegClass::Err,
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,6 +313,7 @@ pub fn emit(
|
||||
Self::RiscV(r) => r.emit(out, arch, modifier),
|
||||
Self::Hexagon(r) => r.emit(out, arch, modifier),
|
||||
Self::Mips(r) => r.emit(out, arch, modifier),
|
||||
Self::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -320,6 +325,7 @@ pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
|
||||
Self::RiscV(_) => cb(self),
|
||||
Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
|
||||
Self::Mips(_) => cb(self),
|
||||
Self::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -346,6 +352,8 @@ pub enum InlineAsmRegClass {
|
||||
Mips(MipsInlineAsmRegClass),
|
||||
SpirV(SpirVInlineAsmRegClass),
|
||||
Wasm(WasmInlineAsmRegClass),
|
||||
// Placeholder for invalid register constraints for the current target
|
||||
Err,
|
||||
}
|
||||
|
||||
impl InlineAsmRegClass {
|
||||
@ -360,6 +368,7 @@ pub fn name(self) -> Symbol {
|
||||
Self::Mips(r) => r.name(),
|
||||
Self::SpirV(r) => r.name(),
|
||||
Self::Wasm(r) => r.name(),
|
||||
Self::Err => rustc_span::symbol::sym::reg,
|
||||
}
|
||||
}
|
||||
|
||||
@ -377,6 +386,7 @@ pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Sel
|
||||
Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
|
||||
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
|
||||
Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
|
||||
Self::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,6 +411,7 @@ pub fn suggest_modifier(
|
||||
Self::Mips(r) => r.suggest_modifier(arch, ty),
|
||||
Self::SpirV(r) => r.suggest_modifier(arch, ty),
|
||||
Self::Wasm(r) => r.suggest_modifier(arch, ty),
|
||||
Self::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,6 +432,7 @@ pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str
|
||||
Self::Mips(r) => r.default_modifier(arch),
|
||||
Self::SpirV(r) => r.default_modifier(arch),
|
||||
Self::Wasm(r) => r.default_modifier(arch),
|
||||
Self::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -440,6 +452,7 @@ pub fn supported_types(
|
||||
Self::Mips(r) => r.supported_types(arch),
|
||||
Self::SpirV(r) => r.supported_types(arch),
|
||||
Self::Wasm(r) => r.supported_types(arch),
|
||||
Self::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -476,6 +489,7 @@ pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
|
||||
Self::Mips(r) => r.valid_modifiers(arch),
|
||||
Self::SpirV(r) => r.valid_modifiers(arch),
|
||||
Self::Wasm(r) => r.valid_modifiers(arch),
|
||||
Self::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
src/test/rustdoc-ui/asm-foreign.rs
Normal file
19
src/test/rustdoc-ui/asm-foreign.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// check-pass
|
||||
// Make sure rustdoc accepts asm! for a foreign architecture.
|
||||
|
||||
#![feature(asm)]
|
||||
|
||||
pub unsafe fn aarch64(a: f64, b: f64) {
|
||||
let c;
|
||||
asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
|
||||
|| {};
|
||||
b
|
||||
});
|
||||
c
|
||||
}
|
||||
|
||||
pub unsafe fn x86(a: f64, b: f64) {
|
||||
let c;
|
||||
asm!("addsd {}, {}, xmm0", out(xmm_reg) c, in(xmm_reg) a, in("xmm0") b);
|
||||
c
|
||||
}
|
Loading…
Reference in New Issue
Block a user