diff options
-rw-r--r-- | llvm/lib/CodeGen/MachineSSAUpdater.cpp | 18 | ||||
-rwxr-xr-x | llvm/test/CodeGen/AArch64/taildup-ssa-update-pr62712.mir | 302 |
2 files changed, 319 insertions, 1 deletions
diff --git a/llvm/lib/CodeGen/MachineSSAUpdater.cpp b/llvm/lib/CodeGen/MachineSSAUpdater.cpp index 8d6ea9c..5b21c56 100644 --- a/llvm/lib/CodeGen/MachineSSAUpdater.cpp +++ b/llvm/lib/CodeGen/MachineSSAUpdater.cpp @@ -209,7 +209,7 @@ Register MachineSSAUpdater::GetValueInMiddleOfBlock(MachineBasicBlock *BB, // If the client wants to know about all new instructions, tell it. if (InsertedPHIs) InsertedPHIs->push_back(InsertedPHI); - LLVM_DEBUG(dbgs() << " Inserted PHI: " << *InsertedPHI << "\n"); + LLVM_DEBUG(dbgs() << " Inserted PHI: " << *InsertedPHI); return InsertedPHI.getReg(0); } @@ -236,6 +236,22 @@ void MachineSSAUpdater::RewriteUse(MachineOperand &U) { NewVR = GetValueInMiddleOfBlock(UseMI->getParent()); } + // Insert a COPY if needed to satisfy register class constraints for the using + // MO. Or, if possible, just constrain the class for NewVR to avoid the need + // for a COPY. + if (NewVR) { + const TargetRegisterClass *UseRC = + dyn_cast_or_null<const TargetRegisterClass *>(RegAttrs.RCOrRB); + if (UseRC && !MRI->constrainRegClass(NewVR, UseRC)) { + MachineBasicBlock *UseBB = UseMI->getParent(); + MachineInstr *InsertedCopy = + InsertNewDef(TargetOpcode::COPY, UseBB, UseBB->getFirstNonPHI(), + RegAttrs, MRI, TII) + .addReg(NewVR); + NewVR = InsertedCopy->getOperand(0).getReg(); + LLVM_DEBUG(dbgs() << " Inserted COPY: " << *InsertedCopy); + } + } U.setReg(NewVR); } diff --git a/llvm/test/CodeGen/AArch64/taildup-ssa-update-pr62712.mir b/llvm/test/CodeGen/AArch64/taildup-ssa-update-pr62712.mir new file mode 100755 index 0000000..abe1813 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/taildup-ssa-update-pr62712.mir @@ -0,0 +1,302 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5 +# RUN: llc -verify-machineinstrs -mtriple aarch64-none-linux-gnu -run-pass early-tailduplication -o - %s | FileCheck %s + +# These tests used to hit verification failure due to register class +# mismatches after tail dupilication (and the SSA form updates). + +# In test1 we have a simple case when the COPY already is duplicated, but +# TailDuplication will try to eliminate the PHI in bb.2 by adding a new PHI in +# bb.4. The presence of a PHI node in bb.4, which happens to assign to a +# fpr32 register, was enough to mess up the result. The PHI node was reused +# and the use of %2 in the CBNZW was changed into using %3 instead. But the +# register class of %3 is not correct for CBNZW. +# The fix involves adding a COPY instruction that moves the value to +# a register of correct regclass. +--- +name: test1 +tracksRegLiveness: true +body: | + ; CHECK-LABEL: name: test1 + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit-def %0 + ; CHECK-NEXT: B %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit-def %1 + ; CHECK-NEXT: B %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.3: + ; CHECK-NEXT: successors: %bb.3(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: B %bb.3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.4: + ; CHECK-NEXT: successors: %bb.5(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[PHI:%[0-9]+]]:fpr32 = PHI %0, %bb.0, %1, %bb.1 + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY [[PHI]] + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit [[PHI]] + ; CHECK-NEXT: CBNZW [[COPY]], %bb.5 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.5: + bb.0: + $x0 = COPY undef $x0, implicit-def %0:gpr32 + B %bb.2 + + bb.1: + $x0 = COPY undef $x0, implicit-def %1:gpr32 + + bb.2: + %2:gpr32 = PHI %1, %bb.1, %0, %bb.0 + B %bb.4 + + bb.3: + B %bb.3 + + bb.4: + %3:fpr32 = PHI %2, %bb.2 + $x0 = COPY undef $x0, implicit %3:fpr32 + CBNZW %2, %bb.5 + + bb.5: + +... + +# In test2 there are two PHIs already present, one with the wanted register +# class. No idea if this is a common scenario in reality (hand written mir +# test case). +# FIXME: Can we pick the best PHI directly instead of getting a COPY from the +# one with wrong register class? +--- +name: test2 +tracksRegLiveness: true +body: | + ; CHECK-LABEL: name: test2 + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit-def %0 + ; CHECK-NEXT: B %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit-def %1 + ; CHECK-NEXT: B %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.3: + ; CHECK-NEXT: successors: %bb.3(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: B %bb.3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.4: + ; CHECK-NEXT: successors: %bb.5(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[PHI:%[0-9]+]]:fpr32 = PHI %0, %bb.0, %1, %bb.1 + ; CHECK-NEXT: [[PHI1:%[0-9]+]]:gpr32 = PHI %0, %bb.0, %1, %bb.1 + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY [[PHI]] + ; CHECK-NEXT: CBNZW [[COPY]], %bb.5 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.5: + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit [[PHI]] + bb.0: + $x0 = COPY undef $x0, implicit-def %0:gpr32 + B %bb.2 + + bb.1: + $x0 = COPY undef $x0, implicit-def %1:gpr32 + + bb.2: + %2:gpr32 = PHI %1, %bb.1, %0, %bb.0 + B %bb.4 + + bb.3: + B %bb.3 + + bb.4: + %3:fpr32 = PHI %2, %bb.2 + %4:gpr32 = PHI %2, %bb.2 + CBNZW %2, %bb.5 + + bb.5: + $x0 = COPY undef $x0, implicit %3:fpr32 +... + +# In test3 we have multiple uses, and in multiple BBs. This test is to show +# that we get one COPY instruction inserted for each BB where there is a use. +--- +name: test3 +tracksRegLiveness: true +body: | + ; CHECK-LABEL: name: test3 + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit-def %0 + ; CHECK-NEXT: B %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit-def %1 + ; CHECK-NEXT: B %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.3: + ; CHECK-NEXT: successors: %bb.3(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: B %bb.3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.4: + ; CHECK-NEXT: successors: %bb.5(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[PHI:%[0-9]+]]:fpr32 = PHI %0, %bb.0, %1, %bb.1 + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit [[PHI]] + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.5: + ; CHECK-NEXT: successors: %bb.6(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr32 = COPY [[PHI]] + ; CHECK-NEXT: CBNZW [[COPY]], %bb.6 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.6: + ; CHECK-NEXT: successors: %bb.7(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr32 = COPY [[PHI]] + ; CHECK-NEXT: CBNZW [[COPY1]], %bb.7 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.7: + bb.0: + $x0 = COPY undef $x0, implicit-def %0:gpr32 + B %bb.2 + + bb.1: + $x0 = COPY undef $x0, implicit-def %1:gpr32 + + bb.2: + %2:gpr32 = PHI %1, %bb.1, %0, %bb.0 + B %bb.4 + + bb.3: + B %bb.3 + + bb.4: + %3:fpr32 = PHI %2, %bb.2 + $x0 = COPY undef $x0, implicit %3:fpr32 + + bb.5: + CBNZW %2, %bb.6 + + bb.6: + CBNZW %2, %bb.7 + + bb.7: +... + +# In test4 we do not need to insert a COPY. +# The register class can be constrained instead. +--- +name: test4 +tracksRegLiveness: true +body: | + ; CHECK-LABEL: name: test4 + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit-def %0 + ; CHECK-NEXT: B %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit-def %1 + ; CHECK-NEXT: B %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.3: + ; CHECK-NEXT: successors: %bb.3(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: B %bb.3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.4: + ; CHECK-NEXT: successors: %bb.5(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[PHI:%[0-9]+]]:gpr32common = PHI %0, %bb.0, %1, %bb.1 + ; CHECK-NEXT: CBNZW [[PHI]], %bb.5 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.5: + bb.0: + $x0 = COPY undef $x0, implicit-def %0:gpr32 + B %bb.2 + + bb.1: + $x0 = COPY undef $x0, implicit-def %1:gpr32 + + bb.2: + %2:gpr32 = PHI %1, %bb.1, %0, %bb.0 + B %bb.4 + + bb.3: + B %bb.3 + + bb.4: + %3:gpr32sp = PHI %2, %bb.2 + CBNZW %2, %bb.5 + + bb.5: + +... + +# In test5 we do not need to insert a COPY. +# The register class can be constrained instead. +--- +name: test5 +tracksRegLiveness: true +body: | + ; CHECK-LABEL: name: test5 + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit-def %0 + ; CHECK-NEXT: B %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: successors: %bb.4(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: $x0 = COPY undef $x0, implicit-def %1 + ; CHECK-NEXT: B %bb.4 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.3: + ; CHECK-NEXT: successors: %bb.3(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: B %bb.3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.4: + ; CHECK-NEXT: successors: %bb.5(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[PHI:%[0-9]+]]:gpr32common = PHI %0, %bb.0, %1, %bb.1 + ; CHECK-NEXT: CBNZW [[PHI]], %bb.5 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.5: + bb.0: + $x0 = COPY undef $x0, implicit-def %0:gpr32common + B %bb.2 + + bb.1: + $x0 = COPY undef $x0, implicit-def %1:gpr32common + + bb.2: + %2:gpr32common = PHI %1, %bb.1, %0, %bb.0 + B %bb.4 + + bb.3: + B %bb.3 + + bb.4: + %3:gpr32 = PHI %2, %bb.2 + CBNZW %2, %bb.5 + + bb.5: +... |