mirror of
https://github.com/RPCS3/llvm.git
synced 2025-04-09 09:01:25 +00:00
Introduce "expect" intrinsic instructions.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@134516 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
d7c7e2ff7d
commit
9da9934e27
@ -141,6 +141,7 @@ void initializeLoopUnrollPass(PassRegistry&);
|
|||||||
void initializeLoopUnswitchPass(PassRegistry&);
|
void initializeLoopUnswitchPass(PassRegistry&);
|
||||||
void initializeLoopIdiomRecognizePass(PassRegistry&);
|
void initializeLoopIdiomRecognizePass(PassRegistry&);
|
||||||
void initializeLowerAtomicPass(PassRegistry&);
|
void initializeLowerAtomicPass(PassRegistry&);
|
||||||
|
void initializeLowerExpectIntrinsicPass(PassRegistry&);
|
||||||
void initializeLowerIntrinsicsPass(PassRegistry&);
|
void initializeLowerIntrinsicsPass(PassRegistry&);
|
||||||
void initializeLowerInvokePass(PassRegistry&);
|
void initializeLowerInvokePass(PassRegistry&);
|
||||||
void initializeLowerSetJmpPass(PassRegistry&);
|
void initializeLowerSetJmpPass(PassRegistry&);
|
||||||
|
@ -266,6 +266,11 @@ def int_objectsize : Intrinsic<[llvm_anyint_ty], [llvm_ptr_ty, llvm_i1_ty],
|
|||||||
[IntrNoMem]>,
|
[IntrNoMem]>,
|
||||||
GCCBuiltin<"__builtin_object_size">;
|
GCCBuiltin<"__builtin_object_size">;
|
||||||
|
|
||||||
|
//===------------------------- Expect Intrinsics --------------------------===//
|
||||||
|
//
|
||||||
|
def int_expect : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>,
|
||||||
|
LLVMMatchType<0>], [IntrNoMem]>;
|
||||||
|
|
||||||
//===-------------------- Bit Manipulation Intrinsics ---------------------===//
|
//===-------------------- Bit Manipulation Intrinsics ---------------------===//
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -39,7 +39,8 @@ public:
|
|||||||
// compile-time performance optimization, not a correctness optimization.
|
// compile-time performance optimization, not a correctness optimization.
|
||||||
enum {
|
enum {
|
||||||
MD_dbg = 0, // "dbg"
|
MD_dbg = 0, // "dbg"
|
||||||
MD_tbaa = 1 // "tbaa"
|
MD_tbaa = 1, // "tbaa"
|
||||||
|
MD_prof = 2 // "prof"
|
||||||
};
|
};
|
||||||
|
|
||||||
/// getMDKindID - Return a unique non-zero ID for the specified metadata kind.
|
/// getMDKindID - Return a unique non-zero ID for the specified metadata kind.
|
||||||
|
@ -92,6 +92,7 @@ namespace {
|
|||||||
(void) llvm::createLoopUnswitchPass();
|
(void) llvm::createLoopUnswitchPass();
|
||||||
(void) llvm::createLoopIdiomPass();
|
(void) llvm::createLoopIdiomPass();
|
||||||
(void) llvm::createLoopRotatePass();
|
(void) llvm::createLoopRotatePass();
|
||||||
|
(void) llvm::createLowerExpectIntrinsicPass();
|
||||||
(void) llvm::createLowerInvokePass();
|
(void) llvm::createLowerInvokePass();
|
||||||
(void) llvm::createLowerSetJmpPass();
|
(void) llvm::createLowerSetJmpPass();
|
||||||
(void) llvm::createLowerSwitchPass();
|
(void) llvm::createLowerSwitchPass();
|
||||||
|
@ -152,6 +152,7 @@ public:
|
|||||||
FPM.add(createCFGSimplificationPass());
|
FPM.add(createCFGSimplificationPass());
|
||||||
FPM.add(createScalarReplAggregatesPass());
|
FPM.add(createScalarReplAggregatesPass());
|
||||||
FPM.add(createEarlyCSEPass());
|
FPM.add(createEarlyCSEPass());
|
||||||
|
FPM.add(createLowerExpectIntrinsicPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// populateModulePassManager - This sets up the primary pass manager.
|
/// populateModulePassManager - This sets up the primary pass manager.
|
||||||
|
@ -361,6 +361,14 @@ Pass *createObjCARCOptPass();
|
|||||||
FunctionPass *createInstructionSimplifierPass();
|
FunctionPass *createInstructionSimplifierPass();
|
||||||
extern char &InstructionSimplifierID;
|
extern char &InstructionSimplifierID;
|
||||||
|
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// LowerExpectIntriniscs - Removes llvm.expect intrinsics and creates
|
||||||
|
// "block_weights" metadata.
|
||||||
|
FunctionPass *createLowerExpectIntrinsicPass();
|
||||||
|
|
||||||
|
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -353,6 +353,13 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
|
|||||||
report_fatal_error("Code generator does not support intrinsic function '"+
|
report_fatal_error("Code generator does not support intrinsic function '"+
|
||||||
Callee->getName()+"'!");
|
Callee->getName()+"'!");
|
||||||
|
|
||||||
|
case Intrinsic::expect: {
|
||||||
|
// Just replace __builtin_expect(exp, c) with EXP.
|
||||||
|
Value *V = CI->getArgOperand(0);
|
||||||
|
CI->replaceAllUsesWith(V);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// The setjmp/longjmp intrinsics should only exist in the code if it was
|
// The setjmp/longjmp intrinsics should only exist in the code if it was
|
||||||
// never optimized (ie, right out of the CFE), or if it has been hacked on
|
// never optimized (ie, right out of the CFE), or if it has been hacked on
|
||||||
// by the lowerinvoke pass. In both cases, the right thing to do is to
|
// by the lowerinvoke pass. In both cases, the right thing to do is to
|
||||||
|
@ -4771,6 +4771,13 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
|
|||||||
case Intrinsic::flt_rounds:
|
case Intrinsic::flt_rounds:
|
||||||
setValue(&I, DAG.getNode(ISD::FLT_ROUNDS_, dl, MVT::i32));
|
setValue(&I, DAG.getNode(ISD::FLT_ROUNDS_, dl, MVT::i32));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case Intrinsic::expect: {
|
||||||
|
// Just replace __builtin_expect(exp, c) with EXP.
|
||||||
|
setValue(&I, getValue(I.getArgOperand(0)));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
case Intrinsic::trap: {
|
case Intrinsic::trap: {
|
||||||
StringRef TrapFuncName = getTrapFunctionName();
|
StringRef TrapFuncName = getTrapFunctionName();
|
||||||
if (TrapFuncName.empty()) {
|
if (TrapFuncName.empty()) {
|
||||||
|
@ -48,6 +48,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
|
|||||||
initializeLoopUnswitchPass(Registry);
|
initializeLoopUnswitchPass(Registry);
|
||||||
initializeLoopIdiomRecognizePass(Registry);
|
initializeLoopIdiomRecognizePass(Registry);
|
||||||
initializeLowerAtomicPass(Registry);
|
initializeLowerAtomicPass(Registry);
|
||||||
|
initializeLowerExpectIntrinsicPass(Registry);
|
||||||
initializeMemCpyOptPass(Registry);
|
initializeMemCpyOptPass(Registry);
|
||||||
initializeObjCARCAliasAnalysisPass(Registry);
|
initializeObjCARCAliasAnalysisPass(Registry);
|
||||||
initializeObjCARCExpandPass(Registry);
|
initializeObjCARCExpandPass(Registry);
|
||||||
|
@ -14,6 +14,7 @@ add_llvm_library(LLVMTransformUtils
|
|||||||
Local.cpp
|
Local.cpp
|
||||||
LoopSimplify.cpp
|
LoopSimplify.cpp
|
||||||
LoopUnroll.cpp
|
LoopUnroll.cpp
|
||||||
|
LowerExpectIntrinsic.cpp
|
||||||
LowerInvoke.cpp
|
LowerInvoke.cpp
|
||||||
LowerSwitch.cpp
|
LowerSwitch.cpp
|
||||||
Mem2Reg.cpp
|
Mem2Reg.cpp
|
||||||
|
163
lib/Transforms/Utils/LowerExpectIntrinsic.cpp
Normal file
163
lib/Transforms/Utils/LowerExpectIntrinsic.cpp
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#define DEBUG_TYPE "lower-expect-intrinsic"
|
||||||
|
#include "llvm/Constants.h"
|
||||||
|
#include "llvm/Function.h"
|
||||||
|
#include "llvm/BasicBlock.h"
|
||||||
|
#include "llvm/LLVMContext.h"
|
||||||
|
#include "llvm/Instructions.h"
|
||||||
|
#include "llvm/Intrinsics.h"
|
||||||
|
#include "llvm/Metadata.h"
|
||||||
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/Transforms/Scalar.h"
|
||||||
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
#include "llvm/Support/Debug.h"
|
||||||
|
#include "llvm/ADT/Statistic.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
STATISTIC(IfHandled, "Number of 'expect' intrinsic intructions handled");
|
||||||
|
|
||||||
|
static cl::opt<uint32_t>
|
||||||
|
LikelyBranchWeight("likely-branch-weight", cl::Hidden, cl::init(64),
|
||||||
|
cl::desc("Weight of the branch likely to be taken (default = 64)"));
|
||||||
|
static cl::opt<uint32_t>
|
||||||
|
UnlikelyBranchWeight("unlikely-branch-weight", cl::Hidden, cl::init(4),
|
||||||
|
cl::desc("Weight of the branch unlikely to be taken (default = 4)"));
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class LowerExpectIntrinsic : public FunctionPass {
|
||||||
|
|
||||||
|
bool HandleSwitchExpect(SwitchInst *SI);
|
||||||
|
|
||||||
|
bool HandleIfExpect(BranchInst *BI);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
LowerExpectIntrinsic() : FunctionPass(ID) {
|
||||||
|
initializeLowerExpectIntrinsicPass(*PassRegistry::getPassRegistry());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool runOnFunction(Function &F);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LowerExpectIntrinsic::HandleSwitchExpect(SwitchInst *SI) {
|
||||||
|
CallInst *CI = dyn_cast<CallInst>(SI->getCondition());
|
||||||
|
if (!CI)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Function *Fn = CI->getCalledFunction();
|
||||||
|
if (!Fn || Fn->getIntrinsicID() != Intrinsic::expect)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Value *ArgValue = CI->getArgOperand(0);
|
||||||
|
ConstantInt *ExpectedValue = dyn_cast<ConstantInt>(CI->getArgOperand(1));
|
||||||
|
if (!ExpectedValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LLVMContext &Context = CI->getContext();
|
||||||
|
const Type *Int32Ty = Type::getInt32Ty(Context);
|
||||||
|
|
||||||
|
unsigned caseNo = SI->findCaseValue(ExpectedValue);
|
||||||
|
std::vector<Value *> Vec;
|
||||||
|
unsigned n = SI->getNumCases();
|
||||||
|
Vec.resize(n + 1); // +1 for MDString
|
||||||
|
|
||||||
|
Vec[0] = MDString::get(Context, "branch_weights");
|
||||||
|
for (unsigned i = 0; i < n; ++i) {
|
||||||
|
Vec[i + 1] = ConstantInt::get(Int32Ty, i == caseNo ? LikelyBranchWeight : UnlikelyBranchWeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
MDNode *WeightsNode = llvm::MDNode::get(Context, Vec);
|
||||||
|
SI->setMetadata(LLVMContext::MD_prof, WeightsNode);
|
||||||
|
|
||||||
|
SI->setCondition(ArgValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LowerExpectIntrinsic::HandleIfExpect(BranchInst *BI) {
|
||||||
|
if (BI->isUnconditional())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Handle non-optimized IR code like:
|
||||||
|
// %expval = call i64 @llvm.expect.i64.i64(i64 %conv1, i64 1)
|
||||||
|
// %tobool = icmp ne i64 %expval, 0
|
||||||
|
// br i1 %tobool, label %if.then, label %if.end
|
||||||
|
|
||||||
|
ICmpInst *CmpI = dyn_cast<ICmpInst>(BI->getCondition());
|
||||||
|
if (!CmpI || CmpI->getPredicate() != CmpInst::ICMP_NE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CallInst *CI = dyn_cast<CallInst>(CmpI->getOperand(0));
|
||||||
|
if (!CI)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Function *Fn = CI->getCalledFunction();
|
||||||
|
if (!Fn || Fn->getIntrinsicID() != Intrinsic::expect)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Value *ArgValue = CI->getArgOperand(0);
|
||||||
|
ConstantInt *ExpectedValue = dyn_cast<ConstantInt>(CI->getArgOperand(1));
|
||||||
|
if (!ExpectedValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LLVMContext &Context = CI->getContext();
|
||||||
|
const Type *Int32Ty = Type::getInt32Ty(Context);
|
||||||
|
bool Likely = ExpectedValue->isOne();
|
||||||
|
|
||||||
|
// If expect value is equal to 1 it means that we are more likely to take
|
||||||
|
// branch 0, in other case more likely is branch 1.
|
||||||
|
Value *Ops[] = {
|
||||||
|
MDString::get(Context, "branch_weights"),
|
||||||
|
ConstantInt::get(Int32Ty, Likely ? LikelyBranchWeight : UnlikelyBranchWeight),
|
||||||
|
ConstantInt::get(Int32Ty, Likely ? UnlikelyBranchWeight : LikelyBranchWeight)
|
||||||
|
};
|
||||||
|
|
||||||
|
MDNode *WeightsNode = MDNode::get(Context, ArrayRef<Value *>(Ops, 3));
|
||||||
|
BI->setMetadata(LLVMContext::MD_prof, WeightsNode);
|
||||||
|
|
||||||
|
CmpI->setOperand(0, ArgValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LowerExpectIntrinsic::runOnFunction(Function &F) {
|
||||||
|
for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
|
||||||
|
BasicBlock *BB = I++;
|
||||||
|
|
||||||
|
// Create "block_weights" metadata.
|
||||||
|
if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator())) {
|
||||||
|
if (HandleIfExpect(BI))
|
||||||
|
IfHandled++;
|
||||||
|
} else if (SwitchInst *SI = dyn_cast<SwitchInst>(BB->getTerminator())) {
|
||||||
|
if (HandleSwitchExpect(SI))
|
||||||
|
IfHandled++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove llvm.expect intrinsics.
|
||||||
|
for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();
|
||||||
|
BI != BE; ) {
|
||||||
|
CallInst *CI = dyn_cast<CallInst>(BI++);
|
||||||
|
if (!CI)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Function *Fn = CI->getCalledFunction();
|
||||||
|
if (Fn && Fn->getIntrinsicID() == Intrinsic::expect)
|
||||||
|
CI->eraseFromParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char LowerExpectIntrinsic::ID = 0;
|
||||||
|
INITIALIZE_PASS(LowerExpectIntrinsic, "lower-expect", "Lower 'expect' "
|
||||||
|
"Intrinsics", false, false)
|
||||||
|
|
||||||
|
FunctionPass *llvm::createLowerExpectIntrinsicPass() {
|
||||||
|
return new LowerExpectIntrinsic();
|
||||||
|
}
|
@ -39,6 +39,10 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) {
|
|||||||
// Create the 'tbaa' metadata kind.
|
// Create the 'tbaa' metadata kind.
|
||||||
unsigned TBAAID = getMDKindID("tbaa");
|
unsigned TBAAID = getMDKindID("tbaa");
|
||||||
assert(TBAAID == MD_tbaa && "tbaa kind id drifted"); (void)TBAAID;
|
assert(TBAAID == MD_tbaa && "tbaa kind id drifted"); (void)TBAAID;
|
||||||
|
|
||||||
|
// Create the 'prof' metadata kind.
|
||||||
|
unsigned ProfID = getMDKindID("prof");
|
||||||
|
assert(ProfID == MD_prof && "prof kind id drifted"); (void)ProfID;
|
||||||
}
|
}
|
||||||
LLVMContext::~LLVMContext() { delete pImpl; }
|
LLVMContext::~LLVMContext() { delete pImpl; }
|
||||||
|
|
||||||
|
223
test/CodeGen/Generic/builtin-expect.ll
Normal file
223
test/CodeGen/Generic/builtin-expect.ll
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
; RUN: llc < %s
|
||||||
|
|
||||||
|
define i32 @test1(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%cmp = icmp sgt i32 %tmp, 1
|
||||||
|
%conv = zext i1 %cmp to i32
|
||||||
|
%conv1 = sext i32 %conv to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv1, i64 1)
|
||||||
|
%tobool = icmp ne i64 %expval, 0
|
||||||
|
br i1 %tobool, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i64 @llvm.expect.i64(i64, i64) nounwind readnone
|
||||||
|
|
||||||
|
declare i32 @f(...)
|
||||||
|
|
||||||
|
define i32 @test2(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%conv = sext i32 %tmp to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
|
||||||
|
%tobool = icmp ne i64 %expval, 0
|
||||||
|
br i1 %tobool, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test3(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%tobool = icmp ne i32 %tmp, 0
|
||||||
|
%lnot = xor i1 %tobool, true
|
||||||
|
%lnot.ext = zext i1 %lnot to i32
|
||||||
|
%conv = sext i32 %lnot.ext to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
|
||||||
|
%tobool1 = icmp ne i64 %expval, 0
|
||||||
|
br i1 %tobool1, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test4(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%tobool = icmp ne i32 %tmp, 0
|
||||||
|
%lnot = xor i1 %tobool, true
|
||||||
|
%lnot1 = xor i1 %lnot, true
|
||||||
|
%lnot.ext = zext i1 %lnot1 to i32
|
||||||
|
%conv = sext i32 %lnot.ext to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
|
||||||
|
%tobool2 = icmp ne i64 %expval, 0
|
||||||
|
br i1 %tobool2, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test5(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%cmp = icmp slt i32 %tmp, 0
|
||||||
|
%conv = zext i1 %cmp to i32
|
||||||
|
%conv1 = sext i32 %conv to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv1, i64 0)
|
||||||
|
%tobool = icmp ne i64 %expval, 0
|
||||||
|
br i1 %tobool, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test6(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%conv = sext i32 %tmp to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
|
||||||
|
switch i64 %expval, label %sw.epilog [
|
||||||
|
i64 1, label %sw.bb
|
||||||
|
i64 2, label %sw.bb
|
||||||
|
]
|
||||||
|
|
||||||
|
sw.bb: ; preds = %entry, %entry
|
||||||
|
store i32 0, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
sw.epilog: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %sw.epilog, %sw.bb
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test7(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%conv = sext i32 %tmp to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
|
||||||
|
switch i64 %expval, label %sw.epilog [
|
||||||
|
i64 2, label %sw.bb
|
||||||
|
i64 3, label %sw.bb
|
||||||
|
]
|
||||||
|
|
||||||
|
sw.bb: ; preds = %entry, %entry
|
||||||
|
%tmp1 = load i32* %x.addr, align 4
|
||||||
|
store i32 %tmp1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
sw.epilog: ; preds = %entry
|
||||||
|
store i32 0, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %sw.epilog, %sw.bb
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test8(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%cmp = icmp sgt i32 %tmp, 1
|
||||||
|
%conv = zext i1 %cmp to i32
|
||||||
|
%expval = call i32 @llvm.expect.i32(i32 %conv, i32 1)
|
||||||
|
%tobool = icmp ne i32 %expval, 0
|
||||||
|
br i1 %tobool, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i32 @llvm.expect.i32(i32, i32) nounwind readnone
|
||||||
|
|
251
test/Transforms/LowerExpectIntrinsic/basic.ll
Normal file
251
test/Transforms/LowerExpectIntrinsic/basic.ll
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
; RUN: opt -lower-expect -strip-dead-prototypes -S -o - < %s | FileCheck %s
|
||||||
|
|
||||||
|
; CHECK: @test1
|
||||||
|
define i32 @test1(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%cmp = icmp sgt i32 %tmp, 1
|
||||||
|
%conv = zext i1 %cmp to i32
|
||||||
|
%conv1 = sext i32 %conv to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv1, i64 1)
|
||||||
|
%tobool = icmp ne i64 %expval, 0
|
||||||
|
; CHECK: !prof !0
|
||||||
|
; CHECK-NOT: @llvm.expect
|
||||||
|
br i1 %tobool, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i64 @llvm.expect.i64(i64, i64) nounwind readnone
|
||||||
|
|
||||||
|
declare i32 @f(...)
|
||||||
|
|
||||||
|
; CHECK: @test2
|
||||||
|
define i32 @test2(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%conv = sext i32 %tmp to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
|
||||||
|
%tobool = icmp ne i64 %expval, 0
|
||||||
|
; CHECK: !prof !0
|
||||||
|
; CHECK-NOT: @llvm.expect
|
||||||
|
br i1 %tobool, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: @test3
|
||||||
|
define i32 @test3(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%tobool = icmp ne i32 %tmp, 0
|
||||||
|
%lnot = xor i1 %tobool, true
|
||||||
|
%lnot.ext = zext i1 %lnot to i32
|
||||||
|
%conv = sext i32 %lnot.ext to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
|
||||||
|
%tobool1 = icmp ne i64 %expval, 0
|
||||||
|
; CHECK: !prof !0
|
||||||
|
; CHECK-NOT: @llvm.expect
|
||||||
|
br i1 %tobool1, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: @test4
|
||||||
|
define i32 @test4(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%tobool = icmp ne i32 %tmp, 0
|
||||||
|
%lnot = xor i1 %tobool, true
|
||||||
|
%lnot1 = xor i1 %lnot, true
|
||||||
|
%lnot.ext = zext i1 %lnot1 to i32
|
||||||
|
%conv = sext i32 %lnot.ext to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
|
||||||
|
%tobool2 = icmp ne i64 %expval, 0
|
||||||
|
; CHECK: !prof !0
|
||||||
|
; CHECK-NOT: @llvm.expect
|
||||||
|
br i1 %tobool2, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: @test5
|
||||||
|
define i32 @test5(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%cmp = icmp slt i32 %tmp, 0
|
||||||
|
%conv = zext i1 %cmp to i32
|
||||||
|
%conv1 = sext i32 %conv to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv1, i64 0)
|
||||||
|
%tobool = icmp ne i64 %expval, 0
|
||||||
|
; CHECK: !prof !1
|
||||||
|
; CHECK-NOT: @llvm.expect
|
||||||
|
br i1 %tobool, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: @test6
|
||||||
|
define i32 @test6(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%conv = sext i32 %tmp to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
|
||||||
|
; CHECK: !prof !2
|
||||||
|
; CHECK-NOT: @llvm.expect
|
||||||
|
switch i64 %expval, label %sw.epilog [
|
||||||
|
i64 1, label %sw.bb
|
||||||
|
i64 2, label %sw.bb
|
||||||
|
]
|
||||||
|
|
||||||
|
sw.bb: ; preds = %entry, %entry
|
||||||
|
store i32 0, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
sw.epilog: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %sw.epilog, %sw.bb
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: @test7
|
||||||
|
define i32 @test7(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%conv = sext i32 %tmp to i64
|
||||||
|
%expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
|
||||||
|
; CHECK: !prof !3
|
||||||
|
; CHECK-NOT: @llvm.expect
|
||||||
|
switch i64 %expval, label %sw.epilog [
|
||||||
|
i64 2, label %sw.bb
|
||||||
|
i64 3, label %sw.bb
|
||||||
|
]
|
||||||
|
|
||||||
|
sw.bb: ; preds = %entry, %entry
|
||||||
|
%tmp1 = load i32* %x.addr, align 4
|
||||||
|
store i32 %tmp1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
sw.epilog: ; preds = %entry
|
||||||
|
store i32 0, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %sw.epilog, %sw.bb
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: @test8
|
||||||
|
define i32 @test8(i32 %x) nounwind uwtable ssp {
|
||||||
|
entry:
|
||||||
|
%retval = alloca i32, align 4
|
||||||
|
%x.addr = alloca i32, align 4
|
||||||
|
store i32 %x, i32* %x.addr, align 4
|
||||||
|
%tmp = load i32* %x.addr, align 4
|
||||||
|
%cmp = icmp sgt i32 %tmp, 1
|
||||||
|
%conv = zext i1 %cmp to i32
|
||||||
|
%expval = call i32 @llvm.expect.i32(i32 %conv, i32 1)
|
||||||
|
%tobool = icmp ne i32 %expval, 0
|
||||||
|
; CHECK: !prof !0
|
||||||
|
; CHECK-NOT: @llvm.expect
|
||||||
|
br i1 %tobool, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%call = call i32 (...)* @f()
|
||||||
|
store i32 %call, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
if.end: ; preds = %entry
|
||||||
|
store i32 1, i32* %retval
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return: ; preds = %if.end, %if.then
|
||||||
|
%0 = load i32* %retval
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i32 @llvm.expect.i32(i32, i32) nounwind readnone
|
||||||
|
|
||||||
|
; CHECK: !0 = metadata !{metadata !"branch_weights", i32 64, i32 4}
|
||||||
|
; CHECK: !1 = metadata !{metadata !"branch_weights", i32 4, i32 64}
|
||||||
|
; CHECK: !2 = metadata !{metadata !"branch_weights", i32 4, i32 64, i32 4}
|
||||||
|
; CHECK: !3 = metadata !{metadata !"branch_weights", i32 64, i32 4, i32 4}
|
3
test/Transforms/LowerExpectIntrinsic/dg.exp
Normal file
3
test/Transforms/LowerExpectIntrinsic/dg.exp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
load_lib llvm.exp
|
||||||
|
|
||||||
|
RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]]
|
Loading…
x
Reference in New Issue
Block a user