Skip to content

Commit ae3e825

Browse files
authored
[SandboxIR] Implement GlobalIFunc (#108622)
This patch implements sandboxir::GlobalIFunc mirroring llvm::GlobalIFunc.
1 parent aca226c commit ae3e825

File tree

4 files changed

+279
-17
lines changed

4 files changed

+279
-17
lines changed

llvm/include/llvm/SandboxIR/SandboxIR.h

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class DSOLocalEquivalent;
128128
class ConstantTokenNone;
129129
class GlobalValue;
130130
class GlobalObject;
131+
class GlobalIFunc;
131132
class Context;
132133
class Function;
133134
class Instruction;
@@ -332,6 +333,7 @@ class Value {
332333
friend class GlobalValue; // For `Val`.
333334
friend class DSOLocalEquivalent; // For `Val`.
334335
friend class GlobalObject; // For `Val`.
336+
friend class GlobalIFunc; // For `Val`.
335337

336338
/// All values point to the context.
337339
Context &Ctx;
@@ -1128,6 +1130,7 @@ class GlobalValue : public Constant {
11281130
friend class Context; // For constructor.
11291131

11301132
public:
1133+
using LinkageTypes = llvm::GlobalValue::LinkageTypes;
11311134
/// For isa/dyn_cast.
11321135
static bool classof(const sandboxir::Value *From) {
11331136
switch (From->getSubclassID()) {
@@ -1285,6 +1288,88 @@ class GlobalObject : public GlobalValue {
12851288
}
12861289
};
12871290

1291+
/// Provides API functions, like getIterator() and getReverseIterator() to
1292+
/// GlobalIFunc, Function, GlobalVariable and GlobalAlias. In LLVM IR these are
1293+
/// provided by ilist_node.
1294+
template <typename GlobalT, typename LLVMGlobalT, typename ParentT,
1295+
typename LLVMParentT>
1296+
class GlobalWithNodeAPI : public ParentT {
1297+
/// Helper for mapped_iterator.
1298+
struct LLVMGVToGV {
1299+
Context &Ctx;
1300+
LLVMGVToGV(Context &Ctx) : Ctx(Ctx) {}
1301+
GlobalT &operator()(LLVMGlobalT &LLVMGV) const;
1302+
};
1303+
1304+
public:
1305+
GlobalWithNodeAPI(Value::ClassID ID, LLVMParentT *C, Context &Ctx)
1306+
: ParentT(ID, C, Ctx) {}
1307+
1308+
// TODO: Missing getParent(). Should be added once Module is available.
1309+
1310+
using iterator = mapped_iterator<
1311+
decltype(static_cast<LLVMGlobalT *>(nullptr)->getIterator()), LLVMGVToGV>;
1312+
using reverse_iterator = mapped_iterator<
1313+
decltype(static_cast<LLVMGlobalT *>(nullptr)->getReverseIterator()),
1314+
LLVMGVToGV>;
1315+
iterator getIterator() const {
1316+
auto *LLVMGV = cast<LLVMGlobalT>(this->Val);
1317+
LLVMGVToGV ToGV(this->Ctx);
1318+
return map_iterator(LLVMGV->getIterator(), ToGV);
1319+
}
1320+
reverse_iterator getReverseIterator() const {
1321+
auto *LLVMGV = cast<LLVMGlobalT>(this->Val);
1322+
LLVMGVToGV ToGV(this->Ctx);
1323+
return map_iterator(LLVMGV->getReverseIterator(), ToGV);
1324+
}
1325+
};
1326+
1327+
class GlobalIFunc final
1328+
: public GlobalWithNodeAPI<GlobalIFunc, llvm::GlobalIFunc, GlobalObject,
1329+
llvm::GlobalObject> {
1330+
GlobalIFunc(llvm::GlobalObject *C, Context &Ctx)
1331+
: GlobalWithNodeAPI(ClassID::GlobalIFunc, C, Ctx) {}
1332+
friend class Context; // For constructor.
1333+
1334+
public:
1335+
/// For isa/dyn_cast.
1336+
static bool classof(const sandboxir::Value *From) {
1337+
return From->getSubclassID() == ClassID::GlobalIFunc;
1338+
}
1339+
1340+
// TODO: Missing create() because we don't have a sandboxir::Module yet.
1341+
1342+
// TODO: Missing functions: copyAttributesFrom(), removeFromParent(),
1343+
// eraseFromParent()
1344+
1345+
void setResolver(Constant *Resolver);
1346+
1347+
Constant *getResolver() const;
1348+
1349+
// Return the resolver function after peeling off potential ConstantExpr
1350+
// indirection.
1351+
Function *getResolverFunction();
1352+
const Function *getResolverFunction() const {
1353+
return const_cast<GlobalIFunc *>(this)->getResolverFunction();
1354+
}
1355+
1356+
static bool isValidLinkage(LinkageTypes L) {
1357+
return llvm::GlobalIFunc::isValidLinkage(L);
1358+
}
1359+
1360+
// TODO: Missing applyAlongResolverPath().
1361+
1362+
#ifndef NDEBUG
1363+
void verify() const override {
1364+
assert(isa<llvm::GlobalIFunc>(Val) && "Expected a GlobalIFunc!");
1365+
}
1366+
void dumpOS(raw_ostream &OS) const override {
1367+
dumpCommonPrefix(OS);
1368+
dumpCommonSuffix(OS);
1369+
}
1370+
#endif
1371+
};
1372+
12881373
class BlockAddress final : public Constant {
12891374
BlockAddress(llvm::BlockAddress *C, Context &Ctx)
12901375
: Constant(ClassID::BlockAddress, C, Ctx) {}
@@ -4219,7 +4304,8 @@ class Context {
42194304
size_t getNumValues() const { return LLVMValueToValueMap.size(); }
42204305
};
42214306

4222-
class Function : public GlobalObject {
4307+
class Function : public GlobalWithNodeAPI<Function, llvm::Function,
4308+
GlobalObject, llvm::GlobalObject> {
42234309
/// Helper for mapped_iterator.
42244310
struct LLVMBBToBB {
42254311
Context &Ctx;
@@ -4230,7 +4316,7 @@ class Function : public GlobalObject {
42304316
};
42314317
/// Use Context::createFunction() instead.
42324318
Function(llvm::Function *F, sandboxir::Context &Ctx)
4233-
: GlobalObject(ClassID::Function, F, Ctx) {}
4319+
: GlobalWithNodeAPI(ClassID::Function, F, Ctx) {}
42344320
friend class Context; // For constructor.
42354321

42364322
public:

llvm/lib/SandboxIR/SandboxIR.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2519,6 +2519,39 @@ void GlobalObject::setSection(StringRef S) {
25192519
cast<llvm::GlobalObject>(Val)->setSection(S);
25202520
}
25212521

2522+
template <typename GlobalT, typename LLVMGlobalT, typename ParentT,
2523+
typename LLVMParentT>
2524+
GlobalT &GlobalWithNodeAPI<GlobalT, LLVMGlobalT, ParentT, LLVMParentT>::
2525+
LLVMGVToGV::operator()(LLVMGlobalT &LLVMGV) const {
2526+
return cast<GlobalT>(*Ctx.getValue(&LLVMGV));
2527+
}
2528+
2529+
namespace llvm::sandboxir {
2530+
// Explicit instantiations.
2531+
template class GlobalWithNodeAPI<GlobalIFunc, llvm::GlobalIFunc, GlobalObject,
2532+
llvm::GlobalObject>;
2533+
template class GlobalWithNodeAPI<Function, llvm::Function, GlobalObject,
2534+
llvm::GlobalObject>;
2535+
} // namespace llvm::sandboxir
2536+
2537+
void GlobalIFunc::setResolver(Constant *Resolver) {
2538+
Ctx.getTracker()
2539+
.emplaceIfTracking<
2540+
GenericSetter<&GlobalIFunc::getResolver, &GlobalIFunc::setResolver>>(
2541+
this);
2542+
cast<llvm::GlobalIFunc>(Val)->setResolver(
2543+
cast<llvm::Constant>(Resolver->Val));
2544+
}
2545+
2546+
Constant *GlobalIFunc::getResolver() const {
2547+
return Ctx.getOrCreateConstant(cast<llvm::GlobalIFunc>(Val)->getResolver());
2548+
}
2549+
2550+
Function *GlobalIFunc::getResolverFunction() {
2551+
return cast<Function>(Ctx.getOrCreateConstant(
2552+
cast<llvm::GlobalIFunc>(Val)->getResolverFunction()));
2553+
}
2554+
25222555
void GlobalValue::setUnnamedAddr(UnnamedAddr V) {
25232556
Ctx.getTracker()
25242557
.emplaceIfTracking<GenericSetter<&GlobalValue::getUnnamedAddr,
@@ -2727,6 +2760,10 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
27272760
It->second = std::unique_ptr<Function>(
27282761
new Function(cast<llvm::Function>(C), *this));
27292762
break;
2763+
case llvm::Value::GlobalIFuncVal:
2764+
It->second = std::unique_ptr<GlobalIFunc>(
2765+
new GlobalIFunc(cast<llvm::GlobalIFunc>(C), *this));
2766+
break;
27302767
default:
27312768
It->second = std::unique_ptr<Constant>(new Constant(C, *this));
27322769
break;

llvm/unittests/SandboxIR/SandboxIRTest.cpp

Lines changed: 122 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,84 @@ define void @foo() {
859859
EXPECT_EQ(GO->canIncreaseAlignment(), LLVMGO->canIncreaseAlignment());
860860
}
861861

862+
TEST_F(SandboxIRTest, GlobalIFunc) {
863+
parseIR(C, R"IR(
864+
declare external void @bar()
865+
@ifunc0 = ifunc void(), ptr @foo
866+
@ifunc1 = ifunc void(), ptr @foo
867+
define void @foo() {
868+
call void @ifunc0()
869+
call void @ifunc1()
870+
call void @bar()
871+
ret void
872+
}
873+
)IR");
874+
Function &LLVMF = *M->getFunction("foo");
875+
auto *LLVMBB = &*LLVMF.begin();
876+
auto LLVMIt = LLVMBB->begin();
877+
auto *LLVMCall0 = cast<llvm::CallInst>(&*LLVMIt++);
878+
auto *LLVMIFunc0 = cast<llvm::GlobalIFunc>(LLVMCall0->getCalledOperand());
879+
880+
sandboxir::Context Ctx(C);
881+
882+
auto &F = *Ctx.createFunction(&LLVMF);
883+
auto *BB = &*F.begin();
884+
auto It = BB->begin();
885+
auto *Call0 = cast<sandboxir::CallInst>(&*It++);
886+
auto *Call1 = cast<sandboxir::CallInst>(&*It++);
887+
auto *CallBar = cast<sandboxir::CallInst>(&*It++);
888+
// Check classof(), creation.
889+
auto *IFunc0 = cast<sandboxir::GlobalIFunc>(Call0->getCalledOperand());
890+
auto *IFunc1 = cast<sandboxir::GlobalIFunc>(Call1->getCalledOperand());
891+
auto *Bar = cast<sandboxir::Function>(CallBar->getCalledOperand());
892+
893+
// Check getIterator().
894+
{
895+
auto It0 = IFunc0->getIterator();
896+
auto It1 = IFunc1->getIterator();
897+
EXPECT_EQ(&*It0, IFunc0);
898+
EXPECT_EQ(&*It1, IFunc1);
899+
EXPECT_EQ(std::next(It0), It1);
900+
EXPECT_EQ(std::prev(It1), It0);
901+
EXPECT_EQ(&*std::next(It0), IFunc1);
902+
EXPECT_EQ(&*std::prev(It1), IFunc0);
903+
}
904+
// Check getReverseIterator().
905+
{
906+
auto RevIt0 = IFunc0->getReverseIterator();
907+
auto RevIt1 = IFunc1->getReverseIterator();
908+
EXPECT_EQ(&*RevIt0, IFunc0);
909+
EXPECT_EQ(&*RevIt1, IFunc1);
910+
EXPECT_EQ(std::prev(RevIt0), RevIt1);
911+
EXPECT_EQ(std::next(RevIt1), RevIt0);
912+
EXPECT_EQ(&*std::prev(RevIt0), IFunc1);
913+
EXPECT_EQ(&*std::next(RevIt1), IFunc0);
914+
}
915+
916+
// Check setResolver(), getResolver().
917+
EXPECT_EQ(IFunc0->getResolver(), Ctx.getValue(LLVMIFunc0->getResolver()));
918+
auto *OrigResolver = IFunc0->getResolver();
919+
auto *NewResolver = Bar;
920+
EXPECT_NE(NewResolver, OrigResolver);
921+
IFunc0->setResolver(NewResolver);
922+
EXPECT_EQ(IFunc0->getResolver(), NewResolver);
923+
IFunc0->setResolver(OrigResolver);
924+
EXPECT_EQ(IFunc0->getResolver(), OrigResolver);
925+
// Check getResolverFunction().
926+
EXPECT_EQ(IFunc0->getResolverFunction(),
927+
Ctx.getValue(LLVMIFunc0->getResolverFunction()));
928+
// Check isValidLinkage().
929+
for (auto L :
930+
{GlobalValue::ExternalLinkage, GlobalValue::AvailableExternallyLinkage,
931+
GlobalValue::LinkOnceAnyLinkage, GlobalValue::LinkOnceODRLinkage,
932+
GlobalValue::WeakAnyLinkage, GlobalValue::WeakODRLinkage,
933+
GlobalValue::AppendingLinkage, GlobalValue::InternalLinkage,
934+
GlobalValue::PrivateLinkage, GlobalValue::ExternalWeakLinkage,
935+
GlobalValue::CommonLinkage}) {
936+
EXPECT_EQ(IFunc0->isValidLinkage(L), LLVMIFunc0->isValidLinkage(L));
937+
}
938+
}
939+
862940
TEST_F(SandboxIRTest, BlockAddress) {
863941
parseIR(C, R"IR(
864942
define void @foo(ptr %ptr) {
@@ -1200,29 +1278,58 @@ define void @foo(i8 %v) {
12001278

12011279
TEST_F(SandboxIRTest, Function) {
12021280
parseIR(C, R"IR(
1203-
define void @foo(i32 %arg0, i32 %arg1) {
1281+
define void @foo0(i32 %arg0, i32 %arg1) {
12041282
bb0:
12051283
br label %bb1
12061284
bb1:
12071285
ret void
12081286
}
1287+
define void @foo1() {
1288+
ret void
1289+
}
1290+
12091291
)IR");
1210-
llvm::Function *LLVMF = &*M->getFunction("foo");
1211-
llvm::Argument *LLVMArg0 = LLVMF->getArg(0);
1212-
llvm::Argument *LLVMArg1 = LLVMF->getArg(1);
1292+
llvm::Function *LLVMF0 = &*M->getFunction("foo0");
1293+
llvm::Function *LLVMF1 = &*M->getFunction("foo1");
1294+
llvm::Argument *LLVMArg0 = LLVMF0->getArg(0);
1295+
llvm::Argument *LLVMArg1 = LLVMF0->getArg(1);
12131296

12141297
sandboxir::Context Ctx(C);
1215-
sandboxir::Function *F = Ctx.createFunction(LLVMF);
1298+
sandboxir::Function *F0 = Ctx.createFunction(LLVMF0);
1299+
sandboxir::Function *F1 = Ctx.createFunction(LLVMF1);
1300+
1301+
// Check getIterator().
1302+
{
1303+
auto It0 = F0->getIterator();
1304+
auto It1 = F1->getIterator();
1305+
EXPECT_EQ(&*It0, F0);
1306+
EXPECT_EQ(&*It1, F1);
1307+
EXPECT_EQ(std::next(It0), It1);
1308+
EXPECT_EQ(std::prev(It1), It0);
1309+
EXPECT_EQ(&*std::next(It0), F1);
1310+
EXPECT_EQ(&*std::prev(It1), F0);
1311+
}
1312+
// Check getReverseIterator().
1313+
{
1314+
auto RevIt0 = F0->getReverseIterator();
1315+
auto RevIt1 = F1->getReverseIterator();
1316+
EXPECT_EQ(&*RevIt0, F0);
1317+
EXPECT_EQ(&*RevIt1, F1);
1318+
EXPECT_EQ(std::prev(RevIt0), RevIt1);
1319+
EXPECT_EQ(std::next(RevIt1), RevIt0);
1320+
EXPECT_EQ(&*std::prev(RevIt0), F1);
1321+
EXPECT_EQ(&*std::next(RevIt1), F0);
1322+
}
12161323

12171324
// Check F arguments
1218-
EXPECT_EQ(F->arg_size(), 2u);
1219-
EXPECT_FALSE(F->arg_empty());
1220-
EXPECT_EQ(F->getArg(0), Ctx.getValue(LLVMArg0));
1221-
EXPECT_EQ(F->getArg(1), Ctx.getValue(LLVMArg1));
1325+
EXPECT_EQ(F0->arg_size(), 2u);
1326+
EXPECT_FALSE(F0->arg_empty());
1327+
EXPECT_EQ(F0->getArg(0), Ctx.getValue(LLVMArg0));
1328+
EXPECT_EQ(F0->getArg(1), Ctx.getValue(LLVMArg1));
12221329

12231330
// Check F.begin(), F.end(), Function::iterator
1224-
llvm::BasicBlock *LLVMBB = &*LLVMF->begin();
1225-
for (sandboxir::BasicBlock &BB : *F) {
1331+
llvm::BasicBlock *LLVMBB = &*LLVMF0->begin();
1332+
for (sandboxir::BasicBlock &BB : *F0) {
12261333
EXPECT_EQ(&BB, Ctx.getValue(LLVMBB));
12271334
LLVMBB = LLVMBB->getNextNode();
12281335
}
@@ -1232,17 +1339,17 @@ define void @foo(i32 %arg0, i32 %arg1) {
12321339
// Check F.dumpNameAndArgs()
12331340
std::string Buff;
12341341
raw_string_ostream BS(Buff);
1235-
F->dumpNameAndArgs(BS);
1236-
EXPECT_EQ(Buff, "void @foo(i32 %arg0, i32 %arg1)");
1342+
F0->dumpNameAndArgs(BS);
1343+
EXPECT_EQ(Buff, "void @foo0(i32 %arg0, i32 %arg1)");
12371344
}
12381345
{
12391346
// Check F.dump()
12401347
std::string Buff;
12411348
raw_string_ostream BS(Buff);
12421349
BS << "\n";
1243-
F->dumpOS(BS);
1350+
F0->dumpOS(BS);
12441351
EXPECT_EQ(Buff, R"IR(
1245-
void @foo(i32 %arg0, i32 %arg1) {
1352+
void @foo0(i32 %arg0, i32 %arg1) {
12461353
bb0:
12471354
br label %bb1 ; SB4. (Br)
12481355

llvm/unittests/SandboxIR/TrackerTest.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,38 @@ define void @foo() {
15581558
EXPECT_EQ(GV->getVisibility(), OrigVisibility);
15591559
}
15601560

1561+
TEST_F(TrackerTest, GlobalIFuncSetters) {
1562+
parseIR(C, R"IR(
1563+
declare external void @bar()
1564+
@ifunc = ifunc void(), ptr @foo
1565+
define void @foo() {
1566+
call void @ifunc()
1567+
call void @bar()
1568+
ret void
1569+
}
1570+
)IR");
1571+
Function &LLVMF = *M->getFunction("foo");
1572+
sandboxir::Context Ctx(C);
1573+
1574+
auto &F = *Ctx.createFunction(&LLVMF);
1575+
auto *BB = &*F.begin();
1576+
auto It = BB->begin();
1577+
auto *Call0 = cast<sandboxir::CallInst>(&*It++);
1578+
auto *Call1 = cast<sandboxir::CallInst>(&*It++);
1579+
// Check classof(), creation.
1580+
auto *IFunc = cast<sandboxir::GlobalIFunc>(Call0->getCalledOperand());
1581+
auto *Bar = cast<sandboxir::Function>(Call1->getCalledOperand());
1582+
// Check setResolver().
1583+
auto *OrigResolver = IFunc->getResolver();
1584+
auto *NewResolver = Bar;
1585+
EXPECT_NE(NewResolver, OrigResolver);
1586+
Ctx.save();
1587+
IFunc->setResolver(NewResolver);
1588+
EXPECT_EQ(IFunc->getResolver(), NewResolver);
1589+
Ctx.revert();
1590+
EXPECT_EQ(IFunc->getResolver(), OrigResolver);
1591+
}
1592+
15611593
TEST_F(TrackerTest, SetVolatile) {
15621594
parseIR(C, R"IR(
15631595
define void @foo(ptr %arg0, i8 %val) {

0 commit comments

Comments
 (0)