Skip to content

Commit b24acc0

Browse files
authored
[Flang][LoongArch] Add sign extension for i32 arguments and returns in function signatures. (llvm#116146)
In loongarch64 LP64D ABI, `unsigned 32-bit` types, such as unsigned int, are stored in general-purpose registers as proper sign extensions of their 32-bit values. Therefore, Flang also follows it if a function needs to be interoperable with C. Reference: https://github.com/loongson/la-abi-specs/blob/release/lapcs.adoc#Fundamental-types
1 parent 8a6a76b commit b24acc0

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

flang/lib/Optimizer/CodeGen/Target.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,30 @@ struct TargetLoongArch64 : public GenericTarget<TargetLoongArch64> {
11271127
}
11281128
return marshal;
11291129
}
1130+
1131+
CodeGenSpecifics::Marshalling
1132+
integerArgumentType(mlir::Location loc,
1133+
mlir::IntegerType argTy) const override {
1134+
if (argTy.getWidth() == 32) {
1135+
// LA64 LP64D ABI requires unsigned 32 bit integers to be sign extended.
1136+
// Therefore, Flang also follows it if a function needs to be
1137+
// interoperable with C.
1138+
//
1139+
// Currently, it only adds `signext` attribute to the dummy arguments and
1140+
// return values in the function signatures, but it does not add the
1141+
// corresponding attribute to the actual arguments and return values in
1142+
// `fir.call` instruction. Thanks to LLVM's integration of all these
1143+
// attributes, the modification is still effective.
1144+
CodeGenSpecifics::Marshalling marshal;
1145+
AT::IntegerExtension intExt = AT::IntegerExtension::Sign;
1146+
marshal.emplace_back(argTy, AT{/*alignment=*/0, /*byval=*/false,
1147+
/*sret=*/false, /*append=*/false,
1148+
/*intExt=*/intExt});
1149+
return marshal;
1150+
}
1151+
1152+
return GenericTarget::integerArgumentType(loc, argTy);
1153+
}
11301154
};
11311155
} // namespace
11321156

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/// Test i32 passing and returning on LoongArch64
2+
/// LoongArch64 LP64D ABI requires unsigned 32 bit integers to be sign extended.
3+
4+
// REQUIRES: loongarch-registered-target
5+
// RUN: fir-opt --target-rewrite="target=loongarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefix=LOONGARCH64
6+
// RUN: tco -target="loongarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefix=LOONGARCH64_LLVM
7+
8+
// LOONGARCH64: func.func private @cfunc32(i32 {llvm.signext}) -> (i32 {llvm.signext}) attributes {fir.bindc_name = "cfunc32"}
9+
10+
// LOONGARCH64_LLVM: declare signext i32 @cfunc32(i32 signext)
11+
func.func private @cfunc32(i32) -> i32 attributes {fir.bindc_name = "cfunc32"}
12+
13+
// LOONGARCH64-LABEL: func.func @foo(
14+
// LOONGARCH64-SAME: %[[VAL_0:.*]]: i32 {llvm.signext}) -> (i32 {llvm.signext}) attributes {fir.bindc_name = "foo"} {
15+
// LOONGARCH64: %[[VAL_1:.*]] = fir.call @cfunc32(%[[VAL_0]]) fastmath<contract> : (i32) -> i32
16+
// LOONGARCH64: return %[[VAL_1]] : i32
17+
// LOONGARCH64: }
18+
19+
// LOONGARCH64_LLVM-LABEL: define signext i32 @foo(
20+
// LOONGARCH64_LLVM: i32 signext %[[VAL_0:.*]]) {
21+
// LOONGARCH64_LLVM: %[[VAL_1:.*]] = call i32 @cfunc32(i32 %[[VAL_0]])
22+
// LOONGARCH64_LLVM: ret i32 %[[VAL_1]]
23+
// LOONGARCH64_LLVM: }
24+
func.func @foo(%0: i32) -> i32 attributes {fir.bindc_name = "foo"} {
25+
%1 = fir.call @cfunc32(%0) fastmath<contract> : (i32) -> i32
26+
return %1 : i32
27+
}

0 commit comments

Comments
 (0)