Index: lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- lib/Transforms/Scalar/EarlyCSE.cpp +++ lib/Transforms/Scalar/EarlyCSE.cpp @@ -67,11 +67,10 @@ static bool canHandle(Value *Val) { Instruction *Inst = dyn_cast(Val); - // TODO: We reject all non-instruction values so far, but will accept them - // in follow-up patch. This is done to diagnose the reason of potential - // problems with transition from working with instructions only to values. + // Since non-instruction values hever have side effects, we can safely work + // with them. if (!Inst) - return false; + return true; // This can only handle non-void readnone functions. if (CallInst *CI = dyn_cast(Inst)) return CI->doesNotAccessMemory() && !CI->getType()->isVoidTy(); @@ -98,7 +97,10 @@ } unsigned DenseMapInfo::getHashValue(SimpleValue Val) { - Instruction *Inst = cast(Val.Val); + Instruction *Inst = dyn_cast(Val.Val); + // Non-instruction values do not have operands. + if (!Inst) + return hash_combine(Val.Val); // Hash in all of the operands as pointers. if (BinaryOperator *BinOp = dyn_cast(Inst)) { Value *LHS = BinOp->getOperand(0); @@ -149,8 +151,12 @@ return LHS.Val == RHS.Val; // Otherwise try to prove equality of instructions. - Instruction *LHSI = cast(LHS.Val); - Instruction *RHSI = cast(RHS.Val); + Instruction *LHSI = dyn_cast(LHS.Val); + Instruction *RHSI = dyn_cast(RHS.Val); + + // For non-instruction values, we just compare references. + if (!LHSI || !RHSI) + return LHS.Val == RHS.Val; if (LHSI->getOpcode() != RHSI->getOpcode()) return false; Index: test/Transforms/EarlyCSE/guards.ll =================================================================== --- test/Transforms/EarlyCSE/guards.ll +++ test/Transforms/EarlyCSE/guards.ll @@ -526,3 +526,141 @@ call void @llvm.assume(i1 %c) ret void } + +define void @test19(i1 %c) { +; Check that assume can mark a non-instruction value as true. + +; CHECK-LABEL: @test19( +; CHECK-NEXT: call void @llvm.assume(i1 %c) +; CHECK-NEXT: ret void + + call void @llvm.assume(i1 %c) + call void (i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ] + ret void +} + +define void @test20(i1 %c) { +; Check that guard can mark a non-instruction value as true. + +; CHECK-LABEL: @test20( +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ] +; CHECK-NEXT: ret void + + call void (i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ] + call void (i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ] + call void (i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ] + ret void +} + +define void @test21(i1 %c) { +; Check that branching by a non-instruction condition allows to remove guards. + +; CHECK-LABEL: @test21( +; CHECK: entry: +; CHECK-NEXT: br i1 %c, label %if.true, label %if.false +; CHECK: if.true: +; CHECK-NEXT: br label %merge +; CHECK: if.false: +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] +; CHECK-NEXT: br label %merge +; CHECK: merge: +; CHECK-NEXT: ret void + +entry: + br i1 %c, label %if.true, label %if.false + +if.true: + call void (i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ] + br label %merge + +if.false: + call void (i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ] + br label %merge + +merge: + ret void +} + +define void @test22(i1 %cmp, i1 %c, i32* %ptr) { +; Similar to test14, but with assumed condition being non-instruction. + +; CHECK-LABEL: @test22( +; CHECK: entry: +; CHECK-NEXT: call void @llvm.assume(i1 %cmp) +; CHECK-NEXT: store i32 400, i32* %ptr +; CHECK-NEXT: br i1 %c, label %if.true, label %if.false +; CHECK: if.true: +; CHECK-NEXT: store i32 500, i32* %ptr +; CHECK-NEXT: br label %merge +; CHECK: if.false: +; CHECK-NEXT: store i32 600, i32* %ptr +; CHECK-NEXT: br label %merge +; CHECK: merge: +; CHECK-NEXT: ret void + +entry: + call void @llvm.assume(i1 %cmp) + store i32 100, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 200, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 300, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 400, i32* %ptr + br i1 %c, label %if.true, label %if.false + +if.true: + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 500, i32* %ptr + br label %merge + +if.false: + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 600, i32* %ptr + br label %merge + +merge: + ret void +} + +define void @test23(i1 %cmp, i1 %c, i32* %ptr) { +; Similar to test22, guard instead of assume. + +; CHECK-LABEL: @test23( +; CHECK: entry: +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] +; CHECK-NEXT: store i32 400, i32* %ptr +; CHECK-NEXT: br i1 %c, label %if.true, label %if.false +; CHECK: if.true: +; CHECK-NEXT: store i32 500, i32* %ptr +; CHECK-NEXT: br label %merge +; CHECK: if.false: +; CHECK-NEXT: store i32 600, i32* %ptr +; CHECK-NEXT: br label %merge +; CHECK: merge: +; CHECK-NEXT: ret void + +entry: + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 100, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 200, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 300, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 400, i32* %ptr + br i1 %c, label %if.true, label %if.false + +if.true: + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 500, i32* %ptr + br label %merge + +if.false: + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 600, i32* %ptr + br label %merge + +merge: + ret void +}