-
Notifications
You must be signed in to change notification settings - Fork 15.6k
[profcheck] Fix profile metadata in IntegerDivision/ExpandIRinsts #173114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,13 +16,22 @@ | |
| #include "llvm/Transforms/Utils/IntegerDivision.h" | ||
| #include "llvm/IR/Function.h" | ||
| #include "llvm/IR/IRBuilder.h" | ||
| #include "llvm/IR/Instruction.h" | ||
| #include "llvm/IR/Instructions.h" | ||
| #include "llvm/IR/Intrinsics.h" | ||
| #include "llvm/IR/MDBuilder.h" | ||
| #include "llvm/IR/ProfDataUtils.h" | ||
| #include "llvm/Support/Casting.h" | ||
| #include "llvm/Support/CommandLine.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "integer-division" | ||
|
|
||
| namespace llvm { | ||
| extern cl::opt<bool> ProfcheckDisableMetadataFixes; | ||
| } | ||
|
|
||
| /// Generate code to compute the remainder of two signed integers. Returns the | ||
| /// remainder, which will have the sign of the dividend. Builder's insert point | ||
| /// should be pointing where the caller wants code generated, e.g. at the srem | ||
|
|
@@ -235,11 +244,53 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor, | |
| Value *Tmp1 = Builder.CreateCall(CTLZ, {Dividend, True}); | ||
| Value *SR = Builder.CreateSub(Tmp0, Tmp1); | ||
| Value *Ret0_4 = Builder.CreateICmpUGT(SR, MSB); | ||
|
|
||
| // Add 'unlikely' branch weights to the select instruction ('Ret0') generated | ||
| // by 'CreateLogicalOr'. We assume the 'true' path, where either the divisor | ||
| // or dividend is zero ('Ret0_3'), is less likely than the 'false' path, | ||
| // which corresponds to the |divisor| > |dividend| ('Ret0_4'). | ||
| Value *Ret0 = Builder.CreateLogicalOr(Ret0_3, Ret0_4); | ||
| if (!ProfcheckDisableMetadataFixes) { | ||
| if (Instruction *Ret0SelectI = dyn_cast<Instruction>(Ret0)) { | ||
| Ret0SelectI->setMetadata( | ||
| LLVMContext::MD_prof, | ||
| MDBuilder(Ret0SelectI->getContext()).createUnlikelyBranchWeights()); | ||
| } | ||
| } | ||
| Value *RetDividend = Builder.CreateICmpEQ(SR, MSB); | ||
| Value *RetVal = Builder.CreateSelect(Ret0, Zero, Dividend); | ||
| Value *EarlyRet = Builder.CreateLogicalOr(Ret0, RetDividend); | ||
| Builder.CreateCondBr(EarlyRet, End, BB1); | ||
|
|
||
| // This select instruction (RetVal) immediately follows the Ret0 check. Since | ||
| // Ret0_4 determines if the divisor is greater then the dividend so the | ||
| // unknown (50/50) branch weights are fairly accurate for RetVal. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be reworded too. I'm also suspect of this logic. You're basically making the assumption that both the dividend and the divisor are being randomly sampled from the same distribution, which I would not expect to be the case. I would expect the common case to be that the dividend is greater than the divisor. |
||
| Value *RetVal; | ||
| if (!ProfcheckDisableMetadataFixes) { | ||
| RetVal = Builder.CreateSelectWithUnknownProfile(Ret0, Zero, Dividend, | ||
| DEBUG_TYPE); | ||
| } else { | ||
| RetVal = Builder.CreateSelect(Ret0, Zero, Dividend); | ||
| } | ||
| // This select instruction (EarlyRet) is used to check another edge case, and | ||
| // it share the same branch weights as RetVal so the unknown (50/50)branch | ||
| // weights are also accurate for EarlyRet. | ||
| Value *EarlyRet; | ||
| if (!ProfcheckDisableMetadataFixes) { | ||
| EarlyRet = Builder.CreateSelectWithUnknownProfile( | ||
| Ret0, ConstantInt::getAllOnesValue(Ret0->getType()), RetDividend, | ||
| DEBUG_TYPE); | ||
| } else { | ||
| EarlyRet = Builder.CreateLogicalOr(Ret0, RetDividend); | ||
| } | ||
|
|
||
| // The condition of this branch is based on `EarlyRet`. `EarlyRet` is true | ||
| // only for special cases like dividend or divisor being zero, or the divisor | ||
| // being greater than the dividend. Thus, the branch to `End` is unlikely, | ||
| // and we expect to more frequently enter `BB1`. | ||
| Instruction *ConBrSpecialCases = Builder.CreateCondBr(EarlyRet, End, BB1); | ||
| if (!ProfcheckDisableMetadataFixes) { | ||
| ConBrSpecialCases->setMetadata(LLVMContext::MD_prof, | ||
| MDBuilder(ConBrSpecialCases->getContext()) | ||
| .createUnlikelyBranchWeights()); | ||
| } | ||
|
|
||
| // ; bb1: ; preds = %special-cases | ||
| // ; %sr_1 = add i32 %sr, 1 | ||
|
|
@@ -252,7 +303,15 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor, | |
| Value *Tmp2 = Builder.CreateSub(MSB, SR); | ||
| Value *Q = Builder.CreateShl(Dividend, Tmp2); | ||
| Value *SkipLoop = Builder.CreateICmpEQ(SR_1, Zero); | ||
| Builder.CreateCondBr(SkipLoop, LoopExit, Preheader); | ||
| // This branch is highly unlikely. SR_1 (SR + 1) is expected to be in [1, 129] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This numbers are not necessarily right. This function should be able to handle arbitrary bit widths, but this number looks specific to the 32-bit case used for the example IR. |
||
| // because the case where |divisor| > |dividend| (which would make SR | ||
| // negative) has alredy been intercepted in the previous SpecialCases BB. | ||
| Instruction *ConBrBB1 = Builder.CreateCondBr(SkipLoop, LoopExit, Preheader); | ||
| if (!ProfcheckDisableMetadataFixes) { | ||
| ConBrBB1->setMetadata(LLVMContext::MD_prof, | ||
| MDBuilder(ConBrBB1->getContext()) | ||
| .createUnlikelyBranchWeights()); | ||
| } | ||
|
|
||
| // ; preheader: ; preds = %bb1 | ||
| // ; %tmp3 = lshr i32 %dividend, %sr_1 | ||
|
|
@@ -298,7 +357,13 @@ static Value *generateUnsignedDivisionCode(Value *Dividend, Value *Divisor, | |
| Value *R = Builder.CreateSub(Tmp7, Tmp11); | ||
| Value *SR_2 = Builder.CreateAdd(SR_3, NegOne); | ||
| Value *Tmp12 = Builder.CreateICmpEQ(SR_2, Zero); | ||
| Builder.CreateCondBr(Tmp12, LoopExit, DoWhile); | ||
| // The loop implements the core bit-by-bit binary long division algorithm. | ||
| // Since each iteration generates one bit of the quotient until covering all | ||
| // significant bits so we would label it as unknown (50/50) branch weights. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic doesn't really follow for me. The back edge would be significantly more likely to be taken than 50/50 odds, assuming that the typical bit width used is >2 which I assume would be the case? |
||
| Instruction *ConBrDoWhile = Builder.CreateCondBr(Tmp12, LoopExit, DoWhile); | ||
| if (!ProfcheckDisableMetadataFixes) { | ||
| setExplicitlyUnknownBranchWeightsIfProfiled(*ConBrDoWhile, DEBUG_TYPE, F); | ||
| } | ||
|
|
||
| // ; loop-exit: ; preds = %do-while, %bb1 | ||
| // ; %carry_2 = phi i32 [ 0, %bb1 ], [ %carry, %do-while ] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,8 +2,9 @@ | |
| ; RUN: opt -S -mtriple=x86_64-- -expand-ir-insts -expand-div-rem-bits 128 < %s | FileCheck %s | ||
| ; RUN: opt -S -mtriple=x86_64-- -passes='require<libcall-lowering-info>,expand-ir-insts' -expand-div-rem-bits 128 < %s | FileCheck %s | ||
|
|
||
| define void @test(ptr %ptr, ptr %out) nounwind { | ||
| define void @test(ptr %ptr, ptr %out) nounwind !prof !0 { | ||
| ; CHECK-LABEL: @test( | ||
| ; CHECK: !prof [[PROF_0:![0-9]+]] { | ||
| ; CHECK-NEXT: _udiv-special-cases: | ||
| ; CHECK-NEXT: [[A:%.*]] = load i129, ptr [[PTR:%.*]], align 16 | ||
| ; CHECK-NEXT: [[TMP0:%.*]] = freeze i129 [[A]] | ||
|
|
@@ -17,11 +18,11 @@ define void @test(ptr %ptr, ptr %out) nounwind { | |
| ; CHECK-NEXT: [[TMP8:%.*]] = call i129 @llvm.ctlz.i129(i129 [[TMP3]], i1 true) | ||
| ; CHECK-NEXT: [[TMP9:%.*]] = sub i129 [[TMP7]], [[TMP8]] | ||
| ; CHECK-NEXT: [[TMP10:%.*]] = icmp ugt i129 [[TMP9]], 128 | ||
| ; CHECK-NEXT: [[TMP11:%.*]] = select i1 [[TMP6]], i1 true, i1 [[TMP10]] | ||
| ; CHECK-NEXT: [[TMP11:%.*]] = select i1 [[TMP6]], i1 true, i1 [[TMP10]], !prof [[PROF_1:![0-9]+]] | ||
| ; CHECK-NEXT: [[TMP12:%.*]] = icmp eq i129 [[TMP9]], 128 | ||
| ; CHECK-NEXT: [[TMP13:%.*]] = select i1 [[TMP11]], i129 0, i129 [[TMP3]] | ||
| ; CHECK-NEXT: [[TMP14:%.*]] = select i1 [[TMP11]], i1 true, i1 [[TMP12]] | ||
| ; CHECK-NEXT: br i1 [[TMP14]], label [[UDIV_END:%.*]], label [[UDIV_BB1:%.*]] | ||
| ; CHECK-NEXT: [[TMP13:%.*]] = select i1 [[TMP11]], i129 0, i129 [[TMP3]], !prof [[PROF_2:![0-9]+]] | ||
| ; CHECK-NEXT: [[TMP14:%.*]] = select i1 [[TMP11]], i1 true, i1 [[TMP12]], !prof [[PROF_2:![0-9]+]] | ||
| ; CHECK-NEXT: br i1 [[TMP14]], label [[UDIV_END:%.*]], label [[UDIV_BB1:%.*]], !prof [[PROF_1:![0-9]+]] | ||
| ; CHECK: udiv-loop-exit: | ||
| ; CHECK-NEXT: [[TMP15:%.*]] = phi i129 [ 0, [[UDIV_BB1]] ], [ [[TMP30:%.*]], [[UDIV_DO_WHILE:%.*]] ] | ||
| ; CHECK-NEXT: [[TMP16:%.*]] = phi i129 [ [[TMP39:%.*]], [[UDIV_BB1]] ], [ [[TMP27:%.*]], [[UDIV_DO_WHILE]] ] | ||
|
|
@@ -45,7 +46,7 @@ define void @test(ptr %ptr, ptr %out) nounwind { | |
| ; CHECK-NEXT: [[TMP32]] = sub i129 [[TMP25]], [[TMP31]] | ||
| ; CHECK-NEXT: [[TMP33]] = add i129 [[TMP20]], -1 | ||
| ; CHECK-NEXT: [[TMP34:%.*]] = icmp eq i129 [[TMP33]], 0 | ||
| ; CHECK-NEXT: br i1 [[TMP34]], label [[UDIV_LOOP_EXIT:%.*]], label [[UDIV_DO_WHILE]] | ||
| ; CHECK-NEXT: br i1 [[TMP34]], label [[UDIV_LOOP_EXIT:%.*]], label [[UDIV_DO_WHILE]], !prof [[PROF_2:![0-9]+]] | ||
| ; CHECK: udiv-preheader: | ||
| ; CHECK-NEXT: [[TMP35]] = lshr i129 [[TMP3]], [[TMP37]] | ||
| ; CHECK-NEXT: [[TMP36]] = add i129 [[TMP2]], -1 | ||
|
|
@@ -55,7 +56,7 @@ define void @test(ptr %ptr, ptr %out) nounwind { | |
| ; CHECK-NEXT: [[TMP38:%.*]] = sub i129 128, [[TMP9]] | ||
| ; CHECK-NEXT: [[TMP39]] = shl i129 [[TMP3]], [[TMP38]] | ||
| ; CHECK-NEXT: [[TMP40:%.*]] = icmp eq i129 [[TMP37]], 0 | ||
| ; CHECK-NEXT: br i1 [[TMP40]], label [[UDIV_LOOP_EXIT]], label [[UDIV_PREHEADER]] | ||
| ; CHECK-NEXT: br i1 [[TMP40]], label [[UDIV_LOOP_EXIT]], label [[UDIV_PREHEADER]], !prof [[PROF_1:![0-9]+]] | ||
| ; CHECK: udiv-end: | ||
| ; CHECK-NEXT: [[TMP41:%.*]] = phi i129 [ [[TMP18]], [[UDIV_LOOP_EXIT]] ], [ [[TMP13]], [[_UDIV_SPECIAL_CASES:%.*]] ] | ||
| ; CHECK-NEXT: [[TMP42:%.*]] = mul i129 [[TMP1]], [[TMP41]] | ||
|
|
@@ -68,3 +69,8 @@ define void @test(ptr %ptr, ptr %out) nounwind { | |
| store i129 %res, ptr %out | ||
| ret void | ||
| } | ||
|
|
||
| !0 = !{!"function_entry_count", i64 1000} | ||
| ; CHECK: [[PROF_0]] = !{!"function_entry_count", i64 1000} | ||
| ; CHECK: [[PROF_1]] = !{!"branch_weights", i32 1, i32 1048575} | ||
| ; CHECK: [[PROF_2]] = !{!"unknown", !"integer-division"} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: missing a newline here |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would reword this to talk about the actual case we're marking unlikely rather than to mention all of the implementation details.
Something like the following: