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);
这应该可以解决问题。
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);
这应该可以解决问题。