Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions flang/test/Lower/OpenMP/atomic-read-complex.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
! Test lowering of atomic read to LLVM IR for complex types.
! This is a regression test for issue #165184.

! RUN: %flang_fc1 -emit-llvm -fopenmp -o - %s | FileCheck %s

! Test that atomic read operations with complex types emit the correct
! size parameter to __atomic_load:
! - complex(4) (8 bytes total): should call __atomic_load(i64 8, ...)
! - complex(8) (16 bytes total): should call __atomic_load(i64 16, ...)

program atomic_read_complex
implicit none

! Test complex(4) - single precision (8 bytes)
complex(4) :: c41, c42
! Test complex(8) - double precision (16 bytes)
complex(8) :: c81, c82

c42 = (1.0_4, 1.0_4)
c82 = (1.0_8, 1.0_8)

! CHECK-LABEL: define {{.*}} @_QQmain

! Single precision complex: 8 bytes
! CHECK: call void @__atomic_load(i64 8, ptr {{.*}}, ptr {{.*}}, i32 {{.*}})
!$omp atomic read
c41 = c42

! Double precision complex: 16 bytes (this was broken before the fix)
! CHECK: call void @__atomic_load(i64 16, ptr {{.*}}, ptr {{.*}}, i32 {{.*}})
!$omp atomic read
c81 = c82

end program atomic_read_complex
34 changes: 34 additions & 0 deletions flang/test/Lower/OpenMP/atomic-write-complex.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
! Test lowering of atomic write to LLVM IR for complex types.
! This is a regression test for issue #165184.

! RUN: %flang_fc1 -emit-llvm -fopenmp -o - %s | FileCheck %s

! Test that atomic write operations with complex types emit the correct
! size parameter to __atomic_store:
! - complex(4) (8 bytes total): should call __atomic_store(i64 8, ...)
! - complex(8) (16 bytes total): should call __atomic_store(i64 16, ...)

program atomic_write_complex
implicit none

! Test complex(4) - single precision (8 bytes)
complex(4) :: c41, c42
! Test complex(8) - double precision (16 bytes)
complex(8) :: c81, c82

c42 = (1.0_4, 1.0_4)
c82 = (1.0_8, 1.0_8)

! CHECK-LABEL: define {{.*}} @_QQmain

! Single precision complex: 8 bytes
! CHECK: call void @__atomic_store(i64 8, ptr {{.*}}, ptr {{.*}}, i32 {{.*}})
!$omp atomic write
c41 = c42

! Double precision complex: 16 bytes (this was broken before the fix)
! CHECK: call void @__atomic_store(i64 16, ptr {{.*}}, ptr {{.*}}, i32 {{.*}})
!$omp atomic write
c81 = c82

end program atomic_write_complex
15 changes: 7 additions & 8 deletions llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5473,7 +5473,8 @@ OpenMPIRBuilder::collapseLoops(DebugLoc DL, ArrayRef<CanonicalLoopInfo *> Loops,
}

// TODO: Enable UndefinedSanitizer to diagnose an overflow here.
CollapsedTripCount = Builder.CreateNUWMul(CollapsedTripCount, OrigTripCount);
CollapsedTripCount =
Builder.CreateNUWMul(CollapsedTripCount, OrigTripCount);
}

