5

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().

4
  • Can you include what you used to initialize instr_exe_gv so others don’t have to search it up? Commented Jan 11, 2018 at 20:29
  • llvm::Instruction *instr_exe_gv = llvm::dyn_cast<llvm::Instruction>(user_of_load); Commented Jan 12, 2018 at 5:30
  • That doesn't look right. The dyn_cast type isn't a pointer like the variable's type is. Can you update your answer with a complete, minimal example that others can compile and execute? Commented Jan 12, 2018 at 5:38
  • Sorry for the unclear code. I have updated the code and the example above. Commented Jan 12, 2018 at 6:53

1 Answer 1

1

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..

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! It works like a charm. In addition to the improper using of iterator, I think that I shouldn't use the float value converted from APFloat to construct a Constant object because of the data type conversion in C++. Is that correct ?
Great ! .. Have a look at the precision, if it the value change from the value you specify in the source code, maybe you can try something else, I haven't try other way of converting from APFloat. Let me know if you find some better way!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.