in lib/BPFCov.cpp [166:426]
bool convertStructs(Module &M)
{
bool Changed = false;
auto &CTX = M.getContext();
SmallVector<GlobalVariable *, 8> ToDelete;
auto CountersSizeAcc = 0;
for (auto gv_iter = M.global_begin(); gv_iter != M.global_end(); gv_iter++)
{
GlobalVariable *GV = &*gv_iter;
if (GV->hasName())
{
auto Name = GV->getName();
if (Name.startswith("__profd") && GV->getValueType()->isStructTy())
{
errs() << "converting " << Name << " struct to globals\n";
// Translate the function ID to a global scalar
ConstantInt *C0 = dyn_cast<ConstantInt>(GV->getInitializer()->getOperand(0));
if (!C0)
{
// TODO(leodido) > bail out
errs() << Name << ": cast failed\n";
}
auto Ty = C0->getType();
if (!Ty->isIntegerTy(64))
{
// TODO(leodido) > bail out
errs() << Name << ": wrong type bandwidth\n";
}
auto *GV0 = new GlobalVariable(
M,
/*Ty=*/Ty,
/*isConstant=*/true,
/*Linkage=*/GlobalVariable::ExternalLinkage,
/*Initializer=*/ConstantInt::get(Ty, C0->getSExtValue(), true),
/*Name=*/Name + ".0",
/*InsertBefore=*/GV);
GV0->setDSOLocal(true);
GV0->setAlignment(MaybeAlign(8));
GV0->setSection(GV->getSection());
appendToUsed(M, GV0);
Changed = true;
// Translate the function hash to a global scalar
ConstantInt *C1 = dyn_cast<ConstantInt>(GV->getInitializer()->getOperand(1));
if (!C1)
{
// TODO(leodido) > bail out
errs() << Name << ": cast failed\n";
}
auto Ty1 = C1->getType();
if (!Ty1->isIntegerTy(64))
{
// TODO(leodido) > bail out
errs() << Name << ": wrong type bandwidth\n";
}
auto *GV1 = new GlobalVariable(
M,
/*Ty=*/Ty1,
/*isConstant=*/true,
/*Linkage=*/GlobalVariable::ExternalLinkage,
/*Initializer=*/ConstantInt::get(Ty1, C1->getSExtValue(), true),
/*Name=*/Name + ".1",
/*InsertBefore=*/GV);
GV1->setDSOLocal(true);
GV1->setAlignment(MaybeAlign(8));
GV1->setSection(GV->getSection());
appendToUsed(M, GV1);
// Get the number of counters for current __profd_*
ConstantInt *C5 = dyn_cast<ConstantInt>(GV->getInitializer()->getOperand(5));
if (!C5)
{
// TODO(leodido) > bail out
errs() << Name << ": cast failed\n";
}
auto Ty5 = C5->getType();
if (!Ty5->isIntegerTy(32))
{
// TODO(leodido) > bail out
errs() << Name << ": wrong type bandwidth\n";
}
auto NumCounters = C5->getSExtValue();
// Translate the address of the counter to a global scalar containing the relative offset
auto *GV2 = new GlobalVariable(
M,
/*Ty=*/Ty1,
/*isConstant=*/true,
/*Linkage=*/GlobalVariable::ExternalLinkage,
/*Initializer=*/ConstantInt::get(Ty1, CountersSizeAcc, true),
/*Name=*/Name + ".2",
/*InsertBefore=*/GV);
GV2->setDSOLocal(true);
GV2->setAlignment(MaybeAlign(8));
GV2->setSection(GV->getSection());
appendToUsed(M, GV2);
// Increment the counter offset for the next __profd_*
CountersSizeAcc += NumCounters * 8;
// Create fake (zero) global scalars for 4th and 5th field of __profd_* structs
auto *GV3 = new GlobalVariable(
M,
/*Ty=*/Ty1,
/*isConstant=*/true,
/*Linkage=*/GlobalVariable::ExternalLinkage,
/*Initializer=*/ConstantInt::get(Ty1, 0, true), // TODO > we want this or zeroinitializer?
/*Name=*/Name + ".3",
/*InsertBefore=*/GV);
GV3->setDSOLocal(true);
GV3->setAlignment(MaybeAlign(8));
GV3->setSection(GV->getSection());
appendToUsed(M, GV3);
auto *GV4 = new GlobalVariable(
M,
/*Ty=*/Ty1,
/*isConstant=*/true,
/*Linkage=*/GlobalVariable::ExternalLinkage,
/*Initializer=*/ConstantInt::get(Ty1, 0, true), // TODO > we want this or zeroinitializer?
/*Name=*/Name + ".4",
/*InsertBefore=*/GV);
GV4->setDSOLocal(true);
GV4->setAlignment(MaybeAlign(8));
GV4->setSection(GV->getSection());
appendToUsed(M, GV4);
// Translate the number of counters (that this data refers to) to a global scalar
auto NumCountersC = ConstantInt::get(Ty5, NumCounters, true);
auto *GV5 = new GlobalVariable(
M,
/*Ty=*/Ty5,
/*isConstant=*/true,
/*Linkage=*/GlobalVariable::ExternalLinkage,
/*Initializer=*/NumCountersC,
/*Name=*/Name + ".5",
/*InsertBefore=*/GV);
GV5->setDSOLocal(true);
GV5->setAlignment(MaybeAlign(4));
GV5->setSection(GV->getSection());
appendToUsed(M, GV5);
// Translate the value sites [2 x i16] into a single i32
auto *GV6 = new GlobalVariable(
M,
/*Ty=*/Ty5,
/*isConstant=*/true,
/*Linkage=*/GlobalVariable::ExternalLinkage,
/*Initializer=*/ConstantInt::get(Ty5, 0, true), // TODO > obtain from the array values
/*Name=*/Name + ".6",
/*InsertBefore=*/GV);
GV6->setDSOLocal(true);
GV6->setAlignment(MaybeAlign(4));
GV6->setSection(GV->getSection());
appendToUsed(M, GV6);
ToDelete.push_back(GV);
}
else if (Name.startswith("__covrec") && GV->getValueType()->isStructTy())
{
ToDelete.push_back(GV);
}
else if (Name.startswith("__llvm_coverage") && GV->getValueType()->isStructTy())
{
errs() << "converting " << Name << " struct to globals\n";
ConstantStruct *C0 = dyn_cast<ConstantStruct>(GV->getInitializer()->getOperand(0));
if (!C0)
{
// TODO(leodido) > bail out
errs() << Name << ": cast failed\n";
}
auto Ty0 = C0->getType();
if (!Ty0->isStructTy())
{
// TODO(leodido) > bail out
errs() << Name << ": wrong type\n";
}
SmallVector<Constant *, 8> Vals;
for (unsigned int i = 0; i < C0->getNumOperands(); i++)
{
ConstantInt *C = dyn_cast<ConstantInt>(C0->getOperand(i));
if (!C)
{
// TODO(leodido) > bail out
errs() << Name << ": cast failed\n";
}
if (!C->getType()->isIntegerTy(32))
{
// TODO(leodido) > bail out
errs() << Name << ": wrong type\n";
}
Vals.push_back(C);
}
ArrayType *ATy = ArrayType::get(Type::getInt32Ty(CTX), Vals.size());
auto *GV0 = new GlobalVariable(
M,
/*Ty=*/ATy,
/*isConstant=*/true,
/*Linkage=*/GlobalVariable::ExternalLinkage,
/*Initializer=*/ConstantArray::get(ATy, Vals),
/*Name=*/Name + ".0",
/*InsertBefore=*/GV);
GV0->setDSOLocal(true);
GV0->setSection(GV->getSection());
GV0->setAlignment(MaybeAlign(4));
Changed = true;
appendToUsed(M, GV0);
ConstantDataArray *C1 = dyn_cast<ConstantDataArray>(GV->getInitializer()->getOperand(1));
if (!C1)
{
// TODO(leodido) > bail out
errs() << Name << ": cast failed\n";
}
auto Ty1 = C1->getType();
if (!Ty1->isArrayTy())
{
// TODO(leodido) > bail out
errs() << Name << ": wrong type\n";
}
auto *GV1 = new GlobalVariable(
M,
/*Ty=*/Ty1,
/*isConstant=*/true,
/*Linkage=*/GlobalVariable::ExternalLinkage,
/*Initializer=*/ConstantDataArray::getString(CTX, C1->getRawDataValues(), false),
/*Name=*/Name + ".1",
/*InsertBefore=*/GV);
GV1->setDSOLocal(true);
GV1->setAlignment(MaybeAlign(1));
GV1->setSection(GV->getSection());
appendToUsed(M, GV1);
ToDelete.push_back(GV);
}
}
}
for (auto *GV : ToDelete)
{
errs() << "erasing " << GV->getName() << "\n";
GV->eraseFromParent();
}
return Changed;
}