llvm-project/flang/test/Fir/struct-passing-x86-64-several-fields-inreg.fir
jeanPerier 15e335f04f
[flang] also set llvm ABI argument attributes on direct calls (#130736)
So far, flang was not setting argument attributes on direct calls
assuming that putting them on the function operation was enough.

It was clarified in
38565da525
that they must be set on both call and functions, even for direct calls.

Crashes have been observed because of the lack of the attribute when
compiling `abs(x)` at `O2` and above on X86-64 for complex(16).
2025-03-12 09:55:05 +01:00

159 lines
7.8 KiB
Plaintext

// Test X86-64 passing ABI of struct in registers for the cases where the
// struct has more than one field.
// RUN: fir-opt -target-rewrite="target=x86_64-unknown-linux-gnu" %s -o - | FileCheck %s
module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
func.func @test_call_i8_a16(%0 : !fir.ref<!fir.type<ti8_a16{a:!fir.array<16xi8>}>>) {
%1 = fir.load %0 : !fir.ref<!fir.type<ti8_a16{a:!fir.array<16xi8>}>>
fir.call @test_func_i8_a16(%1) : (!fir.type<ti8_a16{a:!fir.array<16xi8>}>) -> ()
return
}
// CHECK-LABEL: func.func @test_call_i8_a16(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<ti8_a16{a:!fir.array<16xi8>}>>) {
// CHECK: %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.type<ti8_a16{a:!fir.array<16xi8>}>>
// CHECK: %[[VAL_2:.*]] = llvm.intr.stacksave : !llvm.ptr
// CHECK: %[[VAL_3:.*]] = fir.alloca tuple<i64, i64>
// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<tuple<i64, i64>>) -> !fir.ref<!fir.type<ti8_a16{a:!fir.array<16xi8>}>>
// CHECK: fir.store %[[VAL_1]] to %[[VAL_4]] : !fir.ref<!fir.type<ti8_a16{a:!fir.array<16xi8>}>>
// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_3]] : !fir.ref<tuple<i64, i64>>
// CHECK: %[[VAL_6:.*]] = fir.extract_value %[[VAL_5]], [0 : i32] : (tuple<i64, i64>) -> i64
// CHECK: %[[VAL_7:.*]] = fir.extract_value %[[VAL_5]], [1 : i32] : (tuple<i64, i64>) -> i64
// CHECK: fir.call @test_func_i8_a16(%[[VAL_6]], %[[VAL_7]]) : (i64, i64) -> ()
// CHECK: llvm.intr.stackrestore %[[VAL_2]] : !llvm.ptr
// CHECK: return
func.func private @test_func_i8_a16(%0 : !fir.type<ti8_a16{a:!fir.array<16xi8>}>) -> () {
return
}
// CHECK-LABEL: func.func private @test_func_i8_a16(
// CHECK-SAME: %[[VAL_0:.*]]: i64,
// CHECK-SAME: %[[VAL_1:.*]]: i64) {
// CHECK: %[[VAL_2:.*]] = fir.undefined tuple<i64, i64>
// CHECK: %[[VAL_3:.*]] = fir.insert_value %[[VAL_2]], %[[VAL_0]], [0 : i32] : (tuple<i64, i64>, i64) -> tuple<i64, i64>
// CHECK: %[[VAL_4:.*]] = fir.insert_value %[[VAL_3]], %[[VAL_1]], [1 : i32] : (tuple<i64, i64>, i64) -> tuple<i64, i64>
// CHECK: %[[VAL_5:.*]] = fir.alloca tuple<i64, i64>
// CHECK: fir.store %[[VAL_4]] to %[[VAL_5]] : !fir.ref<tuple<i64, i64>>
// CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (!fir.ref<tuple<i64, i64>>) -> !fir.ref<!fir.type<ti8_a16{a:!fir.array<16xi8>}>>
// CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_6]] : !fir.ref<!fir.type<ti8_a16{a:!fir.array<16xi8>}>>
// CHECK: return
// For the cases below, the argument marshalling logic is the same as above,
// so only the chosen signature is tested at the end.
func.func @test_call_i32_f32(%0 : !fir.ref<!fir.type<ti32_f32{i:i32,x:f32}>>) {
%1 = fir.load %0 : !fir.ref<!fir.type<ti32_f32{i:i32,x:f32}>>
fir.call @test_func_i32_f32(%1) : (!fir.type<ti32_f32{i:i32,x:f32}>) -> ()
return
}
func.func private @test_func_i32_f32(%0 : !fir.type<ti32_f32{i:i32,x:f32}>) -> () {
return
}
func.func @test_call_i32_i16(%0 : !fir.ref<!fir.type<ti32_i16{i:i32,x:i16}>>) {
%1 = fir.load %0 : !fir.ref<!fir.type<ti32_i16{i:i32,x:i16}>>
fir.call @test_func_i32_i16(%1) : (!fir.type<ti32_i16{i:i32,x:i16}>) -> ()
return
}
func.func private @test_func_i32_i16(%0 : !fir.type<ti32_i16{i:i32,x:i16}>) -> () {
return
}
func.func @test_call_f16_i16(%0 : !fir.ref<!fir.type<tf16_i16{i:f16,x:i16}>>) {
%1 = fir.load %0 : !fir.ref<!fir.type<tf16_i16{i:f16,x:i16}>>
fir.call @test_func_f16_i16(%1) : (!fir.type<tf16_i16{i:f16,x:i16}>) -> ()
return
}
func.func private @test_func_f16_i16(%0 : !fir.type<tf16_i16{i:f16,x:i16}>) -> () {
return
}
func.func @test_call_f16_f16(%0 : !fir.ref<!fir.type<tf16_f16{i:f16,x:f16}>>) {
%1 = fir.load %0 : !fir.ref<!fir.type<tf16_f16{i:f16,x:f16}>>
fir.call @test_func_f16_f16(%1) : (!fir.type<tf16_f16{i:f16,x:f16}>) -> ()
return
}
func.func private @test_func_f16_f16(%0 : !fir.type<tf16_f16{i:f16,x:f16}>) -> () {
return
}
func.func @test_call_i32_f64(%0 : !fir.ref<!fir.type<ti32_f64{i:i32,x:f64}>>) {
%1 = fir.load %0 : !fir.ref<!fir.type<ti32_f64{i:i32,x:f64}>>
fir.call @test_func_i32_f64(%1) : (!fir.type<ti32_f64{i:i32,x:f64}>) -> ()
return
}
func.func private @test_func_i32_f64(%0 : !fir.type<ti32_f64{i:i32,x:f64}>) -> () {
return
}
func.func @test_call_f64_f32(%0 : !fir.ref<!fir.type<tf64_f32{i:f64,x:f32}>>) {
%1 = fir.load %0 : !fir.ref<!fir.type<tf64_f32{i:f64,x:f32}>>
fir.call @test_func_f64_f32(%1) : (!fir.type<tf64_f32{i:f64,x:f32}>) -> ()
return
}
func.func private @test_func_f64_f32(%0 : !fir.type<tf64_f32{i:f64,x:f32}>) -> () {
return
}
func.func @test_call_f32_i32_f32_f32(%0 : !fir.ref<!fir.type<tf32_i32_f32_f32{i:i32,x:f32,y:f32,z:f32}>>) {
%1 = fir.load %0 : !fir.ref<!fir.type<tf32_i32_f32_f32{i:i32,x:f32,y:f32,z:f32}>>
fir.call @test_func_f32_i32_f32_f32(%1) : (!fir.type<tf32_i32_f32_f32{i:i32,x:f32,y:f32,z:f32}>) -> ()
return
}
func.func private @test_func_f32_i32_f32_f32(%0 : !fir.type<tf32_i32_f32_f32{i:i32,x:f32,y:f32,z:f32}>) -> () {
return
}
func.func @test_call_f64_i32(%before : i16, %0 : !fir.ref<!fir.type<tf64_i32{i:f64,x:i32}>>, %after : f128) {
%1 = fir.load %0 : !fir.ref<!fir.type<tf64_i32{i:f64,x:i32}>>
fir.call @test_func_f64_i32(%before, %1, %after) : (i16, !fir.type<tf64_i32{i:f64,x:i32}>, f128) -> ()
return
}
func.func private @test_func_f64_i32(%before : i16, %0 : !fir.type<tf64_i32{i:f64,x:i32}>, %after : f128) -> () {
return
}
}
// CHECK-LABEL: func.func @test_call_i32_f32(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<ti32_f32{i:i32,x:f32}>>) {
// CHECK-LABEL: func.func private @test_func_i32_f32(
// CHECK-SAME: %[[VAL_0:.*]]: i64) {
// CHECK-LABEL: func.func @test_call_i32_i16(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<ti32_i16{i:i32,x:i16}>>) {
// CHECK-LABEL: func.func private @test_func_i32_i16(
// CHECK-SAME: %[[VAL_0:.*]]: i64) {
// CHECK-LABEL: func.func @test_call_f16_i16(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<tf16_i16{i:f16,x:i16}>>) {
// CHECK-LABEL: func.func private @test_func_f16_i16(
// CHECK-SAME: %[[VAL_0:.*]]: i32) {
// CHECK-LABEL: func.func @test_call_f16_f16(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<tf16_f16{i:f16,x:f16}>>) {
// CHECK-LABEL: func.func private @test_func_f16_f16(
// CHECK-SAME: %[[VAL_0:.*]]: f32) {
// CHECK-LABEL: func.func @test_call_i32_f64(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<ti32_f64{i:i32,x:f64}>>) {
// CHECK-LABEL: func.func private @test_func_i32_f64(
// CHECK-SAME: %[[VAL_0:.*]]: i64,
// CHECK-SAME: %[[VAL_1:.*]]: f64) {
// CHECK-LABEL: func.func @test_call_f64_f32(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<tf64_f32{i:f64,x:f32}>>) {
// CHECK-LABEL: func.func private @test_func_f64_f32(
// CHECK-SAME: %[[VAL_0:.*]]: f64,
// CHECK-SAME: %[[VAL_1:.*]]: f32) {
// CHECK-LABEL: func.func @test_call_f32_i32_f32_f32(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<tf32_i32_f32_f32{i:i32,x:f32,y:f32,z:f32}>>) {
// CHECK-LABEL: func.func private @test_func_f32_i32_f32_f32(
// CHECK-SAME: %[[VAL_0:.*]]: i64,
// CHECK-SAME: %[[VAL_1:.*]]: f64) {
// CHECK-LABEL: func.func @test_call_f64_i32(
// CHECK-SAME: %[[VAL_0:.*]]: i16,
// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.type<tf64_i32{i:f64,x:i32}>>,
// CHECK-SAME: %[[VAL_2:.*]]: f128) {
// CHECK-LABEL: func.func private @test_func_f64_i32(
// CHECK-SAME: %[[VAL_0:.*]]: i16,
// CHECK-SAME: %[[VAL_1:.*]]: f64,
// CHECK-SAME: %[[VAL_2:.*]]: i32,
// CHECK-SAME: %[[VAL_3:.*]]: f128) {