Skip to content

Commit 58de0db

Browse files
committed
Don't do casting of atomic FP loads/stores in FE.
1 parent d41615e commit 58de0db

File tree

6 files changed

+156
-58
lines changed

6 files changed

+156
-58
lines changed

clang/lib/CodeGen/CGAtomic.cpp

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,14 @@ namespace {
194194
RValue convertAtomicTempToRValue(Address addr, AggValueSlot resultSlot,
195195
SourceLocation loc, bool AsValue) const;
196196

197-
/// Converts a rvalue to integer value.
198-
llvm::Value *convertRValueToInt(RValue RVal) const;
197+
llvm::Value *getScalarRValValueOrNull(RValue RVal) const;
199198

200-
RValue ConvertIntToValueOrAtomic(llvm::Value *IntVal,
201-
AggValueSlot ResultSlot,
202-
SourceLocation Loc, bool AsValue) const;
199+
/// Converts an rvalue to integer value if needed.
200+
llvm::Value *convertRValueToInt(RValue RVal, bool CastFP = true) const;
201+
202+
RValue ConvertToValueOrAtomic(llvm::Value *IntVal, AggValueSlot ResultSlot,
203+
SourceLocation Loc, bool AsValue,
204+
bool CastFP = true) const;
203205

204206
/// Copy an atomic r-value into atomic-layout memory.
205207
void emitCopyIntoMemory(RValue rvalue) const;
@@ -261,7 +263,8 @@ namespace {
261263
void EmitAtomicLoadLibcall(llvm::Value *AddForLoaded,
262264
llvm::AtomicOrdering AO, bool IsVolatile);
263265
/// Emits atomic load as LLVM instruction.
264-
llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile);
266+
llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile,
267+
bool CastFP = true);
265268
/// Emits atomic compare-and-exchange op as a libcall.
266269
llvm::Value *EmitAtomicCompareExchangeLibcall(
267270
llvm::Value *ExpectedAddr, llvm::Value *DesiredAddr,
@@ -1396,12 +1399,13 @@ RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
13961399
LVal.getBaseInfo(), TBAAAccessInfo()));
13971400
}
13981401

