Index: include/llvm/CodeGen/TargetRegisterInfo.h =================================================================== --- include/llvm/CodeGen/TargetRegisterInfo.h +++ include/llvm/CodeGen/TargetRegisterInfo.h @@ -752,6 +752,9 @@ virtual const RegClassWeight &getRegClassWeight( const TargetRegisterClass *RC) const = 0; + /// Returns size in bits of a phys/virtual/generic register. + unsigned getRegSizeInBits(unsigned Reg, const MachineRegisterInfo &MRI) const; + /// Get the weight in units of pressure for this register unit. virtual unsigned getRegUnitWeight(unsigned RegUnit) const = 0; Index: lib/CodeGen/GlobalISel/RegisterBankInfo.cpp =================================================================== --- lib/CodeGen/GlobalISel/RegisterBankInfo.cpp +++ lib/CodeGen/GlobalISel/RegisterBankInfo.cpp @@ -458,24 +458,16 @@ unsigned RegisterBankInfo::getSizeInBits(unsigned Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const { - const TargetRegisterClass *RC = nullptr; if (TargetRegisterInfo::isPhysicalRegister(Reg)) { // The size is not directly available for physical registers. // Instead, we need to access a register class that contains Reg and // get the size of that register class. - RC = &getMinimalPhysRegClass(Reg, TRI); - } else { - LLT Ty = MRI.getType(Reg); - unsigned RegSize = Ty.isValid() ? Ty.getSizeInBits() : 0; - // If Reg is not a generic register, query the register class to - // get its size. - if (RegSize) - return RegSize; - // Since Reg is not a generic register, it must have a register class. - RC = MRI.getRegClass(Reg); + // Because this is expensive, we'll cache the register class by calling + auto *RC = &getMinimalPhysRegClass(Reg, TRI); + assert(RC && "Expecting Register class"); + return TRI.getRegSizeInBits(*RC); } - assert(RC && "Unable to deduce the register class"); - return TRI.getRegSizeInBits(*RC); + return TRI.getRegSizeInBits(Reg, MRI); } //------------------------------------------------------------------------------ Index: lib/CodeGen/MachineVerifier.cpp =================================================================== --- lib/CodeGen/MachineVerifier.cpp +++ lib/CodeGen/MachineVerifier.cpp @@ -971,6 +971,36 @@ MI); break; } + case TargetOpcode::COPY: { + if (foundErrors) + break; + const MachineOperand &DstOp = MI->getOperand(0); + const MachineOperand &SrcOp = MI->getOperand(1); + LLT DstTy = MRI->getType(DstOp.getReg()); + LLT SrcTy = MRI->getType(SrcOp.getReg()); + if (SrcTy.isValid() && DstTy.isValid()) { + // If both types are valid, check that the types are the same. + if (SrcTy != DstTy) { + report("Copy Instruction is illegal with mismatching types", MI); + errs() << "Def = " << DstTy << ", Src = " << SrcTy << "\n"; + } + } + if (SrcTy.isValid() || DstTy.isValid()) { + // If one of them have valid types, let's just check they have the same + // size. + unsigned SrcSize = TRI->getRegSizeInBits(SrcOp.getReg(), *MRI); + unsigned DstSize = TRI->getRegSizeInBits(DstOp.getReg(), *MRI); + assert(SrcSize && "Expecting size here"); + assert(DstSize && "Expecting size here"); + if (SrcSize != DstSize) + if (!DstOp.getSubReg() && !SrcOp.getSubReg()) { + report("Copy Instruction is illegal with mismatching sizes", MI); + errs() << "Def Size = " << DstSize << ", Src Size = " << SrcSize + << "\n"; + } + } + break; + } case TargetOpcode::STATEPOINT: if (!MI->getOperand(StatepointOpers::IDPos).isImm() || !MI->getOperand(StatepointOpers::NBytesPos).isImm() || Index: lib/CodeGen/TargetRegisterInfo.cpp =================================================================== --- lib/CodeGen/TargetRegisterInfo.cpp +++ lib/CodeGen/TargetRegisterInfo.cpp @@ -450,6 +450,28 @@ return true; } +unsigned TargetRegisterInfo::getRegSizeInBits(unsigned Reg, + const MachineRegisterInfo &MRI) const { + const TargetRegisterClass *RC{}; + if (isPhysicalRegister(Reg)) { + // The size is not directly available for physical registers. + // Instead, we need to access a register class that contains Reg and + // get the size of that register class. + RC = getMinimalPhysRegClass(Reg); + } else { + LLT Ty = MRI.getType(Reg); + unsigned RegSize = Ty.isValid() ? Ty.getSizeInBits() : 0; + // If Reg is not a generic register, query the register class to + // get its size. + if (RegSize) + return RegSize; + // Since Reg is not a generic register, it must have a register class. + RC = MRI.getRegClass(Reg); + } + assert(RC && "Unable to deduce the register class"); + return getRegSizeInBits(*RC); +} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void TargetRegisterInfo::dumpReg(unsigned Reg, unsigned SubRegIndex, Index: test/CodeGen/AArch64/GlobalISel/legalize-combines.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-combines.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-combines.mir @@ -68,7 +68,7 @@ %1:_(s128) = G_MERGE_VALUES %0, %0 %2:_(s64) = G_EXTRACT %1, 0 %3:_(s64) = G_ADD %2, %2 - $w0 = COPY %3 + $x0 = COPY %3 ... --- Index: test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir @@ -147,11 +147,12 @@ ; CHECK-LABEL: name: test_fptosi_s1_s32 ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 ; CHECK: [[FPTOSI:%[0-9]+]]:_(s32) = G_FPTOSI [[COPY]](s32) - ; CHECK: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[FPTOSI]](s32) - ; CHECK: $x0 = COPY [[TRUNC]](s1) + ; CHECK: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[FPTOSI]](s32) + ; CHECK: $x0 = COPY [[ANYEXT]](s64) %0:_(s32) = COPY $w0 %1:_(s1) = G_FPTOSI %0 - $x0 = COPY %1 + %2:_(s64) = G_ANYEXT %1 + $x0 = COPY %2 ... --- Index: test/CodeGen/AArch64/GlobalISel/legalize-itofp.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-itofp.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-itofp.mir @@ -87,7 +87,7 @@ ; CHECK: [[SITOFP:%[0-9]+]]:_(s64) = G_SITOFP [[COPY]](s32) %0:_(s32) = COPY $w0 %1:_(s64) = G_SITOFP %0 - $w0 = COPY %1 + $x0 = COPY %1 ... --- Index: test/CodeGen/AArch64/GlobalISel/legalize-or.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/legalize-or.mir +++ test/CodeGen/AArch64/GlobalISel/legalize-or.mir @@ -12,14 +12,15 @@ ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) ; CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[COPY1]](s64) ; CHECK: [[OR:%[0-9]+]]:_(s32) = G_OR [[TRUNC]], [[TRUNC1]] - ; CHECK: [[TRUNC2:%[0-9]+]]:_(s8) = G_TRUNC [[OR]](s32) - ; CHECK: $x0 = COPY [[TRUNC2]](s8) + ; CHECK: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[OR]](s32) + ; CHECK: $x0 = COPY [[ANYEXT]](s64) %0:_(s64) = COPY $x0 %1:_(s64) = COPY $x1 %2:_(s8) = G_TRUNC %0 %3:_(s8) = G_TRUNC %1 %4:_(s8) = G_OR %2, %3 - $x0 = COPY %4 + %5:_(s64) = G_ANYEXT %4 + $x0 = COPY %5 ... --- Index: test/CodeGen/MIR/AArch64/intrinsics.mir =================================================================== --- test/CodeGen/MIR/AArch64/intrinsics.mir +++ test/CodeGen/MIR/AArch64/intrinsics.mir @@ -9,10 +9,10 @@ ... --- # Completely invalid code, but it checks that intrinsics round-trip properly. -# CHECK: $x0 = COPY intrinsic(@llvm.returnaddress) +# CHECK: G_INTRINSIC intrinsic(@llvm.returnaddress) name: use_intrin body: | bb.0: - $x0 = COPY intrinsic(@llvm.returnaddress) + %0:_(s64) = G_INTRINSIC intrinsic(@llvm.returnaddress) RET_ReallyLR ... Index: test/CodeGen/MIR/AMDGPU/intrinsics.mir =================================================================== --- test/CodeGen/MIR/AMDGPU/intrinsics.mir +++ test/CodeGen/MIR/AMDGPU/intrinsics.mir @@ -16,6 +16,6 @@ body: | bb.0: ; CHECK-LABEL: name: use_intrin - ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY intrinsic(@llvm.amdgcn.sbfe) - %0(s64) = COPY intrinsic(@llvm.amdgcn.sbfe.i32) + ; CHECK: %0:_(s64) = G_INTRINSIC intrinsic(@llvm.amdgcn.sbfe) + %0(s64) = G_INTRINSIC intrinsic(@llvm.amdgcn.sbfe.i32) ... Index: test/Verifier/test_copy.mir =================================================================== --- /dev/null +++ test/Verifier/test_copy.mir @@ -0,0 +1,33 @@ +#RUN: not llc -o - -global-isel -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s +# REQUIRES: global-isel, aarch64-registered-target +--- | + ; ModuleID = 'test.ll' + source_filename = "test.ll" + target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" + target triple = "aarch64-unknown-unknown" + + define i32 @test_copy(i32 %argc) { + ret i32 0 + } + define i32 @test_copy_type_mismatch(i32 %argc) { + ret i32 0 + } + +... +--- +name: test_copy +legalized: true +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _, preferred-register: '' } +liveins: +body: | + bb.0: + liveins: $w0 + ; This test is used to catch verifier errors with copys having mismatching sizes + ; CHECK: Bad machine code: Copy Instruction is illegal with mismatching sizes + + %0(s8) = COPY $w0 +... Index: test/Verifier/test_copy_mismatch_types.mir =================================================================== --- /dev/null +++ test/Verifier/test_copy_mismatch_types.mir @@ -0,0 +1,31 @@ +#RUN: not llc -o - -global-isel -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s +# REQUIRES: global-isel, aarch64-registered-target +--- | + ; ModuleID = 'test.ll' + source_filename = "test.ll" + target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" + target triple = "aarch64-unknown-unknown" + + define i32 @test_copy(i32 %argc) { + ret i32 0 + } + +... +--- +name: test_copy +legalized: true +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _, preferred-register: '' } +liveins: +body: | + bb.0: + liveins: $w0 + ; This test is used to catch verifier errors with copys having mismatching sizes + ; CHECK: Bad machine code: Copy Instruction is illegal with mismatching types + + %0(s32) = COPY $w0 + %1:_(<2 x s16>) = COPY %0 +...