Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1514,8 +1514,37 @@ if (!I2) return false; + // Check for physical registers on the instructions first to avoid cases like + // this: + // + // %a = COPY $physreg + // ... + // SOMETHING implicit-def $physreg + // ... + // %b = COPY $physreg + // + // These copies are not equivalent. + // + // FIXME: We can probably do better here by checking register liveness. + if (any_of(I1->uses(), [](const MachineOperand &MO) { + return MO.isReg() && MO.getReg().isPhysical(); + })) { + // Check if we have a case like this: + // + // %a = COPY $physreg + // %b = COPY %a + // + // In this case, I1 and I2 will both be equal to %a = COPY $physreg. + // From that, we know that they must have the same value, since they must + // have come from the same COPY. + return I1->isIdenticalTo(*I2); + } + + // We don't have any physical registers, so we don't necessarily need the + // same vreg defs. + // // On the off-chance that there's some target instruction feeding into the - // select, let's use produceSameValue instead of isIdenticalTo. + // instruction, let's use produceSameValue instead of isIdenticalTo. return Builder.getTII().produceSameValue(*I1, *I2, &MRI); } Index: llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-select.mir =================================================================== --- llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-select.mir +++ llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-select.mir @@ -46,20 +46,23 @@ ... --- -name: self_with_equivalent +name: self_not_equivalent_1 tracksRegLiveness: true body: | bb.1.entry: liveins: $w0, $w1 - ; Optimize (cond ? %a : %b) -> %a ; - ; This shows that we can detect when %a == %b, even though they define - ; different virtual registers. + ; %a and %b are both copies from $w0, but we don't want to optimize here + ; because we don't know if $w0 is the same between them. ; - ; CHECK-LABEL: name: self_with_equivalent + ; CHECK-LABEL: name: self_not_equivalent_1 ; CHECK: liveins: $w0, $w1 ; CHECK: %a:_(s32) = COPY $w0 - ; CHECK: $w0 = COPY %a(s32) + ; CHECK: %b:_(s32) = COPY $w0 + ; CHECK: %cond_wide:gpr(s32) = COPY $w1 + ; CHECK: %cond:gpr(s1) = G_TRUNC %cond_wide(s32) + ; CHECK: %select:_(s32) = G_SELECT %cond(s1), %a, %b + ; CHECK: $w0 = COPY %select(s32) ; CHECK: RET_ReallyLR implicit $w0 %a:_(s32) = COPY $w0 %b:_(s32) = COPY $w0 @@ -71,13 +74,13 @@ ... --- -name: self_not_equivalent +name: self_not_equivalent_2 tracksRegLiveness: true body: | bb.1.entry: liveins: $w0, $w1 ; In this case, the copies are not equivalent, so there is no optimization. - ; CHECK-LABEL: name: self_not_equivalent + ; CHECK-LABEL: name: self_not_equivalent_2 ; CHECK: liveins: $w0, $w1 ; CHECK: %a:_(s32) = COPY $w0 ; CHECK: %b:_(s32) = COPY $w1