about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-03-13 11:28:20 +0100
committerGitHub <noreply@github.com>2025-03-13 11:28:20 +0100
commit762acf53cb5be986e8bce6de687083334a9c9c78 (patch)
treecb075e45d588fd73e29f9e5d0a7414afe78499b8 /compiler/rustc_codegen_ssa/src
parent961351c76c812e3aeb65bfb542742500a6436aed (diff)
parentf35bda3997d285618b267f1b25eebff2ff467387 (diff)
downloadrust-762acf53cb5be986e8bce6de687083334a9c9c78.tar.gz
rust-762acf53cb5be986e8bce6de687083334a9c9c78.zip
Rollup merge of #137816 - folkertdev:naked-asm-xcoff, r=Noratrieb
attempt to support `BinaryFormat::Xcoff` in `naked_asm!`

Fixes https://github.com/rust-lang/rust/issues/137219

So, the inline assembly support for xcoff is extremely limited. The LLVM [XCOFFAsmParser](https://github.com/llvm/llvm-project/blob/1b25c0c4da968fe78921ce77736e5baef4db75e3/llvm/lib/MC/MCParser/XCOFFAsmParser.cpp) does not support many of the attributes that LLVM itself emits, and that should exist based on [the assembler docs](https://www.ibm.com/docs/en/ssw_aix_71/assembler/assembler_pdf.pdf). It also does accept some that should not exist based on those docs.

So, I've tried to do the best I can given those limitations. At least it's better than emitting the directives for elf and having that fail somewhere deep in LLVM. Given that inline assembly for this target is incomplete (under `asm_experimental_arch`), I think that's OK (and again I don't see how we can do better given the limitations in LLVM).

r? ```@Noratrieb``` (given that you reviewed https://github.com/rust-lang/rust/pull/136637)

It seems reasonable to ping the [`powerpc64-ibm-aix` target maintainers](https://doc.rust-lang.org/rustc/platform-support/aix.html), hopefully they have thoughts too: ```@daltenty``` ```@gilamn5tr```
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/naked_asm.rs50
1 files changed, 41 insertions, 9 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
index 96d1ab018f6..26468b6a047 100644
--- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
@@ -125,7 +125,8 @@ fn prefix_and_suffix<'tcx>(
     // the alignment from a `#[repr(align(<n>))]` is used if it specifies a higher alignment.
     // if no alignment is specified, an alignment of 4 bytes is used.
     let min_function_alignment = tcx.sess.opts.unstable_opts.min_function_alignment;
-    let align = Ord::max(min_function_alignment, attrs.alignment).map(|a| a.bytes()).unwrap_or(4);
+    let align_bytes =
+        Ord::max(min_function_alignment, attrs.alignment).map(|a| a.bytes()).unwrap_or(4);
 
     // In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`.
     let (arch_prefix, arch_suffix) = if is_arm {
@@ -157,12 +158,16 @@ fn prefix_and_suffix<'tcx>(
             }
             Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => {
                 match asm_binary_format {
-                    BinaryFormat::Elf
-                    | BinaryFormat::Coff
-                    | BinaryFormat::Wasm
-                    | BinaryFormat::Xcoff => {
+                    BinaryFormat::Elf | BinaryFormat::Coff | BinaryFormat::Wasm => {
                         writeln!(w, ".weak {asm_name}")?;
                     }
+                    BinaryFormat::Xcoff => {
+                        // FIXME: there is currently no way of defining a weak symbol in inline assembly
+                        // for AIX. See https://github.com/llvm/llvm-project/issues/130269
+                        emit_fatal(
+                            "cannot create weak symbols from inline assembly for this target",
+                        )
+                    }
                     BinaryFormat::MachO => {
                         writeln!(w, ".globl {asm_name}")?;
                         writeln!(w, ".weak_definition {asm_name}")?;
@@ -189,7 +194,7 @@ fn prefix_and_suffix<'tcx>(
     let mut begin = String::new();
     let mut end = String::new();
     match asm_binary_format {
-        BinaryFormat::Elf | BinaryFormat::Xcoff => {
+        BinaryFormat::Elf => {
             let section = link_section.unwrap_or(format!(".text.{asm_name}"));
 
             let progbits = match is_arm {
@@ -203,7 +208,7 @@ fn prefix_and_suffix<'tcx>(
             };
 
             writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap();
-            writeln!(begin, ".balign {align}").unwrap();
+            writeln!(begin, ".balign {align_bytes}").unwrap();
             write_linkage(&mut begin).unwrap();
             if let Visibility::Hidden = item_data.visibility {
                 writeln!(begin, ".hidden {asm_name}").unwrap();
@@ -224,7 +229,7 @@ fn prefix_and_suffix<'tcx>(
         BinaryFormat::MachO => {
             let section = link_section.unwrap_or("__TEXT,__text".to_string());
             writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap();
-            writeln!(begin, ".balign {align}").unwrap();
+            writeln!(begin, ".balign {align_bytes}").unwrap();
             write_linkage(&mut begin).unwrap();
             if let Visibility::Hidden = item_data.visibility {
                 writeln!(begin, ".private_extern {asm_name}").unwrap();
@@ -240,7 +245,7 @@ fn prefix_and_suffix<'tcx>(
         BinaryFormat::Coff => {
             let section = link_section.unwrap_or(format!(".text.{asm_name}"));
             writeln!(begin, ".pushsection {},\"xr\"", section).unwrap();
-            writeln!(begin, ".balign {align}").unwrap();
+            writeln!(begin, ".balign {align_bytes}").unwrap();
             write_linkage(&mut begin).unwrap();
             writeln!(begin, ".def {asm_name}").unwrap();
             writeln!(begin, ".scl 2").unwrap();
@@ -279,6 +284,33 @@ fn prefix_and_suffix<'tcx>(
             // .size is ignored for function symbols, so we can skip it
             writeln!(end, "end_function").unwrap();
         }
+        BinaryFormat::Xcoff => {
+            // the LLVM XCOFFAsmParser is extremely incomplete and does not implement many of the
+            // documented directives.
+            //
+            // - https://github.com/llvm/llvm-project/blob/1b25c0c4da968fe78921ce77736e5baef4db75e3/llvm/lib/MC/MCParser/XCOFFAsmParser.cpp
+            // - https://www.ibm.com/docs/en/ssw_aix_71/assembler/assembler_pdf.pdf
+            //
+            // Consequently, we try our best here but cannot do as good a job as for other binary
+            // formats.
+
+            // FIXME: start a section. `.csect` is not currently implemented in LLVM
+
+            // fun fact: according to the assembler documentation, .align takes an exponent,
+            // but LLVM only accepts powers of 2 (but does emit the exponent)
+            // so when we hand `.align 32` to LLVM, the assembly output will contain `.align 5`
+            writeln!(begin, ".align {}", align_bytes).unwrap();
+
+            write_linkage(&mut begin).unwrap();
+            if let Visibility::Hidden = item_data.visibility {
+                // FIXME apparently `.globl {asm_name}, hidden` is valid
+                // but due to limitations with `.weak` (see above) we can't really use that in general yet
+            }
+            writeln!(begin, "{asm_name}:").unwrap();
+
+            writeln!(end).unwrap();
+            // FIXME: end the section?
+        }
     }
 
     (begin, end)