LLVM:更改增量计数器以使用饱和增量

LLVM: changing increment counter to use saturating increment

Clang 有一个内置的(标记为实验性的)方法来添加简单的代码覆盖率计数器。只需使用 -fsanitize-coverage=inline-8bit-counters.

编译

不幸的是,计数器可以回绕,有时倒霉地归零,使它们不太值得信赖。我想将其更改为饱和计数器,但我对 LLVM 不是很熟悉。

目前,如果在 x86-64 上编译时没有优化,检测看起来像:

mov    al, [counter]
add    al, 1
mov    [counter], al

或者通过优化,可以得到

add    byte ptr [counter], 1

我想要的是:

add    byte ptr [counter], 1
sbb    byte ptr [counter], 0

或者至少我是这样写的。或者,也许单个加载和存储更快?

mov    al, [counter]
add    al, 1
sbb    al, 0
mov    [counter], al

不幸的是,我不太了解 LLVM,也不确定如何将其转换为 LLVM 工具。

Questions:
* It seems like I'd somehow need to tell it to subtract with flags, but how do I refer to the flags?
* Or is there an intrinsic saturating add?
* Or do I have to put in a conditional set to 0xff somehow and hope it is smart enough to optimize without putting in a conditional jump?

我觉得我什至不适合 LLVM "mindset",这些问题是离题的。因此,如果我的问题本身是 'wrong'.

,我将不胜感激

作为参考,这是当前 LLVM 工具的样子。

https://github.com/llvm-mirror/llvm/blob/master/lib/Transforms/Instrumentation/SanitizerCoverage.cpp

if (Options.Inline8bitCounters) {
  auto CounterPtr = IRB.CreateGEP(
      Function8bitCounterArray,
      {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
  auto Load = IRB.CreateLoad(CounterPtr);
  auto Inc = IRB.CreateAdd(Load, ConstantInt::get(Int8Ty, 1));
  auto Store = IRB.CreateStore(Inc, CounterPtr);
  SetNoSanitizeMetadata(Load);
  SetNoSanitizeMetadata(Store);
}

LLVM IR 没有标志,甚至没有变量。你想要的可能是在商店之前添加一个比较和一个 select 。 Compare Load against 255, then select either Load or Inc depending on the comparison,最后将select的结果存入CreateStore。

替换行

  auto Inc = IRB.CreateAdd(Load, ConstantInt::get(Int8Ty, 1));

  CallInst *AddOv = IRB.CreateBinaryIntrinsic(Intrinsic::uadd_with_overflow,
                       Load, ConstantInt::get(Int8Ty, 1));
  Value *SumWithOverflowBit = AddOv;
  auto Inc = IRB.CreateSub(
                IRB.CreateExtractValue(SumWithOverflowBit, 0),  /* sum */
                IRB.CreateZExt( /* convert from one bit type to 8 bits type */
                   IRB.CreateExtractValue(SumWithOverflowBit, 1) /* overflow */
                      , Int8Ty));
  SetNoSanitizeMetadata(AddOv);

这应该可以解决问题。