Skip to content

Commit ab5102d

Browse files
authored
[SandboxIR] Implement AtomicRMWInst (#104529)
This patch implements sandboxir::AtomicRMWInst mirroring llvm::AtomicRMWInst.
1 parent aba3476 commit ab5102d

File tree

5 files changed

+373
-0
lines changed

5 files changed

+373
-0
lines changed

llvm/include/llvm/SandboxIR/SandboxIR.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class BitCastInst;
132132
class AllocaInst;
133133
class UnaryOperator;
134134
class BinaryOperator;
135+
class AtomicRMWInst;
135136
class AtomicCmpXchgInst;
136137

137138
/// Iterator for the `Use` edges of a User's operands.
@@ -253,6 +254,7 @@ class Value {
253254
friend class GetElementPtrInst; // For getting `Val`.
254255
friend class UnaryOperator; // For getting `Val`.
255256
friend class BinaryOperator; // For getting `Val`.
257+
friend class AtomicRMWInst; // For getting `Val`.
256258
friend class AtomicCmpXchgInst; // For getting `Val`.
257259
friend class AllocaInst; // For getting `Val`.
258260
friend class CastInst; // For getting `Val`.
@@ -636,6 +638,7 @@ class Instruction : public sandboxir::User {
636638
friend class GetElementPtrInst; // For getTopmostLLVMInstruction().
637639
friend class UnaryOperator; // For getTopmostLLVMInstruction().
638640
friend class BinaryOperator; // For getTopmostLLVMInstruction().
641+
friend class AtomicRMWInst; // For getTopmostLLVMInstruction().
639642
friend class AtomicCmpXchgInst; // For getTopmostLLVMInstruction().
640643
friend class AllocaInst; // For getTopmostLLVMInstruction().
641644
friend class CastInst; // For getTopmostLLVMInstruction().
@@ -1559,6 +1562,77 @@ class BinaryOperator : public SingleLLVMInstructionImpl<llvm::BinaryOperator> {
15591562
void swapOperands() { swapOperandsInternal(0, 1); }
15601563
};
15611564

1565+
class AtomicRMWInst : public SingleLLVMInstructionImpl<llvm::AtomicRMWInst> {
1566+
AtomicRMWInst(llvm::AtomicRMWInst *Atomic, Context &Ctx)
1567+
: SingleLLVMInstructionImpl(ClassID::AtomicRMW,
1568+
Instruction::Opcode::AtomicRMW, Atomic, Ctx) {
1569+
}
1570+
friend class Context; // For constructor.
1571+
1572+
public:
1573+
using BinOp = llvm::AtomicRMWInst::BinOp;
1574+
BinOp getOperation() const {
1575+
return cast<llvm::AtomicRMWInst>(Val)->getOperation();
1576+
}
1577+
static StringRef getOperationName(BinOp Op) {
1578+
return llvm::AtomicRMWInst::getOperationName(Op);
1579+
}
1580+
static bool isFPOperation(BinOp Op) {
1581+
return llvm::AtomicRMWInst::isFPOperation(Op);
1582+
}
1583+
void setOperation(BinOp Op) {
1584+
cast<llvm::AtomicRMWInst>(Val)->setOperation(Op);
1585+
}
1586+
Align getAlign() const { return cast<llvm::AtomicRMWInst>(Val)->getAlign(); }
1587+
void setAlignment(Align Align);
1588+
bool isVolatile() const {
1589+
return cast<llvm::AtomicRMWInst>(Val)->isVolatile();
1590+
}
1591+
void setVolatile(bool V);
1592+
AtomicOrdering getOrdering() const {
1593+
return cast<llvm::AtomicRMWInst>(Val)->getOrdering();
1594+
}
1595+
void setOrdering(AtomicOrdering Ordering);
1596+
SyncScope::ID getSyncScopeID() const {
1597+
return cast<llvm::AtomicRMWInst>(Val)->getSyncScopeID();
1598+
}
1599+
void setSyncScopeID(SyncScope::ID SSID);
1600+
Value *getPointerOperand();
1601+
const Value *getPointerOperand() const {
1602+
return const_cast<AtomicRMWInst *>(this)->getPointerOperand();
1603+
}
1604+
Value *getValOperand();
1605+
const Value *getValOperand() const {
1606+
return const_cast<AtomicRMWInst *>(this)->getValOperand();
1607+
}
1608+
unsigned getPointerAddressSpace() const {
1609+
return cast<llvm::AtomicRMWInst>(Val)->getPointerAddressSpace();
1610+
}
1611+
bool isFloatingPointOperation() const {
1612+
return cast<llvm::AtomicRMWInst>(Val)->isFloatingPointOperation();
1613+
}
1614+
static bool classof(const Value *From) {
1615+
return From->getSubclassID() == ClassID::AtomicRMW;
1616+
}
1617+
1618+
static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val,
1619+
MaybeAlign Align, AtomicOrdering Ordering,
1620+
BBIterator WhereIt, BasicBlock *WhereBB,
1621+
Context &Ctx,
1622+
SyncScope::ID SSID = SyncScope::System,
1623+
const Twine &Name = "");
1624+
static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val,
1625+
MaybeAlign Align, AtomicOrdering Ordering,
1626+
Instruction *InsertBefore, Context &Ctx,
1627+
SyncScope::ID SSID = SyncScope::System,
1628+
const Twine &Name = "");
1629+
static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val,
1630+
MaybeAlign Align, AtomicOrdering Ordering,
1631+
BasicBlock *InsertAtEnd, Context &Ctx,
1632+
SyncScope::ID SSID = SyncScope::System,
1633+
const Twine &Name = "");
1634+
};
1635+
15621636
class AtomicCmpXchgInst
15631637
: public SingleLLVMInstructionImpl<llvm::AtomicCmpXchgInst> {
15641638
AtomicCmpXchgInst(llvm::AtomicCmpXchgInst *Atomic, Context &Ctx)
@@ -2007,6 +2081,8 @@ class Context {
20072081
friend UnaryOperator; // For createUnaryOperator()
20082082
BinaryOperator *createBinaryOperator(llvm::BinaryOperator *I);
20092083
friend BinaryOperator; // For createBinaryOperator()
2084+
AtomicRMWInst *createAtomicRMWInst(llvm::AtomicRMWInst *I);
2085+
friend AtomicRMWInst; // For createAtomicRMWInst()
20102086
AtomicCmpXchgInst *createAtomicCmpXchgInst(llvm::AtomicCmpXchgInst *I);
20112087
friend AtomicCmpXchgInst; // For createAtomicCmpXchgInst()
20122088
AllocaInst *createAllocaInst(llvm::AllocaInst *I);

llvm/include/llvm/SandboxIR/SandboxIRValues.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ DEF_INSTR(BinaryOperator, OPCODES(\
6868
OP(Or) \
6969
OP(Xor) \
7070
), BinaryOperator)
71+
DEF_INSTR(AtomicRMW, OP(AtomicRMW), AtomicRMWInst)
7172
DEF_INSTR(AtomicCmpXchg, OP(AtomicCmpXchg), AtomicCmpXchgInst)
7273
DEF_INSTR(Alloca, OP(Alloca), AllocaInst)
7374
DEF_INSTR(Cast, OPCODES(\

llvm/lib/SandboxIR/SandboxIR.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,74 @@ Value *BinaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
13851385
InsertAtEnd, Ctx, Name);
13861386
}
13871387

1388+
void AtomicRMWInst::setAlignment(Align Align) {
1389+
Ctx.getTracker()
1390+
.emplaceIfTracking<GenericSetter<&AtomicRMWInst::getAlign,
1391+
&AtomicRMWInst::setAlignment>>(this);
1392+
cast<llvm::AtomicRMWInst>(Val)->setAlignment(Align);
1393+
}
1394+
1395+
void AtomicRMWInst::setVolatile(bool V) {
1396+
Ctx.getTracker()
1397+
.emplaceIfTracking<GenericSetter<&AtomicRMWInst::isVolatile,
1398+
&AtomicRMWInst::setVolatile>>(this);
1399+
cast<llvm::AtomicRMWInst>(Val)->setVolatile(V);
1400+
}
1401+
1402+
void AtomicRMWInst::setOrdering(AtomicOrdering Ordering) {
1403+
Ctx.getTracker()
1404+
.emplaceIfTracking<GenericSetter<&AtomicRMWInst::getOrdering,
1405+
&AtomicRMWInst::setOrdering>>(this);
1406+
cast<llvm::AtomicRMWInst>(Val)->setOrdering(Ordering);
1407+
}
1408+
1409+
void AtomicRMWInst::setSyncScopeID(SyncScope::ID SSID) {
1410+
Ctx.getTracker()
1411+
.emplaceIfTracking<GenericSetter<&AtomicRMWInst::getSyncScopeID,
1412+
&AtomicRMWInst::setSyncScopeID>>(this);
1413+
cast<llvm::AtomicRMWInst>(Val)->setSyncScopeID(SSID);
1414+
}
1415+
1416+
Value *AtomicRMWInst::getPointerOperand() {
1417+
return Ctx.getValue(cast<llvm::AtomicRMWInst>(Val)->getPointerOperand());
1418+
}
1419+
1420+
Value *AtomicRMWInst::getValOperand() {
1421+
return Ctx.getValue(cast<llvm::AtomicRMWInst>(Val)->getValOperand());
1422+
}
1423+
1424+
AtomicRMWInst *AtomicRMWInst::create(BinOp Op, Value *Ptr, Value *Val,
1425+
MaybeAlign Align, AtomicOrdering Ordering,
1426+
BBIterator WhereIt, BasicBlock *WhereBB,
1427+
Context &Ctx, SyncScope::ID SSID,
1428+
const Twine &Name) {
1429+
auto &Builder = Ctx.getLLVMIRBuilder();
1430+
if (WhereIt == WhereBB->end())
1431+
Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
1432+
else
1433+
Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
1434+
auto *LLVMAtomicRMW =
1435+
Builder.CreateAtomicRMW(Op, Ptr->Val, Val->Val, Align, Ordering, SSID);
1436+
LLVMAtomicRMW->setName(Name);
1437+
return Ctx.createAtomicRMWInst(LLVMAtomicRMW);
1438+
}
1439+
1440+
AtomicRMWInst *AtomicRMWInst::create(BinOp Op, Value *Ptr, Value *Val,
1441+
MaybeAlign Align, AtomicOrdering Ordering,
1442+
Instruction *InsertBefore, Context &Ctx,
1443+
SyncScope::ID SSID, const Twine &Name) {
1444+
return create(Op, Ptr, Val, Align, Ordering, InsertBefore->getIterator(),
1445+
InsertBefore->getParent(), Ctx, SSID, Name);
1446+
}
1447+
1448+
AtomicRMWInst *AtomicRMWInst::create(BinOp Op, Value *Ptr, Value *Val,
1449+
MaybeAlign Align, AtomicOrdering Ordering,
1450+
BasicBlock *InsertAtEnd, Context &Ctx,
1451+
SyncScope::ID SSID, const Twine &Name) {
1452+
return create(Op, Ptr, Val, Align, Ordering, InsertAtEnd->end(), InsertAtEnd,
1453+
Ctx, SSID, Name);
1454+
}
1455+
13881456
void AtomicCmpXchgInst::setSyncScopeID(SyncScope::ID SSID) {
13891457
Ctx.getTracker()
13901458
.emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::getSyncScopeID,
@@ -1823,6 +1891,12 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
18231891
new BinaryOperator(LLVMBinaryOperator, *this));
18241892
return It->second.get();
18251893
}
1894+
case llvm::Instruction::AtomicRMW: {
1895+
auto *LLVMAtomicRMW = cast<llvm::AtomicRMWInst>(LLVMV);
1896+
It->second =
1897+
std::unique_ptr<AtomicRMWInst>(new AtomicRMWInst(LLVMAtomicRMW, *this));
1898+
return It->second.get();
1899+
}
18261900
case llvm::Instruction::AtomicCmpXchg: {
18271901
auto *LLVMAtomicCmpXchg = cast<llvm::AtomicCmpXchgInst>(LLVMV);
18281902
It->second = std::unique_ptr<AtomicCmpXchgInst>(
@@ -1954,6 +2028,10 @@ BinaryOperator *Context::createBinaryOperator(llvm::BinaryOperator *I) {
19542028
auto NewPtr = std::unique_ptr<BinaryOperator>(new BinaryOperator(I, *this));
19552029
return cast<BinaryOperator>(registerValue(std::move(NewPtr)));
19562030
}
2031+
AtomicRMWInst *Context::createAtomicRMWInst(llvm::AtomicRMWInst *I) {
2032+
auto NewPtr = std::unique_ptr<AtomicRMWInst>(new AtomicRMWInst(I, *this));
2033+
return cast<AtomicRMWInst>(registerValue(std::move(NewPtr)));
2034+
}
19572035
AtomicCmpXchgInst *
19582036
Context::createAtomicCmpXchgInst(llvm::AtomicCmpXchgInst *I) {
19592037
auto NewPtr =

llvm/unittests/SandboxIR/SandboxIRTest.cpp

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,169 @@ define void @foo(i8 %arg0, i8 %arg1, float %farg0, float %farg1) {
19321932
}
19331933
}
19341934

1935+
TEST_F(SandboxIRTest, AtomicRMWInst) {
1936+
parseIR(C, R"IR(
1937+
define void @foo(ptr %ptr, i8 %arg) {
1938+
%atomicrmw = atomicrmw add ptr %ptr, i8 %arg acquire, align 128
1939+
ret void
1940+
}
1941+
)IR");
1942+
llvm::Function &LLVMF = *M->getFunction("foo");
1943+
llvm::BasicBlock *LLVMBB = &*LLVMF.begin();
1944+
auto LLVMIt = LLVMBB->begin();
1945+
auto *LLVMRMW = cast<llvm::AtomicRMWInst>(&*LLVMIt++);
1946+
1947+
sandboxir::Context Ctx(C);
1948+
sandboxir::Function *F = Ctx.createFunction(&LLVMF);
1949+
auto *Ptr = F->getArg(0);
1950+
auto *Arg = F->getArg(1);
1951+
auto *BB = &*F->begin();
1952+
auto It = BB->begin();
1953+
auto *RMW = cast<sandboxir::AtomicRMWInst>(&*It++);
1954+
auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
1955+
1956+
// Check getOperationName().
1957+
EXPECT_EQ(
1958+
sandboxir::AtomicRMWInst::getOperationName(
1959+
sandboxir::AtomicRMWInst::BinOp::Add),
1960+
llvm::AtomicRMWInst::getOperationName(llvm::AtomicRMWInst::BinOp::Add));
1961+
// Check isFPOperation().
1962+
EXPECT_EQ(
1963+
sandboxir::AtomicRMWInst::isFPOperation(
1964+
sandboxir::AtomicRMWInst::BinOp::Add),
1965+
llvm::AtomicRMWInst::isFPOperation(llvm::AtomicRMWInst::BinOp::Add));
1966+
EXPECT_FALSE(sandboxir::AtomicRMWInst::isFPOperation(
1967+
sandboxir::AtomicRMWInst::BinOp::Add));
1968+
EXPECT_TRUE(sandboxir::AtomicRMWInst::isFPOperation(
1969+
sandboxir::AtomicRMWInst::BinOp::FAdd));
1970+
// Check setOperation(), getOperation().
1971+
EXPECT_EQ(RMW->getOperation(), LLVMRMW->getOperation());
1972+
RMW->setOperation(sandboxir::AtomicRMWInst::BinOp::Sub);
1973+
EXPECT_EQ(RMW->getOperation(), sandboxir::AtomicRMWInst::BinOp::Sub);
1974+
RMW->setOperation(sandboxir::AtomicRMWInst::BinOp::Add);
1975+
// Check getAlign().
1976+
EXPECT_EQ(RMW->getAlign(), LLVMRMW->getAlign());
1977+
auto OrigAlign = RMW->getAlign();
1978+
Align NewAlign(256);
1979+
EXPECT_NE(NewAlign, OrigAlign);
1980+
RMW->setAlignment(NewAlign);
1981+
EXPECT_EQ(RMW->getAlign(), NewAlign);
1982+
RMW->setAlignment(OrigAlign);
1983+
EXPECT_EQ(RMW->getAlign(), OrigAlign);
1984+
// Check isVolatile(), setVolatile().
1985+
EXPECT_EQ(RMW->isVolatile(), LLVMRMW->isVolatile());
1986+
bool OrigV = RMW->isVolatile();
1987+
bool NewV = true;
1988+
EXPECT_NE(NewV, OrigV);
1989+
RMW->setVolatile(NewV);
1990+
EXPECT_EQ(RMW->isVolatile(), NewV);
1991+
RMW->setVolatile(OrigV);
1992+
EXPECT_EQ(RMW->isVolatile(), OrigV);
1993+
// Check getOrdering(), setOrdering().
1994+
EXPECT_EQ(RMW->getOrdering(), LLVMRMW->getOrdering());
1995+
auto OldOrdering = RMW->getOrdering();
1996+
auto NewOrdering = AtomicOrdering::Monotonic;
1997+
EXPECT_NE(NewOrdering, OldOrdering);
1998+
RMW->setOrdering(NewOrdering);
1999+
EXPECT_EQ(RMW->getOrdering(), NewOrdering);
2000+
RMW->setOrdering(OldOrdering);
2001+
EXPECT_EQ(RMW->getOrdering(), OldOrdering);
2002+
// Check getSyncScopeID(), setSyncScopeID().
2003+
EXPECT_EQ(RMW->getSyncScopeID(), LLVMRMW->getSyncScopeID());
2004+
auto OrigSSID = RMW->getSyncScopeID();
2005+
SyncScope::ID NewSSID = SyncScope::SingleThread;
2006+
EXPECT_NE(NewSSID, OrigSSID);
2007+
RMW->setSyncScopeID(NewSSID);
2008+
EXPECT_EQ(RMW->getSyncScopeID(), NewSSID);
2009+
RMW->setSyncScopeID(OrigSSID);
2010+
EXPECT_EQ(RMW->getSyncScopeID(), OrigSSID);
2011+
// Check getPointerOperand().
2012+
EXPECT_EQ(RMW->getPointerOperand(),
2013+
Ctx.getValue(LLVMRMW->getPointerOperand()));
2014+
// Check getValOperand().
2015+
EXPECT_EQ(RMW->getValOperand(), Ctx.getValue(LLVMRMW->getValOperand()));
2016+
// Check getPointerAddressSpace().
2017+
EXPECT_EQ(RMW->getPointerAddressSpace(), LLVMRMW->getPointerAddressSpace());
2018+
// Check isFloatingPointOperation().
2019+
EXPECT_EQ(RMW->isFloatingPointOperation(),
2020+
LLVMRMW->isFloatingPointOperation());
2021+
2022+
Align Align(1024);
2023+
auto Ordering = AtomicOrdering::Acquire;
2024+
auto SSID = SyncScope::System;
2025+
{
2026+
// Check create() WhereIt, WhereBB.
2027+
auto *NewI =
2028+
cast<sandboxir::AtomicRMWInst>(sandboxir::AtomicRMWInst::create(
2029+
sandboxir::AtomicRMWInst::BinOp::Sub, Ptr, Arg, Align, Ordering,
2030+
/*WhereIt=*/Ret->getIterator(),
2031+
/*WhereBB=*/Ret->getParent(), Ctx, SSID, "NewAtomicRMW1"));
2032+
// Check getOpcode().
2033+
EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::AtomicRMW);
2034+
// Check getAlign().
2035+
EXPECT_EQ(NewI->getAlign(), Align);
2036+
// Check getSuccessOrdering().
2037+
EXPECT_EQ(NewI->getOrdering(), Ordering);
2038+
// Check instr position.
2039+
EXPECT_EQ(NewI->getNextNode(), Ret);
2040+
// Check getPointerOperand().
2041+
EXPECT_EQ(NewI->getPointerOperand(), Ptr);
2042+
// Check getValOperand().
2043+
EXPECT_EQ(NewI->getValOperand(), Arg);
2044+
#ifndef NDEBUG
2045+
// Check getName().
2046+
EXPECT_EQ(NewI->getName(), "NewAtomicRMW1");
2047+
#endif // NDEBUG
2048+
}
2049+
{
2050+
// Check create() InsertBefore.
2051+
auto *NewI =
2052+
cast<sandboxir::AtomicRMWInst>(sandboxir::AtomicRMWInst::create(
2053+
sandboxir::AtomicRMWInst::BinOp::Sub, Ptr, Arg, Align, Ordering,
2054+
/*InsertBefore=*/Ret, Ctx, SSID, "NewAtomicRMW2"));
2055+
// Check getOpcode().
2056+
EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::AtomicRMW);
2057+
// Check getAlign().
2058+
EXPECT_EQ(NewI->getAlign(), Align);
2059+
// Check getSuccessOrdering().
2060+
EXPECT_EQ(NewI->getOrdering(), Ordering);
2061+
// Check instr position.
2062+
EXPECT_EQ(NewI->getNextNode(), Ret);
2063+
// Check getPointerOperand().
2064+
EXPECT_EQ(NewI->getPointerOperand(), Ptr);
2065+
// Check getValOperand().
2066+
EXPECT_EQ(NewI->getValOperand(), Arg);
2067+
#ifndef NDEBUG
2068+
// Check getName().
2069+
EXPECT_EQ(NewI->getName(), "NewAtomicRMW2");
2070+
#endif // NDEBUG
2071+
}
2072+
{
2073+
// Check create() InsertAtEnd.
2074+
auto *NewI =
2075+
cast<sandboxir::AtomicRMWInst>(sandboxir::AtomicRMWInst::create(
2076+
sandboxir::AtomicRMWInst::BinOp::Sub, Ptr, Arg, Align, Ordering,
2077+
/*InsertAtEnd=*/BB, Ctx, SSID, "NewAtomicRMW3"));
2078+
// Check getOpcode().
2079+
EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::AtomicRMW);
2080+
// Check getAlign().
2081+
EXPECT_EQ(NewI->getAlign(), Align);
2082+
// Check getSuccessOrdering().
2083+
EXPECT_EQ(NewI->getOrdering(), Ordering);
2084+
// Check instr position.
2085+
EXPECT_EQ(NewI->getParent(), BB);
2086+
EXPECT_EQ(NewI->getNextNode(), nullptr);
2087+
// Check getPointerOperand().
2088+
EXPECT_EQ(NewI->getPointerOperand(), Ptr);
2089+
// Check getValOperand().
2090+
EXPECT_EQ(NewI->getValOperand(), Arg);
2091+
#ifndef NDEBUG
2092+
// Check getName().
2093+
EXPECT_EQ(NewI->getName(), "NewAtomicRMW3");
2094+
#endif // NDEBUG
2095+
}
2096+
}
2097+
19352098
TEST_F(SandboxIRTest, AtomicCmpXchgInst) {
19362099
parseIR(C, R"IR(
19372100
define void @foo(ptr %ptr, i8 %cmp, i8 %new) {

0 commit comments

Comments
 (0)