<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/92246>92246</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [PowerPC] power9 f128 ABI issue: bitcasts can change endianness
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          tgross35
      </td>
    </tr>
</table>

<pre>
    Doing a roundtrip i128 -> f128 -> i128 should work but it appears to be broken, depending on some optimizations. Originally identified with rust in https://github.com/rust-lang/rust/issues/125102. Source files:

```rust
// transmute_lib.rs

#![feature(f128)]
#![allow(improper_ctypes_definitions)] // ok since llvm 18

use std::mem::transmute;

#[no_mangle]
pub extern "C" fn entry(a: u128) -> f128 {
    unsafe { transmute::<u128, f128>(a) }
}
```

```rust
// transmute_call_lib.rs

#![feature(f128)]
#![allow(improper_ctypes)] // ok since llvm 18

extern crate transmute_lib;

use std::mem::transmute;
use std::process::exit;

extern "C" {
 fn entry(a: u128) -> f128;
}

fn main() {
    let a = unsafe { entry(0x1) }; // bitcast in an external function
    let res = unsafe { transmute::<f128, u128>(a) }; // bitcast back

    if res == 0x1 {
 exit(0); // correct
    } else if res == 0x1 << 64 {
 exit(1); // incorrect value with endianness flipped
    } else {
 exit(2); // unexpected value
 }
}
```

Versions:

```
$ rustc -Vv
rustc 1.80.0-nightly (9c9b56879 2024-05-05)
binary: rustc
commit-hash: 9c9b568792ef20d8459c745345dd3e79b7c7fa8c
commit-date: 2024-05-05
host: x86_64-unknown-linux-gnu
release: 1.80.0-nightly
LLVM version: 18.1.
```

Compilation:

```
rustc transmute_lib.rs --target powerpc64-unknown-linux-gnu -C linker=powerpc64-linux-gnu-gcc -Ctarget-cpu=pwr9 --crate-type=lib
rustc transmute_call_lib.rs --target powerpc64-unknown-linux-gnu -C linker=powerpc64-linux-gnu-gcc -Ctarget-cpu=pwr9 -o transmute_call_lib.rs.ppc64.pwr9 --extern transmute_lib=libtransmute_lib.rlib
```

Execution:

```
$ qemu-ppc64 -L /usr/powerpc64-linux-gnu/ transmute_call_lib.rs.ppc64.pwr9; echo $?
1
```

The above should output 0. Full IR:

<details>
<summary>Library function</summary>
```llvm
; ModuleID = 'transmute_lib.1e179323af95c5c5-cgu.0'
source_filename = "transmute_lib.1e179323af95c5c5-cgu.0"
target datalayout = "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512"
target triple = "powerpc64-unknown-linux-gnu"

; Function Attrs: uwtable
define fp128 @entry(i128 %a) unnamed_addr #0 {
start:
  %_0 = bitcast i128 %a to fp128
  ret fp128 %_0
}

attributes #0 = { uwtable "probe-stack"="inline-asm" "target-cpu"="pwr9" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{!"rustc version 1.80.0-nightly (9c9b56879 2024-05-05)"}
```
</details>

