bool convertStructs()

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;
    }