Reputation: 329
Clang has a built-in (marked experimental) method for adding simple code coverage counters. Just compile with -fsanitize-coverage=inline-8bit-counters
.
Unfortunately the counters can wrap, sometimes unluckily to zero, making them not very trustworthy. I would like to change this to saturating counters, but I'm not very familiar with LLVM.
Currently, if compiling without optimization on x86-64, the instrumentation looks like:
mov al, [counter]
add al, 1
mov [counter], al
or with optimization, it is able to obtain
add byte ptr [counter], 1
What I'd like is for something like:
add byte ptr [counter], 1
sbb byte ptr [counter], 0
Or at least that is how I'd write it. Or maybe a single load and store is faster?
mov al, [counter]
add al, 1
sbb al, 0
mov [counter], al
Unfortunately I don't really understand LLVM, and am unsure how to translate this to LLVM instrumentation.
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?
I have a feeling I'm not even in the right "mindset" for LLVM, and these questions are off base. So I'd appreciate redirection if my questions themselves are 'wrong'.
For reference, here is what the current LLVM instrumentation looks like.
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);
}
Upvotes: 2
Views: 375
Reputation: 1220
replace the line
auto Inc = IRB.CreateAdd(Load, ConstantInt::get(Int8Ty, 1));
with
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);
That should do the trick.
Upvotes: 3
Reputation: 9675
LLVM IR doesn't have flags, or even variables. What you want is probably do add a comparison and a select before the store. Compare Load
against 255, then select
either Load
or Inc
depending on the comparison, finally store the result of the select
in the CreateStore.
Upvotes: 2