如何获取 LLVM 全局变量常量值?
Posted
技术标签:
【中文标题】如何获取 LLVM 全局变量常量值?【英文标题】:How to get LLVM global variable constant value? 【发布时间】:2018-01-11 17:02:43 【问题描述】:我正在尝试从全局变量中获取浮点值并将其设置为指令的操作数。
这是我想做的:
@a = private constant float 0x3FB99999A0000000
...
%1 = load float, float* @a ---> removed
%3 = fmul fast %1, %2 ---> %3 = fmul fast float 0x3FB99999A0000000, %2
以下是我迄今为止尝试过的:
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();
但是,当我尝试运行我的代码时,它会导致分段错误。
我确定我已经访问了我想要的全局变量和指令 通过打印
的值gv_fpval
是 0.1
因为 0x3FB99999A0000000 等于 0.10000000149011612 in double
精度。程序似乎在setOperand()
崩溃。
【问题讨论】:
你能把你用来初始化instr_exe_gv
的东西包括进来,这样其他人就不必搜索了吗?
llvm::Instruction *instr_exe_gv = llvm::dyn_cast<llvm::Instruction>(user_of_load);
看起来不太对劲。 dyn_cast
类型不像变量的类型那样是指针。您可以使用其他人可以编译和执行的complete, minimal example 更新您的答案吗?
抱歉代码不清楚。我已经更新了上面的代码和示例。
【参考方案1】:
考虑以下示例
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;
模块传递将循环浮点全局变量,程序中的任何使用都将替换为常量 FP 值。 LLVM pass 如下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;
/* *** : https://***.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);
关键点:-
在对指令进行任何修改之前。在工作清单中先收集。
对工作清单进行修改。
在使用迭代器时不能进行修改。
我在上面的源代码hello.cpp
上测试成功,通过后对应的IR如下:-
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
也许使用 -O3 优化标志会消灭一切......
希望这会有所帮助..
【讨论】:
谢谢!它就像一个魅力。除了迭代器使用不当之外,由于C++中的数据类型转换,我认为我不应该使用从APFloat
转换而来的浮点值来构造Constant
对象。对吗?
太棒了! .. 看看精度,如果它的值与您在源代码中指定的值发生变化,也许您可以尝试其他方法,我没有尝试从 APFloat 转换的其他方式。如果您找到更好的方法,请告诉我!以上是关于如何获取 LLVM 全局变量常量值?的主要内容,如果未能解决你的问题,请参考以下文章