Index: llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp +++ llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp @@ -630,7 +630,8 @@ "Unexpected hint opcode!"); // The only correct mapping for these is to always use the source register // bank. - const RegisterBank *RB = MRI->getRegBankOrNull(MI.getOperand(1).getReg()); + const RegisterBank *RB = + RBI->getRegBank(MI.getOperand(1).getReg(), *MRI, *TRI); // We can assume every instruction above this one has a selected register // bank. assert(RB && "Expected source register to have a register bank?"); Index: llvm/lib/CodeGen/MachineVerifier.cpp =================================================================== --- llvm/lib/CodeGen/MachineVerifier.cpp +++ llvm/lib/CodeGen/MachineVerifier.cpp @@ -48,6 +48,7 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/CodeGen/RegisterBank.h" +#include "llvm/CodeGen/RegisterBankInfo.h" #include "llvm/CodeGen/SlotIndexes.h" #include "llvm/CodeGen/StackMaps.h" #include "llvm/CodeGen/TargetInstrInfo.h" @@ -96,6 +97,7 @@ const TargetInstrInfo *TII; const TargetRegisterInfo *TRI; const MachineRegisterInfo *MRI; + const RegisterBankInfo *RBI; unsigned foundErrors; @@ -371,6 +373,7 @@ TM = &MF.getTarget(); TII = MF.getSubtarget().getInstrInfo(); TRI = MF.getSubtarget().getRegisterInfo(); + RBI = MF.getSubtarget().getRegBankInfo(); MRI = &MF.getRegInfo(); const bool isFunctionFailedISel = MF.getProperties().hasProperty( @@ -1001,17 +1004,23 @@ break; } - if (MRI->getRegBankOrNull(Src) != MRI->getRegBankOrNull(Dst)) { - report( - Twine(OpcName, " source and destination register banks must match"), - MI); + const RegisterBank *SrcRB = RBI->getRegBank(Src, *MRI, *TRI); + const RegisterBank *DstRB = RBI->getRegBank(Dst, *MRI, *TRI); + + // Allow only the source bank to be set. + if ((SrcRB && DstRB && SrcRB != DstRB) || (DstRB && !SrcRB)) { + report(Twine(OpcName, " cannot change register bank"), MI); break; } - if (MRI->getRegClassOrNull(Src) != MRI->getRegClassOrNull(Dst)) + // Don't allow a class change. Do allow member class->regbank. + const TargetRegisterClass *DstRC = MRI->getRegClassOrNull(Dst); + if (DstRC && DstRC != MRI->getRegClassOrNull(Src)) { report( Twine(OpcName, " source and destination register classes must match"), MI); + break; + } break; } Index: llvm/test/CodeGen/AMDGPU/GlobalISel/regbankselect-assert-zext.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AMDGPU/GlobalISel/regbankselect-assert-zext.mir @@ -0,0 +1,102 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -march=amdgcn -mcpu=gfx90a -run-pass=regbankselect %s -verify-machineinstrs -o - | FileCheck %s + +--- +name: assert_zext_vgpr +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $vgpr0 + + ; CHECK-LABEL: name: assert_zext_vgpr + ; CHECK: liveins: $vgpr0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %copy:vgpr(s32) = COPY $vgpr0 + ; CHECK-NEXT: %assert_zext:vgpr(s32) = G_ASSERT_ZEXT %copy, 4 + ; CHECK-NEXT: S_ENDPGM 0, implicit %assert_zext(s32) + %copy:_(s32) = COPY $vgpr0 + %assert_zext:_(s32) = G_ASSERT_ZEXT %copy, 4 + S_ENDPGM 0, implicit %assert_zext +... + +--- +name: assert_zext_sgpr +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $sgpr8 + + ; CHECK-LABEL: name: assert_zext_sgpr + ; CHECK: liveins: $sgpr8 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %copy:sgpr(s32) = COPY $sgpr8 + ; CHECK-NEXT: %assert_zext:sgpr(s32) = G_ASSERT_ZEXT %copy, 4 + ; CHECK-NEXT: S_ENDPGM 0, implicit %assert_zext(s32) + %copy:_(s32) = COPY $sgpr8 + %assert_zext:_(s32) = G_ASSERT_ZEXT %copy, 4 + S_ENDPGM 0, implicit %assert_zext +... + +--- +name: assert_zext_agpr +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $agpr0 + + ; CHECK-LABEL: name: assert_zext_agpr + ; CHECK: liveins: $agpr0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %copy:agpr(s32) = COPY $agpr0 + ; CHECK-NEXT: %assert_zext:agpr(s32) = G_ASSERT_ZEXT %copy, 4 + ; CHECK-NEXT: S_ENDPGM 0, implicit %assert_zext(s32) + %copy:_(s32) = COPY $agpr0 + %assert_zext:_(s32) = G_ASSERT_ZEXT %copy, 4 + S_ENDPGM 0, implicit %assert_zext +... + +--- +name: assert_zext_vgpr_regclass +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $vgpr0 + + ; CHECK-LABEL: name: assert_zext_vgpr_regclass + ; CHECK: liveins: $vgpr0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %copy:vgpr_32(s32) = COPY $vgpr0 + ; CHECK-NEXT: %assert_zext:vgpr(s32) = G_ASSERT_ZEXT %copy, 4 + ; CHECK-NEXT: S_ENDPGM 0, implicit %assert_zext(s32) + %copy:vgpr_32(s32) = COPY $vgpr0 + %assert_zext:_(s32) = G_ASSERT_ZEXT %copy, 4 + S_ENDPGM 0, implicit %assert_zext +... + +--- +name: assert_zext_sgpr_regcllass +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $sgpr8 + + ; CHECK-LABEL: name: assert_zext_sgpr_regcllass + ; CHECK: liveins: $sgpr8 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %copy:sgpr_32(s32) = COPY $sgpr8 + ; CHECK-NEXT: %assert_zext:sgpr(s32) = G_ASSERT_ZEXT %copy, 4 + ; CHECK-NEXT: S_ENDPGM 0, implicit %assert_zext(s32) + %copy:sgpr_32(s32) = COPY $sgpr8 + %assert_zext:_(s32) = G_ASSERT_ZEXT %copy, 4 + S_ENDPGM 0, implicit %assert_zext +... Index: llvm/test/MachineVerifier/test_g_assert_sext_register_bank_class.mir =================================================================== --- llvm/test/MachineVerifier/test_g_assert_sext_register_bank_class.mir +++ llvm/test/MachineVerifier/test_g_assert_sext_register_bank_class.mir @@ -3,14 +3,14 @@ name: test legalized: true -regBankSelected: true +regBankSelected: false body: | bb.0: liveins: $w0, $w1 %bank:gpr(s32) = COPY $w0 %class:gpr32(s32) = COPY $w1 - ; CHECK: *** Bad machine code: G_ASSERT_SEXT source and destination register banks must match *** + ; CHECK: *** Bad machine code: G_ASSERT_SEXT cannot change register bank *** ; CHECK: instruction: %bank_mismatch:fpr(s32) = G_ASSERT_SEXT %bank:gpr, 16 %bank_mismatch:fpr(s32) = G_ASSERT_SEXT %bank, 16 @@ -18,18 +18,14 @@ ; CHECK: instruction: %class_mismatch_gpr:gpr32all(s32) = G_ASSERT_SEXT %class:gpr32, 16 %class_mismatch_gpr:gpr32all(s32) = G_ASSERT_SEXT %class, 16 - ; CHECK: *** Bad machine code: G_ASSERT_SEXT source and destination register classes must match *** + ; CHECK: *** Bad machine code: G_ASSERT_SEXT cannot change register bank *** ; CHECK: instruction: %class_mismatch_fpr:fpr32(s32) = G_ASSERT_SEXT %class:gpr32, 16 %class_mismatch_fpr:fpr32(s32) = G_ASSERT_SEXT %class, 16 - ; CHECK: *** Bad machine code: G_ASSERT_SEXT source and destination register banks must match *** + ; CHECK: *** Bad machine code: G_ASSERT_SEXT source and destination register classes must match *** ; CHECK: instruction: %dst_has_class_src_has_bank:gpr32all(s32) = G_ASSERT_SEXT %bank:gpr, 16 %dst_has_class_src_has_bank:gpr32all(s32) = G_ASSERT_SEXT %bank, 16 - ; CHECK: *** Bad machine code: G_ASSERT_SEXT source and destination register banks must match *** - ; CHECK: instruction: %dst_has_bank_src_has_class:gpr(s32) = G_ASSERT_SEXT %class:gpr32, 16 - %dst_has_bank_src_has_class:gpr(s32) = G_ASSERT_SEXT %class, 16 - ; CHECK: *** Bad machine code: Generic instruction cannot have physical register *** ; CHECK: instruction: %implicit_physreg:gpr(s32) = G_ASSERT_SEXT %class:gpr32, 16, implicit-def $w0 %implicit_physreg:gpr(s32) = G_ASSERT_SEXT %class, 16, implicit-def $w0 Index: llvm/test/MachineVerifier/test_g_assert_zext_register_bank_class.mir =================================================================== --- llvm/test/MachineVerifier/test_g_assert_zext_register_bank_class.mir +++ llvm/test/MachineVerifier/test_g_assert_zext_register_bank_class.mir @@ -3,14 +3,14 @@ name: test legalized: true -regBankSelected: true +regBankSelected: false body: | bb.0: liveins: $w0, $w1 %bank:gpr(s32) = COPY $w0 %class:gpr32(s32) = COPY $w1 - ; CHECK: *** Bad machine code: G_ASSERT_ZEXT source and destination register banks must match *** + ; CHECK: *** Bad machine code: G_ASSERT_ZEXT cannot change register bank *** ; CHECK: instruction: %bank_mismatch:fpr(s32) = G_ASSERT_ZEXT %bank:gpr, 16 %bank_mismatch:fpr(s32) = G_ASSERT_ZEXT %bank, 16 @@ -18,18 +18,24 @@ ; CHECK: instruction: %class_mismatch_gpr:gpr32all(s32) = G_ASSERT_ZEXT %class:gpr32, 16 %class_mismatch_gpr:gpr32all(s32) = G_ASSERT_ZEXT %class, 16 - ; CHECK: *** Bad machine code: G_ASSERT_ZEXT source and destination register classes must match *** + ; CHECK: *** Bad machine code: G_ASSERT_ZEXT cannot change register bank *** ; CHECK: instruction: %class_mismatch_fpr:fpr32(s32) = G_ASSERT_ZEXT %class:gpr32, 16 %class_mismatch_fpr:fpr32(s32) = G_ASSERT_ZEXT %class, 16 - ; CHECK: *** Bad machine code: G_ASSERT_ZEXT source and destination register banks must match *** + ; CHECK: *** Bad machine code: G_ASSERT_ZEXT source and destination register classes must match *** ; CHECK: instruction: %dst_has_class_src_has_bank:gpr32all(s32) = G_ASSERT_ZEXT %bank:gpr, 16 %dst_has_class_src_has_bank:gpr32all(s32) = G_ASSERT_ZEXT %bank, 16 - ; CHECK: *** Bad machine code: G_ASSERT_ZEXT source and destination register banks must match *** - ; CHECK: instruction: %dst_has_bank_src_has_class:gpr(s32) = G_ASSERT_ZEXT %class:gpr32, 16 - %dst_has_bank_src_has_class:gpr(s32) = G_ASSERT_ZEXT %class, 16 - ; CHECK: *** Bad machine code: Generic instruction cannot have physical register *** ; CHECK: instruction: %implicit_physreg:gpr(s32) = G_ASSERT_ZEXT %class:gpr32, 16, implicit-def $w0 %implicit_physreg:gpr(s32) = G_ASSERT_ZEXT %class, 16, implicit-def $w0 + + %nothing:_(s32) = G_IMPLICIT_DEF + + ; CHECK: *** Bad machine code: G_ASSERT_ZEXT cannot change register bank *** + ; CHECK: %only_dst_has_bank:gpr(s32) = G_ASSERT_ZEXT %nothing:_, 4 + %only_dst_has_bank:gpr(s32) = G_ASSERT_ZEXT %nothing, 4 + + ; CHECK: *** Bad machine code: G_ASSERT_ZEXT cannot change register bank *** + ; CHECK: %only_dst_has_class:gpr32all(s32) = G_ASSERT_ZEXT %nothing:_, 4 + %only_dst_has_class:gpr32all(s32) = G_ASSERT_ZEXT %nothing, 4