Skip to content

Commit 631f70b

Browse files
committed
[clang][LoongArch] Add support for the _Float16 type
Enable _Float16 for LoongArch target. Additionally, this change fixes incorrect ABI lowering of _Float16 in the case of structs containing fp16 that are eligible for passing via GPR+FPR or FPR+FPR. Finally, it also fixes int16 -> __fp16 conversion code gen, which uses generic LLVM IR rather than llvm.convert.to.fp16 intrinsics.
1 parent 80da58d commit 631f70b

File tree

5 files changed

+108
-4
lines changed

5 files changed

+108
-4
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ to ``float``; see below for more information on this emulation.
10011001
* X86 (if SSE2 is available; natively if AVX512-FP16 is also available)
10021002
* RISC-V (natively if Zfh or Zhinx is available)
10031003
* SystemZ (emulated)
1004+
* LoongArch (emulated)
10041005

10051006
* ``__bf16`` is supported on the following targets (currently never natively):
10061007

clang/lib/Basic/Targets/LoongArch.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
5353
LongDoubleAlign = 128;
5454
LongDoubleFormat = &llvm::APFloat::IEEEquad();
5555
MCountName = "_mcount";
56+
HasFloat16 = true;
5657
SuitableAlign = 128;
5758
WCharType = SignedInt;
5859
WIntType = UnsignedInt;
@@ -98,6 +99,8 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
9899

99100
bool hasBitIntType() const override { return true; }
100101

102+
bool useFP16ConversionIntrinsics() const override { return false; }
103+
101104
bool handleTargetFeatures(std::vector<std::string> &Features,
102105
DiagnosticsEngine &Diags) override;
103106