<details>
<summary>Executable</summary>
```llvm
; ModuleID = 'transmute_call_lib.1791869a4d73965-cgu.0'
source_filename = "transmute_call_lib.1791869a4d73965-cgu.0"
target datalayout = "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512"
target triple = "powerpc64-unknown-linux-gnu"

@vtable.0 = private unnamed_addr constant <{ ptr, [16 x i8], ptr, ptr, ptr }> <{ ptr @"_ZN4core3ptr85drop_in_place$LT$std..rt..lan

; std::sys_common::backtrace::__rust_begin_short_backtrace
; Function Attrs: noinline uwtable
define internal void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17hf94855fdbb5829c5E(ptr %f) unnamed_addr #0 {
start:
; call core::ops::function::FnOnce::call_once
  call void @_ZN4core3ops8function6FnOnce9call_once17h3056e9bd87d66482E(ptr %f)
  call void asm sideeffect "", "~{memory}"(), !srcloc !3
  ret void
}

; std::rt::lang_start
; Function Attrs: uwtable
define hidden i64 @_ZN3std2rt10lang_start17hdc6989dbc5702db1E(ptr %main, i64 %argc, ptr %argv, i8 %sigpipe) unnamed_addr #1 {
start:
  %_8 = alloca [8 x i8], align 8
  %_5 = alloca [8 x i8], align 8
  store ptr %main, ptr %_8, align 8
; call std::rt::lang_start_internal
  %0 = call i64 @_ZN3std2rt19lang_start_internal17he440c14c55fd4760E(ptr align 1 %_8, ptr align 8 @vtable.0, i64 %argc, ptr %argv,
  store i64 %0, ptr %_5, align 8
  %v = load i64, ptr %_5, align 8
  ret i64 %v
}

; std::rt::lang_start::{{closure}}
; Function Attrs: inlinehint uwtable
define internal i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17hdb386b686ec8565dE"(ptr align 8 %_1) unnamed_addr #2 {
start:
  %self = alloca [1 x i8], align 1
  %_4 = load ptr, ptr %_1, align 8
; call std::sys_common::backtrace::__rust_begin_short_backtrace
  call void @_ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17hf94855fdbb5829c5E(ptr %_4)
; call <() as std::process::Termination>::report
  %0 = call i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h3606faab680ab85fE"()
 store i8 %0, ptr %self, align 1
  %_6 = load i8, ptr %self, align 1
 %_0 = zext i8 %_6 to i32
  ret i32 %_0
}

; core::ops::function::FnOnce::call_once{{vtable.shim}}
; Function Attrs: inlinehint uwtable
define internal i32 @"_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h956497c27ef6ef7fE"(ptr %_1) unnamed
start:
  %_2 = alloca [0 x i8], align 1
  %0 = load ptr, ptr %_1, align 8
; call core::ops::function::FnOnce::call_once
 %_0 = call i32 @_ZN4core3ops8function6FnOnce9call_once17h9737a54d47c05e22E(ptr %0)
  ret i32 %_0
}

; core::ops::function::FnOnce::call_once
; Function Attrs: inlinehint uwtable
define internal void @_ZN4core3ops8function6FnOnce9call_once17h3056e9bd87d66482E(ptr %_1) unnamed_addr #2 {
start:
  %_2 = alloca [0 x i8], align 1
  call void %_1()
  ret void
}

; core::ops::function::FnOnce::call_once
; Function Attrs: inlinehint uwtable
define internal i32 @_ZN4core3ops8function6FnOnce9call_once17h9737a54d47c05e22E(ptr %0) unnamed_addr #2 personality ptr @rust_eh_p
start:
  %1 = alloca [16 x i8], align 8
  %_2 = alloca [0 x i8], align 1
  %_1 = alloca [8 x i8], align 8
  store ptr %0, ptr %_1, align 8
; invoke std::rt::lang_start::{{closure}}
  %_0 = invoke i32 @"_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17hdb386b686ec8565dE"(ptr align 8 %_1)
          to label %bb1 unwind label %cleanup

bb3: ; preds = %cleanup
  %2 = load ptr, ptr %1, align 8
  %3 = getelementptr inbounds i8, ptr %1, i64 8
 %4 = load i32, ptr %3, align 8
  %5 = insertvalue { ptr, i32 } poison, ptr %2, 0
  %6 = insertvalue { ptr, i32 } %5, i32 %4, 1
  resume { ptr, i32 } %6

cleanup:                                          ; preds = %start
  %7 = landingpad { ptr, i32 }
          cleanup
  %8 = extractvalue { ptr, i32 } %7, 0
  %9 = extractvalue { ptr, i32 } %7, 1
 store ptr %8, ptr %1, align 8
  %10 = getelementptr inbounds i8, ptr %1, i64 8
  store i32 %9, ptr %10, align 8
  br label %bb3

bb1: ; preds = %start
  ret i32 %_0
}

; core::ptr::drop_in_place<std::rt::lang_start<()>::{{closure}}>
; Function Attrs: inlinehint uwtable
define internal void @"_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17h64db6
start:
 ret void
}

; <() as std::process::Termination>::report
; Function Attrs: inlinehint uwtable
define internal i8 @"_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h3606faab680ab85fE"() unnamed_addr #2 {
start:
  ret i8 0
}

; transmute_call_lib::main
; Function Attrs: uwtable
define internal void @_ZN18transmute_call_lib4main17hfa19d9d60e61b95dE() unnamed_addr #1 {
start:
  %a = call fp128 @entry(i128 1)
  %res = bitcast fp128 %a to i128
  %0 = icmp eq i128 %res, 1
  br i1 %0, label %bb2, label %bb3

bb2:                                              ; preds = %start
; call std::process::exit
  call void @_ZN3std7process4exit17hb2f96155fda111fdE(i32 0) #5
 unreachable

bb3:                                              ; preds = %start
  %_4 = icmp eq i128 %res, 18446744073709551616
  br i1 %_4, label %bb5, label %bb6

bb6: ; preds = %bb3
; call std::process::exit
  call void @_ZN3std7process4exit17hb2f96155fda111fdE(i32 2) #5
 unreachable

bb5:                                              ; preds = %bb3
; call std::process::exit
  call void @_ZN3std7process4exit17hb2f96155fda111fdE(i32 1) #5
 unreachable
}

; std::rt::lang_start_internal
; Function Attrs: uwtable
declare i64 @_ZN3std2rt19lang_start_internal17he440c14c55fd4760E(ptr align 1, ptr align 8, i64, ptr, i8) unnamed_addr #1

; Function Attrs: uwtable
declare zeroext i32 @rust_eh_personality(i32 signext, i32 zeroext, i64, ptr, ptr) unnamed_addr #1

; Function Attrs: uwtable
declare fp128 @entry(i128) unnamed_addr #1

; std::process::exit
; Function Attrs: noreturn uwtable
declare void @_ZN3std7process4exit17hb2f96155fda111fdE(i32) unnamed_addr #3

define i32 @main(i32 %0, ptr %1) unnamed_addr #4 {
top:
  %2 = sext i32 %0 to i64
; call std::rt::lang_start
  %3 = call i64 @_ZN3std2rt10lang_start17hdc6989dbc5702db1E(ptr @_ZN18transmute_call_lib4main17hfa19d9d60e61b95dE, i64 %2, ptr %1, i8 0)
 %4 = trunc i64 %3 to i32
  ret i32 %4
}

attributes #0 = { noinline uwtable "probe-stack"="inline-asm" "target-cpu"="pwr9" }
attributes #1 = { uwtable "probe-stack"="inline-asm" "target-cpu"="pwr9" }
attributes #2 = { inlinehint uwtable "probe-stack"="inline-asm" "target-cpu"="pwr9" }
attributes #3 = { noreturn uwtable "probe-stack"="inline-asm" "target-cpu"="pwr9" }
attributes #4 = { "target-cpu"="pwr9" }
attributes #5 = { noreturn }

!llvm.module.flags = !{!0, !1}
!llvm.ident = !{!2}

!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{i32 7, !"PIE Level", i32 2}
!2 = !{!"rustc version 1.80.0-nightly (9c9b56879 2024-05-05)"}
!3 = !{i32 1628919}
```
</details>
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzUO0lv47b-n0a5EDJEaj_kkDjJHwNM20Fb9NCLQUmUzf_IpEpSTtLD--wPJLVbduxM0uIFga2F_O0rSWMp6ZYRcuuE9074cIMbtePiVm0Fl9IPbzJevN4-cMq2AAPBG1YoQWtAIUqA6_iPoOyvzDO5401VgGcuvoOsUYAqgOuaYCGB4iAjIBP8O2EOWoOC1IQVGjJnQPI9AbxWdE__xopyJlfgF0G3lOGqegW0IEzRkpICPFO1A6KRClAGdkrV0vHvHPTkoKctVbsmW-V876AnPcStMNu21w56olI2RDroCaIQemgFfuONyAkoaUUMFO_B8brPyLP_Zq59ZJAAJTCT-0aRTUWzlZCTWch3EHTC-5Jg1QjioEQLyEGpEz7MhuCq4s8OSui-FrwmYpOr15rITUFKyqiRgZ0HWsT8O5CU5QRU1WEPYDJG3EgCpCo0E_7dnuztRU-q49_PyQzvGd_sMdtWpKetbjJAXhQRDDgIrR2EQMkAYUq8OijBjn8HGsvOSPlO3MIGAICGSVwS_QyMkN-Z_7WduzbTHP_RgEQpcOJONP1FJ_xrNZLjqvoctVyuilaAucCKTI1lpoVLdTYZVwueEyntDXmhagZ0pr5BOW8qcgDUq8F8lgzsMWWOHT7RdkUUwMDxH8Z677B4L7DTrn_fCS6jKsfWdzFrbQ1XoGxYri1-CloQOQd-bFRla1TNsVEdo81w_n3Mm8ZEyw6RxuW9wBGPRsAo8bT2B2g5F4LkagDhxA-AVJIswfLXjr8GUXAMFU6hUtbCBQdcNcQGOh0hMWNESlBWtK5JsYD1CDKaQm4YealJrkhhQbeDL_S7P4iQJhidCJCd_wQmKufA_eNgH9lbuEq8lecyut2p6hU4KEnzNAujJE4B8lDgeqHrhZpgMymjDItXbaBmun2Y8_2eKneH5U6_6QEgUiKvSIIwzeMg9IOwKHwSp1mcxyVOppMLbIxmjNO83nGp9POXJNpEgduw74w_M7eirHlxt6xpeSEVwdIAmDJkX3_9-sdP4GAFZcYkK7g6I9M139e0MonuvFitDOcpB7iuwmJLFKj5MxF1vkQ4cNegouw7EY7_MIzr37vbPAfu2gJy87rRw55FClzXxC5Xxz3Hf9CBa5GWUbD9ZIL4MtZVrQGsWqLbyDeLuJr8mfh6hhZV8_hC8uZtxWh7_4vsG9fQANyv2tkaKRz0tMDaySw1YkE7LMl3HDgocPwniwaeofT3HQE44wfSVV28UXWjgLcCT01VgS-_zlnw1wVRmFZSB8rukWz2e-Nyj19pJrB4HaKxv3bQ0_B-RovOfR2Ue_ATL5qKfHkwEdtB8VTokMA49ZGPyzTMwzx0822z8hwUWwDSFGIbXYgxvCctDHQZDGRhtAZYYIUr_Mob1UF5dHVqJe4TjQKXRoHj30WBy3xkL36DKHEPKIwc_67_dA8h1O-HzxkaXQZXPaFnrL6fOIjqqZUvuFNKSJOMnxXOqjYwmwKQgLI21VXgdQnVFNgOCk1-a5gWVLHBRSGAg3xvyAJSYaF61QM9ZeMZSvvs20HSRbnB040VRHWI9azFggArJWjWKJ3oDGItg_i-Y8LIQ_CMuFLpdIuQTocIUVZRRlws96YwQWjk6N0Y4wembHmY1m9QG9tqb2xsVVZ4K1vRQ802gt4wox1rWobpIHgM1huNoD4CppTQtwh9-7IGX8mBVJo6tAb6NRqjgVPoDkI2QrZ54IrMh9DJFGxc8MhrL3JnG8mMXX2MI_dxC8YpTKIUB0Xsp9HVzvwWnP8thw68gxHyytpSLehBV_4TB805kwobe1xrV6mVMIYW3sMIvACa6D4Erbvnw5etYx9H83REcBDa_PlzkHNB_FqJJCwErzeUbeoK58RBwdffHRRIVaxWQq1WFWbzENT3E_JVbnSFZPOdf6crZCU0FHO72Wib3mRkS9lG7rhQm2HEmYDGuHX3xchGWVv2HzgtND-bP3_2pSqgN1CT9mhQco4IGO_KNEjCsCyyLExQmoe6BzCCQmF5VajUrGjb1AV-yz-v21ZryIn67on9wjoRGWvmrJMHsCBGrFk98VomHZDIzk_7qTDe-V4YkTQrkriIoiBBMy6OgWO5B5IWhJSlbhpMlEI2fKH_OPH9nuy5eNX2ox-bZtfGNinyiuf6yh-HfQ10Md5P7MWKy7-rMNturPiuzGs7WhSEAapbol71SCjoDTBhvCvyKE3SIsvD2ENFBkfysO3o2oJAIRbbvHcXc3swb00Ok3Rb05os2QE8nzIT4864qniOtacmY0fFFd0ykIzHh1eMl4oLAmbstLeb5GhCb5hn1LDpvGpEk41IZuaxuNOFuTDekSDwchjk2qOCOPI6uVuC4EDh8NBUKV0QfFMxUxm0Q72xAMJlCR8MNxXHhZ711gRt0i3ww7vM2i4wxPdOfJ9XXDaCaAA9jEV7t0FvR5k6H_h0LdHH8QX7R8nGQUETZ7oX6C46KvR90b3QF9pbMj-JsiiJSJ6EUVg8Wqef6AiFG7jkB-isH0hSlTPLhseWDceeEAyKGmcyi_9N0_7hjHQcgT8nuWyCPi73XJhKyyyUYXli0e53IvaUtb3_Y2t-pOZCnfDcZDCVMNh02V1_f7Pfv7bfDfIcFGDZX5oKoEW-Wo0Ro-D_NJDIItbpJ_KiEuMsSjycJWH5OGQNS1XrrsncW7V9nLCDaOSwyZtThjblb_KiWkybSLco1EcTt9Yme7I9Mbp4XwI3zt4GMrmj-09y-JMFQeANtBy5_5iupRCQhlGQxjmKSRmRMi5HIWDu-qeTHpq5unfe1b33ePoPVVeDlVjnsHK9uMpKYz_GYVAEce6FBI2rLG9UZX2qlX2AOX1kdfmepHCVnYyiscWWzCR9tvL894T8wba1IOKaCMkZrqh67Vo7k4zIblOflD2cZ-PojcL0Sp_ezBFcXMh6bwcAyg78O_mBumu8nNUC-zeLqY6o7k9xUOGMVHpAlkHQsGfKiuFZXhHMmnps5Fnma6vU0qkFKbqFrelQwzY6FW2PZW3G-2b8lihSkT1hSo-mLOMNK-Q0I8Ouak-GMDuq4nT-HQb7y9jCVieSCGV3sEYrHUZH8QOoOZV83O0YwN4ITHQJGI2uv0ehaQbgEFJksz81LRqLvhOxP9LgW39Heho1wYaB2MoNm7MNNS4WCJlbzbGqbfNJXnQZelYM8Vx-6VUz4aS6a3VyZBnHym4XTt9lW10paXWXjod6C9gyMXYpf-o6cNF1Jiq5NpdrSZmL6aKavz4btNqyv6_olwLYsEr7Ebn_-kXAjtjTHYRpClarK8JlNwnGuygosmgxbb2Z5D-gbfrBXP8vN1nX1F_GoBNw2paPV9rbMyaYsmtX65ZKTpgcYwg0cN0vY5gWaRF5JIJZanLnIn_nF9_wUOEvb4ONc6-Dwu6kSLfB1W9hmR0uOtrg6psWmu9rQP7q98IEkZMskglAYV_VjCIQmt3PIhK6Kpu8lVGOl0eODwCdWfSI29GBHgjjXYbKNIJhWBYYQlga7ejYaOpTB_ntmQjQMEFwvhusYVKqfBh34-WiU_pIgiCKg8CL_dhLwxBGMDpS0SaY6SSc3UdTLqLFrDGo8p8ROrpU6OGPC_2f5g2-ydtVi7Gzxe2Lwlde4W59-QPWvWcr3m1NM9qso8thbs7khWT_TQQ3q2C2t-m7wqFhbAVtju--qK62a-cdk2e-Po6-xah8EYK37O7UfqIgqhFsmZr3GekSuZNg3qVAq4P2EGRbSnrTCvcY0ujAn-L1NL3ZRk72CtY5SeepKDjlpKe23UZ93oltngt31d6T2PuNHnRU7idgtJzWN5NKNCzvJvmnV3aDxRhx6tzJfK_5Qw-gTJHCTz3sMsWFelzHRewnovVHcp363CciDXqk75oeHtP8jhNEdnccXnKSCH3eSSL9Mh7PfTw_F33KKSQE_RlNMEJJCtNLDyrdFLd-kfopviG3MIZhHCMYJDe7W-T5mY_zkEQJzLys8P00K2GRkSAovASXN_RWk-WFMIQQIZSsQhzBkAQpLHyUoAzqrLPHtFoZ7XCxvTE_7LhNEQqiG1P1SfN7FoQYeQbmpWYufLgRt3qOmzVb6QReRaWSAxRFVWV-CPONPxPxbe2ED_Y4a2p_6HB3_6UF5t91nYYEOWYg32G2JaPD2jeNqG7P_DjFnLiyX24t-P-TfPL7FMPJfwMAAP__nES0Qw">