Skip to content

Commit 41f1663

Browse files
[flang] Use correct int extension flags for C-ABI calls on aarch64 (llvm#137105)
The AArch64 procedure call standard does not mandate that the callee extends the return value. Clang does not add signext to functions returning i8 or i16 on linux aarch64, but flang does. This means that runtime routines returning i8's will have signext on the callsite/declaration, but not on the implementation, and the call site will assume the return value has already been sign extended when it has not. This showed up in a test case calling MINVAL on an array of INTEGER*1. Adjust our integer extension flags to match clang and aarch64pcs on linux. The behavior on Darwin should be preserved. This is listed on the apple developer guide as a divergence from aarch64pcs.
1 parent ade502a commit 41f1663

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

flang/lib/Optimizer/CodeGen/Target.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ struct TargetX86_64Win : public GenericTarget<TargetX86_64Win> {
784784
} // namespace
785785

786786
//===----------------------------------------------------------------------===//
787-
// AArch64 linux target specifics.
787+
// AArch64 target specifics.
788788
//===----------------------------------------------------------------------===//
789789

790790
namespace {
@@ -810,6 +810,34 @@ struct TargetAArch64 : public GenericTarget<TargetAArch64> {
810810
return marshal;
811811
}
812812

813+
CodeGenSpecifics::Marshalling
814+
integerArgumentType(mlir::Location loc,
815+
mlir::IntegerType argTy) const override {
816+
if (argTy.getWidth() < getCIntTypeWidth() && argTy.isSignless()) {
817+
AT::IntegerExtension intExt;
818+
if (argTy.getWidth() == 1) {
819+
// Zero extend for 'i1'.
820+
intExt = AT::IntegerExtension::Zero;
821+
} else {
822+
if (triple.isOSDarwin()) {
823+
// On Darwin, sign extend. The apple developer guide specifies this as
824+
// a divergence from the AArch64PCS:
825+
// https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-arguments-to-functions-correctly
826+
intExt = AT::IntegerExtension::Sign;
827+
} else {
828+
// On linux, pass directly and do not extend.
829+
intExt = AT::IntegerExtension::None;
830+
}
831+
}
832+
CodeGenSpecifics::Marshalling marshal;
833+
marshal.emplace_back(argTy, AT{/*alignment=*/0, /*byval=*/false,
834+
/*sret=*/false, /*append=*/false,
835+
/*intExt=*/intExt});
836+
return marshal;
837+
}
838+
return GenericTarget::integerArgumentType(loc, argTy);
839+
}
840+
813841
CodeGenSpecifics::Marshalling
814842
complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
815843
CodeGenSpecifics::Marshalling marshal;

flang/test/Fir/convert-to-llvm-target.fir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" %s | FileCheck %s --check-prefix INT64
22
// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=aarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes INT64
33
// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=i386-unknown-linux-gnu" %s | FileCheck %s --check-prefixes INT32
4-
// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=powerpc64le-unknown-linux-gn" %s | FileCheck %s --check-prefixes INT64
4+
// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=powerpc64le-unknown-linux-gnu" %s | FileCheck %s --check-prefixes INT64
55

66
//=============================================================================
77
// SUMMARY: Tests for FIR --> LLVM MLIR conversion that *depend* on the target

flang/test/Fir/target-rewrite-integer.fir

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// RUN: fir-opt --split-input-file --target-rewrite="target=i386-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=I32,ALL
22
// RUN: fir-opt --split-input-file --target-rewrite="target=x86_64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=X64,ALL
3+
// RUN: fir-opt --split-input-file --target-rewrite="target=x86_64-apple-darwin" %s | FileCheck %s --check-prefixes=X64,ALL
34
// RUN: fir-opt --split-input-file --target-rewrite="target=aarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=AARCH64,ALL
5+
// RUN: fir-opt --split-input-file --target-rewrite="target=aarch64-apple-darwin" %s | FileCheck %s --check-prefixes=AARCH64DARWIN,ALL
46
// RUN: fir-opt --split-input-file --target-rewrite="target=powerpc64le-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=PPC,ALL
57
// RUN: fir-opt --split-input-file --target-rewrite="target=sparc64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=SPARCV9,ALL
68
// RUN: fir-opt --split-input-file --target-rewrite="target=sparcv9-sun-solaris2.11" %s | FileCheck %s --check-prefixes=SPARCV9,ALL
@@ -17,6 +19,7 @@
1719
// I32: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
1820
// X64: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
1921
// AARCH64: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
22+
// AARCH64DARWIN: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
2023
// PPC: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
2124
// SPARCV9: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
2225
// LOONGARCH64: func.func{{.*}}@_FortranAioOutputLogical({{.*}}i1 {llvm.zeroext}) -> (i1 {llvm.zeroext})
@@ -49,6 +52,7 @@ func.func private @_FortranAioEndIoStatement(!fir.ref<i8>) -> i32 attributes {fi
4952
// I32: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
5053
// X64: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
5154
// AARCH64: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
55+
// AARCH64DARWIN: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
5256
// PPC: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
5357
// SPARCV9: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
5458
// LOONGARCH64: func.func{{.*}}@_SomeFunc_si1(si1 {llvm.signext}) -> (si1 {llvm.signext})
@@ -69,6 +73,7 @@ func.func private @_SomeFunc_si1(si1) -> si1 attributes {fir.runtime}
6973
// I32: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
7074
// X64: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
7175
// AARCH64: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
76+
// AARCH64DARWIN: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
7277
// PPC: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
7378
// SPARCV9: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
7479
// LOONGARCH64: func.func{{.*}}@_SomeFunc_ui1(ui1 {llvm.zeroext}) -> (ui1 {llvm.zeroext})
@@ -99,8 +104,20 @@ func.func private @_SomeFunc_ui1(ui1) -> ui1 attributes {fir.runtime}
99104
// end subroutine test
100105

101106
// ALL-LABEL: @_QPtest_bindc
102-
// ALL: func.func private @cfun8(i8 {llvm.signext}) -> (i8 {llvm.signext}) attributes {fir.bindc_name = "cfun8"}
103-
// ALL: func.func private @cfun16(i16 {llvm.signext}) -> (i16 {llvm.signext}) attributes {fir.bindc_name = "cfun16"}
107+
// I32: func.func private @cfun8(i8 {llvm.signext}) -> (i8 {llvm.signext}) attributes {fir.bindc_name = "cfun8"}
108+
// I32: func.func private @cfun16(i16 {llvm.signext}) -> (i16 {llvm.signext}) attributes {fir.bindc_name = "cfun16"}
109+
// X64: func.func private @cfun8(i8 {llvm.signext}) -> (i8 {llvm.signext}) attributes {fir.bindc_name = "cfun8"}
110+
// X64: func.func private @cfun16(i16 {llvm.signext}) -> (i16 {llvm.signext}) attributes {fir.bindc_name = "cfun16"}
111+
// AARCH64: func.func private @cfun8(i8) -> i8 attributes {fir.bindc_name = "cfun8"}
112+
// AARCH64: func.func private @cfun16(i16) -> i16 attributes {fir.bindc_name = "cfun16"}
113+
// AARCH64DARWIN: func.func private @cfun8(i8 {llvm.signext}) -> (i8 {llvm.signext}) attributes {fir.bindc_name = "cfun8"}
114+
// AARCH64DARWIN: func.func private @cfun16(i16 {llvm.signext}) -> (i16 {llvm.signext}) attributes {fir.bindc_name = "cfun16"}
115+
// PPC: func.func private @cfun8(i8 {llvm.signext}) -> (i8 {llvm.signext}) attributes {fir.bindc_name = "cfun8"}
116+
// PPC: func.func private @cfun16(i16 {llvm.signext}) -> (i16 {llvm.signext}) attributes {fir.bindc_name = "cfun16"}
117+
// SPARCV9: func.func private @cfun8(i8 {llvm.signext}) -> (i8 {llvm.signext}) attributes {fir.bindc_name = "cfun8"}
118+
// SPARCV9: func.func private @cfun16(i16 {llvm.signext}) -> (i16 {llvm.signext}) attributes {fir.bindc_name = "cfun16"}
119+
// LOONGARCH64: func.func private @cfun8(i8 {llvm.signext}) -> (i8 {llvm.signext}) attributes {fir.bindc_name = "cfun8"}
120+
// LOONGARCH64: func.func private @cfun16(i16 {llvm.signext}) -> (i16 {llvm.signext}) attributes {fir.bindc_name = "cfun16"}
104121
func.func @_QPtest_bindc(%arg0: !fir.ref<i8> {fir.bindc_name = "x"}, %arg1: !fir.ref<i16> {fir.bindc_name = "y"}) {
105122
%0 = fir.load %arg0 : !fir.ref<i8>
106123
%1 = fir.call @cfun8(%0) fastmath<contract> : (i8) -> i8

0 commit comments

Comments
 (0)