如果我试图创建一条指令并在函数的开头插入,这是正确的方法吗?因为当我使用opt加载时,我看不到插入的指令。所以归档并处理。ll文件。
if (auto* op = dyn_cast<Instruction>(&I))
{
if(prepend_first == false)
{
llvm::LLVMContext& context = I.getContext();
Value* lhs = ConstantInt::get(Type::getInt32Ty(context), 4);
Value* rhs = ConstantInt::get(Type::getInt32Ty(context), 6);
IRBuilder<> builder(op);
builder.CreateMul(lhs, rhs);
builder.SetInsertPoint(&I);
prepend_first = true;
}
}
编辑(2020年11月27日)这是整个通行证,这是基于其他文章以及。
using namespace llvm;
namespace
{
struct customllvm : public PassInfoMixin<customllvm>
{
llvm:PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
{
for(BasicBlock &BB : F)
{
bool prepend_first = false;
for(Instruction &I : BB)
{
if(auto *op = dyn_cast<Instruction>(&I))
{
if(prepend_first != true)
{
llvm::LLVMContext& context = I.getContext();
Value* lhs = ConstantInt::get(Type::getInt32Ty(context), 4);
Value* rhs = ConstantInt::get(Type::getInt32Ty(context), 6);
IRBuilder<> builder(op);
builder.CreateMul(lhs, rhs);
builder.SetInsertPoint(&I);
prepend_first = true;
}
}
}
}
}
}
}
2条答案
按热度按时间ut6juiuv1#
您需要先设置插入点。只有这样,才能创造奇迹。
idfiyjo82#
这既不是关于错误的插入,也不是优化未使用的指令。这是所有关于不断折叠。
它与
SetInsertPoint()
无关,因为**IRBuilder<> IRB(&I)
默认将新指令插入到指令I
之前。因此,在本例中,您甚至不需要显式设置插入点**。我将很快说明为什么它与删除未使用的指令无关,但我首先解释您的pass的另外两个问题:
for(BasicBlock &BB : F)
循环开始之前,只将prepend_first
设置为false
一次,这样当到达检查if
语句时,prepend_first
仅在第一个基本块中为false。但是,由于不必要的迭代,这种方法并不有趣。dyn_cast<Instruction>(&I)
检查强制转换是不需要。这个强制转换主要检查I
是否为Instruction
类型,显然这总是正确的。下面是我的
first_pass
,它的灵感来自您的代码,但没有上面解释的两个问题:注意,
first_pass
还没有将常数运算new_mul
插入输入IR。在解释常量折叠的根本原因之前,让我先做一个有趣的实验来证明你的问题并不源于删除未使用的代码。下面是我的
test.c
:下面是我用来生成
test.ll
的命令,它将作为输入IR:下面是生成的
test.ll
:下面是我的
second_pass
,它与我的first_pass
相同,不同之处在于它在创建的第二条指令new_add
中使用new_mul
的结果,因此这次将使用new_mul
。new_add
应该被插入到输入IR的第二个指令之前:我运行了
test.ll
到second_pass
,得到了这个结果IR:正如我们所看到的,虽然这次使用了
new_mul
,但它没有插入到结果IR中。更有趣的是,new_add
被成功地插入到结果IR中,尽管它没有被使用。所以很明显,优化未使用的代码不能成为不生成new_mul
的原因。回到我的主要观点:不断折叠!
常量折叠是一种编译器优化,其中常量操作在编译时进行评估,而不是在运行时计算它们。换句话说,编译器不会为常量操作生成代码,并且如果该操作的结果稍后被使用,编译器只使用其值来代替。
在您的示例中,您尝试创建的新指令(
new_mul
)是一个常量操作,因为它的两个参数都是常量(4和6)。因此,在存在常量折叠的情况下,编译器不会为其生成代码,并且如果稍后使用它(如new_add
或second_pass
),编译器将使用其值(4 * 6 = 24)。非常重要的是要知道**
IRBuilder
执行常量折叠,除非另有明确指定折叠类型。换句话说,如果我们希望编译器不执行常量折叠,我们必须使用IRBuilder<llvm::NoFolder>
而不是IRBuilder<>
。**最后,这里是我的
third_pass
,它与我的first_pass
相同,不同之处在于它使用IRBuilder<llvm::NoFolder>
而不是IRBuilder<>
来创建常量操作new_mul
:现在,如果我运行
test.ll
到third_pass
,我会得到这个结果IR:正如我们所看到的,
new_mul
被插入到函数的开头。