1use std::assert_matches;
2use std::fmt::Write;
3
4use rustc_abi::{BackendRepr, Endian, Float, Integer, Primitive, Scalar, Size};
5use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
6use rustc_codegen_ssa::mir::operand::OperandValue;
7use rustc_codegen_ssa::traits::*;
8use rustc_data_structures::fx::FxHashMap;
9use rustc_middle::mir::interpret::{PointerArithmetic, Scalar as ConstScalar};
10use rustc_middle::ty::Instance;
11use rustc_middle::ty::layout::TyAndLayout;
12use rustc_middle::{bug, span_bug};
13use rustc_session::Session;
14use rustc_session::config::Lto;
15use rustc_span::{Pos, Span, Symbol, sym};
16use rustc_target::asm::*;
17use rustc_target::spec::HasTargetSpec;
18use smallvec::SmallVec;
19use tracing::debug;
20
21use crate::builder::Builder;
22use crate::common::Funclet;
23use crate::context::CodegenCx;
24use crate::llvm::{self, ToLlvmBool, Type, Value};
25use crate::type_of::LayoutLlvmExt;
26use crate::{attributes, llvm_util};
27
28impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
29 fn codegen_inline_asm(
30 &mut self,
31 template: &[InlineAsmTemplatePiece],
32 operands: &[InlineAsmOperandRef<'tcx, Self>],
33 options: InlineAsmOptions,
34 line_spans: &[Span],
35 instance: Instance<'_>,
36 dest: Option<Self::BasicBlock>,
37 catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>,
38 ) {
39 let asm_arch = self.tcx.sess.asm_arch.unwrap();
40
41 let mut constraints = ::alloc::vec::Vec::new()vec![];
43 let mut clobbers = ::alloc::vec::Vec::new()vec![];
44 let mut output_types = ::alloc::vec::Vec::new()vec![];
45 let mut op_idx = FxHashMap::default();
46 let mut clobbered_x87 = false;
47 for (idx, op) in operands.iter().enumerate() {
48 match *op {
49 InlineAsmOperandRef::Out { reg, late, place } => {
50 let is_target_supported = |reg_class: InlineAsmRegClass| {
51 for &(_, feature) in reg_class.supported_types(asm_arch, true).as_ref() {
52 if let Some(feature) = feature {
53 if self
54 .tcx
55 .asm_target_features(instance.def_id())
56 .contains(&feature)
57 {
58 return true;
59 }
60 } else {
61 return true;
63 }
64 }
65 false
66 };
67
68 let mut layout = None;
69 let ty = if let Some(ref place) = place {
70 layout = Some(&place.layout);
71 llvm_fixup_output_type(self.cx, reg.reg_class(), &place.layout, instance)
72 } else if #[allow(non_exhaustive_omitted_patterns)] match reg.reg_class() {
InlineAsmRegClass::X86(X86InlineAsmRegClass::mmx_reg |
X86InlineAsmRegClass::x87_reg) => true,
_ => false,
}matches!(
73 reg.reg_class(),
74 InlineAsmRegClass::X86(
75 X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::x87_reg
76 )
77 ) {
78 if !clobbered_x87 {
83 clobbered_x87 = true;
84 clobbers.push("~{st}".to_string());
85 for i in 1..=7 {
86 clobbers.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("~{{st({0})}}", i))
})format!("~{{st({})}}", i));
87 }
88 }
89 continue;
90 } else if !is_target_supported(reg.reg_class())
91 || reg.reg_class().is_clobber_only(asm_arch, true)
92 {
93 {
match reg {
InlineAsmRegOrRegClass::Reg(_) => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"InlineAsmRegOrRegClass::Reg(_)",
::core::option::Option::None);
}
}
};assert_matches!(reg, InlineAsmRegOrRegClass::Reg(_));
98 clobbers.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("~{0}", reg_to_llvm(reg, None)))
})format!("~{}", reg_to_llvm(reg, None)));
99 continue;
100 } else {
101 dummy_output_type(self.cx, reg.reg_class())
105 };
106 output_types.push(ty);
107 op_idx.insert(idx, constraints.len());
108 let prefix = if late { "=" } else { "=&" };
109 constraints.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1}", prefix,
reg_to_llvm(reg, layout)))
})format!("{}{}", prefix, reg_to_llvm(reg, layout)));
110 }
111 InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
112 let layout = if let Some(ref out_place) = out_place {
113 &out_place.layout
114 } else {
115 &in_value.layout
118 };
119 let ty = llvm_fixup_output_type(self.cx, reg.reg_class(), layout, instance);
120 output_types.push(ty);
121 op_idx.insert(idx, constraints.len());
122 let prefix = if late { "=" } else { "=&" };
123 constraints.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1}", prefix,
reg_to_llvm(reg, Some(layout))))
})format!("{}{}", prefix, reg_to_llvm(reg, Some(layout))));
124 }
125 _ => {}
126 }
127 }
128
129 let mut inputs = ::alloc::vec::Vec::new()vec![];
131 for (idx, op) in operands.iter().enumerate() {
132 match *op {
133 InlineAsmOperandRef::In { reg, value } => {
134 let llval = llvm_fixup_input(
135 self,
136 value.immediate(),
137 reg.reg_class(),
138 &value.layout,
139 instance,
140 );
141 inputs.push(llval);
142 op_idx.insert(idx, constraints.len());
143 constraints.push(reg_to_llvm(reg, Some(&value.layout)));
144 }
145 InlineAsmOperandRef::InOut { reg, late, in_value, out_place: _ } => {
146 let value = llvm_fixup_input(
147 self,
148 in_value.immediate(),
149 reg.reg_class(),
150 &in_value.layout,
151 instance,
152 );
153 inputs.push(value);
154
155 if late && #[allow(non_exhaustive_omitted_patterns)] match reg {
InlineAsmRegOrRegClass::Reg(_) => true,
_ => false,
}matches!(reg, InlineAsmRegOrRegClass::Reg(_)) {
160 constraints.push(reg_to_llvm(reg, Some(&in_value.layout)));
161 } else {
162 constraints.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", op_idx[&idx]))
})format!("{}", op_idx[&idx]));
163 }
164 }
165 InlineAsmOperandRef::Const { value, ty: _ } => match value {
166 ConstScalar::Int(_) => (),
167 ConstScalar::Ptr(ptr, _) => {
168 let (prov, _) = ptr.prov_and_relative_offset();
169 let global_alloc = self.tcx.global_alloc(prov.alloc_id());
170 let value = self.cx.alloc_to_backend(global_alloc, false, None).unwrap();
171 inputs.push(value);
172 op_idx.insert(idx, constraints.len());
173 constraints.push("s".to_string());
174 }
175 },
176 InlineAsmOperandRef::SymThreadLocalStatic { def_id } => {
177 inputs.push(self.cx.get_static(def_id));
178 op_idx.insert(idx, constraints.len());
179 constraints.push("s".to_string());
180 }
181 _ => {}
182 }
183 }
184
185 let mut labels = ::alloc::vec::Vec::new()vec![];
187 let mut template_str = String::new();
188 for piece in template {
189 match *piece {
190 InlineAsmTemplatePiece::String(ref s) => {
191 if s.contains('$') {
192 for c in s.chars() {
193 if c == '$' {
194 template_str.push_str("$$");
195 } else {
196 template_str.push(c);
197 }
198 }
199 } else {
200 template_str.push_str(s)
201 }
202 }
203 InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span } => {
204 match operands[operand_idx] {
205 InlineAsmOperandRef::In { reg, .. }
206 | InlineAsmOperandRef::Out { reg, .. }
207 | InlineAsmOperandRef::InOut { reg, .. } => {
208 let modifier = modifier_to_llvm(asm_arch, reg.reg_class(), modifier);
209 if let Some(modifier) = modifier {
210 template_str.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("${{{0}:{1}}}",
op_idx[&operand_idx], modifier))
})format!(
211 "${{{}:{}}}",
212 op_idx[&operand_idx], modifier
213 ));
214 } else {
215 template_str.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("${{{0}}}", op_idx[&operand_idx]))
})format!("${{{}}}", op_idx[&operand_idx]));
216 }
217 }
218 InlineAsmOperandRef::Const { value, ty } => {
219 match value {
220 ConstScalar::Int(int) => {
221 let string = rustc_codegen_ssa::common::asm_const_to_str(
223 self.tcx,
224 span,
225 int,
226 self.layout_of(ty),
227 );
228 template_str.push_str(&string);
229 }
230 ConstScalar::Ptr(ptr, _) => {
231 let (_, offset) = ptr.prov_and_relative_offset();
232
233 template_str
235 .push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("${{{0}:c}}", op_idx[&operand_idx]))
})format!("${{{}:c}}", op_idx[&operand_idx]));
236
237 if offset != Size::ZERO {
238 let offset =
239 self.sign_extend_to_target_isize(offset.bytes());
240 template_str.write_fmt(format_args!("{0:+}", offset))write!(template_str, "{offset:+}").unwrap();
241 }
242 }
243 }
244 }
245 InlineAsmOperandRef::SymThreadLocalStatic { .. } => {
246 template_str.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("${{{0}:c}}", op_idx[&operand_idx]))
})format!("${{{}:c}}", op_idx[&operand_idx]));
248 }
249 InlineAsmOperandRef::Label { label } => {
250 template_str.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("${{{0}:l}}", constraints.len()))
})format!("${{{}:l}}", constraints.len()));
251 constraints.push("!i".to_owned());
252 labels.push(label);
253 }
254 }
255 }
256 }
257 }
258
259 constraints.append(&mut clobbers);
260 if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) {
261 match asm_arch {
262 InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC | InlineAsmArch::Arm => {
263 constraints.push("~{cc}".to_string());
264 }
265 InlineAsmArch::Amdgpu => {}
266 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
267 constraints.extend_from_slice(&[
268 "~{dirflag}".to_string(),
269 "~{fpsr}".to_string(),
270 "~{flags}".to_string(),
271 ]);
272 }
273 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
274 constraints.extend_from_slice(&[
275 "~{fflags}".to_string(),
276 "~{vtype}".to_string(),
277 "~{vl}".to_string(),
278 "~{vxsat}".to_string(),
279 "~{vxrm}".to_string(),
280 ]);
281 }
282 InlineAsmArch::Avr => {
283 constraints.push("~{sreg}".to_string());
284 }
285 InlineAsmArch::Nvptx64 => {}
286 InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {}
287 InlineAsmArch::Hexagon => {}
288 InlineAsmArch::LoongArch32 | InlineAsmArch::LoongArch64 => {
289 constraints.extend_from_slice(&[
290 "~{$fcc0}".to_string(),
291 "~{$fcc1}".to_string(),
292 "~{$fcc2}".to_string(),
293 "~{$fcc3}".to_string(),
294 "~{$fcc4}".to_string(),
295 "~{$fcc5}".to_string(),
296 "~{$fcc6}".to_string(),
297 "~{$fcc7}".to_string(),
298 ]);
299 }
300 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
301 InlineAsmArch::S390x => {
302 constraints.push("~{cc}".to_string());
303 }
304 InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => {
305 constraints.push("~{icc}".to_string());
308 constraints.push("~{fcc0}".to_string());
309 constraints.push("~{fcc1}".to_string());
310 constraints.push("~{fcc2}".to_string());
311 constraints.push("~{fcc3}".to_string());
312 }
313 InlineAsmArch::SpirV => {}
314 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {}
315 InlineAsmArch::Xtensa => {}
316 InlineAsmArch::Bpf => {}
317 InlineAsmArch::Msp430 => {
318 constraints.push("~{sr}".to_string());
319 }
320 InlineAsmArch::M68k => {
321 constraints.push("~{ccr}".to_string());
322 }
323 InlineAsmArch::CSKY => {
324 constraints.push("~{psr}".to_string());
325 }
326 }
327 }
328 if !options.contains(InlineAsmOptions::NOMEM) {
329 constraints.push("~{memory}".to_string());
333 }
334 let volatile = !options.contains(InlineAsmOptions::PURE);
335 let alignstack = !options.contains(InlineAsmOptions::NOSTACK);
336 let output_type = match &output_types[..] {
337 [] => self.type_void(),
338 [ty] => ty,
339 tys => self.type_struct(tys, false),
340 };
341 let dialect = match asm_arch {
342 InlineAsmArch::X86 | InlineAsmArch::X86_64
343 if !options.contains(InlineAsmOptions::ATT_SYNTAX) =>
344 {
345 llvm::AsmDialect::Intel
346 }
347 _ => llvm::AsmDialect::Att,
348 };
349 let result = inline_asm_call(
350 self,
351 &template_str,
352 &constraints.join(","),
353 &inputs,
354 output_type,
355 &labels,
356 volatile,
357 alignstack,
358 dialect,
359 line_spans,
360 options.contains(InlineAsmOptions::MAY_UNWIND),
361 dest,
362 catch_funclet,
363 )
364 .unwrap_or_else(|| ::rustc_middle::util::bug::span_bug_fmt(line_spans[0],
format_args!("LLVM asm constraint validation failed"))span_bug!(line_spans[0], "LLVM asm constraint validation failed"));
365
366 let mut attrs = SmallVec::<[_; 2]>::new();
367 if options.contains(InlineAsmOptions::PURE) {
368 if options.contains(InlineAsmOptions::NOMEM) {
369 attrs.push(llvm::MemoryEffects::None.create_attr(self.cx.llcx));
370 } else if options.contains(InlineAsmOptions::READONLY) {
371 attrs.push(llvm::MemoryEffects::ReadOnly.create_attr(self.cx.llcx));
372 }
373 attrs.push(llvm::AttributeKind::WillReturn.create_attr(self.cx.llcx));
374 } else if options.contains(InlineAsmOptions::NOMEM) {
375 attrs.push(llvm::MemoryEffects::InaccessibleMemOnly.create_attr(self.cx.llcx));
376 } else if options.contains(InlineAsmOptions::READONLY) {
377 attrs.push(llvm::MemoryEffects::ReadOnlyNotPure.create_attr(self.cx.llcx));
378 }
379 attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
380
381 for block in (if options.contains(InlineAsmOptions::NORETURN) { None } else { Some(dest) })
387 .into_iter()
388 .chain(labels.iter().copied().map(Some))
389 {
390 if let Some(block) = block {
391 self.switch_to_block(block);
392 }
393
394 for (idx, op) in operands.iter().enumerate() {
395 if let InlineAsmOperandRef::Out { reg, place: Some(place), .. }
396 | InlineAsmOperandRef::InOut { reg, out_place: Some(place), .. } = *op
397 {
398 let value = if output_types.len() == 1 {
399 result
400 } else {
401 self.extract_value(result, op_idx[&idx] as u64)
402 };
403 let value =
404 llvm_fixup_output(self, value, reg.reg_class(), &place.layout, instance);
405 OperandValue::Immediate(value).store(self, place);
406 }
407 }
408 }
409 }
410}
411
412impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
413 fn codegen_global_asm(
414 &mut self,
415 template: &[InlineAsmTemplatePiece],
416 operands: &[GlobalAsmOperandRef<'tcx>],
417 options: InlineAsmOptions,
418 _line_spans: &[Span],
419 extra_rust_target_features: &[String],
420 ) {
421 let asm_arch = self.tcx.sess.asm_arch.unwrap();
422
423 let mut template_str = String::new();
425
426 if #[allow(non_exhaustive_omitted_patterns)] match asm_arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => true,
_ => false,
}matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) {
429 if options.contains(InlineAsmOptions::ATT_SYNTAX) {
430 template_str.push_str(".att_syntax\n")
431 } else {
432 template_str.push_str(".intel_syntax\n")
433 }
434 }
435
436 for piece in template {
437 match *piece {
438 InlineAsmTemplatePiece::String(ref s) => template_str.push_str(s),
439 InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => {
440 use rustc_codegen_ssa::back::symbol_export::escape_symbol_name;
441 match operands[operand_idx] {
442 GlobalAsmOperandRef::Const { value, ty } => {
443 match value {
444 ConstScalar::Int(int) => {
445 let string = rustc_codegen_ssa::common::asm_const_to_str(
449 self.tcx,
450 span,
451 int,
452 self.layout_of(ty),
453 );
454 template_str.push_str(&string);
455 }
456
457 ConstScalar::Ptr(ptr, _) => {
458 let (prov, offset) = ptr.prov_and_relative_offset();
459 let global_alloc = self.tcx.global_alloc(prov.alloc_id());
460 let llval =
461 self.alloc_to_backend(global_alloc, true, None).unwrap();
462
463 self.add_compiler_used_global(llval);
464 let symbol = llvm::build_string(|s| unsafe {
465 llvm::LLVMRustGetMangledName(llval, s);
466 })
467 .expect("symbol is not valid UTF-8");
468 template_str
469 .push_str(&escape_symbol_name(self.tcx, &symbol, span));
470
471 if offset != Size::ZERO {
472 let offset =
473 self.sign_extend_to_target_isize(offset.bytes());
474 template_str.write_fmt(format_args!("{0:+}", offset))write!(template_str, "{offset:+}").unwrap();
475 }
476 }
477 }
478 }
479 GlobalAsmOperandRef::SymThreadLocalStatic { def_id } => {
480 let llval = self
481 .renamed_statics
482 .borrow()
483 .get(&def_id)
484 .copied()
485 .unwrap_or_else(|| self.get_static(def_id));
486 self.add_compiler_used_global(llval);
487 let symbol = llvm::build_string(|s| unsafe {
488 llvm::LLVMRustGetMangledName(llval, s);
489 })
490 .expect("symbol is not valid UTF-8");
491 template_str.push_str(&escape_symbol_name(self.tcx, &symbol, span));
492 }
493 }
494 }
495 }
496 }
497
498 if #[allow(non_exhaustive_omitted_patterns)] match asm_arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => true,
_ => false,
}matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64)
500 && !options.contains(InlineAsmOptions::ATT_SYNTAX)
501 {
502 template_str.push_str("\n.att_syntax\n");
503 }
504
505 let global_features = self.tcx.global_backend_features(()).iter().map(String::as_str);
507
508 let function_features: Vec<_> = extra_rust_target_features
511 .iter()
512 .flat_map(|feat| llvm_util::to_llvm_features(self.tcx.sess, feat))
513 .flat_map(|feat| feat.into_iter().map(|f| ::alloc::__export::must_use({ ::alloc::fmt::format(format_args!("+{0}", f)) })format!("+{f}")))
514 .collect();
515
516 let function_features = function_features.iter().map(String::as_str);
517 let target_features =
518 global_features.chain(function_features).intersperse(",").collect::<String>();
519
520 llvm::append_module_inline_asm(
521 self.llmod,
522 template_str.as_bytes(),
523 &target_features,
524 llvm_util::target_cpu(self.tcx.sess),
525 );
526 }
527
528 fn mangled_name(&self, instance: Instance<'tcx>) -> String {
529 let llval = self.get_fn(instance);
530 llvm::build_string(|s| unsafe {
531 llvm::LLVMRustGetMangledName(llval, s);
532 })
533 .expect("symbol is not valid UTF-8")
534 }
535}
536
537pub(crate) fn inline_asm_call<'ll>(
538 bx: &mut Builder<'_, 'll, '_>,
539 asm: &str,
540 cons: &str,
541 inputs: &[&'ll Value],
542 output: &'ll llvm::Type,
543 labels: &[&'ll llvm::BasicBlock],
544 volatile: bool,
545 alignstack: bool,
546 dia: llvm::AsmDialect,
547 line_spans: &[Span],
548 unwind: bool,
549 dest: Option<&'ll llvm::BasicBlock>,
550 catch_funclet: Option<(&'ll llvm::BasicBlock, Option<&Funclet<'ll>>)>,
551) -> Option<&'ll Value> {
552 let argtys = inputs
553 .iter()
554 .map(|v| {
555 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_codegen_llvm/src/asm.rs:555",
"rustc_codegen_llvm::asm", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_codegen_llvm/src/asm.rs"),
::tracing_core::__macro_support::Option::Some(555u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::asm"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Asm Input Type: {0:?}",
*v) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("Asm Input Type: {:?}", *v);
556 bx.cx.val_ty(*v)
557 })
558 .collect::<Vec<_>>();
559
560 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_codegen_llvm/src/asm.rs:560",
"rustc_codegen_llvm::asm", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_codegen_llvm/src/asm.rs"),
::tracing_core::__macro_support::Option::Some(560u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::asm"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Asm Output Type: {0:?}",
output) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("Asm Output Type: {:?}", output);
561 let fty = bx.cx.type_func(&argtys, output);
562
563 let constraints_ok = unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr(), cons.len()) };
565 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_codegen_llvm/src/asm.rs:565",
"rustc_codegen_llvm::asm", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/809936eac66c547a5127ce1da805f0d3a6789b98/compiler/rustc_codegen_llvm/src/asm.rs"),
::tracing_core::__macro_support::Option::Some(565u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::asm"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("constraint verification result: {0:?}",
constraints_ok) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("constraint verification result: {:?}", constraints_ok);
566 if !constraints_ok {
567 return None;
569 }
570
571 let v = unsafe {
572 llvm::LLVMGetInlineAsm(
573 fty,
574 asm.as_ptr(),
575 asm.len(),
576 cons.as_ptr(),
577 cons.len(),
578 volatile.to_llvm_bool(),
579 alignstack.to_llvm_bool(),
580 dia,
581 unwind.to_llvm_bool(),
582 )
583 };
584
585 let call = if !labels.is_empty() {
586 if !catch_funclet.is_none() {
::core::panicking::panic("assertion failed: catch_funclet.is_none()")
};assert!(catch_funclet.is_none());
587 bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None)
588 } else if let Some((catch, funclet)) = catch_funclet {
589 bx.invoke(
590 fty,
591 None,
592 None,
593 v,
594 ReturnSlot::Direct,
595 inputs,
596 dest.unwrap(),
597 catch,
598 funclet,
599 None,
600 )
601 } else {
602 bx.call(fty, None, None, v, ReturnSlot::Direct, inputs, None, None)
603 };
604
605 let key = "srcloc";
608 let kind = bx.get_md_kind_id(key);
609
610 if allow_raw_span_inline_asm_srcloc(bx.tcx.sess, bx.bitcode_needed) {
611 let mut srcloc = ::alloc::vec::Vec::new()vec![];
615 if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
616 srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0)));
624 }
625 srcloc.extend(line_spans.iter().map(|span| {
626 llvm::LLVMValueAsMetadata(
627 bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)),
628 )
629 }));
630 bx.cx.set_metadata_node(call, kind, &srcloc);
631 }
632
633 Some(call)
634}
635
636fn allow_raw_span_inline_asm_srcloc(sess: &Session, bitcode_needed: bool) -> bool {
643 sess.lto() == Lto::No && !bitcode_needed
647}
648
649fn xmm_reg_index(reg: InlineAsmReg) -> Option<u32> {
651 use X86InlineAsmReg::*;
652 match reg {
653 InlineAsmReg::X86(reg) if reg as u32 >= xmm0 as u32 && reg as u32 <= xmm15 as u32 => {
654 Some(reg as u32 - xmm0 as u32)
655 }
656 InlineAsmReg::X86(reg) if reg as u32 >= ymm0 as u32 && reg as u32 <= ymm15 as u32 => {
657 Some(reg as u32 - ymm0 as u32)
658 }
659 InlineAsmReg::X86(reg) if reg as u32 >= zmm0 as u32 && reg as u32 <= zmm31 as u32 => {
660 Some(reg as u32 - zmm0 as u32)
661 }
662 _ => None,
663 }
664}
665
666fn a64_reg_index(reg: InlineAsmReg) -> Option<u32> {
668 match reg {
669 InlineAsmReg::AArch64(r) => r.reg_index(),
670 _ => None,
671 }
672}
673
674fn a64_vreg_index(reg: InlineAsmReg) -> Option<u32> {
676 match reg {
677 InlineAsmReg::AArch64(reg) => reg.vreg_index(),
678 _ => None,
679 }
680}
681
682fn hexagon_reg_pair_index(reg: InlineAsmReg) -> Option<u32> {
686 match reg {
687 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r1_0) => Some(0),
688 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r3_2) => Some(1),
689 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r5_4) => Some(2),
690 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r7_6) => Some(3),
691 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r9_8) => Some(4),
692 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r11_10) => Some(5),
693 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r13_12) => Some(6),
694 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r15_14) => Some(7),
695 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r17_16) => Some(8),
696 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r21_20) => Some(10),
697 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r23_22) => Some(11),
698 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r25_24) => Some(12),
699 InlineAsmReg::Hexagon(HexagonInlineAsmReg::r27_26) => Some(13),
700 _ => None,
701 }
702}
703
704fn hexagon_vreg_pair_index(reg: InlineAsmReg) -> Option<u32> {
707 match reg {
708 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v1_0) => Some(0),
709 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v3_2) => Some(1),
710 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v5_4) => Some(2),
711 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v7_6) => Some(3),
712 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v9_8) => Some(4),
713 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v11_10) => Some(5),
714 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v13_12) => Some(6),
715 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v15_14) => Some(7),
716 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v17_16) => Some(8),
717 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v19_18) => Some(9),
718 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v21_20) => Some(10),
719 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v23_22) => Some(11),
720 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v25_24) => Some(12),
721 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v27_26) => Some(13),
722 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v29_28) => Some(14),
723 InlineAsmReg::Hexagon(HexagonInlineAsmReg::v31_30) => Some(15),
724 _ => None,
725 }
726}
727
728fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> String {
730 use InlineAsmRegClass::*;
731 match reg {
732 InlineAsmRegOrRegClass::Reg(reg) => {
734 if let Some(idx) = xmm_reg_index(reg) {
735 let class = if let Some(layout) = layout {
736 match layout.size.bytes() {
737 64 => 'z',
738 32 => 'y',
739 _ => 'x',
740 }
741 } else {
742 'x'
744 };
745 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}mm{1}}}", class, idx))
})format!("{{{}mm{}}}", class, idx)
746 } else if let Some(idx) = a64_reg_index(reg) {
747 let class = if let Some(layout) = layout {
748 match layout.size.bytes() {
749 8 => 'x',
750 _ => 'w',
751 }
752 } else {
753 'w'
755 };
756 if class == 'x' && reg == InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) {
757 "{lr}".to_string()
759 } else {
760 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}{1}}}", class, idx))
})format!("{{{}{}}}", class, idx)
761 }
762 } else if let Some(idx) = a64_vreg_index(reg) {
763 let class = match layout {
764 Some(layout)
765 if #[allow(non_exhaustive_omitted_patterns)] match layout.backend_repr {
BackendRepr::SimdScalableVector { .. } => true,
_ => false,
}matches!(
766 layout.backend_repr,
767 BackendRepr::SimdScalableVector { .. }
768 ) =>
769 {
770 'z'
771 }
772 Some(layout) => match layout.size.bytes() {
773 16 => 'q',
774 8 => 'd',
775 4 => 's',
776 2 => 'h',
777 1 => 'd', _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
779 },
780 None => 'q',
782 };
783 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}{1}}}", class, idx))
})format!("{{{}{}}}", class, idx)
784 } else if let Some(idx) = hexagon_reg_pair_index(reg) {
785 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{d{0}}}", idx))
})format!("{{d{}}}", idx)
787 } else if let Some(idx) = hexagon_vreg_pair_index(reg) {
788 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{w{0}}}", idx))
})format!("{{w{}}}", idx)
790 } else if reg == InlineAsmReg::Arm(ArmInlineAsmReg::r14) {
791 "{lr}".to_string()
793 } else if let InlineAsmReg::Sparc(reg) = reg
794 && let Some(num) = reg.dreg_number()
795 {
796 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{d{0}}}", num / 2))
})format!("{{d{}}}", num / 2)
798 } else if let InlineAsmReg::Sparc(reg) = reg
799 && let Some(num) = reg.qreg_number()
800 {
801 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{q{0}}}", num / 4))
})format!("{{q{}}}", num / 4)
803 } else {
804 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{{0}}}", reg.name()))
})format!("{{{}}}", reg.name())
805 }
806 }
807 InlineAsmRegOrRegClass::RegClass(reg) => match reg {
810 AArch64(AArch64InlineAsmRegClass::reg) => "r",
811 AArch64(AArch64InlineAsmRegClass::vreg) => "w",
812 AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
813 AArch64(AArch64InlineAsmRegClass::preg) => "@3Upa",
816 AArch64(AArch64InlineAsmRegClass::ffr) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
817 Arm(ArmInlineAsmRegClass::reg) => "r",
818 Arm(ArmInlineAsmRegClass::sreg)
819 | Arm(ArmInlineAsmRegClass::dreg_low16)
820 | Arm(ArmInlineAsmRegClass::qreg_low8) => "t",
821 Arm(ArmInlineAsmRegClass::sreg_low16)
822 | Arm(ArmInlineAsmRegClass::dreg_low8)
823 | Arm(ArmInlineAsmRegClass::qreg_low4) => "x",
824 Arm(ArmInlineAsmRegClass::dreg) | Arm(ArmInlineAsmRegClass::qreg) => "w",
825 Amdgpu(AmdgpuInlineAsmRegClass::Sgpr(_)) => "s",
826 Amdgpu(AmdgpuInlineAsmRegClass::Vgpr(_)) => "v",
827 Hexagon(HexagonInlineAsmRegClass::reg) => "r",
828 Hexagon(HexagonInlineAsmRegClass::reg_pair) => "r",
829 Hexagon(HexagonInlineAsmRegClass::preg) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
830 Hexagon(HexagonInlineAsmRegClass::vreg) => "v",
831 Hexagon(HexagonInlineAsmRegClass::vreg_pair) => "v",
832 Hexagon(HexagonInlineAsmRegClass::qreg) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
833 LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
834 LoongArch(LoongArchInlineAsmRegClass::freg)
835 | LoongArch(LoongArchInlineAsmRegClass::vreg)
836 | LoongArch(LoongArchInlineAsmRegClass::xreg) => "f",
837 Mips(MipsInlineAsmRegClass::reg) => "r",
838 Mips(MipsInlineAsmRegClass::freg | MipsInlineAsmRegClass::wreg) => "f",
839 Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
840 Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
841 Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
842 PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
843 PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
844 PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
845 PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
846 PowerPC(PowerPCInlineAsmRegClass::vsreg) => "^wa",
847 PowerPC(
848 PowerPCInlineAsmRegClass::cr
849 | PowerPCInlineAsmRegClass::ctr
850 | PowerPCInlineAsmRegClass::lr
851 | PowerPCInlineAsmRegClass::xer
852 | PowerPCInlineAsmRegClass::spe_acc,
853 ) => {
854 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only")
855 }
856 RiscV(RiscVInlineAsmRegClass::reg) => "r",
857 RiscV(RiscVInlineAsmRegClass::freg) => "f",
858 RiscV(RiscVInlineAsmRegClass::vreg) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
859 X86(X86InlineAsmRegClass::reg) => "r",
860 X86(X86InlineAsmRegClass::reg_abcd) => "Q",
861 X86(X86InlineAsmRegClass::reg_byte) => "q",
862 X86(X86InlineAsmRegClass::xmm_reg) | X86(X86InlineAsmRegClass::ymm_reg) => "x",
863 X86(X86InlineAsmRegClass::zmm_reg) => "v",
864 X86(X86InlineAsmRegClass::kreg) => "^Yk",
865 X86(
866 X86InlineAsmRegClass::x87_reg
867 | X86InlineAsmRegClass::mmx_reg
868 | X86InlineAsmRegClass::kreg0
869 | X86InlineAsmRegClass::tmm_reg,
870 ) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
871 Xtensa(XtensaInlineAsmRegClass::freg) => "f",
872 Xtensa(XtensaInlineAsmRegClass::reg) => "r",
873 Xtensa(XtensaInlineAsmRegClass::sreg | XtensaInlineAsmRegClass::breg) => {
874 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only")
875 }
876 Wasm(WasmInlineAsmRegClass::local) => "r",
877 Bpf(BpfInlineAsmRegClass::reg) => "r",
878 Bpf(BpfInlineAsmRegClass::wreg) => "w",
879 Avr(AvrInlineAsmRegClass::reg) => "r",
880 Avr(AvrInlineAsmRegClass::reg_upper) => "d",
881 Avr(AvrInlineAsmRegClass::reg_pair) => "r",
882 Avr(AvrInlineAsmRegClass::reg_iw) => "w",
883 Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
884 S390x(S390xInlineAsmRegClass::reg) => "r",
885 S390x(S390xInlineAsmRegClass::reg_addr) => "a",
886 S390x(S390xInlineAsmRegClass::freg) => "f",
887 S390x(S390xInlineAsmRegClass::vreg) => "v",
888 S390x(S390xInlineAsmRegClass::areg) => {
889 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only")
890 }
891 Sparc(SparcInlineAsmRegClass::reg) => "r",
892 Sparc(SparcInlineAsmRegClass::freg) => "f",
893 Sparc(SparcInlineAsmRegClass::dreg | SparcInlineAsmRegClass::qreg) => "e",
894 Sparc(SparcInlineAsmRegClass::yreg) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
895 Msp430(Msp430InlineAsmRegClass::reg) => "r",
896 M68k(M68kInlineAsmRegClass::reg) => "r",
897 M68k(M68kInlineAsmRegClass::reg_addr) => "a",
898 M68k(M68kInlineAsmRegClass::reg_data) => "d",
899 CSKY(CSKYInlineAsmRegClass::reg) => "r",
900 CSKY(CSKYInlineAsmRegClass::freg) => "f",
901 SpirV(SpirVInlineAsmRegClass::reg) => ::rustc_middle::util::bug::bug_fmt(format_args!("LLVM backend does not support SPIR-V"))bug!("LLVM backend does not support SPIR-V"),
902 Err => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
903 }
904 .to_string(),
905 }
906}
907
908fn modifier_to_llvm(
910 arch: InlineAsmArch,
911 reg: InlineAsmRegClass,
912 modifier: Option<char>,
913) -> Option<char> {
914 use InlineAsmRegClass::*;
915 match reg {
918 AArch64(AArch64InlineAsmRegClass::reg) => modifier,
919 AArch64(AArch64InlineAsmRegClass::vreg) | AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
920 if modifier == Some('v') {
921 None
922 } else {
923 modifier
924 }
925 }
926 AArch64(AArch64InlineAsmRegClass::preg | AArch64InlineAsmRegClass::ffr) => None,
927 Arm(ArmInlineAsmRegClass::reg) => None,
928 Arm(ArmInlineAsmRegClass::sreg) | Arm(ArmInlineAsmRegClass::sreg_low16) => None,
929 Arm(ArmInlineAsmRegClass::dreg)
930 | Arm(ArmInlineAsmRegClass::dreg_low16)
931 | Arm(ArmInlineAsmRegClass::dreg_low8) => Some('P'),
932 Arm(ArmInlineAsmRegClass::qreg)
933 | Arm(ArmInlineAsmRegClass::qreg_low8)
934 | Arm(ArmInlineAsmRegClass::qreg_low4) => {
935 if modifier.is_none() {
936 Some('q')
937 } else {
938 modifier
939 }
940 }
941 Amdgpu(_) => None,
942 Hexagon(_) => None,
943 LoongArch(LoongArchInlineAsmRegClass::reg) => None,
944 LoongArch(LoongArchInlineAsmRegClass::freg) => modifier,
945 LoongArch(LoongArchInlineAsmRegClass::vreg) => {
946 if modifier.is_none() {
947 Some('w')
948 } else {
949 modifier
950 }
951 }
952 LoongArch(LoongArchInlineAsmRegClass::xreg) => {
953 if modifier.is_none() {
954 Some('u')
955 } else {
956 modifier
957 }
958 }
959 Mips(MipsInlineAsmRegClass::reg) => None,
960 Mips(MipsInlineAsmRegClass::freg) => modifier,
961 Mips(MipsInlineAsmRegClass::wreg) => Some('w'),
962 Nvptx(_) => None,
963 PowerPC(PowerPCInlineAsmRegClass::vsreg) => {
964 if modifier.is_none() { Some('x') } else { modifier }
968 }
969 PowerPC(_) => None,
970 RiscV(RiscVInlineAsmRegClass::reg) | RiscV(RiscVInlineAsmRegClass::freg) => None,
971 RiscV(RiscVInlineAsmRegClass::vreg) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
972 X86(X86InlineAsmRegClass::reg) | X86(X86InlineAsmRegClass::reg_abcd) => match modifier {
973 None if arch == InlineAsmArch::X86_64 => Some('q'),
974 None => Some('k'),
975 Some('l') => Some('b'),
976 Some('h') => Some('h'),
977 Some('x') => Some('w'),
978 Some('e') => Some('k'),
979 Some('r') => Some('q'),
980 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
981 },
982 X86(X86InlineAsmRegClass::reg_byte) => None,
983 X86(reg @ X86InlineAsmRegClass::xmm_reg)
984 | X86(reg @ X86InlineAsmRegClass::ymm_reg)
985 | X86(reg @ X86InlineAsmRegClass::zmm_reg) => match (reg, modifier) {
986 (X86InlineAsmRegClass::xmm_reg, None) => Some('x'),
987 (X86InlineAsmRegClass::ymm_reg, None) => Some('t'),
988 (X86InlineAsmRegClass::zmm_reg, None) => Some('g'),
989 (_, Some('x')) => Some('x'),
990 (_, Some('y')) => Some('t'),
991 (_, Some('z')) => Some('g'),
992 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
993 },
994 X86(X86InlineAsmRegClass::kreg) => None,
995 X86(
996 X86InlineAsmRegClass::x87_reg
997 | X86InlineAsmRegClass::mmx_reg
998 | X86InlineAsmRegClass::kreg0
999 | X86InlineAsmRegClass::tmm_reg,
1000 ) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
1001 Xtensa(_) => None,
1002 Wasm(WasmInlineAsmRegClass::local) => None,
1003 Bpf(_) => None,
1004 Avr(AvrInlineAsmRegClass::reg_pair)
1005 | Avr(AvrInlineAsmRegClass::reg_iw)
1006 | Avr(AvrInlineAsmRegClass::reg_ptr) => match modifier {
1007 Some('h') => Some('B'),
1008 Some('l') => Some('A'),
1009 _ => None,
1010 },
1011 Avr(_) => None,
1012 S390x(_) => None,
1013 Sparc(_) => None,
1014 Msp430(_) => None,
1015 SpirV(SpirVInlineAsmRegClass::reg) => ::rustc_middle::util::bug::bug_fmt(format_args!("LLVM backend does not support SPIR-V"))bug!("LLVM backend does not support SPIR-V"),
1016 M68k(_) => None,
1017 CSKY(_) => None,
1018 Err => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1019 }
1020}
1021
1022fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'ll Type {
1025 use InlineAsmRegClass::*;
1026 match reg {
1027 AArch64(AArch64InlineAsmRegClass::reg) => cx.type_i32(),
1028 AArch64(AArch64InlineAsmRegClass::vreg) | AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
1029 cx.type_vector(cx.type_i64(), 2)
1030 }
1031 AArch64(AArch64InlineAsmRegClass::preg) => cx.type_scalable_vector(cx.type_i1(), 16),
1032 AArch64(AArch64InlineAsmRegClass::ffr) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
1033 Arm(ArmInlineAsmRegClass::reg) => cx.type_i32(),
1034 Arm(ArmInlineAsmRegClass::sreg) | Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(),
1035 Arm(ArmInlineAsmRegClass::dreg)
1036 | Arm(ArmInlineAsmRegClass::dreg_low16)
1037 | Arm(ArmInlineAsmRegClass::dreg_low8) => cx.type_f64(),
1038 Arm(ArmInlineAsmRegClass::qreg)
1039 | Arm(ArmInlineAsmRegClass::qreg_low8)
1040 | Arm(ArmInlineAsmRegClass::qreg_low4) => cx.type_vector(cx.type_i64(), 2),
1041 Amdgpu(_) => cx.type_i32(),
1042 Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
1043 Hexagon(HexagonInlineAsmRegClass::reg_pair) => cx.type_i64(),
1044 Hexagon(HexagonInlineAsmRegClass::preg) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
1045 Hexagon(HexagonInlineAsmRegClass::vreg) => {
1046 if cx.tcx.sess.internal_target_features.contains(&sym::hvx_length128b) {
1049 cx.type_vector(cx.type_i32(), 32) } else {
1051 cx.type_vector(cx.type_i32(), 16) }
1053 }
1054 Hexagon(HexagonInlineAsmRegClass::vreg_pair) => {
1055 if cx.tcx.sess.internal_target_features.contains(&sym::hvx_length128b) {
1056 cx.type_vector(cx.type_i32(), 64) } else {
1058 cx.type_vector(cx.type_i32(), 32) }
1060 }
1061 Hexagon(HexagonInlineAsmRegClass::qreg) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
1062 LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(),
1063 LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(),
1064 LoongArch(LoongArchInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i32(), 4),
1065 LoongArch(LoongArchInlineAsmRegClass::xreg) => cx.type_vector(cx.type_i32(), 8),
1066 Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
1067 Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
1068 Mips(MipsInlineAsmRegClass::wreg) => cx.type_vector(cx.type_i32(), 4),
1069 Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
1070 Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
1071 Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
1072 PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
1073 PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
1074 PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
1075 PowerPC(PowerPCInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i32(), 4),
1076 PowerPC(PowerPCInlineAsmRegClass::vsreg) => cx.type_vector(cx.type_i32(), 4),
1077 PowerPC(
1078 PowerPCInlineAsmRegClass::cr
1079 | PowerPCInlineAsmRegClass::ctr
1080 | PowerPCInlineAsmRegClass::lr
1081 | PowerPCInlineAsmRegClass::xer
1082 | PowerPCInlineAsmRegClass::spe_acc,
1083 ) => {
1084 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only")
1085 }
1086 RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
1087 RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
1088 RiscV(RiscVInlineAsmRegClass::vreg) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
1089 X86(X86InlineAsmRegClass::reg) | X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(),
1090 X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(),
1091 X86(X86InlineAsmRegClass::xmm_reg)
1092 | X86(X86InlineAsmRegClass::ymm_reg)
1093 | X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
1094 X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
1095 X86(
1096 X86InlineAsmRegClass::x87_reg
1097 | X86InlineAsmRegClass::mmx_reg
1098 | X86InlineAsmRegClass::kreg0
1099 | X86InlineAsmRegClass::tmm_reg,
1100 ) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
1101 Xtensa(XtensaInlineAsmRegClass::reg) => cx.type_i32(),
1102 Xtensa(XtensaInlineAsmRegClass::freg) => cx.type_f32(),
1103 Xtensa(XtensaInlineAsmRegClass::sreg | XtensaInlineAsmRegClass::breg) => {
1104 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only")
1105 }
1106 Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
1107 Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(),
1108 Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(),
1109 Avr(AvrInlineAsmRegClass::reg) => cx.type_i8(),
1110 Avr(AvrInlineAsmRegClass::reg_upper) => cx.type_i8(),
1111 Avr(AvrInlineAsmRegClass::reg_pair) => cx.type_i16(),
1112 Avr(AvrInlineAsmRegClass::reg_iw) => cx.type_i16(),
1113 Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
1114 S390x(S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr) => cx.type_i32(),
1115 S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
1116 S390x(S390xInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i64(), 2),
1117 S390x(S390xInlineAsmRegClass::areg) => {
1118 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only")
1119 }
1120 Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(),
1121 Sparc(SparcInlineAsmRegClass::freg) => cx.type_f32(),
1122 Sparc(SparcInlineAsmRegClass::dreg) => cx.type_f64(),
1123 Sparc(SparcInlineAsmRegClass::qreg) => cx.type_f128(),
1124 Sparc(SparcInlineAsmRegClass::yreg) => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("clobber-only")));
}unreachable!("clobber-only"),
1125 Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
1126 M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
1127 M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
1128 M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(),
1129 CSKY(CSKYInlineAsmRegClass::reg) => cx.type_i32(),
1130 CSKY(CSKYInlineAsmRegClass::freg) => cx.type_f32(),
1131 SpirV(SpirVInlineAsmRegClass::reg) => ::rustc_middle::util::bug::bug_fmt(format_args!("LLVM backend does not support SPIR-V"))bug!("LLVM backend does not support SPIR-V"),
1132 Err => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1133 }
1134}
1135
1136fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Type {
1139 let dl = &cx.tcx.data_layout;
1140 match scalar.primitive() {
1141 Primitive::Int(Integer::I8, _) => cx.type_i8(),
1142 Primitive::Int(Integer::I16, _) => cx.type_i16(),
1143 Primitive::Int(Integer::I32, _) => cx.type_i32(),
1144 Primitive::Int(Integer::I64, _) => cx.type_i64(),
1145 Primitive::Float(Float::F16) => cx.type_f16(),
1146 Primitive::Float(Float::F32) => cx.type_f32(),
1147 Primitive::Float(Float::F64) => cx.type_f64(),
1148 Primitive::Float(Float::F128) => cx.type_f128(),
1149 Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()),
1151 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1152 }
1153}
1154
1155fn any_target_feature_enabled(
1156 cx: &CodegenCx<'_, '_>,
1157 instance: Instance<'_>,
1158 features: &[Symbol],
1159) -> bool {
1160 let enabled = cx.tcx.asm_target_features(instance.def_id());
1161 features.iter().any(|feat| enabled.contains(feat))
1162}
1163
1164fn llvm_fixup_input<'ll, 'tcx>(
1166 bx: &mut Builder<'_, 'll, 'tcx>,
1167 mut value: &'ll Value,
1168 reg: InlineAsmRegClass,
1169 layout: &TyAndLayout<'tcx>,
1170 instance: Instance<'_>,
1171) -> &'ll Value {
1172 use InlineAsmRegClass::*;
1173 let dl = &bx.tcx.data_layout;
1174 match (reg, layout.backend_repr) {
1175 (AArch64(AArch64InlineAsmRegClass::vreg), BackendRepr::Scalar(s)) => {
1176 if let Primitive::Int(Integer::I8, _) = s.primitive() {
1177 let vec_ty = bx.cx.type_vector(bx.cx.type_i8(), 8);
1178 bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0))
1179 } else {
1180 value
1181 }
1182 }
1183 (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Scalar(s))
1184 if s.primitive() != Primitive::Float(Float::F128) =>
1185 {
1186 let elem_ty = llvm_asm_scalar_type(bx.cx, s);
1187 let count = 16 / layout.size.bytes();
1188 let vec_ty = bx.cx.type_vector(elem_ty, count);
1189 if let Primitive::Pointer(_) = s.primitive() {
1191 let t = bx.type_from_integer(dl.ptr_sized_integer());
1192 value = bx.ptrtoint(value, t);
1193 }
1194 bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0))
1195 }
1196 (
1197 AArch64(AArch64InlineAsmRegClass::vreg_low16),
1198 BackendRepr::SimdVector { element, count },
1199 ) if layout.size.bytes() == 8 => {
1200 let elem_ty = llvm_asm_scalar_type(bx.cx, element);
1201 let count = count.as_u32();
1202 let vec_ty = bx.cx.type_vector(elem_ty, u64::from(count));
1203 let indices: Vec<_> = (0..count * 2).map(|x| bx.const_u32(x)).collect();
1204 bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices))
1205 }
1206 (X86(X86InlineAsmRegClass::reg_abcd), BackendRepr::Scalar(s))
1207 if s.primitive() == Primitive::Float(Float::F64) =>
1208 {
1209 bx.bitcast(value, bx.cx.type_i64())
1210 }
1211 (
1212 X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg),
1213 BackendRepr::SimdVector { .. },
1214 ) if layout.size.bytes() == 64 => bx.bitcast(value, bx.cx.type_vector(bx.cx.type_f64(), 8)),
1215 (
1216 X86(
1217 X86InlineAsmRegClass::xmm_reg
1218 | X86InlineAsmRegClass::ymm_reg
1219 | X86InlineAsmRegClass::zmm_reg,
1220 ),
1221 BackendRepr::Scalar(s),
1222 ) if bx.sess().asm_arch == Some(InlineAsmArch::X86)
1223 && s.primitive() == Primitive::Float(Float::F128) =>
1224 {
1225 bx.bitcast(value, bx.type_vector(bx.type_i32(), 4))
1226 }
1227 (
1228 X86(
1229 X86InlineAsmRegClass::xmm_reg
1230 | X86InlineAsmRegClass::ymm_reg
1231 | X86InlineAsmRegClass::zmm_reg,
1232 ),
1233 BackendRepr::Scalar(s),
1234 ) if s.primitive() == Primitive::Float(Float::F16) => {
1235 let value = bx.insert_element(
1236 bx.const_undef(bx.type_vector(bx.type_f16(), 8)),
1237 value,
1238 bx.const_usize(0),
1239 );
1240 bx.bitcast(value, bx.type_vector(bx.type_i16(), 8))
1241 }
1242 (
1243 X86(
1244 X86InlineAsmRegClass::xmm_reg
1245 | X86InlineAsmRegClass::ymm_reg
1246 | X86InlineAsmRegClass::zmm_reg,
1247 ),
1248 BackendRepr::SimdVector { element, count },
1249 ) if let count = count.as_u64()
1250 && let 8 | 16 = count
1251 && element.primitive() == Primitive::Float(Float::F16) =>
1252 {
1253 bx.bitcast(value, bx.type_vector(bx.type_i16(), count))
1254 }
1255 (
1256 Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16),
1257 BackendRepr::Scalar(s),
1258 ) => {
1259 if let Primitive::Int(Integer::I32, _) = s.primitive() {
1260 bx.bitcast(value, bx.cx.type_f32())
1261 } else {
1262 value
1263 }
1264 }
1265 (
1266 Arm(
1267 ArmInlineAsmRegClass::dreg
1268 | ArmInlineAsmRegClass::dreg_low8
1269 | ArmInlineAsmRegClass::dreg_low16,
1270 ),
1271 BackendRepr::Scalar(s),
1272 ) => {
1273 if let Primitive::Int(Integer::I64, _) = s.primitive() {
1274 bx.bitcast(value, bx.cx.type_f64())
1275 } else {
1276 value
1277 }
1278 }
1279 (
1280 Arm(
1281 ArmInlineAsmRegClass::dreg
1282 | ArmInlineAsmRegClass::dreg_low8
1283 | ArmInlineAsmRegClass::dreg_low16
1284 | ArmInlineAsmRegClass::qreg
1285 | ArmInlineAsmRegClass::qreg_low4
1286 | ArmInlineAsmRegClass::qreg_low8,
1287 ),
1288 BackendRepr::SimdVector { element, count },
1289 ) if let count = count.as_u64()
1290 && let 4 | 8 = count
1291 && element.primitive() == Primitive::Float(Float::F16) =>
1292 {
1293 bx.bitcast(value, bx.type_vector(bx.type_i16(), count))
1294 }
1295 (LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s))
1296 if s.primitive() == Primitive::Float(Float::F16) =>
1297 {
1298 let value = bx.bitcast(value, bx.type_i16());
1303 let value = bx.zext(value, bx.type_i32());
1304 let value = bx.or(value, bx.const_u32(0xFFFF_0000));
1305 bx.bitcast(value, bx.type_f32())
1306 }
1307 (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => {
1308 match s.primitive() {
1309 Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.type_i32()),
1311 Primitive::Float(Float::F16) => {
1312 let value = bx.bitcast(value, bx.type_i16());
1313 bx.zext(value, bx.type_i32())
1314 }
1315 Primitive::Float(Float::F32) => bx.bitcast(value, bx.type_i32()),
1316 Primitive::Float(Float::F64) => bx.bitcast(value, bx.type_i64()),
1317 _ => value,
1318 }
1319 }
1320 (
1321 Mips(MipsInlineAsmRegClass::freg | MipsInlineAsmRegClass::wreg),
1322 BackendRepr::Scalar(s),
1323 ) if s.primitive() == Primitive::Float(Float::F16) => {
1324 let value = bx.bitcast(value, bx.type_i16());
1325 let value = bx.zext(value, bx.type_i32());
1326 bx.bitcast(value, bx.type_f32())
1327 }
1328 (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s))
1329 if s.primitive() == Primitive::Float(Float::F16)
1330 && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) =>
1331 {
1332 let value = bx.bitcast(value, bx.type_i16());
1334 let value = bx.zext(value, bx.type_i32());
1335 let value = bx.or(value, bx.const_u32(0xFFFF_0000));
1336 bx.bitcast(value, bx.type_f32())
1337 }
1338 (
1339 PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
1340 BackendRepr::Scalar(s),
1341 ) if let Primitive::Float(float @ (Float::F16 | Float::F32 | Float::F64)) =
1342 s.primitive() =>
1343 {
1344 let num_lanes = 16 / float.size().bytes();
1345 let offset = if float == Float::F16 { 3 } else { 0 };
1348 bx.insert_element(
1349 bx.const_undef(bx.type_vector(bx.type_from_float(float), num_lanes)),
1350 value,
1351 bx.const_usize(match bx.target_spec().endian {
1352 Endian::Little => num_lanes - 1 - offset,
1353 Endian::Big => offset,
1354 }),
1355 )
1356 }
1357 (
1358 PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
1359 BackendRepr::Scalar(s),
1360 ) if s.primitive() == Primitive::Float(Float::F128) => {
1361 bx.bitcast(value, bx.type_vector(bx.type_f64(), 2))
1362 }
1363 _ => value,
1364 }
1365}
1366
1367fn llvm_fixup_output<'ll, 'tcx>(
1369 bx: &mut Builder<'_, 'll, 'tcx>,
1370 mut value: &'ll Value,
1371 reg: InlineAsmRegClass,
1372 layout: &TyAndLayout<'tcx>,
1373 instance: Instance<'_>,
1374) -> &'ll Value {
1375 use InlineAsmRegClass::*;
1376 match (reg, layout.backend_repr) {
1377 (AArch64(AArch64InlineAsmRegClass::vreg), BackendRepr::Scalar(s)) => {
1378 if let Primitive::Int(Integer::I8, _) = s.primitive() {
1379 bx.extract_element(value, bx.const_i32(0))
1380 } else {
1381 value
1382 }
1383 }
1384 (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Scalar(s))
1385 if s.primitive() != Primitive::Float(Float::F128) =>
1386 {
1387 value = bx.extract_element(value, bx.const_i32(0));
1388 if let Primitive::Pointer(_) = s.primitive() {
1389 value = bx.inttoptr(value, layout.llvm_type(bx.cx));
1390 }
1391 value
1392 }
1393 (
1394 AArch64(AArch64InlineAsmRegClass::vreg_low16),
1395 BackendRepr::SimdVector { element, count },
1396 ) if layout.size.bytes() == 8 => {
1397 let elem_ty = llvm_asm_scalar_type(bx.cx, element);
1398 let count = count.as_u64();
1399 let vec_ty = bx.cx.type_vector(elem_ty, count * 2);
1400 let indices: Vec<_> = (0..count).map(|x| bx.const_i32(x as i32)).collect();
1401 bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices))
1402 }
1403 (X86(X86InlineAsmRegClass::reg_abcd), BackendRepr::Scalar(s))
1404 if s.primitive() == Primitive::Float(Float::F64) =>
1405 {
1406 bx.bitcast(value, bx.cx.type_f64())
1407 }
1408 (
1409 X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg),
1410 BackendRepr::SimdVector { .. },
1411 ) if layout.size.bytes() == 64 => bx.bitcast(value, layout.llvm_type(bx.cx)),
1412 (
1413 X86(
1414 X86InlineAsmRegClass::xmm_reg
1415 | X86InlineAsmRegClass::ymm_reg
1416 | X86InlineAsmRegClass::zmm_reg,
1417 ),
1418 BackendRepr::Scalar(s),
1419 ) if bx.sess().asm_arch == Some(InlineAsmArch::X86)
1420 && s.primitive() == Primitive::Float(Float::F128) =>
1421 {
1422 bx.bitcast(value, bx.type_f128())
1423 }
1424 (
1425 X86(
1426 X86InlineAsmRegClass::xmm_reg
1427 | X86InlineAsmRegClass::ymm_reg
1428 | X86InlineAsmRegClass::zmm_reg,
1429 ),
1430 BackendRepr::Scalar(s),
1431 ) if s.primitive() == Primitive::Float(Float::F16) => {
1432 let value = bx.bitcast(value, bx.type_vector(bx.type_f16(), 8));
1433 bx.extract_element(value, bx.const_usize(0))
1434 }
1435 (
1436 X86(
1437 X86InlineAsmRegClass::xmm_reg
1438 | X86InlineAsmRegClass::ymm_reg
1439 | X86InlineAsmRegClass::zmm_reg,
1440 ),
1441 BackendRepr::SimdVector { element, count },
1442 ) if let count = count.as_u64()
1443 && let 8 | 16 = count
1444 && element.primitive() == Primitive::Float(Float::F16) =>
1445 {
1446 bx.bitcast(value, bx.type_vector(bx.type_f16(), count))
1447 }
1448 (
1449 Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16),
1450 BackendRepr::Scalar(s),
1451 ) => {
1452 if let Primitive::Int(Integer::I32, _) = s.primitive() {
1453 bx.bitcast(value, bx.cx.type_i32())
1454 } else {
1455 value
1456 }
1457 }
1458 (
1459 Arm(
1460 ArmInlineAsmRegClass::dreg
1461 | ArmInlineAsmRegClass::dreg_low8
1462 | ArmInlineAsmRegClass::dreg_low16,
1463 ),
1464 BackendRepr::Scalar(s),
1465 ) => {
1466 if let Primitive::Int(Integer::I64, _) = s.primitive() {
1467 bx.bitcast(value, bx.cx.type_i64())
1468 } else {
1469 value
1470 }
1471 }
1472 (
1473 Arm(
1474 ArmInlineAsmRegClass::dreg
1475 | ArmInlineAsmRegClass::dreg_low8
1476 | ArmInlineAsmRegClass::dreg_low16
1477 | ArmInlineAsmRegClass::qreg
1478 | ArmInlineAsmRegClass::qreg_low4
1479 | ArmInlineAsmRegClass::qreg_low8,
1480 ),
1481 BackendRepr::SimdVector { element, count },
1482 ) if let count = count.as_u64()
1483 && let 4 | 8 = count
1484 && element.primitive() == Primitive::Float(Float::F16) =>
1485 {
1486 bx.bitcast(value, bx.type_vector(bx.type_f16(), count))
1487 }
1488 (LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s))
1489 if s.primitive() == Primitive::Float(Float::F16) =>
1490 {
1491 let value = bx.bitcast(value, bx.type_i32());
1492 let value = bx.trunc(value, bx.type_i16());
1493 bx.bitcast(value, bx.type_f16())
1494 }
1495 (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => {
1496 match s.primitive() {
1497 Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.type_i8()),
1499 Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.type_i16()),
1500 Primitive::Float(Float::F16) => {
1501 let value = bx.trunc(value, bx.type_i16());
1502 bx.bitcast(value, bx.type_f16())
1503 }
1504 Primitive::Float(Float::F32) => bx.bitcast(value, bx.type_f32()),
1505 Primitive::Float(Float::F64) => bx.bitcast(value, bx.type_f64()),
1506 _ => value,
1507 }
1508 }
1509 (
1510 Mips(MipsInlineAsmRegClass::freg | MipsInlineAsmRegClass::wreg),
1511 BackendRepr::Scalar(s),
1512 ) if s.primitive() == Primitive::Float(Float::F16) => {
1513 let value = bx.bitcast(value, bx.type_i32());
1514 let value = bx.trunc(value, bx.type_i16());
1515 bx.bitcast(value, bx.type_f16())
1516 }
1517 (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s))
1518 if s.primitive() == Primitive::Float(Float::F16)
1519 && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) =>
1520 {
1521 let value = bx.bitcast(value, bx.type_i32());
1522 let value = bx.trunc(value, bx.type_i16());
1523 bx.bitcast(value, bx.type_f16())
1524 }
1525 (
1526 PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
1527 BackendRepr::Scalar(s),
1528 ) if let Primitive::Float(float @ (Float::F16 | Float::F32 | Float::F64)) =
1529 s.primitive() =>
1530 {
1531 let num_lanes = 16 / float.size().bytes();
1532 let offset = if float == Float::F16 { 3 } else { 0 };
1535 bx.extract_element(
1536 value,
1537 bx.const_usize(match bx.target_spec().endian {
1538 Endian::Little => num_lanes - 1 - offset,
1539 Endian::Big => offset,
1540 }),
1541 )
1542 }
1543 (
1544 PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
1545 BackendRepr::Scalar(s),
1546 ) if s.primitive() == Primitive::Float(Float::F128) => bx.bitcast(value, bx.type_f128()),
1547 _ => value,
1548 }
1549}
1550
1551fn llvm_fixup_output_type<'ll, 'tcx>(
1553 cx: &CodegenCx<'ll, 'tcx>,
1554 reg: InlineAsmRegClass,
1555 layout: &TyAndLayout<'tcx>,
1556 instance: Instance<'_>,
1557) -> &'ll Type {
1558 use InlineAsmRegClass::*;
1559 match (reg, layout.backend_repr) {
1560 (AArch64(AArch64InlineAsmRegClass::vreg), BackendRepr::Scalar(s)) => {
1561 if let Primitive::Int(Integer::I8, _) = s.primitive() {
1562 cx.type_vector(cx.type_i8(), 8)
1563 } else {
1564 layout.llvm_type(cx)
1565 }
1566 }
1567 (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Scalar(s))
1568 if s.primitive() != Primitive::Float(Float::F128) =>
1569 {
1570 let elem_ty = llvm_asm_scalar_type(cx, s);
1571 let count = 16 / layout.size.bytes();
1572 cx.type_vector(elem_ty, count)
1573 }
1574 (
1575 AArch64(AArch64InlineAsmRegClass::vreg_low16),
1576 BackendRepr::SimdVector { element, count },
1577 ) if layout.size.bytes() == 8 => {
1578 let elem_ty = llvm_asm_scalar_type(cx, element);
1579 cx.type_vector(elem_ty, count.as_u64() * 2)
1580 }
1581 (X86(X86InlineAsmRegClass::reg_abcd), BackendRepr::Scalar(s))
1582 if s.primitive() == Primitive::Float(Float::F64) =>
1583 {
1584 cx.type_i64()
1585 }
1586 (
1587 X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg),
1588 BackendRepr::SimdVector { .. },
1589 ) if layout.size.bytes() == 64 => cx.type_vector(cx.type_f64(), 8),
1590 (
1591 X86(
1592 X86InlineAsmRegClass::xmm_reg
1593 | X86InlineAsmRegClass::ymm_reg
1594 | X86InlineAsmRegClass::zmm_reg,
1595 ),
1596 BackendRepr::Scalar(s),
1597 ) if cx.sess().asm_arch == Some(InlineAsmArch::X86)
1598 && s.primitive() == Primitive::Float(Float::F128) =>
1599 {
1600 cx.type_vector(cx.type_i32(), 4)
1601 }
1602 (
1603 X86(
1604 X86InlineAsmRegClass::xmm_reg
1605 | X86InlineAsmRegClass::ymm_reg
1606 | X86InlineAsmRegClass::zmm_reg,
1607 ),
1608 BackendRepr::Scalar(s),
1609 ) if s.primitive() == Primitive::Float(Float::F16) => cx.type_vector(cx.type_i16(), 8),
1610 (
1611 X86(
1612 X86InlineAsmRegClass::xmm_reg
1613 | X86InlineAsmRegClass::ymm_reg
1614 | X86InlineAsmRegClass::zmm_reg,
1615 ),
1616 BackendRepr::SimdVector { element, count },
1617 ) if let count = count.as_u64()
1618 && let 8 | 16 = count
1619 && element.primitive() == Primitive::Float(Float::F16) =>
1620 {
1621 cx.type_vector(cx.type_i16(), count)
1622 }
1623 (
1624 Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16),
1625 BackendRepr::Scalar(s),
1626 ) => {
1627 if let Primitive::Int(Integer::I32, _) = s.primitive() {
1628 cx.type_f32()
1629 } else {
1630 layout.llvm_type(cx)
1631 }
1632 }
1633 (
1634 Arm(
1635 ArmInlineAsmRegClass::dreg
1636 | ArmInlineAsmRegClass::dreg_low8
1637 | ArmInlineAsmRegClass::dreg_low16,
1638 ),
1639 BackendRepr::Scalar(s),
1640 ) => {
1641 if let Primitive::Int(Integer::I64, _) = s.primitive() {
1642 cx.type_f64()
1643 } else {
1644 layout.llvm_type(cx)
1645 }
1646 }
1647 (
1648 Arm(
1649 ArmInlineAsmRegClass::dreg
1650 | ArmInlineAsmRegClass::dreg_low8
1651 | ArmInlineAsmRegClass::dreg_low16
1652 | ArmInlineAsmRegClass::qreg
1653 | ArmInlineAsmRegClass::qreg_low4
1654 | ArmInlineAsmRegClass::qreg_low8,
1655 ),
1656 BackendRepr::SimdVector { element, count },
1657 ) if let count = count.as_u64()
1658 && let 4 | 8 = count
1659 && element.primitive() == Primitive::Float(Float::F16) =>
1660 {
1661 cx.type_vector(cx.type_i16(), count)
1662 }
1663 (LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s))
1664 if s.primitive() == Primitive::Float(Float::F16) =>
1665 {
1666 cx.type_f32()
1667 }
1668 (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => {
1669 match s.primitive() {
1670 Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(),
1672 Primitive::Float(Float::F16 | Float::F32) => cx.type_i32(),
1673 Primitive::Float(Float::F64) => cx.type_i64(),
1674 _ => layout.llvm_type(cx),
1675 }
1676 }
1677
1678 (
1679 Mips(MipsInlineAsmRegClass::freg | MipsInlineAsmRegClass::wreg),
1680 BackendRepr::Scalar(s),
1681 ) if s.primitive() == Primitive::Float(Float::F16) => cx.type_f32(),
1682 (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s))
1683 if s.primitive() == Primitive::Float(Float::F16)
1684 && !any_target_feature_enabled(cx, instance, &[sym::zfhmin, sym::zfh]) =>
1685 {
1686 cx.type_f32()
1687 }
1688 (
1689 PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
1690 BackendRepr::Scalar(s),
1691 ) if let Primitive::Float(float @ (Float::F16 | Float::F32 | Float::F64)) =
1692 s.primitive() =>
1693 {
1694 cx.type_vector(cx.type_from_float(float), 16 / float.size().bytes())
1695 }
1696 (
1697 PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
1698 BackendRepr::Scalar(s),
1699 ) if s.primitive() == Primitive::Float(Float::F128) => cx.type_vector(cx.type_f64(), 2),
1700 _ => layout.llvm_type(cx),
1701 }
1702}