Index: lib/Target/AMDGPU/AMDGPUInstructionSelector.h =================================================================== --- lib/Target/AMDGPU/AMDGPUInstructionSelector.h +++ lib/Target/AMDGPU/AMDGPUInstructionSelector.h @@ -66,6 +66,7 @@ MachineOperand getSubOperand64(MachineOperand &MO, unsigned SubIdx) const; bool selectCOPY(MachineInstr &I) const; + bool selectPHI(MachineInstr &I) const; bool selectG_TRUNC(MachineInstr &I) const; bool selectG_SZA_EXT(MachineInstr &I) const; bool selectG_CONSTANT(MachineInstr &I) const; Index: lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp =================================================================== --- lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp +++ lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp @@ -132,6 +132,44 @@ return true; } +bool AMDGPUInstructionSelector::selectPHI(MachineInstr &I) const { + MachineBasicBlock *BB = I.getParent(); + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + + const Register DefReg = I.getOperand(0).getReg(); + const LLT DefTy = MRI.getType(DefReg); + + // TODO: Verify this doesn't have insane operands (i.e. VGPR to SGPR copy) + + const RegClassOrRegBank &RegClassOrBank = + MRI.getRegClassOrRegBank(DefReg); + + const TargetRegisterClass *DefRC + = RegClassOrBank.dyn_cast(); + if (!DefRC) { + if (!DefTy.isValid()) { + LLVM_DEBUG(dbgs() << "PHI operand has no type, not a gvreg?\n"); + return false; + } + + const RegisterBank &RB = *RegClassOrBank.get(); + if (RB.getID() == AMDGPU::SCCRegBankID) { + LLVM_DEBUG(dbgs() << "illegal scc phi\n"); + return false; + } + + DefRC = TRI.getRegClassForTypeOnBank(DefTy, RB, MRI); + if (!DefRC) { + LLVM_DEBUG(dbgs() << "PHI operand has unexpected size/bank\n"); + return false; + } + } + + I.setDesc(TII.get(TargetOpcode::PHI)); + return RBI.constrainGenericRegister(DefReg, *DefRC, MRI); +} + MachineOperand AMDGPUInstructionSelector::getSubOperand64(MachineOperand &MO, unsigned SubIdx) const { @@ -995,6 +1033,8 @@ bool AMDGPUInstructionSelector::select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const { + if (I.isPHI()) + return selectPHI(I); if (!isPreISelGenericOpcode(I.getOpcode())) { if (I.isCopy()) Index: test/CodeGen/AMDGPU/GlobalISel/inst-select-phi-invalid.mir =================================================================== --- /dev/null +++ test/CodeGen/AMDGPU/GlobalISel/inst-select-phi-invalid.mir @@ -0,0 +1,31 @@ +# RUN: llc -march=amdgcn -run-pass=instruction-select -global-isel-abort=2 -pass-remarks-missed='gisel*' %s -o /dev/null 2>&1 | FileCheck %s -check-prefix=ERR +# ERR: remark: :0:0: cannot select: %7:scc(s1) = G_PHI %4:scc(s1), %bb.0, %6:scc(s1), %bb.1 (in function: g_phi_scc_s1_sbranch) + +--- +name: g_phi_scc_s1_sbranch +legalized: true +regBankSelected: true +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + bb.0: + liveins: $sgpr0, $sgpr1, $sgpr2 + + %0:sgpr(s32) = COPY $sgpr0 + %1:sgpr(s32) = COPY $sgpr1 + %2:sgpr(s32) = COPY $sgpr2 + %3:sgpr(s32) = G_CONSTANT i32 0 + %4:scc(s1) = G_ICMP intpred(eq), %0, %3 + %5:scc(s1) = G_ICMP intpred(eq), %2(s32), %3 + G_BRCOND %5(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %6:scc(s1) = G_ICMP intpred(eq), %1, %3 + G_BR %bb.2 + + bb.2: + %7:scc(s1) = G_PHI %4, %bb.0, %6, %bb.1 + S_SETPC_B64 undef $sgpr30_sgpr31, implicit %7 + +... Index: test/CodeGen/AMDGPU/GlobalISel/inst-select-phi.mir =================================================================== --- /dev/null +++ test/CodeGen/AMDGPU/GlobalISel/inst-select-phi.mir @@ -0,0 +1,385 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -march=amdgcn -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s -check-prefix=GCN + +--- +name: g_phi_s32_ss_sbranch +legalized: true +regBankSelected: true +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + ; GCN-LABEL: name: g_phi_s32_ss_sbranch + ; GCN: bb.0: + ; GCN: successors: %bb.1(0x40000000), %bb.2(0x40000000) + ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2 + ; GCN: [[COPY:%[0-9]+]]:sreg_32_xm0 = COPY $sgpr0 + ; GCN: [[COPY1:%[0-9]+]]:sreg_32_xm0 = COPY $sgpr1 + ; GCN: [[COPY2:%[0-9]+]]:sreg_32 = COPY $sgpr2 + ; GCN: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0 + ; GCN: S_CMP_EQ_U32 [[COPY2]], [[S_MOV_B32_]], implicit-def $scc + ; GCN: [[COPY3:%[0-9]+]]:sreg_32_xm0 = COPY $scc + ; GCN: $scc = COPY [[COPY3]] + ; GCN: S_CBRANCH_SCC1 %bb.1, implicit $scc + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.1: + ; GCN: successors: %bb.2(0x80000000) + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.2: + ; GCN: [[PHI:%[0-9]+]]:sreg_32_xm0 = PHI [[COPY]], %bb.0, [[COPY1]], %bb.1 + ; GCN: $sgpr0 = COPY [[PHI]] + ; GCN: S_SETPC_B64 undef $sgpr30_sgpr31 + bb.0: + liveins: $sgpr0, $sgpr1, $sgpr2 + + %0:sgpr(s32) = COPY $sgpr0 + %1:sgpr(s32) = COPY $sgpr1 + %2:sgpr(s32) = COPY $sgpr2 + %3:sgpr(s32) = G_CONSTANT i32 0 + %4:scc(s1) = G_ICMP intpred(eq), %2(s32), %3 + G_BRCOND %4(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %5:sgpr(s32) = COPY %1 + G_BR %bb.2 + + bb.2: + %6:sgpr(s32) = G_PHI %0(s32), %bb.0, %5(s32), %bb.1 + $sgpr0 = COPY %6 + S_SETPC_B64 undef $sgpr30_sgpr31 + +... + +--- +name: g_phi_s32_vv_sbranch +legalized: true +regBankSelected: true +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + ; GCN-LABEL: name: g_phi_s32_vv_sbranch + ; GCN: bb.0: + ; GCN: successors: %bb.1(0x40000000), %bb.2(0x40000000) + ; GCN: liveins: $vgpr0, $vgpr1, $sgpr2 + ; GCN: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0 + ; GCN: [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr1 + ; GCN: [[COPY2:%[0-9]+]]:sreg_32 = COPY $sgpr2 + ; GCN: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0 + ; GCN: S_CMP_EQ_U32 [[COPY2]], [[S_MOV_B32_]], implicit-def $scc + ; GCN: [[COPY3:%[0-9]+]]:sreg_32_xm0 = COPY $scc + ; GCN: $scc = COPY [[COPY3]] + ; GCN: S_CBRANCH_SCC1 %bb.1, implicit $scc + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.1: + ; GCN: successors: %bb.2(0x80000000) + ; GCN: [[COPY4:%[0-9]+]]:sreg_32_xm0 = COPY [[COPY1]] + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.2: + ; GCN: [[PHI:%[0-9]+]]:vgpr_32 = PHI [[COPY]], %bb.0, [[COPY4]], %bb.1 + ; GCN: $vgpr0 = COPY [[PHI]] + ; GCN: S_SETPC_B64 undef $sgpr30_sgpr31 + bb.0: + liveins: $vgpr0, $vgpr1, $sgpr2 + + %0:vgpr(s32) = COPY $vgpr0 + %1:vgpr(s32) = COPY $vgpr1 + %2:sgpr(s32) = COPY $sgpr2 + %3:sgpr(s32) = G_CONSTANT i32 0 + %4:scc(s1) = G_ICMP intpred(eq), %2(s32), %3 + G_BRCOND %4(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %5:sgpr(s32) = COPY %1 + G_BR %bb.2 + + bb.2: + %6:vgpr(s32) = G_PHI %0(s32), %bb.0, %5(s32), %bb.1 + $vgpr0 = COPY %6(s32) + S_SETPC_B64 undef $sgpr30_sgpr31 + +... + +--- +name: g_phi_s32_sv_sbranch +legalized: true +regBankSelected: true +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + bb.0: + liveins: $sgpr0, $vgpr0, $sgpr1, $sgpr2 + + %0:sgpr(s32) = COPY $sgpr0 + %1:vgpr(s32) = COPY $vgpr0 + %2:sgpr(s32) = COPY $sgpr2 + %3:sgpr(s32) = G_CONSTANT i32 0 + %4:scc(s1) = G_ICMP intpred(eq), %2(s32), %3 + G_BRCOND %4(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %5:vgpr(s32) = COPY %1 + G_BR %bb.2 + + bb.2: + %6:vgpr(s32) = G_PHI %0(s32), %bb.0, %5(s32), %bb.1 + $vgpr0 = COPY %6 + S_SETPC_B64 undef $sgpr30_sgpr31 + +... + +--- +name: g_phi_s32_vs_sbranch +legalized: true +regBankSelected: true +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + bb.0: + liveins: $sgpr0, $vgpr0, $sgpr1 + + %0:vgpr(s32) = COPY $vgpr0 + %1:sgpr(s32) = COPY $sgpr0 + %2:sgpr(s32) = COPY $sgpr1 + %3:sgpr(s32) = G_CONSTANT i32 0 + %4:scc(s1) = G_ICMP intpred(eq), %2(s32), %3 + G_BRCOND %4(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %5:vgpr(s32) = COPY %1 + G_BR %bb.2 + + bb.2: + %6:vgpr(s32) = G_PHI %0(s32), %bb.0, %5(s32), %bb.1 + $vgpr0 = COPY %6 + S_SETPC_B64 undef $sgpr30_sgpr31 + +... + +--- +name: g_phi_s64_ss_sbranch +legalized: true +regBankSelected: true +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + ; GCN-LABEL: name: g_phi_s64_ss_sbranch + ; GCN: bb.0: + ; GCN: successors: %bb.1(0x40000000), %bb.2(0x40000000) + ; GCN: liveins: $sgpr0_sgpr1, $sgpr2_sgpr3, $sgpr4 + ; GCN: [[COPY:%[0-9]+]]:sreg_64_xexec = COPY $sgpr0_sgpr1 + ; GCN: [[COPY1:%[0-9]+]]:sreg_64_xexec = COPY $sgpr2_sgpr3 + ; GCN: [[COPY2:%[0-9]+]]:sreg_32 = COPY $sgpr4 + ; GCN: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0 + ; GCN: S_CMP_EQ_U32 [[COPY2]], [[S_MOV_B32_]], implicit-def $scc + ; GCN: [[COPY3:%[0-9]+]]:sreg_32_xm0 = COPY $scc + ; GCN: $scc = COPY [[COPY3]] + ; GCN: S_CBRANCH_SCC1 %bb.1, implicit $scc + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.1: + ; GCN: successors: %bb.2(0x80000000) + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.2: + ; GCN: [[PHI:%[0-9]+]]:sreg_64_xexec = PHI [[COPY]], %bb.0, [[COPY1]], %bb.1 + ; GCN: $sgpr0_sgpr1 = COPY [[PHI]] + ; GCN: S_SETPC_B64 undef $sgpr30_sgpr31 + bb.0: + liveins: $sgpr0_sgpr1, $sgpr2_sgpr3, $sgpr4 + + %0:sgpr(s64) = COPY $sgpr0_sgpr1 + %1:sgpr(s64) = COPY $sgpr2_sgpr3 + %2:sgpr(s32) = COPY $sgpr4 + %3:sgpr(s32) = G_CONSTANT i32 0 + %4:scc(s1) = G_ICMP intpred(eq), %2(s32), %3 + G_BRCOND %4(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %5:sgpr(s64) = COPY %1 + G_BR %bb.2 + + bb.2: + %6:sgpr(s64) = G_PHI %0(s64), %bb.0, %5(s64), %bb.1 + $sgpr0_sgpr1 = COPY %6 + S_SETPC_B64 undef $sgpr30_sgpr31 + +... +--- +name: g_phi_v2s16_vv_sbranch +legalized: true +regBankSelected: true +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + ; GCN-LABEL: name: g_phi_v2s16_vv_sbranch + ; GCN: bb.0: + ; GCN: successors: %bb.1(0x40000000), %bb.2(0x40000000) + ; GCN: liveins: $vgpr0, $vgpr1, $sgpr2 + ; GCN: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0 + ; GCN: [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr1 + ; GCN: [[COPY2:%[0-9]+]]:sreg_32 = COPY $sgpr2 + ; GCN: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0 + ; GCN: S_CMP_EQ_U32 [[COPY2]], [[S_MOV_B32_]], implicit-def $scc + ; GCN: [[COPY3:%[0-9]+]]:sreg_32_xm0 = COPY $scc + ; GCN: $scc = COPY [[COPY3]] + ; GCN: S_CBRANCH_SCC1 %bb.1, implicit $scc + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.1: + ; GCN: successors: %bb.2(0x80000000) + ; GCN: [[COPY4:%[0-9]+]]:sreg_32_xm0 = COPY [[COPY1]] + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.2: + ; GCN: [[PHI:%[0-9]+]]:vgpr_32 = PHI [[COPY]], %bb.0, [[COPY4]], %bb.1 + ; GCN: $vgpr0 = COPY [[PHI]] + ; GCN: S_SETPC_B64 undef $sgpr30_sgpr31 + bb.0: + liveins: $vgpr0, $vgpr1, $sgpr2 + + %0:vgpr(<2 x s16>) = COPY $vgpr0 + %1:vgpr(<2 x s16>) = COPY $vgpr1 + %2:sgpr(s32) = COPY $sgpr2 + %3:sgpr(s32) = G_CONSTANT i32 0 + %4:scc(s1) = G_ICMP intpred(eq), %2(s32), %3 + G_BRCOND %4(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %5:sgpr(<2 x s16>) = COPY %1 + G_BR %bb.2 + + bb.2: + %6:vgpr(<2 x s16>) = G_PHI %0(<2 x s16>), %bb.0, %5(<2 x s16>), %bb.1 + $vgpr0 = COPY %6 + S_SETPC_B64 undef $sgpr30_sgpr31 + +... + +--- +name: g_phi_vcc_s1_sbranch +legalized: true +regBankSelected: true +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + bb.0: + liveins: $vgpr0, $vgpr1, $sgpr2 + + %0:vgpr(s32) = COPY $vgpr0 + %1:vgpr(s32) = COPY $vgpr1 + %2:sgpr(s32) = COPY $sgpr2 + %3:sgpr(s32) = G_CONSTANT i32 0 + %4:vcc(s1) = G_ICMP intpred(eq), %0, %3 + %5:scc(s1) = G_ICMP intpred(eq), %2(s32), %3 + G_BRCOND %5(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %6:vcc(s1) = G_ICMP intpred(eq), %1, %3 + G_BR %bb.2 + + bb.2: + %7:vcc(s1) = G_PHI %4, %bb.0, %6, %bb.1 + S_SETPC_B64 undef $sgpr30_sgpr31, implicit %7 + +... + +--- +name: phi_s32_ss_sbranch +legalized: true +regBankSelected: true +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + ; GCN-LABEL: name: phi_s32_ss_sbranch + ; GCN: bb.0: + ; GCN: successors: %bb.1(0x40000000), %bb.2(0x40000000) + ; GCN: liveins: $sgpr0, $sgpr1, $sgpr2 + ; GCN: [[COPY:%[0-9]+]]:sreg_32_xm0 = COPY $sgpr0 + ; GCN: [[COPY1:%[0-9]+]]:sreg_32_xm0 = COPY $sgpr1 + ; GCN: [[COPY2:%[0-9]+]]:sreg_32 = COPY $sgpr2 + ; GCN: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0 + ; GCN: S_CMP_EQ_U32 [[COPY2]], [[S_MOV_B32_]], implicit-def $scc + ; GCN: [[COPY3:%[0-9]+]]:sreg_32_xm0 = COPY $scc + ; GCN: $scc = COPY [[COPY3]] + ; GCN: S_CBRANCH_SCC1 %bb.1, implicit $scc + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.1: + ; GCN: successors: %bb.2(0x80000000) + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.2: + ; GCN: [[PHI:%[0-9]+]]:sreg_32_xm0 = PHI [[COPY]], %bb.0, [[COPY1]], %bb.1 + ; GCN: $sgpr0 = COPY [[PHI]] + ; GCN: S_SETPC_B64 undef $sgpr30_sgpr31 + bb.0: + liveins: $sgpr0, $sgpr1, $sgpr2 + + %0:sgpr(s32) = COPY $sgpr0 + %1:sgpr(s32) = COPY $sgpr1 + %2:sgpr(s32) = COPY $sgpr2 + %3:sgpr(s32) = G_CONSTANT i32 0 + %4:scc(s1) = G_ICMP intpred(eq), %2(s32), %3 + G_BRCOND %4(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %5:sgpr(s32) = COPY %1 + G_BR %bb.2 + + bb.2: + %6:sgpr(s32) = PHI %0(s32), %bb.0, %5(s32), %bb.1 + $sgpr0 = COPY %6(s32) + S_SETPC_B64 undef $sgpr30_sgpr31 + +... + +--- +name: phi_s32_vv_sbranch +legalized: true +regBankSelected: true +tracksRegLiveness: true +machineFunctionInfo: {} +body: | + ; GCN-LABEL: name: phi_s32_vv_sbranch + ; GCN: bb.0: + ; GCN: successors: %bb.1(0x40000000), %bb.2(0x40000000) + ; GCN: liveins: $vgpr0, $vgpr1, $sgpr2 + ; GCN: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0 + ; GCN: [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr1 + ; GCN: [[COPY2:%[0-9]+]]:sreg_32 = COPY $sgpr2 + ; GCN: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0 + ; GCN: S_CMP_EQ_U32 [[COPY2]], [[S_MOV_B32_]], implicit-def $scc + ; GCN: [[COPY3:%[0-9]+]]:sreg_32_xm0 = COPY $scc + ; GCN: $scc = COPY [[COPY3]] + ; GCN: S_CBRANCH_SCC1 %bb.1, implicit $scc + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.1: + ; GCN: successors: %bb.2(0x80000000) + ; GCN: [[COPY4:%[0-9]+]]:sreg_32_xm0 = COPY [[COPY1]] + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.2: + ; GCN: [[PHI:%[0-9]+]]:vgpr_32 = PHI [[COPY]], %bb.0, [[COPY4]], %bb.1 + ; GCN: $vgpr0 = COPY [[PHI]] + ; GCN: S_SETPC_B64 undef $sgpr30_sgpr31 + bb.0: + liveins: $vgpr0, $vgpr1, $sgpr2 + + %0:vgpr(s32) = COPY $vgpr0 + %1:vgpr(s32) = COPY $vgpr1 + %2:sgpr(s32) = COPY $sgpr2 + %3:sgpr(s32) = G_CONSTANT i32 0 + %4:scc(s1) = G_ICMP intpred(eq), %2(s32), %3 + G_BRCOND %4(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %5:sgpr(s32) = COPY %1 + G_BR %bb.2 + + bb.2: + %6:vgpr(s32) = PHI %0(s32), %bb.0, %5(s32), %bb.1 + $vgpr0 = COPY %6 + S_SETPC_B64 undef $sgpr30_sgpr31 + +...