1399-
RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal,
1400-
AggValueSlot ResultSlot,
1401-
SourceLocation Loc,
1402-
bool AsValue) const {
1402+
RValue AtomicInfo::ConvertToValueOrAtomic(llvm::Value *Val,
1403+
AggValueSlot ResultSlot,
1404+
SourceLocation Loc, bool AsValue,
1405+
bool CastFP) const {
14031406
// Try not to in some easy cases.
1404-
assert(IntVal->getType()->isIntegerTy() && "Expected integer value");
1407+
assert((Val->getType()->isIntegerTy() || Val->getType()->isIEEELikeFPTy()) &&
1408+
"Expected integer or floating point value");
14051409
if (getEvaluationKind() == TEK_Scalar &&
14061410
(((!LVal.isBitField() ||
14071411
LVal.getBitFieldInfo().Size == ValueSizeInBits) &&
@@ -1410,13 +1414,14 @@ RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal,
14101414
auto *ValTy = AsValue
14111415
? CGF.ConvertTypeForMem(ValueTy)
14121416
: getAtomicAddress().getElementType();
1413-
if (ValTy->isIntegerTy()) {
1414-
assert(IntVal->getType() == ValTy && "Different integer types.");
1415-
return RValue::get(CGF.EmitFromMemory(IntVal, ValueTy));
1417+
if (ValTy->isIntegerTy() || (!CastFP && ValTy->isIEEELikeFPTy())) {
1418+
assert((!ValTy->isIntegerTy() || Val->getType() == ValTy) &&
1419+
"Different integer types.");
1420+
return RValue::get(CGF.EmitFromMemory(Val, ValueTy));
14161421
} else if (ValTy->isPointerTy())
1417-
return RValue::get(CGF.Builder.CreateIntToPtr(IntVal, ValTy));
1418-
else if (llvm::CastInst::isBitCastable(IntVal->getType(), ValTy))
1419-
return RValue::get(CGF.Builder.CreateBitCast(IntVal, ValTy));
1422+
return RValue::get(CGF.Builder.CreateIntToPtr(Val, ValTy));
1423+
else if (llvm::CastInst::isBitCastable(Val->getType(), ValTy))
1424+
return RValue::get(CGF.Builder.CreateBitCast(Val, ValTy));
14201425
}
14211426

14221427
// Create a temporary. This needs to be big enough to hold the
@@ -1433,8 +1438,7 @@ RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal,
14331438

14341439
// Slam the integer into the temporary.
14351440
Address CastTemp = castToAtomicIntPointer(Temp);
1436-
CGF.Builder.CreateStore(IntVal, CastTemp)
1437-
->setVolatile(TempIsVolatile);
1441+
CGF.Builder.CreateStore(Val, CastTemp)->setVolatile(TempIsVolatile);
14381442

14391443
return convertAtomicTempToRValue(Temp, ResultSlot, Loc, AsValue);
14401444
}
@@ -1453,9 +1457,11 @@ void AtomicInfo::EmitAtomicLoadLibcall(llvm::Value *AddForLoaded,
14531457
}
14541458

14551459
llvm::Value *AtomicInfo::EmitAtomicLoadOp(llvm::AtomicOrdering AO,
1456-
bool IsVolatile) {
1460+
bool IsVolatile, bool CastFP) {
14571461
// Okay, we're doing this natively.
1458-
Address Addr = getAtomicAddressAsAtomicIntPointer();
1462+
Address Addr = getAtomicAddress();
1463+
if (!(Addr.getElementType()->isIEEELikeFPTy() && !CastFP))
1464+
Addr = castToAtomicIntPointer(Addr);
14591465
llvm::LoadInst *Load = CGF.Builder.CreateLoad(Addr, "atomic-load");
14601466
Load->setAtomic(AO);
14611467

@@ -1515,15 +1521,16 @@ RValue AtomicInfo::EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc,
15151521
}
15161522

15171523
// Okay, we're doing this natively.
1518-
auto *Load = EmitAtomicLoadOp(AO, IsVolatile);
1524+
auto *Load = EmitAtomicLoadOp(AO, IsVolatile, /*CastFP=*/false);
15191525

15201526
// If we're ignoring an aggregate return, don't do anything.
15211527
if (getEvaluationKind() == TEK_Aggregate && ResultSlot.isIgnored())
15221528
return RValue::getAggregate(Address::invalid(), false);
15231529

15241530
// Okay, turn that back into the original value or atomic (for non-simple
15251531
// lvalues) type.
1526-
return ConvertIntToValueOrAtomic(Load, ResultSlot, Loc, AsValue);
1532+
return ConvertToValueOrAtomic(Load, ResultSlot, Loc, AsValue,
1533+
/*CastFP=*/false);
15271534
}
15281535

15291536
/// Emit a load from an l-value of atomic type. Note that the r-value
@@ -1586,12 +1593,18 @@ Address AtomicInfo::materializeRValue(RValue rvalue) const {
15861593
return TempLV.getAddress(CGF);
15871594
}
15881595

1589-
llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const {
1596+
llvm::Value *AtomicInfo::getScalarRValValueOrNull(RValue RVal) const {
1597+
if (RVal.isScalar() && (!hasPadding() || !LVal.isSimple()))
1598+
return RVal.getScalarVal();
1599+
return nullptr;
1600+
}
1601+
1602+
llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal, bool CastFP) const {
15901603
// If we've got a scalar value of the right size, try to avoid going
1591-
// through memory.
1592-
if (RVal.isScalar() && (!hasPadding() || !LVal.isSimple())) {
1593-
llvm::Value *Value = RVal.getScalarVal();
1594-
if (isa<llvm::IntegerType>(Value->getType()))
1604+
// through memory. Floats get casted if needed by AtomicExpandPass.
1605+
if (llvm::Value *Value = getScalarRValValueOrNull(RVal)) {
1606+
if (isa<llvm::IntegerType>(Value->getType()) ||
1607+
(!CastFP && Value->getType()->isIEEELikeFPTy()))
15951608
return CGF.EmitToMemory(Value, ValueTy);
15961609
else {
15971610
llvm::IntegerType *InputIntTy = llvm::IntegerType::get(
@@ -1677,8 +1690,8 @@ std::pair<RValue, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange(
16771690
auto Res = EmitAtomicCompareExchangeOp(ExpectedVal, DesiredVal, Success,
16781691
Failure, IsWeak);
16791692
return std::make_pair(
1680-
ConvertIntToValueOrAtomic(Res.first, AggValueSlot::ignored(),
1681-
SourceLocation(), /*AsValue=*/false),
1693+
ConvertToValueOrAtomic(Res.first, AggValueSlot::ignored(),
1694+
SourceLocation(), /*AsValue=*/false),
16821695
Res.second);
16831696
}
16841697

@@ -1787,8 +1800,8 @@ void AtomicInfo::EmitAtomicUpdateOp(
17871800
requiresMemSetZero(getAtomicAddress().getElementType())) {
17881801
CGF.Builder.CreateStore(PHI, NewAtomicIntAddr);
17891802
}
1790-
auto OldRVal = ConvertIntToValueOrAtomic(PHI, AggValueSlot::ignored(),
1791-
SourceLocation(), /*AsValue=*/false);
1803+
auto OldRVal = ConvertToValueOrAtomic(PHI, AggValueSlot::ignored(),
1804+
SourceLocation(), /*AsValue=*/false);
17921805
EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, NewAtomicAddr);
17931806
auto *DesiredVal = CGF.Builder.CreateLoad(NewAtomicIntAddr);
17941807
// Try to write new value using cmpxchg operation.
@@ -1953,13 +1966,22 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
19531966
}
19541967

19551968
// Okay, we're doing this natively.
1956-
llvm::Value *intValue = atomics.convertRValueToInt(rvalue);
1969+
llvm::Value *ValToStore =
1970+
atomics.convertRValueToInt(rvalue, /*CastFP=*/false);
19571971

19581972
// Do the atomic store.
1959-
Address addr = atomics.castToAtomicIntPointer(atomics.getAtomicAddress());
1960-
intValue = Builder.CreateIntCast(
1961-
intValue, addr.getElementType(), /*isSigned=*/false);
1962-
llvm::StoreInst *store = Builder.CreateStore(intValue, addr);
1973+
Address Addr = atomics.getAtomicAddress();
1974+
bool ShouldCastToInt = true;
1975+
if (llvm::Value *Value = atomics.getScalarRValValueOrNull(rvalue))
1976+
if (isa<llvm::IntegerType>(Value->getType()) ||
1977+
Value->getType()->isIEEELikeFPTy())
1978+
ShouldCastToInt = false;
1979+
if (ShouldCastToInt) {
1980+
Addr = atomics.castToAtomicIntPointer(Addr);
1981+
ValToStore = Builder.CreateIntCast(ValToStore, Addr.getElementType(),
1982+
/*isSigned=*/false);
1983+
}
1984+
llvm::StoreInst *store = Builder.CreateStore(ValToStore, Addr);
19631985

19641986
if (AO == llvm::AtomicOrdering::Acquire)
19651987
AO = llvm::AtomicOrdering::Monotonic;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// RUN: %clang_cc1 -triple s390x-linux-gnu -O1 -emit-llvm %s -o - | FileCheck %s
2+
//
3+
// Test that floating point atomic stores and loads do not get casted to/from
4+
// integer.
5+
6+
#include <stdatomic.h>
7+
8+
_Atomic float Af;
9+
_Atomic double Ad;
10+
_Atomic long double Ald;
11+
12+
//// Atomic stores of floating point values.
13+
void fun0(float Arg) {
14+
// CHECK-LABEL: @fun0
15+
// CHECK: store atomic float %Arg, ptr @Af seq_cst, align 4
16+
Af = Arg;
17+
}
18+
19+
void fun1(double Arg) {
20+
// CHECK-LABEL: @fun1
21+
// CHECK: store atomic double %Arg, ptr @Ad seq_cst, align 8
22+
Ad = Arg;
23+
}
24+
25+
void fun2(long double Arg) {
26+
// CHECK-LABEL: @fun2
27+
// CHECK: store atomic fp128 %Arg, ptr @Ald seq_cst, align 16
28+
Ald = Arg;
29+
}
30+
31+
void fun3(_Atomic float *Dst, float Arg) {
32+
// CHECK-LABEL: @fun
33+
// CHECK: store atomic float %Arg, ptr %Dst seq_cst, align 4
34+
*Dst = Arg;
35+
}
36+
37+
void fun4(_Atomic double *Dst, double Arg) {
38+
// CHECK-LABEL: @fun4
39+
// CHECK: store atomic double %Arg, ptr %Dst seq_cst, align 8
40+
*Dst = Arg;
41+
}
42+
43+
void fun5(_Atomic long double *Dst, long double Arg) {
44+
// CHECK-LABEL: @fun5
45+
// CHECK: store atomic fp128 %Arg, ptr %Dst seq_cst, align 16
46+
*Dst = Arg;
47+
}
48+
49+
//// Atomic loads of floating point values.
50+
float fun6() {
51+
// CHECK-LABEL: @fun6
52+
// CHECK: %atomic-load = load atomic float, ptr @Af seq_cst, align 4
53+
return Af;
54+
}
55+
56+
float fun7() {
57+
// CHECK-LABEL: @fun7
58+
// CHECK: %atomic-load = load atomic double, ptr @Ad seq_cst, align 8
59+
return Ad;
60+
}
61+
62+
float fun8() {
63+
// CHECK-LABEL: @fun8
64+
// CHECK: %atomic-load = load atomic fp128, ptr @Ald seq_cst, align 16
65+
return Ald;
66+
}
67+
68+
float fun9(_Atomic float *Src) {
69+
// CHECK-LABEL: @fun9
70+
// CHECK: %atomic-load = load atomic float, ptr %Src seq_cst, align 4
71+
return *Src;
72+
}
73+
74+
double fun10(_Atomic double *Src) {
75+
// CHECK-LABEL: @fun10
76+
// CHECK: %atomic-load = load atomic double, ptr %Src seq_cst, align 8
77+
return *Src;
78+
}
79+
80+
long double fun11(_Atomic long double *Src) {
81+
// CHECK-LABEL: @fun11
82+
// CHECK: %atomic-load = load atomic fp128, ptr %Src seq_cst, align 16
83+
return *Src;
84+
}

clang/test/CodeGen/atomic.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,5 @@ void force_global_uses(void) {
145145
(void)glob_int;
146146
// CHECK: load atomic i32, ptr @[[GLOB_INT]] seq_cst
147147
(void)glob_flt;
148-
// CHECK: %[[LOCAL_FLT:.+]] = load atomic i32, ptr @[[GLOB_FLT]] seq_cst
149-
// CHECK-NEXT: bitcast i32 %[[LOCAL_FLT]] to float
148+
// CHECK: load atomic float, ptr @[[GLOB_FLT]] seq_cst
150149
}

clang/test/CodeGen/c11atomics-ios.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@ void testFloat(_Atomic(float) *fp) {
1919
_Atomic(float) x = 2.0f;
2020

2121
// CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[FP]]
22-
// CHECK-NEXT: [[T2:%.*]] = load atomic i32, ptr [[T0]] seq_cst, align 4
23-
// CHECK-NEXT: [[T3:%.*]] = bitcast i32 [[T2]] to float
24-
// CHECK-NEXT: store float [[T3]], ptr [[F]]
22+
// CHECK-NEXT: [[T2:%.*]] = load atomic float, ptr [[T0]] seq_cst, align 4
23+
// CHECK-NEXT: store float [[T2]], ptr [[F]]
2524
float f = *fp;
2625

2726
// CHECK-NEXT: [[T0:%.*]] = load float, ptr [[F]], align 4
2827
// CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[FP]], align 4
29-
// CHECK-NEXT: [[T2:%.*]] = bitcast float [[T0]] to i32
30-
// CHECK-NEXT: store atomic i32 [[T2]], ptr [[T1]] seq_cst, align 4
28+
// CHECK-NEXT: store atomic float [[T0]], ptr [[T1]] seq_cst, align 4
3129
*fp = f;
3230

3331
// CHECK-NEXT: ret void

clang/test/OpenMP/atomic_read_codegen.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,11 @@ int main(void) {
128128
// CHECK: store i64
129129
#pragma omp atomic read
130130
ullv = ullx;
131-
// CHECK: load atomic i32, ptr {{.*}} monotonic, align 4
132-
// CHECK: bitcast i32 {{.*}} to float
131+
// CHECK: load atomic float, ptr {{.*}} monotonic, align 4
133132
// CHECK: store float
134133
#pragma omp atomic read
135134
fv = fx;
136-
// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8
137-
// CHECK: bitcast i64 {{.*}} to double
135+
// CHECK: load atomic double, ptr {{.*}} monotonic, align 8
138136
// CHECK: store double
139137
#pragma omp atomic read
140138
dv = dx;
@@ -194,11 +192,11 @@ int main(void) {
194192
// CHECK: store i64
195193
#pragma omp atomic read
196194
lv = cix;
197-
// CHECK: load atomic i32, ptr {{.*}} monotonic, align 4
195+
// CHECK: load atomic float, ptr {{.*}} monotonic, align 4
198196
// CHECK: store i64
199197
#pragma omp atomic read
200198
ulv = fx;
201-
// CHECK: load atomic i64, ptr {{.*}} monotonic, align 8
199+
// CHECK: load atomic double, ptr {{.*}} monotonic, align 8
202200
// CHECK: store i64
203201
#pragma omp atomic read
204202
llv = dx;

clang/test/OpenMP/atomic_write_codegen.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,11 @@ int main(void) {
131131
#pragma omp atomic write
132132
ullx = ullv;
133133
// CHECK: load float, ptr
134-
// CHECK: bitcast float {{.*}} to i32
135-
// CHECK: store atomic i32 {{.*}}, ptr {{.*}} monotonic, align 4
134+
// CHECK: store atomic float {{.*}}, ptr {{.*}} monotonic, align 4
136135
#pragma omp atomic write
137136
fx = fv;
138137
// CHECK: load double, ptr
139-
// CHECK: bitcast double {{.*}} to i64
140-
// CHECK: store atomic i64 {{.*}}, ptr {{.*}} monotonic, align 8
138+
// CHECK: store atomic double {{.*}}, ptr {{.*}} monotonic, align 8
141139
#pragma omp atomic write
142140
dx = dv;
143141
// CHECK: [[LD:%.+]] = load x86_fp80, ptr
@@ -215,11 +213,11 @@ int main(void) {
215213
#pragma omp atomic write
216214
cix = lv;
217215
// CHECK: load i64, ptr
218-
// CHECK: store atomic i32 %{{.+}}, ptr {{.*}} monotonic, align 4
216+
// CHECK: store atomic float %{{.+}}, ptr {{.*}} monotonic, align 4
219217
#pragma omp atomic write
220218
fx = ulv;
221219
// CHECK: load i64, ptr
222-
// CHECK: store atomic i64 %{{.+}}, ptr {{.*}} monotonic, align 8
220+
// CHECK: store atomic double %{{.+}}, ptr {{.*}} monotonic, align 8
223221
#pragma omp atomic write
224222
dx = llv;
225223
// CHECK: load i64, ptr
@@ -491,8 +489,7 @@ int main(void) {
491489
float2x.x = ulv;
492490
// CHECK: call i32 @llvm.read_register.i32(
493491
// CHECK: sitofp i32 %{{.+}} to double
494-
// CHECK: bitcast double %{{.+}} to i64
495-
// CHECK: store atomic i64 %{{.+}}, ptr @{{.+}} seq_cst, align 8
492+
// CHECK: store atomic double %{{.+}}, ptr @{{.+}} seq_cst, align 8
496493
// CHECK: call{{.*}} @__kmpc_flush(
497494
#pragma omp atomic write seq_cst
498495
dv = rix;

0 commit comments

Comments
 (0)