Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get LLVM global variable constant value?

I'm trying to get the float value from a global variable and set it as an instruction's operand.

Here is what I want to do:

@a = private constant float 0x3FB99999A0000000

...
%1 = load float, float* @a ---> removed

%3 = fmul fast %1, %2  ---> %3 = fmul fast float 0x3FB99999A0000000, %2

Below is what I haved tried so far:

for (auto gv_iter = llvm_module.global_begin();gv_iter != llvm_module.global_end(); gv_iter++){ 

    llvm::GlobalVariable* gv = &*gv_iter;

    for(auto user_of_gv : gv->users()){

        llvm::Instruction *instr_ld_gv = llvm::dyn_cast<llvm::Instruction>(user_of_gv);
        llvm::Value *val_gv = llvm::cast<llvm::Value>(instr_ld_gv);

        llvm::Constant *const_gv = gv->getInitializer();    
        llvm::ConstantFP *constfp_gv = llvm::dyn_cast<llvm::ConstantFP>(const_gv);
        float gv_fpval = (constfp_gv->getValueAPF()).convertToFloat(); 

        llvm::Constant *const_gv_opd = llvm::ConstantFP::get(llvm::Type::getFloatTy(llvm_context),gv_fpval); 

        for(auto user_of_load : val_gv->users()){ 

            llvm::Instruction *instr_exe_gv = llvm::dyn_cast<llvm::Instruction>(user_of_load);

            //P
            for(int operand_num = 0;operand_num < instr_exe_gv->getNumOperands();operand_num++){ 

                llvm::Value *val_instr_op =  instr_exe_gv->getOperand(operand_num);

                if(val_instr_op == val_gv){

                    instr_exe_gv->setOperand(operand_num,const_gv_opd);
                    instr_ld_gv->removeFromParent();

                }            
            }
        }
    }
}

However, it'll cause segmentation fault when I tried to run my code.

I'm sure that I have accessed the global variable and instruction I wanted by printing the value of

gv_fpval which is 0.1 because 0x3FB99999A0000000 equals 0.10000000149011612 in double

precision. It seems that the program crashes at setOperand().

like image 241
蘇郁翔 Avatar asked Nov 07 '22 12:11

蘇郁翔


1 Answers

Consider the following example

hello.cpp

 #include <stdio.h>
// Global Constant value
float a=1.4f;

float Multiply(){
    float b=2.2f;
    float c=4.32f;
    float d= a*c;
    return d;
}

int main(int argc, char const *argv[])
{

    printf("%f\n",Multiply());

    return 0;
}

The module pass will loop for Floating point global variable and any use in the program will be replaced by the constant FP value. The LLVM pass are as follow ConstantReplacementPass.cpp:-

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DebugInfo.h"
using namespace llvm;

/* StackOverflow : https://stackoverflow.com/questions/48212351/how-to-get-llvm-global-variable-constant-value* /
/**Bernard Nongpoh */

namespace {
    class ConstantReplacementPass : public ModulePass {


    public:
        static char ID;


        ConstantReplacementPass() : ModulePass(ID) {
            srand (time(NULL));
        }

        virtual bool runOnModule(Module &M) {

            // list to collect instruction
            /*
             * You cannot change an iterator while iterating over it
            • To remove instructions or modify, first collect the instructions to remove/modify
            •
             *
             * **/
            // This are the list of load to delete
            SmallVector<Instruction*,128> *WorkListLoad=new SmallVector<Instruction*,128>();
            // This is the list of instruction to modify the source operand
            SmallVector<Instruction*,128> *WorkListUserOfLoad=new SmallVector<Instruction*,128>();


            for (auto gv_iter = M.global_begin();gv_iter != M.global_end(); gv_iter++) {
                   /* GLOBAL DATA INFO*/
                    GlobalVariable *gv = &*gv_iter;
                    Constant *const_gv = gv->getInitializer();
                    ConstantFP *Fvalue;
                    if(!const_gv->isNullValue()) {

                        if (ConstantFP *constfp_gv = llvm::dyn_cast<llvm::ConstantFP>(const_gv)) {
                            float gv_fpval = (constfp_gv->getValueAPF()).convertToFloat();
                            Fvalue = constfp_gv;
                            errs() << gv_fpval; // Value retrieved here
                            // Collect Instruction to modify


                        }

                        for (auto user_of_gv: gv->users()) {
                            // Collect in a worklist
                            if (llvm::Instruction *instr_ld_gv = llvm::dyn_cast<Instruction>(user_of_gv)) {

                                if (LoadInst *loadInst = dyn_cast<LoadInst>(instr_ld_gv)) {

                                    WorkListLoad->push_back(loadInst);
                                    for (auto user_of_load:loadInst->users()) {
                                        user_of_load->dump();
                                        Instruction *instruction1 = dyn_cast<Instruction>(user_of_load);
                                        instruction1->dump();
                                        //instruction1->setOperand(0, Fvalue);
                                        //instruction1->dump();
                                        // if(Instruction *instruction1 = dyn_cast<Instruction>(user_of_load))
                                        WorkListUserOfLoad->push_back(instruction1);
                                        //instruction1->setOperand(0, Fvalue);
                                        //instruction1->dump();
                                    }

                                }
                            }
                        }


                    // Modify Here
                        while (!WorkListUserOfLoad->empty()) {
                            Instruction *instruction = WorkListUserOfLoad->pop_back_val();
                            instruction->setOperand(0, Fvalue);
                            instruction->dump();
                        }

                        // Removing all loads that are used by the global variable
                        while (!WorkListLoad->empty()) {
                            Instruction *instruction = WorkListLoad->pop_back_val();
                            instruction->eraseFromParent();
                        }



                    }
                }








             return true;
    }
  };
}

char ConstantReplacementPass::ID = 0;


static RegisterPass<ConstantReplacementPass> F0("constantREP", "Constant Replacement Pass "
                                         , false,true);

Key points:-

  1. Before doing any modification on the instruction. Collect first in the worklist.

  2. perform the modification on the worklist.

  3. you cannot do the modification while using the iterator.

I successfully tested on the above source code hello.cpp the corresponding IR after the pass is as follow:-

entry:
%b = alloca float, align 4
%c = alloca float, align 4
%d = alloca float, align 4
call void @llvm.dbg.declare(metadata float* %b, metadata !14, metadata !15),
... !dbg !16
store float 0x40019999A0000000, float* %b, align 4, !dbg !16
call void @llvm.dbg.declare(metadata float* %c, metadata !17, metadata !15),
... !dbg !18
store float 0x401147AE20000000, float* %c, align 4, !dbg !18
call void @llvm.dbg.declare(metadata float* %d, metadata !19, metadata !15),
... !dbg !20
%0 = load float, float* %c, align 4, !dbg !21
%mul = fmul float 0x3FF6666660000000, %0, !dbg !22
store float %mul, float* %d, align 4, !dbg !20
%1 = load float, float* %d, align 4, !dbg !23
ret float %1, !dbg !24

Maybe using -O3 optimization flag will wipe out everything...

Hope this helps..

like image 187
Bernard Nongpoh Avatar answered Nov 14 '22 22:11

Bernard Nongpoh