clang/lib/CodeGen/Targets/LoongArch.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,9 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper(
110110
uint64_t Size = getContext().getTypeSize(Ty);
111111
if (IsInt && Size > GRLen)
112112
return false;
113-
// Can't be eligible if larger than the FP registers. Half precision isn't
114-
// currently supported on LoongArch and the ABI hasn't been confirmed, so
115-
// default to the integer ABI in that case.
116-
if (IsFloat && (Size > FRLen || Size < 32))
113+
// Can't be eligible if larger than the FP registers. Handling of half
114+
// precision values has been specified in the ABI, so don't block those.
115+
if (IsFloat && Size > FRLen)
117116
return false;
118117
// Can't be eligible if an integer type was already found (int+int pairs
119118
// are not eligible).
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
// RUN: %clang_cc1 -triple loongarch64 -emit-llvm %s -o - \
3+
// RUN: | FileCheck %s
4+
5+
__fp16 y;
6+
short z;
7+
// CHECK-LABEL: define dso_local void @bar1(
8+
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
9+
// CHECK-NEXT: [[ENTRY:.*:]]
10+
// CHECK-NEXT: [[TMP0:%.*]] = load half, ptr @y, align 2
11+
// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP0]] to float
12+
// CHECK-NEXT: [[CONV1:%.*]] = fptosi float [[CONV]] to i16
13+
// CHECK-NEXT: store i16 [[CONV1]], ptr @z, align 2
14+
// CHECK-NEXT: ret void
15+
//
16+
void bar1(){
17+
z = y;
18+
}
19+
// CHECK-LABEL: define dso_local void @bar2(
20+
// CHECK-SAME: ) #[[ATTR0]] {
21+
// CHECK-NEXT: [[ENTRY:.*:]]
22+
// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr @z, align 2
23+
// CHECK-NEXT: [[CONV:%.*]] = sitofp i16 [[TMP0]] to float
24+
// CHECK-NEXT: [[CONV1:%.*]] = fptrunc float [[CONV]] to half
25+
// CHECK-NEXT: store half [[CONV1]], ptr @y, align 2
26+
// CHECK-NEXT: ret void
27+
//
28+
void bar2(){
29+
y = z;
30+
}

clang/test/CodeGen/LoongArch/abi-lp64d.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ unsigned long check_ulong() { return 0; }
4848
// CHECK-LABEL: define{{.*}} i64 @check_ulonglong()
4949
unsigned long long check_ulonglong() { return 0; }
5050

51+
// CHECK-LABEL: define{{.*}} half @check_float16()
52+
_Float16 check_float16() { return 0; }
53+
5154
// CHECK-LABEL: define{{.*}} float @check_float()
5255
float check_float() { return 0; }
5356

@@ -127,6 +130,14 @@ struct i16x4_s f_i16x4_s(struct i16x4_s x) {
127130
/// available, the value is passed in a GAR; if no GAR is available, the value
128131
/// is passed on the stack.
129132

133+
struct f16x1_s {
134+
__fp16 a;
135+
};
136+
137+
struct float16x1_s {
138+
_Float16 a;
139+
};
140+
130141
struct f32x1_s {
131142
float a;
132143
};
@@ -135,6 +146,16 @@ struct f64x1_s {
135146
double a;
136147
};
137148

149+
// CHECK-LABEL: define{{.*}} half @f_f16x1_s(half %0)
150+
struct f16x1_s f_f16x1_s(struct f16x1_s x) {
151+
return x;
152+
}
153+
154+
// CHECK-LABEL: define{{.*}} half @f_float16x1_s(half %0)
155+
struct float16x1_s f_float16x1_s(struct float16x1_s x) {
156+
return x;
157+
}
158+
138159
// CHECK-LABEL: define{{.*}} float @f_f32x1_s(float %0)
139160
struct f32x1_s f_f32x1_s(struct f32x1_s x) {
140161
return x;
@@ -151,10 +172,20 @@ struct f64x1_s f_f64x1_s(struct f64x1_s x) {
151172
/// number of available FAR is less than 2, it’s passed in a GAR, and passed on
152173
/// the stack if no GAR is available.
153174

175+
struct f16x2_s {
176+
__fp16 a;
177+
_Float16 b;
178+
};
179+
154180
struct f32x2_s {
155181
float a, b;
156182
};
157183

184+
// CHECK-LABEL: define{{.*}} { half, half } @f_f16x2_s(half %0, half %1)
185+
struct f16x2_s f_f16x2_s(struct f16x2_s x) {
186+
return x;
187+
}
188+
158189
// CHECK-LABEL: define{{.*}} { float, float } @f_f32x2_s(float %0, float %1)
159190
struct f32x2_s f_f32x2_s(struct f32x2_s x) {
160191
return x;
@@ -165,11 +196,21 @@ struct f32x2_s f_f32x2_s(struct f32x2_s x) {
165196
/// i. Multiple fixed-point members. If there are available GAR, the structure
166197
/// is passed in a GAR, and passed on the stack if no GAR is available.
167198

199+
struct f16x1_i16x2_s {
200+
_Float16 a;
201+
int16_t b, c;
202+
};
203+
168204
struct f32x1_i16x2_s {
169205
float a;
170206
int16_t b, c;
171207
};
172208

209+
// CHECK-LABEL: define{{.*}} i64 @f_f16x1_i16x2_s(i64 %x.coerce)
210+
struct f16x1_i16x2_s f_f16x1_i16x2_s(struct f16x1_i16x2_s x) {
211+
return x;
212+
}
213+
173214
// CHECK-LABEL: define{{.*}} i64 @f_f32x1_i16x2_s(i64 %x.coerce)
174215
struct f32x1_i16x2_s f_f32x1_i16x2_s(struct f32x1_i16x2_s x) {
175216
return x;
@@ -181,11 +222,21 @@ struct f32x1_i16x2_s f_f32x1_i16x2_s(struct f32x1_i16x2_s x) {
181222
/// but one GAR is available, it’s passed in GAR; If no GAR is available, it’s
182223
/// passed on the stack.
183224

225+
struct f16x1_i32x1_s {
226+
_Float16 a;
227+
int32_t b;
228+
};
229+
184230
struct f32x1_i32x1_s {
185231
float a;
186232
int32_t b;
187233
};
188234

235+
// CHECK-LABEL: define{{.*}} { half, i32 } @f_f16x1_i32x1_s(half %0, i32 %1)
236+
struct f16x1_i32x1_s f_f16x1_i32x1_s(struct f16x1_i32x1_s x) {
237+
return x;
238+
}
239+
189240
// CHECK-LABEL: define{{.*}} { float, i32 } @f_f32x1_i32x1_s(float %0, i32 %1)
190241
struct f32x1_i32x1_s f_f32x1_i32x1_s(struct f32x1_i32x1_s x) {
191242
return x;
@@ -253,6 +304,16 @@ struct f32x4_s f_f32x4_s(struct f32x4_s x) {
253304
return x;
254305
}
255306

307+
struct f16x5_s {
308+
_Float16 a, b, c, d;
309+
__fp16 e;
310+
};
311+
312+
// CHECK-LABEL: define{{.*}} [2 x i64] @f_f16x5_s([2 x i64] %x.coerce)
313+
struct f16x5_s f_f16x5_s(struct f16x5_s x) {
314+
return x;
315+
}
316+
256317
/// ii. The structure with two double members is passed in a pair of available
257318
/// FARs. If no a pair of available FARs, it’s passed in GARs. A structure with
258319
/// one double member and one float member is same.
@@ -312,6 +373,16 @@ struct f32x2_i32x2_s f_f32x2_i32x2_s(struct f32x2_i32x2_s x) {
312373
return x;
313374
}
314375

376+
struct f16x4_i32x2_s {
377+
_Float16 a, b, c, d;
378+
int32_t e, f;
379+
};
380+
381+
// CHECK-LABEL: define{{.*}} [2 x i64] @f_f16x4_i32x2_s([2 x i64] %x.coerce)
382+
struct f16x4_i32x2_s f_f16x4_i32x2_s(struct f16x4_i32x2_s x) {
383+
return x;
384+
}
385+
315386
/// 3. WOA > 2 × GRLEN
316387
/// a. It’s passed by reference and are replaced in the argument list with the
317388
/// address. If there is an available GAR, the reference is passed in the GAR,

0 commit comments

Comments
 (0)