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

时间:2018-07-16 18:50:02

标签: x86 llvm instrumentation llvm-clang

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工具。

  

问题:
   *似乎我需要以某种方式告诉它用标志减去,但是如何引用标志?
   *还是存在固有的饱和添加?
   *还是我必须以某种方式将条件集设置为0xff,并希望它足够聪明以进行优化而无需添加条件跳转?

我觉得我对LLVM甚至还没有正确的“心态”,而这些问题是毫无根据的。因此,如果我的问题本身是“错误的”,我将不胜感激。


作为参考,这是当前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);
}

2 个答案:

答案 0 :(得分:2)

替换行

  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);

应该可以解决问题。

答案 1 :(得分:1)

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