Index: lib/Target/AMDGPU/SIRegisterInfo.h =================================================================== --- lib/Target/AMDGPU/SIRegisterInfo.h +++ lib/Target/AMDGPU/SIRegisterInfo.h @@ -51,9 +51,30 @@ unsigned getRegPressureSetLimit(const MachineFunction &MF, unsigned Idx) const override; + bool requiresRegisterScavenging(const MachineFunction &Fn) const override; + bool requiresFrameIndexScavenging(const MachineFunction &MF) const override; + bool requiresVirtualBaseRegisters(const MachineFunction &Fn) const override; + + int64_t getFrameIndexInstrOffset(const MachineInstr *MI, + int Idx) const override; + + bool needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const override; + + void materializeFrameBaseRegister(MachineBasicBlock *MBB, + unsigned BaseReg, int FrameIdx, + int64_t Offset) const override; + + void resolveFrameIndex(MachineInstr &MI, unsigned BaseReg, + int64_t Offset) const override; + + bool isFrameOffsetLegal(const MachineInstr *MI, unsigned BaseReg, + int64_t Offset) const override; + + const TargetRegisterClass *getPointerRegClass( + const MachineFunction &MF, unsigned Kind = 0) const override; void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, unsigned FIOperandNum, Index: lib/Target/AMDGPU/SIRegisterInfo.cpp =================================================================== --- lib/Target/AMDGPU/SIRegisterInfo.cpp +++ lib/Target/AMDGPU/SIRegisterInfo.cpp @@ -227,6 +227,148 @@ return MF.getFrameInfo()->hasStackObjects(); } +bool SIRegisterInfo::requiresVirtualBaseRegisters( + const MachineFunction &) const { + // There are no special dedicated stack or frame pointers. + return true; +} + +int64_t SIRegisterInfo::getFrameIndexInstrOffset(const MachineInstr *MI, + int Idx) const { + + const MachineFunction *MF = MI->getParent()->getParent(); + const AMDGPUSubtarget &Subtarget = MF->getSubtarget(); + const SIInstrInfo *TII + = static_cast(Subtarget.getInstrInfo()); + + if (!TII->isMUBUF(*MI)) + return 0; + + assert(Idx == AMDGPU::getNamedOperandIdx(MI->getOpcode(), + AMDGPU::OpName::vaddr) && + "Should never see frame index on non-address operand"); + + int OffIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(), + AMDGPU::OpName::offset); + return MI->getOperand(OffIdx).getImm(); +} + +bool SIRegisterInfo::needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const { + return MI->mayLoadOrStore(); +} + +void SIRegisterInfo::materializeFrameBaseRegister(MachineBasicBlock *MBB, + unsigned BaseReg, + int FrameIdx, + int64_t Offset) const { + MachineBasicBlock::iterator Ins = MBB->begin(); + DebugLoc DL; // Defaults to "unknown" + + if (Ins != MBB->end()) + DL = Ins->getDebugLoc(); + + MachineFunction *MF = MBB->getParent(); + const AMDGPUSubtarget &Subtarget = MF->getSubtarget(); + const TargetInstrInfo *TII = Subtarget.getInstrInfo(); + + assert(isUInt<27>(Offset) && + "Private offset should never exceed maximum private size"); + + + if (Offset == 0) { + BuildMI(*MBB, Ins, DL, TII->get(AMDGPU::V_MOV_B32_e32), BaseReg) + .addFrameIndex(FrameIdx); + return; + } + + MachineRegisterInfo &MRI = MF->getRegInfo(); + unsigned UnusedCarry = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass); + + BuildMI(*MBB, Ins, DL, TII->get(AMDGPU::V_ADD_I32_e64), BaseReg) + .addReg(UnusedCarry, RegState::Define | RegState::Dead) + .addImm(Offset) + .addFrameIndex(FrameIdx); +} + +void SIRegisterInfo::resolveFrameIndex(MachineInstr &MI, unsigned BaseReg, + int64_t Offset) const { + + MachineBasicBlock *MBB = MI.getParent(); + MachineFunction *MF = MBB->getParent(); + const AMDGPUSubtarget &Subtarget = MF->getSubtarget(); + const SIInstrInfo *TII + = static_cast(Subtarget.getInstrInfo()); + +#ifndef NDEBUG + // FIXME: Is it possible to be storing a frame index to itself? + bool SeenFI = false; + for (const MachineOperand &MO: MI.operands()) { + if (MO.isFI()) { + if (SeenFI) + llvm_unreachable("should not see multiple frame indices"); + + SeenFI = true; + } + } +#endif + + MachineOperand *FIOp = TII->getNamedOperand(MI, AMDGPU::OpName::vaddr); + assert(FIOp && FIOp->isFI() && "frame index must be address operand"); + + assert(TII->isMUBUF(MI)); + + MachineOperand *OffsetOp = TII->getNamedOperand(MI, AMDGPU::OpName::offset); + int64_t NewOffset = OffsetOp->getImm() + Offset; + if (isUInt<12>(NewOffset)) { + // If we have a legal offset, fold it directly into the instruction. + FIOp->ChangeToRegister(BaseReg, false); + OffsetOp->setImm(NewOffset); + return; + } + + // The offset is not legal, so we must insert an add of the offset. + MachineRegisterInfo &MRI = MF->getRegInfo(); + unsigned NewReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass); + DebugLoc DL = MI.getDebugLoc(); + + if (Offset == 0) { + llvm_unreachable("this ever hapens"); + BuildMI(*MBB, MI, DL, TII->get(AMDGPU::V_MOV_B32_e32), NewReg) + .addReg(BaseReg); + } else { + unsigned UnusedCarry = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass); + + // In the case the instruction already had an immediate offset, here only + // the requested new offset is added because we are leaving the original + // immediate in place. + BuildMI(*MBB, MI, DL, TII->get(AMDGPU::V_ADD_I32_e64), NewReg) + .addReg(UnusedCarry, RegState::Define | RegState::Dead) + .addImm(Offset) + .addReg(BaseReg); + } + + FIOp->ChangeToRegister(NewReg, false); +} + +bool SIRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI, + unsigned BaseReg, + int64_t Offset) const { + const MachineFunction *MF = MI->getParent()->getParent(); + const AMDGPUSubtarget &Subtarget = MF->getSubtarget(); + const SIInstrInfo *TII + = static_cast(Subtarget.getInstrInfo()); + + return TII->isMUBUF(*MI) && isUInt<12>(Offset); +} + +const TargetRegisterClass *SIRegisterInfo::getPointerRegClass( + const MachineFunction &MF, unsigned Kind) const { + // This is inaccurate. It depends on the instruction and address space. The + // only place where we should hit this is for dealing with frame indexes / + // private accesses, so this is correct in that case. + return &AMDGPU::VGPR_32RegClass; +} + static unsigned getNumSubRegsForSpillOp(unsigned Op) { switch (Op) { Index: test/CodeGen/AMDGPU/array-ptr-calc-i32.ll =================================================================== --- test/CodeGen/AMDGPU/array-ptr-calc-i32.ll +++ test/CodeGen/AMDGPU/array-ptr-calc-i32.ll @@ -15,8 +15,11 @@ ; FIXME: We end up with zero argument for ADD, because ; SIRegisterInfo::eliminateFrameIndex() blindly replaces the frame index ; with the appropriate offset. We should fold this into the store. + ; SI-ALLOCA: v_add_i32_e32 [[PTRREG:v[0-9]+]], vcc, 0, v{{[0-9]+}} -; SI-ALLOCA: buffer_store_dword {{v[0-9]+}}, [[PTRREG]], s[{{[0-9]+:[0-9]+}}] +; SI-ALLOCA: buffer_store_dword {{v[0-9]+}}, [[PTRREG]], s[{{[0-9]+:[0-9]+}}], s{{[0-9]+}} offen offset:16 +; SI-ALLOCA: s_barrier +; SI-ALLOCA: buffer_load_dword {{v[0-9]+}}, [[PTRREG]], s[{{[0-9]+:[0-9]+}}], s{{[0-9]+}} offen offset:16 ; ; FIXME: The AMDGPUPromoteAlloca pass should be able to convert this ; alloca to a vector. It currently fails because it does not know how Index: test/CodeGen/AMDGPU/captured-frame-index.ll =================================================================== --- test/CodeGen/AMDGPU/captured-frame-index.ll +++ test/CodeGen/AMDGPU/captured-frame-index.ll @@ -16,25 +16,22 @@ ; Offset is applied ; GCN-LABEL: {{^}}stored_fi_to_lds_2_small_objects: -; GCN: s_load_dword [[LDSPTR:s[0-9]+]] -; GCN: v_mov_b32_e32 [[ZERO1:v[0-9]+]], 0{{$}} -; GCN: buffer_store_dword v{{[0-9]+}}, [[ZERO1]] - -; GCN: v_mov_b32_e32 [[FI1:v[0-9]+]], 4{{$}} -; GCN: buffer_store_dword v{{[0-9]+}}, [[FI1]] +; GCN: v_mov_b32_e32 [[ZERO:v[0-9]+]], 0{{$}} +; GCN: buffer_store_dword v{{[0-9]+}}, [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen{{$}} +; GCN: buffer_store_dword v{{[0-9]+}}, [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen offset:4{{$}} +; GCN: s_load_dword [[LDSPTR:s[0-9]+]] -; GCN-DAG: v_mov_b32_e32 [[ZERO0:v[0-9]+]], 0{{$}} ; GCN-DAG: v_mov_b32_e32 [[VLDSPTR:v[0-9]+]], [[LDSPTR]] -; GCN: ds_write_b32 [[VLDSPTR]], [[ZERO0]] +; GCN: ds_write_b32 [[VLDSPTR]], [[ZERO]] ; GCN-DAG: v_mov_b32_e32 [[FI1:v[0-9]+]], 4{{$}} ; GCN: ds_write_b32 [[VLDSPTR]], [[FI1]] define void @stored_fi_to_lds_2_small_objects(float* addrspace(3)* %ptr) #0 { %tmp0 = alloca float %tmp1 = alloca float - store float 4.0, float *%tmp0 - store float 4.0, float *%tmp1 + store float 4.0, float* %tmp0 + store float 4.0, float* %tmp1 store volatile float* %tmp0, float* addrspace(3)* %ptr store volatile float* %tmp1, float* addrspace(3)* %ptr ret void @@ -42,6 +39,10 @@ ; Same frame index is used multiple times in the store ; GCN-LABEL: {{^}}stored_fi_to_self: +; GCN-DAG: v_mov_b32_e32 [[K:v[0-9]+]], 0x4d2{{$}} +; GCN-DAG: v_mov_b32_e32 [[ZERO:v[0-9]+]], 0{{$}} +; GCN: buffer_store_dword [[K]], [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen{{$}} +; GCN: buffer_store_dword [[ZERO]], [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen{{$}} define void @stored_fi_to_self() #0 { %tmp = alloca i32* @@ -52,18 +53,42 @@ ret void } +; GCN-LABEL: {{^}}stored_fi_to_self_offset: +; GCN-DAG: v_mov_b32_e32 [[ZERO:v[0-9]+]], 0{{$}} +; GCN-DAG: v_mov_b32_e32 [[K0:v[0-9]+]], 32{{$}} +; GCN: buffer_store_dword [[K0]], [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen{{$}} + +; GCN-DAG: v_mov_b32_e32 [[K1:v[0-9]+]], 0x4d2{{$}} +; GCN: buffer_store_dword [[K1]], [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen offset:2048{{$}} + +; GCN: v_mov_b32_e32 [[OFFSETK:v[0-9]+]], 0x800{{$}} +; GCN: buffer_store_dword [[OFFSETK]], [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen offset:2048{{$}} +define void @stored_fi_to_self_offset() #0 { + %tmp0 = alloca [512 x i32] + %tmp1 = alloca i32* + + ; Avoid optimizing everything out + %tmp0.cast = bitcast [512 x i32]* %tmp0 to i32* + store volatile i32 32, i32* %tmp0.cast + + store volatile i32* inttoptr (i32 1234 to i32*), i32** %tmp1 + + %bitcast = bitcast i32** %tmp1 to i32* + store volatile i32* %bitcast, i32** %tmp1 + ret void +} + ; GCN-LABEL: {{^}}stored_fi_to_fi: -; GCN: buffer_store_dword -; GCN: buffer_store_dword -; GCN: buffer_store_dword +; GCN: v_mov_b32_e32 [[ZERO:v[0-9]+]], 0{{$}} +; GCN: buffer_store_dword v{{[0-9]+}}, [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen{{$}} +; GCN: buffer_store_dword v{{[0-9]+}}, [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen offset:4{{$}} +; GCN: buffer_store_dword v{{[0-9]+}}, [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen offset:8{{$}} -; GCN-DAG: v_mov_b32_e32 [[FI1:v[0-9]+]], 4{{$}} -; GCN-DAG: v_mov_b32_e32 [[FI2:v[0-9]+]], 8{{$}} -; GCN: buffer_store_dword [[FI1]], [[FI2]] +; GCN: v_mov_b32_e32 [[FI1:v[0-9]+]], 4{{$}} +; GCN: buffer_store_dword [[FI1]], [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen offset:8{{$}} -; GCN-DAG: v_mov_b32_e32 [[FI1:v[0-9]+]], 4{{$}} -; GCN-DAG: v_mov_b32_e32 [[FI2:v[0-9]+]], 8{{$}} -; GCN: buffer_store_dword [[FI2]], [[FI1]] +; GCN: v_mov_b32_e32 [[FI2:v[0-9]+]], 8{{$}} +; GCN: buffer_store_dword [[FI2]], [[ZERO]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen offset:4{{$}} define void @stored_fi_to_fi() #0 { %tmp0 = alloca i32* %tmp1 = alloca i32* @@ -114,4 +139,28 @@ ret void } +; GCN-LABEL: {{^}}stored_fi_to_global_huge_frame_offset: +; GCN: v_mov_b32_e32 [[BASE_0:v[0-9]+]], 0{{$}} +; GCN: buffer_store_dword v{{[0-9]+}}, v{{[0-9]+}}, s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen + +; GCN-DAG: v_mov_b32_e32 [[K:v[0-9]+]], 0x3e7{{$}} +; GCN-DAG: s_add_i32 [[BASE_1_OFF_0:s[0-9]+]], 0, 0x3ffc +; GCN-DAG: v_mov_b32_e32 [[V_BASE_1_OFF_0:v[0-9]+]], [[BASE_1_OFF_0]] +; GCN: buffer_store_dword [[K]], [[V_BASE_1_OFF_0]], s{{\[[0-9]+:[0-9]+\]}}, s{{[0-9]+}} offen{{$}} + +; GCN-DAG: s_add_i32 [[BASE_1_OFF_1:s[0-9]+]], 0, 56 +; GCN-DAG: v_mov_b32_e32 [[V_BASE_1_OFF_1:v[0-9]+]], [[BASE_1_OFF_1]] +; GCN: buffer_store_dword [[V_BASE_1_OFF_1]], s{{\[[0-9]+:[0-9]+\]}}, 0{{$}} +define void @stored_fi_to_global_huge_frame_offset(i32* addrspace(1)* %ptr) #0 { + %tmp0 = alloca [4096 x i32] + %tmp1 = alloca [4096 x i32] + %gep0.tmp0 = getelementptr [4096 x i32], [4096 x i32]* %tmp0, i32 0, i32 0 + store volatile i32 0, i32* %gep0.tmp0 + %gep1.tmp0 = getelementptr [4096 x i32], [4096 x i32]* %tmp0, i32 0, i32 4095 + store volatile i32 999, i32* %gep1.tmp0 + %gep0.tmp1 = getelementptr [4096 x i32], [4096 x i32]* %tmp0, i32 0, i32 14 + store i32* %gep0.tmp1, i32* addrspace(1)* %ptr + ret void +} + attributes #0 = { nounwind }