在研究ReassociatePass的优化时,我发现了其中有一个函数bool llvm::mayHaveNonDefUseDependency(const Instruction &I) {,这个函数会判断一个指令是否是不可优化的,也即是否是可能会造成NonDefUseDependency的。
潜在的非定义使用依赖关系指的是在程序中,某个指令使用了另一个指令产生的值,但两者之间的关系不是经过明确定义的。这可能导致程序在并行执行或重排序时出现问题,因为执行顺序的改变可能会影响到数据的正确性。
这种所谓的没有经过明确定义的,也即没有通过限制指令标记两个指令之间是不可移动或不可并行的,但两个指令之间有明显的先后关系,如果并行可能会出现某种失败的情况。
一个例子
#include <iostream>
#include <omp.h>
int main() {
int x = 0;
#pragma omp parallel
{
#pragma omp for
for(int i = 0; i < 100; ++i)
x = x + 1;
}
std::cout << x << std::endl;
}
omp.h头文件主要是将#pragma omp编译为openmp代码。运行指令如下:
clang -fopenmp source -o target
mayHaveNonDefUseDependency
bool llvm::mayHaveNonDefUseDependency(const Instruction &I) {
if (I.mayReadOrWriteMemory())
// Memory dependency possible
return true;
if (!isSafeToSpeculativelyExecute(&I))
// Can't move above a maythrow call or infinite loop. Or if an
// inalloca alloca, above a stacksave call.
return true;
if (!isGuaranteedToTransferExecutionToSuccessor(&I))
// 1) Can't reorder two inf-loop calls, even if readonly
// 2) Also can't reorder an inf-loop call below a instruction which isn't
// safe to speculative execute. (Inverse of above)
return true;
return false;
}
- 首先判断是否读写内存,常见的例如Load Store指令,Call, Invoke指令。
- 判断是否是safeToSpeculativelyExecute,此处指的是不能安全的推断执行的指令。能够推测执行的指令,例如如果除数为0,则会返回false,也即mayHaveNonDefUseDependency会返回true.
- 判断GuaranteedtoTransferExecutionToSuccessor,该函数用于判断一个指令是否可以将控制流转移到指令后。如果是Return指令或不可达指令,显然会返回false。如果是CatchPad指令,需要判断。最后判断指令是否mayThrow或者willReturn,如果不满足mayThro且willReturn,就会返回true.
bool llvm::isGuaranteedToTransferExecutionToSuccessor(const Instruction *I) {
// Note: An atomic operation isn't guaranteed to return in a reasonable amount
// of time because it's possible for another thread to interfere with it for an
// arbitrary length of time, but programs aren't allowed to rely on that.
// If there is no successor, then execution can't transfer to it.
if (isa<ReturnInst>(I))
return false;
if (isa<UnreachableInst>(I))
return false;
// Note: Do not add new checks here; instead, change Instruction::mayThrow or
// Instruction::willReturn.
//
// FIXME: Move this check into Instruction::willReturn.
if (isa<CatchPadInst>(I)) {
switch (classifyEHPersonality(I->getFunction()->getPersonalityFn())) {
default:
// A catchpad may invoke exception object constructors and such, which
// in some languages can be arbitrary code, so be conservative by default.
return false;
case EHPersonality::CoreCLR:
// For CoreCLR, it just involves a type test.
return true;
}
}
// An instruction that returns without throwing must transfer control flow
// to a successor.
return !I->mayThrow() && I->willReturn();
}
我编译的clang暂时不支持openmp,故此处不测试。