#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
+#include "llvm/IR/ValueHandle.h"
#include "llvm/Pass.h"
#include "llvm/PassAnalysisSupport.h"
#include "llvm/Support/Casting.h"
// The set of edges along which we can only handle phi uses, due to critical
// edges.
DenseSet<std::pair<BasicBlock *, BasicBlock *>> EdgeUsesOnly;
+ // The set of ssa_copy declarations we created with our custom mangling.
+ SmallSet<AssertingVH<Function>, 20> CreatedDeclarations;
};
// This pass does eager building and then printing of PredicateInfo. It is used
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/IR/AssemblyAnnotationWriter.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstIterator.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
renameUses(OpsToRename);
}
+// Create a ssa_copy declaration with custom mangling, because
+// Intrinsic::getDeclaration does not handle overloaded unnamed types properly:
+// all unnamed types get mangled to the same string. We use the pointer
+// to the type as name here, as it guarantees unique names for different
+// types and we remove the declarations when destroying PredicateInfo.
+// It is a workaround for PR38117, because solving it in a fully general way is
+// tricky (FIXME).
+static Function *getCopyDeclaration(Module *M, Type *Ty) {
+ std::string Name = "llvm.ssa.copy." + utostr((uintptr_t) Ty);
+ return cast<Function>(M->getOrInsertFunction(
+ Name, getType(M->getContext(), Intrinsic::ssa_copy, Ty)));
+}
+
// Given the renaming stack, make all the operands currently on the stack real
// by inserting them into the IR. Return the last operation's value.
Value *PredicateInfo::materializeStack(unsigned int &Counter,
// order in the case of multiple predicateinfo in the same block.
if (isa<PredicateWithEdge>(ValInfo)) {
IRBuilder<> B(getBranchTerminator(ValInfo));
- Function *IF = Intrinsic::getDeclaration(
- F.getParent(), Intrinsic::ssa_copy, Op->getType());
+ Function *IF = getCopyDeclaration(F.getParent(), Op->getType());
+ if (IF->user_begin() == IF->user_end())
+ CreatedDeclarations.insert(IF);
CallInst *PIC =
B.CreateCall(IF, Op, Op->getName() + "." + Twine(Counter++));
PredicateMap.insert({PIC, ValInfo});
assert(PAssume &&
"Should not have gotten here without it being an assume");
IRBuilder<> B(PAssume->AssumeInst);
- Function *IF = Intrinsic::getDeclaration(
- F.getParent(), Intrinsic::ssa_copy, Op->getType());
+ Function *IF = getCopyDeclaration(F.getParent(), Op->getType());
+ if (IF->user_begin() == IF->user_end())
+ CreatedDeclarations.insert(IF);
CallInst *PIC = B.CreateCall(IF, Op);
PredicateMap.insert({PIC, ValInfo});
Result.Def = PIC;
buildPredicateInfo();
}
-PredicateInfo::~PredicateInfo() {}
+// Remove all declarations we created . The PredicateInfo consumers are
+// responsible for remove the ssa_copy calls created.
+PredicateInfo::~PredicateInfo() {
+ // Collect function pointers in set first, as SmallSet uses a SmallVector
+ // internally and we have to remove the asserting value handles first.
+ SmallPtrSet<Function *, 20> FunctionPtrs;
+ for (auto &F : CreatedDeclarations)
+ FunctionPtrs.insert(&*F);
+ CreatedDeclarations.clear();
+
+ for (Function *F : FunctionPtrs) {
+ assert(F->user_begin() == F->user_end() &&
+ "PredicateInfo consumer did not remove all SSA copies.");
+ F->eraseFromParent();
+ }
+}
void PredicateInfo::verifyPredicateInfo() const {}
AU.addRequired<AssumptionCacheTracker>();
}
+// Replace ssa_copy calls created by PredicateInfo with their operand.
+static void replaceCreatedSSACopys(PredicateInfo &PredInfo, Function &F) {
+ for (auto I = inst_begin(F), E = inst_end(F); I != E;) {
+ Instruction *Inst = &*I++;
+ const auto *PI = PredInfo.getPredicateInfoFor(Inst);
+ auto *II = dyn_cast<IntrinsicInst>(Inst);
+ if (!PI || !II || II->getIntrinsicID() != Intrinsic::ssa_copy)
+ continue;
+
+ Inst->replaceAllUsesWith(II->getOperand(0));
+ Inst->eraseFromParent();
+ }
+}
+
bool PredicateInfoPrinterLegacyPass::runOnFunction(Function &F) {
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
PredInfo->print(dbgs());
if (VerifyPredicateInfo)
PredInfo->verifyPredicateInfo();
+
+ replaceCreatedSSACopys(*PredInfo, F);
return false;
}
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &AC = AM.getResult<AssumptionAnalysis>(F);
OS << "PredicateInfo for function: " << F.getName() << "\n";
- make_unique<PredicateInfo>(F, DT, AC)->print(OS);
+ auto PredInfo = make_unique<PredicateInfo>(F, DT, AC);
+ PredInfo->print(OS);
+ replaceCreatedSSACopys(*PredInfo, F);
return PreservedAnalyses::all();
}
; CHECK-NEXT: br label [[BB22:%.*]]
; CHECK: bb22:
; CHECK-NEXT: [[TMP23:%.*]] = icmp eq i32 undef, 2
-; CHECK: [[TMP23_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP23]])
+; CHECK: [[TMP23_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP23]])
; CHECK-NEXT: br i1 [[TMP23]], label [[BB29:%.*]], label [[BB35:%.*]]
; CHECK: bb29:
-; CHECK: [[TMP23_0_1:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP23_0]])
+; CHECK: [[TMP23_0_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP23_0]])
; CHECK-NEXT: br i1 [[TMP23]], label [[BB33:%.*]], label [[BB35]]
; CHECK: bb33:
; CHECK-NEXT: br i1 [[TMP23_0_1]], label [[BB35]], label [[BB35]]
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[PUTS2:%.*]] = tail call i32 @puts(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @str.2, i64 0, i64 0))
-; CHECK-NEXT: tail call void @abort() #4
+; CHECK-NEXT: tail call void @abort()
; CHECK-NEXT: unreachable
; CHECK: if.end:
; CHECK-NEXT: [[PUTS:%.*]] = tail call i32 @puts(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @str, i64 0, i64 0))
; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
; CHECK-NEXT: [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
-; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
-; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
-; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
-; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
+; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
+; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
+; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: br i1 [[Z]], label [[BOTH_ZERO:%.*]], label [[NOPE:%.*]]
; CHECK: both_zero:
; CHECK-NEXT: call void @foo(i1 [[XZ_0]])
; CHECK-NEXT: i32 3, label [[CASE3]]
; CHECK-NEXT: i32 4, label [[DEFAULT:%.*]]
; CHECK-NEXT: ] Edge: [label [[SW]],label %case1] }
-; CHECK-NEXT: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X:%.*]])
+; CHECK-NEXT: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X:%.*]])
; CHECK-NEXT: switch i32 [[X]], label [[DEFAULT]] [
; CHECK-NEXT: i32 0, label [[CASE0]]
; CHECK-NEXT: i32 1, label [[CASE1]]
define i1 @test5(i32 %x, i32 %y) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
-; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
-; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
-; CHECK: [[Y_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
+; CHECK: [[Y_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
; CHECK: same:
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[X_0]], [[Y_0]]
define i1 @test7(i32 %x, i32 %y) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
-; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
-; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
-; CHECK: [[Y_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
+; CHECK: [[Y_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
; CHECK: same:
; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[X_0]], [[Y_0]]
define i1 @test7_fp(float %x, float %y) {
; CHECK-LABEL: @test7_fp(
; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[X:%.*]], [[Y:%.*]]
-; CHECK: [[X_0:%.*]] = call float @llvm.ssa.copy.f32(float [[X]])
-; CHECK: [[X_1:%.*]] = call float @llvm.ssa.copy.f32(float [[X]])
-; CHECK: [[Y_0:%.*]] = call float @llvm.ssa.copy.f32(float [[Y]])
-; CHECK: [[Y_1:%.*]] = call float @llvm.ssa.copy.f32(float [[Y]])
+; CHECK: [[X_0:%.*]] = call float @llvm.ssa.copy.{{.+}}(float [[X]])
+; CHECK: [[X_1:%.*]] = call float @llvm.ssa.copy.{{.+}}(float [[X]])
+; CHECK: [[Y_0:%.*]] = call float @llvm.ssa.copy.{{.+}}(float [[Y]])
+; CHECK: [[Y_1:%.*]] = call float @llvm.ssa.copy.{{.+}}(float [[Y]])
; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
; CHECK: same:
; CHECK-NEXT: [[CMP2:%.*]] = fcmp ule float [[X_0]], [[Y_0]]
define i32 @test9(i32 %i, i32 %j) {
; CHECK-LABEL: @test9(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], [[J:%.*]]
-; CHECK: [[I_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[I]])
-; CHECK: [[J_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[J]])
+; CHECK: [[I_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[I]])
+; CHECK: [[J_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[J]])
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[RET:%.*]]
; CHECK: cond_true:
; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[I_0]], [[J_0]]
define i32 @test10(i32 %j, i32 %i) {
; CHECK-LABEL: @test10(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], [[J:%.*]]
-; CHECK: [[J_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[J]])
-; CHECK: [[I_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[I]])
+; CHECK: [[J_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[J]])
+; CHECK: [[I_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[I]])
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[RET:%.*]]
; CHECK: cond_true:
; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[I_0]], [[J_0]]
; CHECK-NEXT: [[V0:%.*]] = call i32 @yogibar()
; CHECK-NEXT: [[V1:%.*]] = call i32 @yogibar()
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V0]], [[V1]]
-; CHECK: [[V0_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V0]])
-; CHECK: [[V1_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V1]])
+; CHECK: [[V0_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[V0]])
+; CHECK: [[V1_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[V1]])
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[NEXT:%.*]]
; CHECK: cond_true:
; CHECK-NEXT: ret i32 [[V1_0]]
; CHECK: next:
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[X:%.*]], [[V0_0]]
-; CHECK: [[V0_0_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V0_0]])
+; CHECK: [[V0_0_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[V0_0]])
; CHECK-NEXT: br i1 [[CMP2]], label [[COND_TRUE2:%.*]], label [[NEXT2:%.*]]
; CHECK: cond_true2:
; CHECK-NEXT: ret i32 [[V0_0_1]]
define i32 @test12(i32 %x) {
; CHECK-LABEL: @test12(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
-; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond_true:
; CHECK-NEXT: br label [[RET:%.*]]
; CHECK-NEXT: br i1 [[Y:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
; CHECK: bb0:
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[X:%.*]], 0
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK-NEXT: br i1 [[CMP]], label [[BB2:%.*]], label [[BB3:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[X2:%.*]] = add nuw nsw i32 [[X]], 1
; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[X2]], 2
-; CHECK: [[X2_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X2]])
+; CHECK: [[X2_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X2]])
; CHECK-NEXT: br i1 [[CMP2]], label [[BB2]], label [[BB3]]
; CHECK: bb2:
; CHECK-NEXT: [[X3:%.*]] = phi i32 [ [[X_0]], [[BB0]] ], [ [[X2_0]], [[BB1]] ]
; CHECK-NEXT: br i1 [[Y:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
; CHECK: bb0:
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[X:%.*]], 0
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK-NEXT: br i1 [[CMP]], label [[BB3:%.*]], label [[BB2:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[X2:%.*]] = add nuw nsw i32 [[X]], 1
; CHECK-NEXT: [[CMP2:%.*]] = icmp sge i32 [[X2]], 2
-; CHECK: [[X2_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X2]])
+; CHECK: [[X2_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X2]])
; CHECK-NEXT: br i1 [[CMP2]], label [[BB3]], label [[BB2]]
; CHECK: bb2:
; CHECK-NEXT: [[X3:%.*]] = phi i32 [ [[X_0]], [[BB0]] ], [ [[X2_0]], [[BB1]] ]
; CHECK-LABEL: @f1(
; CHECK-NEXT: bb0:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK-NEXT: br i1 [[CMP]], label [[BB2:%.*]], label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: br label [[BB2]]
; CHECK-LABEL: @f2(
; CHECK-NEXT: bb0:
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[X:%.*]], 0
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
; CHECK-NEXT: br i1 [[CMP]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: bb1:
; CHECK-NEXT: br label [[BB2]]
define i32 @f3(i32 %x) {
; CHECK-LABEL: @f3(
; CHECK-NEXT: bb0:
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X:%.*]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X:%.*]])
; CHECK-NEXT: switch i32 [[X]], label [[BB1:%.*]] [
; CHECK-NEXT: i32 0, label [[BB2:%.*]]
; CHECK-NEXT: ]
; CHECK-LABEL: @fcmp_oeq_not_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y:%.*]], 2.000000e+00
-; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Y]])
+; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.{{.+}}(double [[Y]])
; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[RETURN:%.*]]
; CHECK: if:
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Y_0]]
; CHECK-LABEL: @fcmp_une_not_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[Y:%.*]], 2.000000e+00
-; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Y]])
+; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.{{.+}}(double [[Y]])
; CHECK-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[ELSE:%.*]]
; CHECK: else:
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Y_0]]
; CHECK-LABEL: @fcmp_oeq_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y:%.*]], 0.000000e+00
-; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Y]])
+; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.{{.+}}(double [[Y]])
; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[RETURN:%.*]]
; CHECK: if:
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Y_0]]
; CHECK-LABEL: @fcmp_une_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[Y:%.*]], -0.000000e+00
-; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Y]])
+; CHECK: [[Y_0:%.*]] = call double @llvm.ssa.copy.{{.+}}(double [[Y]])
; CHECK-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[ELSE:%.*]]
; CHECK: else:
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Y_0]]
; CHECK-NEXT: entry:
; CHECK-NEXT: [[Z:%.*]] = fadd double [[Z1:%.*]], [[Z2:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[Y:%.*]], [[Z]]
-; CHECK: [[Z_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Z]])
+; CHECK: [[Z_0:%.*]] = call double @llvm.ssa.copy.{{.+}}(double [[Z]])
; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[RETURN:%.*]]
; CHECK: if:
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Z_0]]
; CHECK-NEXT: entry:
; CHECK-NEXT: [[Z:%.*]] = fadd double [[Z1:%.*]], [[Z2:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[Y:%.*]], [[Z]]
-; CHECK: [[Z_0:%.*]] = call double @llvm.ssa.copy.f64(double [[Z]])
+; CHECK: [[Z_0:%.*]] = call double @llvm.ssa.copy.{{.+}}(double [[Z]])
; CHECK-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[ELSE:%.*]]
; CHECK: else:
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[X:%.*]], [[Z_0]]
; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
; CHECK-NEXT: [[Z:%.*]] = or i1 [[XZ]], [[YZ]]
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
-; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
-; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
-; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
-; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
+; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
+; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
+; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: br i1 [[Z]], label [[ONEOF:%.*]], label [[NEITHER:%.*]]
; CHECK: oneof:
; CHECK-NEXT: call void @foo(i1 [[XZ]])
; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
; CHECK-NEXT: [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
-; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
-; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
-; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
-; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
+; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
+; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
+; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: both:
; CHECK-NEXT: call void @foo(i1 [[XZ_0]])
; CHECK-NEXT: [[XGT:%.*]] = icmp sgt i32 [[X:%.*]], 0
; CHECK-NEXT: [[XLT:%.*]] = icmp slt i32 [[X]], 100
; CHECK-NEXT: [[Z:%.*]] = and i1 [[XGT]], [[XLT]]
-; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
-; CHECK: [[X_0_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X_0]])
-; CHECK: [[XGT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XGT]])
-; CHECK: [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XLT]])
-; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
+; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK: [[X_0_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X_0]])
+; CHECK: [[XGT_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XGT]])
+; CHECK: [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XLT]])
+; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: both:
; CHECK-NEXT: call void @foo(i1 [[XGT_0]])
; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
; CHECK-NEXT: [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
-; CHECK: [[TMP1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
-; CHECK: [[TMP2:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
-; CHECK: [[TMP3:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
-; CHECK: [[TMP4:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
-; CHECK: [[TMP5:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
+; CHECK: [[TMP1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK: [[TMP2:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
+; CHECK: [[TMP3:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
+; CHECK: [[TMP4:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
+; CHECK: [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP5]])
-; CHECK: [[DOT0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP1]])
-; CHECK: [[DOT01:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP2]])
-; CHECK: [[DOT02:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP3]])
-; CHECK: [[DOT03:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP4]])
-; CHECK: [[DOT04:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP5]])
+; CHECK: [[DOT0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP1]])
+; CHECK: [[DOT01:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP2]])
+; CHECK: [[DOT02:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP3]])
+; CHECK: [[DOT03:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP4]])
+; CHECK: [[DOT04:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP5]])
; CHECK-NEXT: br i1 [[TMP5]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: both:
; CHECK-NEXT: call void @foo(i1 [[DOT02]])
; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
; CHECK-NEXT: [[Z:%.*]] = or i1 [[XZ]], [[YZ]]
; CHECK-NEXT: call void @llvm.assume(i1 [[Z]])
-; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
+; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
; CHECK: both:
; CHECK-NEXT: call void @foo(i1 [[XZ]])
--- /dev/null
+; RUN: opt < %s -print-predicateinfo 2>&1 | FileCheck %s
+
+%1 = type opaque
+%0 = type opaque
+
+; Check we can use ssa.copy with unnamed types.
+
+; CHECK-LABEL: bb:
+; CHECK: Has predicate info
+; CHECK: branch predicate info { TrueEdge: 1 Comparison: %cmp1 = icmp ne %0* %arg, null Edge: [label %bb,label %bb1] }
+; CHECK-NEXT: %arg.0 = call %0* @llvm.ssa.copy.{{.+}}(%0* %arg)
+
+; CHECK-LABEL: bb1:
+; CHECK: Has predicate info
+; CHECK-NEXT: branch predicate info { TrueEdge: 0 Comparison: %cmp2 = icmp ne %1* null, %tmp Edge: [label %bb1,label %bb3] }
+; CHECK-NEXT: %tmp.0 = call %1* @llvm.ssa.copy.{{.+}}(%1* %tmp)
+
+define void @f0(%0* %arg, %1* %tmp) {
+bb:
+ %cmp1 = icmp ne %0* %arg, null
+ br i1 %cmp1, label %bb1, label %bb2
+
+bb1: ; preds = %bb
+ %cmp2 = icmp ne %1* null, %tmp
+ br i1 %cmp2, label %bb2, label %bb3
+
+bb2: ; preds = %bb
+ ret void
+
+bb3: ; preds = %bb
+ %u1 = call i8* @fun(%1* %tmp)
+ %tmp2 = bitcast %0* %arg to i8*
+ ret void
+}
+
+declare i8* @fun(%1*)