1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 19:12:56 +02:00

[CGP] Convert phi types

If a collection of interconnected phi nodes is only ever loaded, stored
or bitcast then we can convert the whole set to the bitcast type,
potentially helping to reduce the number of register moves needed as the
phi's are passed across basic block boundaries. This has to be done in
CodegenPrepare as it naturally straddles basic blocks.

The alorithm just looks from phi nodes, looking at uses and operands for
a collection of nodes that all together are bitcast between float and
integer types. We record visited phi nodes to not have to process them
more than once. The whole subgraph is then replaced with a new type.
Loads and Stores are bitcast to the correct type, which should then be
folded into the load/store, changing it's type.

This comes up in the biquad testcase due to the way MVE needs to keep
values in integer registers. I have also seen it come up from aarch64
partner example code, where a complicated set of sroa/inlining produced
integer phis, where float would have been a better choice.

I also added undef and extract element handling which increased the
potency in some cases.

This adds it with an option that defaults to off, and disabled for 32bit
X86 due to potential issues around canonicalizing NaNs.

Differential Revision: https://reviews.llvm.org/D81827
This commit is contained in:
David Green 2020-06-21 11:28:31 +01:00
parent 9b2563a43f
commit 0987ead525
6 changed files with 263 additions and 41 deletions

View File