// Create the collapsed loop control flow.
Expand Down Expand Up @@ -9338,9 +9339,8 @@ OpenMPIRBuilder::createAtomicRead(const LocationDescription &Loc,
// target does not support `atomicrmw` of the size of the struct
LoadInst *OldVal = Builder.CreateLoad(XElemTy, X.Var, "omp.atomic.read");
OldVal->setAtomic(AO);
const DataLayout &LoadDL = OldVal->getModule()->getDataLayout();
unsigned LoadSize =
LoadDL.getTypeStoreSize(OldVal->getPointerOperand()->getType());
const DataLayout &DL = OldVal->getModule()->getDataLayout();
unsigned LoadSize = DL.getTypeStoreSize(XElemTy);
OpenMPIRBuilder::AtomicInfo atomicInfo(
&Builder, XElemTy, LoadSize * 8, LoadSize * 8, OldVal->getAlign(),
OldVal->getAlign(), true /* UseLibcall */, AllocaIP, X.Var);
Expand Down Expand Up @@ -9384,9 +9384,8 @@ OpenMPIRBuilder::createAtomicWrite(const LocationDescription &Loc,
XSt->setAtomic(AO);
} else if (XElemTy->isStructTy()) {
LoadInst *OldVal = Builder.CreateLoad(XElemTy, X.Var, "omp.atomic.read");
const DataLayout &LoadDL = OldVal->getModule()->getDataLayout();
unsigned LoadSize =
LoadDL.getTypeStoreSize(OldVal->getPointerOperand()->getType());
const DataLayout &DL = OldVal->getModule()->getDataLayout();
unsigned LoadSize = DL.getTypeStoreSize(XElemTy);
OpenMPIRBuilder::AtomicInfo atomicInfo(
&Builder, XElemTy, LoadSize * 8, LoadSize * 8, OldVal->getAlign(),
OldVal->getAlign(), true /* UseLibcall */, AllocaIP, X.Var);
Expand Down Expand Up @@ -9581,7 +9580,7 @@ Expected<std::pair<Value *, Value *>> OpenMPIRBuilder::emitAtomicUpdate(
OldVal->setAtomic(AO);
// CurBB
// | /---\
// ContBB |
// ContBB |
// | \---/
// ExitBB
BasicBlock *CurBB = Builder.GetInsertBlock();
Expand Down
82 changes: 80 additions & 2 deletions llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4534,6 +4534,85 @@ TEST_F(OpenMPIRBuilderTest, OMPAtomicCompareCapture) {
EXPECT_FALSE(verifyModule(*M, &errs()));
}

TEST_F(OpenMPIRBuilderTest, OMPAtomicRWStructType) {
// Test for issue #165184: atomic read/write on struct types should use
// element type size, not pointer size.
OpenMPIRBuilder OMPBuilder(*M);
OMPBuilder.initialize();
F->setName("func");
IRBuilder<> Builder(BB);

OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
BasicBlock *EntryBB = BB;
OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,
EntryBB->getFirstInsertionPt());

LLVMContext &Ctx = M->getContext();

// Create a struct type {double, double} to simulate complex(8) - 16 bytes
StructType *Complex8Ty = StructType::create(
Ctx, {Type::getDoubleTy(Ctx), Type::getDoubleTy(Ctx)}, "complex");

AllocaInst *XVal = Builder.CreateAlloca(Complex8Ty);
XVal->setName("AtomicVar");
OpenMPIRBuilder::AtomicOpValue X = {XVal, Complex8Ty, false, false};
AtomicOrdering AO = AtomicOrdering::SequentiallyConsistent;

// Create value to write: {1.0, 1.0}
Constant *Real = ConstantFP::get(Type::getDoubleTy(Ctx), 1.0);
Constant *Imag = ConstantFP::get(Type::getDoubleTy(Ctx), 1.0);
Constant *ValToWrite = ConstantStruct::get(Complex8Ty, {Real, Imag});

// Test atomic write
Builder.restoreIP(
OMPBuilder.createAtomicWrite(Loc, X, ValToWrite, AO, AllocaIP));

// Test atomic read
AllocaInst *VVal = Builder.CreateAlloca(Complex8Ty);
VVal->setName("ReadDest");
OpenMPIRBuilder::AtomicOpValue V = {VVal, Complex8Ty, false, false};

Builder.restoreIP(OMPBuilder.createAtomicRead(Loc, X, V, AO, AllocaIP));

Builder.CreateRetVoid();
OMPBuilder.finalize();
EXPECT_FALSE(verifyModule(*M, &errs()));

// Verify that __atomic_store and __atomic_load are called with size 16
bool FoundAtomicStore = false;
bool FoundAtomicLoad = false;

for (Function &Fn : *M) {
if (Fn.getName().starts_with("__atomic_store")) {
// Check that first call to __atomic_store has size argument = 16
for (User *U : Fn.users()) {
if (auto *CB = dyn_cast<CallBase>(U)) {
if (auto *SizeArg = dyn_cast<ConstantInt>(CB->getArgOperand(0))) {
EXPECT_EQ(SizeArg->getZExtValue(), 16U);
FoundAtomicStore = true;
break;
}
}
}
}
if (Fn.getName().starts_with("__atomic_load")) {
// Check that first call to __atomic_load has size argument = 16
for (User *U : Fn.users()) {
if (auto *CB = dyn_cast<CallBase>(U)) {
if (auto *SizeArg = dyn_cast<ConstantInt>(CB->getArgOperand(0))) {
EXPECT_EQ(SizeArg->getZExtValue(), 16U);
FoundAtomicLoad = true;
break;
}
}
}
}
}

EXPECT_TRUE(FoundAtomicStore) << "Did not find __atomic_store call";
EXPECT_TRUE(FoundAtomicLoad) << "Did not find __atomic_load call";
}

TEST_F(OpenMPIRBuilderTest, CreateTeams) {
using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
OpenMPIRBuilder OMPBuilder(*M);
Expand Down Expand Up @@ -7576,8 +7655,7 @@ TEST_F(OpenMPIRBuilderTest, CreateTaskgroup) {
// Checking the general structure of the IR generated is same as expected.
Instruction *GeneratedStoreInst = TaskgroupCall->getNextNode();
EXPECT_EQ(GeneratedStoreInst, InternalStoreInst);
Instruction *GeneratedLoad32 =
GeneratedStoreInst->getNextNode();
Instruction *GeneratedLoad32 = GeneratedStoreInst->getNextNode();
EXPECT_EQ(GeneratedLoad32, InternalLoad32);
Instruction *GeneratedLoad128 = GeneratedLoad32->getNextNode();
EXPECT_EQ(GeneratedLoad128, InternalLoad128);
Expand Down