|
38 | 38 | #include "llvm/IR/Instruction.h"
|
39 | 39 | #include "llvm/IR/Instructions.h"
|
40 | 40 | #include "llvm/IR/IntrinsicInst.h"
|
| 41 | +#include "llvm/IR/MDBuilder.h" |
41 | 42 | #include "llvm/IR/Module.h"
|
42 | 43 | #include "llvm/IR/Type.h"
|
43 | 44 | #include "llvm/InitializePasses.h"
|
@@ -237,6 +238,10 @@ class InstrLowerer final {
|
237 | 238 | GlobalVariable *NamesVar = nullptr;
|
238 | 239 | size_t NamesSize = 0;
|
239 | 240 |
|
| 241 | + /// The instance of [[forceinline]] rmw_or(ptr, i8). |
| 242 | + /// This is name-insensitive. |
| 243 | + Function *RMWOrFunc = nullptr; |
| 244 | + |
240 | 245 | // vector of counter load/store pairs to be register promoted.
|
241 | 246 | std::vector<LoadStorePair> PromotionCandidates;
|
242 | 247 |
|
@@ -297,6 +302,14 @@ class InstrLowerer final {
|
297 | 302 | StringRef Name,
|
298 | 303 | GlobalValue::LinkageTypes Linkage);
|
299 | 304 |
|
| 305 | + /// Create [[forceinline]] rmw_or(ptr, i8). |
| 306 | + /// This doesn't update `RMWOrFunc`. |
| 307 | + Function *createRMWOrFunc(); |
| 308 | + |
| 309 | + /// Get the call to `rmw_or`. |
| 310 | + /// Create the instance if it is unknown. |
| 311 | + CallInst *getRMWOrCall(Value *Addr, Value *Val); |
| 312 | + |
300 | 313 | /// Compute the address of the test vector bitmap that this profiling
|
301 | 314 | /// instruction acts on.
|
302 | 315 | Value *getBitmapAddress(InstrProfMCDCTVBitmapUpdate *I);
|
@@ -937,6 +950,67 @@ Value *InstrLowerer::getCounterAddress(InstrProfCntrInstBase *I) {
|
937 | 950 | return Builder.CreateIntToPtr(Add, Addr->getType());
|
938 | 951 | }
|
939 | 952 |
|
| 953 | +Function *InstrLowerer::createRMWOrFunc() { |
| 954 | + auto &Ctx = M.getContext(); |
| 955 | + auto *Int8Ty = Type::getInt8Ty(Ctx); |
| 956 | + // void alwaysinline rmw_or(ptr, i8) |
| 957 | + Function *Fn = Function::Create( |
| 958 | + FunctionType::get(Type::getVoidTy(Ctx), |
| 959 | + {PointerType::getUnqual(Ctx), Int8Ty}, false), |
| 960 | + Function::LinkageTypes::PrivateLinkage, "rmw_or", M); |
| 961 | + Fn->addFnAttr(Attribute::AlwaysInline); |
| 962 | + auto *ArgAddr = Fn->getArg(0); |
| 963 | + auto *ArgVal = Fn->getArg(1); |
| 964 | + IRBuilder<> Builder(BasicBlock::Create(Ctx, "", Fn)); |
| 965 | + |
| 966 | + // Load profile bitmap byte. |
| 967 | + // %mcdc.bits = load i8, ptr %4, align 1 |
| 968 | + auto *Bitmap = Builder.CreateLoad(Int8Ty, ArgAddr, "mcdc.bits"); |
| 969 | + |
| 970 | + if (Options.Atomic || AtomicCounterUpdateAll) { |
| 971 | + // If ((Bitmap & Val) != Val), then execute atomic (Bitmap |= Val). |
| 972 | + // Note, just-loaded Bitmap might not be up-to-date. Use it just for |
| 973 | + // early testing. |
| 974 | + auto *Masked = Builder.CreateAnd(Bitmap, ArgVal); |
| 975 | + auto *ShouldStore = Builder.CreateICmpNE(Masked, ArgVal); |
| 976 | + auto *ThenTerm = BasicBlock::Create(Ctx, "", Fn); |
| 977 | + auto *ElseTerm = BasicBlock::Create(Ctx, "", Fn); |
| 978 | + // Assume updating will be rare. |
| 979 | + auto *Unlikely = MDBuilder(Ctx).createUnlikelyBranchWeights(); |
| 980 | + Builder.CreateCondBr(ShouldStore, ThenTerm, ElseTerm, Unlikely); |
| 981 | + |
| 982 | + IRBuilder<> ThenBuilder(ThenTerm); |
| 983 | + ThenBuilder.CreateAtomicRMW(AtomicRMWInst::Or, ArgAddr, ArgVal, |
| 984 | + MaybeAlign(), AtomicOrdering::Monotonic); |
| 985 | + ThenBuilder.CreateRetVoid(); |
| 986 | + |
| 987 | + IRBuilder<> ElseBuilder(ElseTerm); |
| 988 | + ElseBuilder.CreateRetVoid(); |
| 989 | + |
| 990 | + return Fn; |
| 991 | + } |
| 992 | + |
| 993 | + // Perform logical OR of profile bitmap byte and shifted bit offset. |
| 994 | + // %8 = or i8 %mcdc.bits, %7 |
| 995 | + auto *Result = Builder.CreateOr(Bitmap, ArgVal); |
| 996 | + |
| 997 | + // Store the updated profile bitmap byte. |
| 998 | + // store i8 %8, ptr %3, align 1 |
| 999 | + Builder.CreateStore(Result, ArgAddr); |
| 1000 | + |
| 1001 | + // Terminator |
| 1002 | + Builder.CreateRetVoid(); |
| 1003 | + |
| 1004 | + return Fn; |
| 1005 | +} |
| 1006 | + |
| 1007 | +CallInst *InstrLowerer::getRMWOrCall(Value *Addr, Value *Val) { |
| 1008 | + if (!RMWOrFunc) |
| 1009 | + RMWOrFunc = createRMWOrFunc(); |
| 1010 | + |
| 1011 | + return CallInst::Create(RMWOrFunc, {Addr, Val}); |
| 1012 | +} |
| 1013 | + |
940 | 1014 | Value *InstrLowerer::getBitmapAddress(InstrProfMCDCTVBitmapUpdate *I) {
|
941 | 1015 | auto *Bitmaps = getOrCreateRegionBitmaps(I);
|
942 | 1016 | IRBuilder<> Builder(I);
|
@@ -1044,17 +1118,7 @@ void InstrLowerer::lowerMCDCTestVectorBitmapUpdate(
|
1044 | 1118 | // %7 = shl i8 1, %6
|
1045 | 1119 | auto *ShiftedVal = Builder.CreateShl(Builder.getInt8(0x1), BitToSet);
|
1046 | 1120 |
|
1047 |
| - // Load profile bitmap byte. |
1048 |
| - // %mcdc.bits = load i8, ptr %4, align 1 |
1049 |
| - auto *Bitmap = Builder.CreateLoad(Int8Ty, BitmapByteAddr, "mcdc.bits"); |
1050 |
| - |
1051 |
| - // Perform logical OR of profile bitmap byte and shifted bit offset. |
1052 |
| - // %8 = or i8 %mcdc.bits, %7 |
1053 |
| - auto *Result = Builder.CreateOr(Bitmap, ShiftedVal); |
1054 |
| - |
1055 |
| - // Store the updated profile bitmap byte. |
1056 |
| - // store i8 %8, ptr %3, align 1 |
1057 |
| - Builder.CreateStore(Result, BitmapByteAddr); |
| 1121 | + Builder.Insert(getRMWOrCall(BitmapByteAddr, ShiftedVal)); |
1058 | 1122 | Update->eraseFromParent();
|
1059 | 1123 | }
|
1060 | 1124 |
|
|
0 commit comments