@ -2368,6 +2368,14 @@ public:
return nullptr; return nullptr;
} }
/// Given a set in interconnected phis of type 'From' that are loaded/stored
/// or bitcast to type 'To', return true if the set should be converted to
/// 'To'.
virtual bool shouldConvertPhiType(Type *From, Type *To) const {
return (From->isIntegerTy() || From->isFloatingPointTy()) &&
(To->isIntegerTy() || To->isFloatingPointTy());
}
/// Returns true if the opcode is a commutative binary operation. /// Returns true if the opcode is a commutative binary operation.
virtual bool isCommutativeBinOp(unsigned Opcode) const { virtual bool isCommutativeBinOp(unsigned Opcode) const {
// FIXME: This should get its info from the td file. // FIXME: This should get its info from the td file.

View File

@ -245,6 +245,10 @@ static cl::opt<bool>
cl::desc("Enable BFI update verification for " cl::desc("Enable BFI update verification for "
"CodeGenPrepare.")); "CodeGenPrepare."));
static cl::opt<bool> OptimizePhiTypes(
"cgp-optimize-phi-types", cl::Hidden, cl::init(false),
cl::desc("Enable converting phi types in CodeGenPrepare"));
namespace { namespace {
enum ExtType { enum ExtType {
@ -407,6 +411,9 @@ class TypePromotionTransaction;
unsigned CreatedInstsCost = 0); unsigned CreatedInstsCost = 0);
bool mergeSExts(Function &F); bool mergeSExts(Function &F);
bool splitLargeGEPOffsets(); bool splitLargeGEPOffsets();
bool optimizePhiType(PHINode *Inst, SmallPtrSetImpl<PHINode *> &Visited,
SmallPtrSetImpl<Instruction *> &DeletedInstrs);
bool optimizePhiTypes(Function &F);
bool performAddressTypePromotion( bool performAddressTypePromotion(
Instruction *&Inst, Instruction *&Inst,
bool AllowPromotionWithoutCommonHeader, bool AllowPromotionWithoutCommonHeader,
@ -515,6 +522,7 @@ bool CodeGenPrepare::runOnFunction(Function &F) {
MadeChange |= mergeSExts(F); MadeChange |= mergeSExts(F);
if (!LargeOffsetGEPMap.empty()) if (!LargeOffsetGEPMap.empty())
MadeChange |= splitLargeGEPOffsets(); MadeChange |= splitLargeGEPOffsets();
MadeChange |= optimizePhiTypes(F);
if (MadeChange) if (MadeChange)
eliminateFallThrough(F); eliminateFallThrough(F);
@ -5717,6 +5725,155 @@ bool CodeGenPrepare::splitLargeGEPOffsets() {
return Changed; return Changed;
} }
bool CodeGenPrepare::optimizePhiType(
PHINode *I, SmallPtrSetImpl<PHINode *> &Visited,
SmallPtrSetImpl<Instruction *> &DeletedInstrs) {
// We are looking for a collection on interconnected phi nodes that together
// only use loads/bitcasts and are used by stores/bitcasts, and the bitcasts
// are of the same type. Convert the whole set of nodes to the type of the
// bitcast.
Type *PhiTy = I->getType();
Type *ConvertTy = nullptr;
if (Visited.count(I) ||
(!I->getType()->isIntegerTy() && !I->getType()->isFloatingPointTy()))
return false;
SmallVector<Instruction *, 4> Worklist;
Worklist.push_back(cast<Instruction>(I));
SmallPtrSet<PHINode *, 4> PhiNodes;
PhiNodes.insert(I);
Visited.insert(I);
SmallPtrSet<Instruction *, 4> Defs;
SmallPtrSet<Instruction *, 4> Uses;
while (!Worklist.empty()) {
Instruction *II = Worklist.pop_back_val();
if (auto *Phi = dyn_cast<PHINode>(II)) {
// Handle Defs, which might also be PHI's
for (Value *V : Phi->incoming_values()) {
if (auto *OpPhi = dyn_cast<PHINode>(V)) {
if (!PhiNodes.count(OpPhi)) {
if (Visited.count(OpPhi))
return false;
PhiNodes.insert(OpPhi);
Visited.insert(OpPhi);
Worklist.push_back(OpPhi);
}
} else if (auto *OpLoad = dyn_cast<LoadInst>(V)) {
if (!Defs.count(OpLoad)) {
Defs.insert(OpLoad);
Worklist.push_back(OpLoad);
}
} else if (auto *OpEx = dyn_cast<ExtractElementInst>(V)) {
if (!Defs.count(OpEx)) {
Defs.insert(OpEx);
Worklist.push_back(OpEx);
}
} else if (auto *OpBC = dyn_cast<BitCastInst>(V)) {
if (!ConvertTy)
ConvertTy = OpBC->getOperand(0)->getType();
if (OpBC->getOperand(0)->getType() != ConvertTy)
return false;
if (!Defs.count(OpBC)) {
Defs.insert(OpBC);
Worklist.push_back(OpBC);
}
} else if (!isa<UndefValue>(V))
return false;
}
}
// Handle uses which might also be phi's
for (User *V : II->users()) {
if (auto *OpPhi = dyn_cast<PHINode>(V)) {
if (!PhiNodes.count(OpPhi)) {
if (Visited.count(OpPhi))
return false;
PhiNodes.insert(OpPhi);
Visited.insert(OpPhi);
Worklist.push_back(OpPhi);
}
} else if (auto *OpStore = dyn_cast<StoreInst>(V)) {
if (OpStore->getOperand(0) != II)
return false;
Uses.insert(OpStore);
} else if (auto *OpBC = dyn_cast<BitCastInst>(V)) {
if (!ConvertTy)
ConvertTy = OpBC->getType();
if (OpBC->getType() != ConvertTy)
return false;
Uses.insert(OpBC);
} else
return false;
}
}
if (!ConvertTy || !TLI->shouldConvertPhiType(PhiTy, ConvertTy))
return false;
LLVM_DEBUG(dbgs() << "Converting " << *I << "\n and connected nodes to "
<< *ConvertTy << "\n");
// Create all the new phi nodes of the new type, and bitcast any loads to the
// correct type.
ValueToValueMap ValMap;
ValMap[UndefValue::get(PhiTy)] = UndefValue::get(ConvertTy);
for (Instruction *D : Defs) {
if (isa<BitCastInst>(D))
ValMap[D] = D->getOperand(0);
else
ValMap[D] =
new BitCastInst(D, ConvertTy, D->getName() + ".bc", D->getNextNode());
}
for (PHINode *Phi : PhiNodes)
ValMap[Phi] = PHINode::Create(ConvertTy, Phi->getNumIncomingValues(),
Phi->getName() + ".tc", Phi);
// Pipe together all the PhiNodes.
for (PHINode *Phi : PhiNodes) {
PHINode *NewPhi = cast<PHINode>(ValMap[Phi]);
for (int i = 0, e = Phi->getNumIncomingValues(); i < e; i++)
NewPhi->addIncoming(ValMap[Phi->getIncomingValue(i)],
Phi->getIncomingBlock(i));
}
// And finally pipe up the stores and bitcasts
for (Instruction *U : Uses) {
if (isa<BitCastInst>(U)) {
DeletedInstrs.insert(U);
U->replaceAllUsesWith(ValMap[U->getOperand(0)]);
} else
U->setOperand(0,
new BitCastInst(ValMap[U->getOperand(0)], PhiTy, "bc", U));
}
// Save the removed phis to be deleted later.
for (PHINode *Phi : PhiNodes)
DeletedInstrs.insert(Phi);
return true;
}
bool CodeGenPrepare::optimizePhiTypes(Function &F) {
if (!OptimizePhiTypes)
return false;
bool Changed = false;
SmallPtrSet<PHINode *, 4> Visited;
SmallPtrSet<Instruction *, 4> DeletedInstrs;
// Attempt to optimize all the phis in the functions to the correct type.
for (auto &BB : F)
for (auto &Phi : BB.phis())
Changed |= optimizePhiType(&Phi, Visited, DeletedInstrs);
// Remove any old phi's that have been converted.
for (auto *I : DeletedInstrs) {
I->replaceAllUsesWith(UndefValue::get(I->getType()));
I->eraseFromParent();
}
return Changed;
}
/// Return true, if an ext(load) can be formed from an extension in /// Return true, if an ext(load) can be formed from an extension in
/// \p MovedExts. /// \p MovedExts.
bool CodeGenPrepare::canFormExtLd( bool CodeGenPrepare::canFormExtLd(

View File

@ -30748,6 +30748,12 @@ bool X86TargetLowering::shouldSinkOperands(Instruction *I,
return false; return false;
} }
bool X86TargetLowering::shouldConvertPhiType(Type *From, Type *To) const {
if (!Subtarget.is64Bit())
return false;
return TargetLowering::shouldConvertPhiType(From, To);
}
bool X86TargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const { bool X86TargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const {
if (isa<MaskedLoadSDNode>(ExtVal.getOperand(0))) if (isa<MaskedLoadSDNode>(ExtVal.getOperand(0)))
return false; return false;

View File

@ -1187,6 +1187,7 @@ namespace llvm {
bool shouldSinkOperands(Instruction *I, bool shouldSinkOperands(Instruction *I,
SmallVectorImpl<Use *> &Ops) const override; SmallVectorImpl<Use *> &Ops) const override;
bool shouldConvertPhiType(Type *From, Type *To) const override;
/// Return true if folding a vector load into ExtVal (a sign, zero, or any /// Return true if folding a vector load into ExtVal (a sign, zero, or any
/// extend node) is profitable. /// extend node) is profitable.

View File

@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -codegenprepare %s -S | FileCheck %s ; RUN: opt -codegenprepare -cgp-optimize-phi-types %s -S | FileCheck %s
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64--linux-gnu" target triple = "aarch64--linux-gnu"
@ -11,14 +11,15 @@ define float @convphi1(i32 *%s, i32 *%d, i32 %n) {
; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then: ; CHECK: then:
; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast i32 [[LS]] to float
; CHECK-NEXT: br label [[END:%.*]] ; CHECK-NEXT: br label [[END:%.*]]
; CHECK: else: ; CHECK: else:
; CHECK-NEXT: [[LD:%.*]] = load i32, i32* [[D:%.*]], align 4 ; CHECK-NEXT: [[LD:%.*]] = load i32, i32* [[D:%.*]], align 4
; CHECK-NEXT: [[LD_BC:%.*]] = bitcast i32 [[LD]] to float
; CHECK-NEXT: br label [[END]] ; CHECK-NEXT: br label [[END]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[LS]], [[THEN]] ], [ [[LD]], [[ELSE]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi float [ [[LS_BC]], [[THEN]] ], [ [[LD_BC]], [[ELSE]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast i32 [[PHI]] to float ; CHECK-NEXT: ret float [[PHI_TC]]
; CHECK-NEXT: ret float [[B]]
; ;
entry: entry:
%cmp15 = icmp sgt i32 %n, 0 %cmp15 = icmp sgt i32 %n, 0
@ -45,11 +46,11 @@ define float @convphi2(i32 *%s, i32 *%d, i32 %n) {
; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[END:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[END:%.*]]
; CHECK: then: ; CHECK: then:
; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast i32 [[LS]] to float
; CHECK-NEXT: br label [[END]] ; CHECK-NEXT: br label [[END]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[LS]], [[THEN]] ], [ undef, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi float [ [[LS_BC]], [[THEN]] ], [ undef, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast i32 [[PHI]] to float ; CHECK-NEXT: ret float [[PHI_TC]]
; CHECK-NEXT: ret float [[B]]
; ;
entry: entry:
%cmp15 = icmp sgt i32 %n, 0 %cmp15 = icmp sgt i32 %n, 0
@ -73,11 +74,11 @@ define float @convphi3(i32 *%s, i32 *%d, i32 %n, float %f) {
; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[END:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[END:%.*]]
; CHECK: then: ; CHECK: then:
; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast i32 [[LS]] to float
; CHECK-NEXT: br label [[END]] ; CHECK-NEXT: br label [[END]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[LS]], [[THEN]] ], [ [[FB]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi float [ [[LS_BC]], [[THEN]] ], [ [[F]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast i32 [[PHI]] to float ; CHECK-NEXT: ret float [[PHI_TC]]
; CHECK-NEXT: ret float [[B]]
; ;
entry: entry:
%cmp15 = icmp sgt i32 %n, 0 %cmp15 = icmp sgt i32 %n, 0
@ -102,10 +103,12 @@ define void @convphi4(i32 *%s, i32 *%d, i32 %n, float %f) {
; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[END:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[END:%.*]]
; CHECK: then: ; CHECK: then:
; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast i32 [[LS]] to float
; CHECK-NEXT: br label [[END]] ; CHECK-NEXT: br label [[END]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[LS]], [[THEN]] ], [ [[FB]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi float [ [[LS_BC]], [[THEN]] ], [ [[F]], [[ENTRY:%.*]] ]
; CHECK-NEXT: store i32 [[PHI]], i32* [[D:%.*]], align 4 ; CHECK-NEXT: [[BC:%.*]] = bitcast float [[PHI_TC]] to i32
; CHECK-NEXT: store i32 [[BC]], i32* [[D:%.*]], align 4
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
; ;
entry: entry:
@ -130,14 +133,15 @@ define i64 @convphi_d2i(double *%s, double *%d, i32 %n) {
; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then: ; CHECK: then:
; CHECK-NEXT: [[LS:%.*]] = load double, double* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load double, double* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast double [[LS]] to i64
; CHECK-NEXT: br label [[END:%.*]] ; CHECK-NEXT: br label [[END:%.*]]
; CHECK: else: ; CHECK: else:
; CHECK-NEXT: [[LD:%.*]] = load double, double* [[D:%.*]], align 4 ; CHECK-NEXT: [[LD:%.*]] = load double, double* [[D:%.*]], align 4
; CHECK-NEXT: [[LD_BC:%.*]] = bitcast double [[LD]] to i64
; CHECK-NEXT: br label [[END]] ; CHECK-NEXT: br label [[END]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi double [ [[LS]], [[THEN]] ], [ [[LD]], [[ELSE]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi i64 [ [[LS_BC]], [[THEN]] ], [ [[LD_BC]], [[ELSE]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast double [[PHI]] to i64 ; CHECK-NEXT: ret i64 [[PHI_TC]]
; CHECK-NEXT: ret i64 [[B]]
; ;
entry: entry:
%cmp15 = icmp sgt i32 %n, 0 %cmp15 = icmp sgt i32 %n, 0
@ -164,14 +168,15 @@ define i32 @convphi_f2i(float *%s, float *%d, i32 %n) {
; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then: ; CHECK: then:
; CHECK-NEXT: [[LS:%.*]] = load float, float* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load float, float* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast float [[LS]] to i32
; CHECK-NEXT: br label [[END:%.*]] ; CHECK-NEXT: br label [[END:%.*]]
; CHECK: else: ; CHECK: else:
; CHECK-NEXT: [[LD:%.*]] = load float, float* [[D:%.*]], align 4 ; CHECK-NEXT: [[LD:%.*]] = load float, float* [[D:%.*]], align 4
; CHECK-NEXT: [[LD_BC:%.*]] = bitcast float [[LD]] to i32
; CHECK-NEXT: br label [[END]] ; CHECK-NEXT: br label [[END]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi float [ [[LS]], [[THEN]] ], [ [[LD]], [[ELSE]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi i32 [ [[LS_BC]], [[THEN]] ], [ [[LD_BC]], [[ELSE]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast float [[PHI]] to i32 ; CHECK-NEXT: ret i32 [[PHI_TC]]
; CHECK-NEXT: ret i32 [[B]]
; ;
entry: entry:
%cmp15 = icmp sgt i32 %n, 0 %cmp15 = icmp sgt i32 %n, 0
@ -198,14 +203,15 @@ define i16 @convphi_h2i(half *%s, half *%d, i32 %n) {
; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then: ; CHECK: then:
; CHECK-NEXT: [[LS:%.*]] = load half, half* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load half, half* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast half [[LS]] to i16
; CHECK-NEXT: br label [[END:%.*]] ; CHECK-NEXT: br label [[END:%.*]]
; CHECK: else: ; CHECK: else:
; CHECK-NEXT: [[LD:%.*]] = load half, half* [[D:%.*]], align 4 ; CHECK-NEXT: [[LD:%.*]] = load half, half* [[D:%.*]], align 4
; CHECK-NEXT: [[LD_BC:%.*]] = bitcast half [[LD]] to i16
; CHECK-NEXT: br label [[END]] ; CHECK-NEXT: br label [[END]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi half [ [[LS]], [[THEN]] ], [ [[LD]], [[ELSE]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi i16 [ [[LS_BC]], [[THEN]] ], [ [[LD_BC]], [[ELSE]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast half [[PHI]] to i16 ; CHECK-NEXT: ret i16 [[PHI_TC]]
; CHECK-NEXT: ret i16 [[B]]
; ;
entry: entry:
%cmp15 = icmp sgt i32 %n, 0 %cmp15 = icmp sgt i32 %n, 0
@ -232,14 +238,15 @@ define i128 @convphi_ld2i(fp128 *%s, fp128 *%d, i32 %n) {
; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then: ; CHECK: then:
; CHECK-NEXT: [[LS:%.*]] = load fp128, fp128* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load fp128, fp128* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast fp128 [[LS]] to i128
; CHECK-NEXT: br label [[END:%.*]] ; CHECK-NEXT: br label [[END:%.*]]
; CHECK: else: ; CHECK: else:
; CHECK-NEXT: [[LD:%.*]] = load fp128, fp128* [[D:%.*]], align 4 ; CHECK-NEXT: [[LD:%.*]] = load fp128, fp128* [[D:%.*]], align 4
; CHECK-NEXT: [[LD_BC:%.*]] = bitcast fp128 [[LD]] to i128
; CHECK-NEXT: br label [[END]] ; CHECK-NEXT: br label [[END]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi fp128 [ [[LS]], [[THEN]] ], [ [[LD]], [[ELSE]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi i128 [ [[LS_BC]], [[THEN]] ], [ [[LD_BC]], [[ELSE]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast fp128 [[PHI]] to i128 ; CHECK-NEXT: ret i128 [[PHI_TC]]
; CHECK-NEXT: ret i128 [[B]]
; ;
entry: entry:
%cmp15 = icmp sgt i32 %n, 0 %cmp15 = icmp sgt i32 %n, 0
@ -298,18 +305,19 @@ define float @convphi_loop(i32 *%s, i32 *%d, i64 %n) {
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP15:%.*]] = icmp sgt i64 [[N:%.*]], 0 ; CHECK-NEXT: [[CMP15:%.*]] = icmp sgt i64 [[N:%.*]], 0
; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast i32 [[LS]] to float
; CHECK-NEXT: br i1 [[CMP15]], label [[LOOP:%.*]], label [[END:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[LOOP:%.*]], label [[END:%.*]]
; CHECK: loop: ; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[LPHI:%.*]] = phi i32 [ [[LS]], [[ENTRY]] ], [ [[LD:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[LPHI_TC:%.*]] = phi float [ [[LS_BC]], [[ENTRY]] ], [ [[LD_BC:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[LD]] = load i32, i32* [[D:%.*]], align 4 ; CHECK-NEXT: [[LD:%.*]] = load i32, i32* [[D:%.*]], align 4
; CHECK-NEXT: [[LD_BC]] = bitcast i32 [[LD]] to float
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]] ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[END]], label [[LOOP]] ; CHECK-NEXT: br i1 [[EXITCOND]], label [[END]], label [[LOOP]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ undef, [[ENTRY]] ], [ [[LPHI]], [[LOOP]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi float [ undef, [[ENTRY]] ], [ [[LPHI_TC]], [[LOOP]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast i32 [[PHI]] to float ; CHECK-NEXT: ret float [[PHI_TC]]
; CHECK-NEXT: ret float [[B]]
; ;
entry: entry:
%cmp15 = icmp sgt i64 %n, 0 %cmp15 = icmp sgt i64 %n, 0
@ -370,19 +378,20 @@ define float @convphi_loopdelayed2(i32 *%s, i32 *%d, i64 %n) {
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP15:%.*]] = icmp sgt i64 [[N:%.*]], 0 ; CHECK-NEXT: [[CMP15:%.*]] = icmp sgt i64 [[N:%.*]], 0
; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast i32 [[LS]] to float
; CHECK-NEXT: br i1 [[CMP15]], label [[LOOP:%.*]], label [[END:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[LOOP:%.*]], label [[END:%.*]]
; CHECK: loop: ; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[LPHI:%.*]] = phi i32 [ [[LS]], [[ENTRY]] ], [ [[LD:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[LPHI_TC:%.*]] = phi float [ [[LS_BC]], [[ENTRY]] ], [ [[LD_BC:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[LPHI2:%.*]] = phi i32 [ undef, [[ENTRY]] ], [ [[LPHI]], [[LOOP]] ] ; CHECK-NEXT: [[LPHI2_TC:%.*]] = phi float [ undef, [[ENTRY]] ], [ [[LPHI_TC]], [[LOOP]] ]
; CHECK-NEXT: [[LD]] = load i32, i32* [[D:%.*]], align 4 ; CHECK-NEXT: [[LD:%.*]] = load i32, i32* [[D:%.*]], align 4
; CHECK-NEXT: [[LD_BC]] = bitcast i32 [[LD]] to float
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]] ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[END]], label [[LOOP]] ; CHECK-NEXT: br i1 [[EXITCOND]], label [[END]], label [[LOOP]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ undef, [[ENTRY]] ], [ [[LPHI2]], [[LOOP]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi float [ undef, [[ENTRY]] ], [ [[LPHI2_TC]], [[LOOP]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast i32 [[PHI]] to float ; CHECK-NEXT: ret float [[PHI_TC]]
; CHECK-NEXT: ret float [[B]]
; ;
entry: entry:
%cmp15 = icmp sgt i64 %n, 0 %cmp15 = icmp sgt i64 %n, 0
@ -409,31 +418,33 @@ define float @convphi_loopmore(i32 *%s, i32 *%d, i64 %n) {
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[N:%.*]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[N:%.*]], 1
; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4 ; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4
; CHECK-NEXT: [[LS_BC:%.*]] = bitcast i32 [[LS]] to float
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[IFEND:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[IFEND:%.*]]
; CHECK: then: ; CHECK: then:
; CHECK-NEXT: [[LD:%.*]] = load i32, i32* [[D:%.*]], align 4 ; CHECK-NEXT: [[LD:%.*]] = load i32, i32* [[D:%.*]], align 4
; CHECK-NEXT: [[LD_BC:%.*]] = bitcast i32 [[LD]] to float
; CHECK-NEXT: br label [[IFEND]] ; CHECK-NEXT: br label [[IFEND]]
; CHECK: ifend: ; CHECK: ifend:
; CHECK-NEXT: [[PHI1:%.*]] = phi i32 [ [[LD]], [[THEN]] ], [ [[LS]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[PHI1_TC:%.*]] = phi float [ [[LD_BC]], [[THEN]] ], [ [[LS_BC]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[CMP15:%.*]] = icmp sgt i64 [[N]], 0 ; CHECK-NEXT: [[CMP15:%.*]] = icmp sgt i64 [[N]], 0
; CHECK-NEXT: br i1 [[CMP15]], label [[LOOP:%.*]], label [[END:%.*]] ; CHECK-NEXT: br i1 [[CMP15]], label [[LOOP:%.*]], label [[END:%.*]]
; CHECK: loop: ; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[IFEND]] ], [ [[IV_NEXT:%.*]], [[LOOPEND:%.*]] ] ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[IFEND]] ], [ [[IV_NEXT:%.*]], [[LOOPEND:%.*]] ]
; CHECK-NEXT: [[PHI2:%.*]] = phi i32 [ [[PHI1]], [[IFEND]] ], [ [[PHI3:%.*]], [[LOOPEND]] ] ; CHECK-NEXT: [[PHI2_TC:%.*]] = phi float [ [[PHI1_TC]], [[IFEND]] ], [ [[PHI3_TC:%.*]], [[LOOPEND]] ]
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[N]], 1 ; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[N]], 1
; CHECK-NEXT: br i1 [[TMP0]], label [[LOOPTHEN:%.*]], label [[LOOPEND]] ; CHECK-NEXT: br i1 [[TMP0]], label [[LOOPTHEN:%.*]], label [[LOOPEND]]
; CHECK: loopthen: ; CHECK: loopthen:
; CHECK-NEXT: [[LL:%.*]] = load i32, i32* [[D]], align 4 ; CHECK-NEXT: [[LL:%.*]] = load i32, i32* [[D]], align 4
; CHECK-NEXT: [[LL_BC:%.*]] = bitcast i32 [[LL]] to float
; CHECK-NEXT: br label [[LOOPEND]] ; CHECK-NEXT: br label [[LOOPEND]]
; CHECK: loopend: ; CHECK: loopend:
; CHECK-NEXT: [[PHI3]] = phi i32 [ [[LL]], [[LOOPTHEN]] ], [ [[PHI2]], [[LOOP]] ] ; CHECK-NEXT: [[PHI3_TC]] = phi float [ [[LL_BC]], [[LOOPTHEN]] ], [ [[PHI2_TC]], [[LOOP]] ]
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]] ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[END]], label [[LOOP]] ; CHECK-NEXT: br i1 [[EXITCOND]], label [[END]], label [[LOOP]]
; CHECK: end: ; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[PHI1]], [[IFEND]] ], [ [[PHI3]], [[LOOPEND]] ] ; CHECK-NEXT: [[PHI_TC:%.*]] = phi float [ [[PHI1_TC]], [[IFEND]] ], [ [[PHI3_TC]], [[LOOPEND]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast i32 [[PHI]] to float ; CHECK-NEXT: ret float [[PHI_TC]]
; CHECK-NEXT: ret float [[B]]
; ;
entry: entry:
%cmp = icmp eq i64 %n, 1 %cmp = icmp eq i64 %n, 1

View File

@ -0,0 +1,39 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -codegenprepare -cgp-optimize-phi-types=true %s -S | FileCheck %s
target datalayout = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"
target triple = "i386-unknown-linux-gnu"
define float @convphi1(i32 *%s, i32 *%d, i32 %n) {
; CHECK-LABEL: @convphi1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP15:%.*]] = icmp sgt i32 [[N:%.*]], 0
; CHECK-NEXT: br i1 [[CMP15]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then:
; CHECK-NEXT: [[LS:%.*]] = load i32, i32* [[S:%.*]], align 4
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: else:
; CHECK-NEXT: [[LD:%.*]] = load i32, i32* [[D:%.*]], align 4
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[LS]], [[THEN]] ], [ [[LD]], [[ELSE]] ]
; CHECK-NEXT: [[B:%.*]] = bitcast i32 [[PHI]] to float
; CHECK-NEXT: ret float [[B]]
;
entry:
%cmp15 = icmp sgt i32 %n, 0
br i1 %cmp15, label %then, label %else
then:
%ls = load i32, i32* %s, align 4
br label %end
else:
%ld = load i32, i32* %d, align 4
br label %end
end:
%phi = phi i32 [ %ls, %then ], [ %ld, %else ]
%b = bitcast i32 %phi to float
ret float %b
}