From c490f78e5398c3333f39e31ca71f077334768616 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Sat, 21 Feb 2015 21:29:07 +0000 Subject: [PATCH] R600/SI: Try to use v_madak_f32 This is a code size optimization when the constant only has one use. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@230148 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/R600/SIInstrInfo.cpp | 78 +++++++++++++ lib/Target/R600/SIInstrInfo.h | 3 + test/CodeGen/R600/madak.ll | 193 ++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+) create mode 100644 test/CodeGen/R600/madak.ll diff --git a/lib/Target/R600/SIInstrInfo.cpp b/lib/Target/R600/SIInstrInfo.cpp index 32daeaed35e..f2e0364e408 100644 --- a/lib/Target/R600/SIInstrInfo.cpp +++ b/lib/Target/R600/SIInstrInfo.cpp @@ -859,6 +859,84 @@ SIInstrInfo::isSafeToMoveRegClassDefs(const TargetRegisterClass *RC) const { return RC != &AMDGPU::EXECRegRegClass; } +static void removeModOperands(MachineInstr &MI) { + unsigned Opc = MI.getOpcode(); + int Src0ModIdx = AMDGPU::getNamedOperandIdx(Opc, + AMDGPU::OpName::src0_modifiers); + int Src1ModIdx = AMDGPU::getNamedOperandIdx(Opc, + AMDGPU::OpName::src1_modifiers); + int Src2ModIdx = AMDGPU::getNamedOperandIdx(Opc, + AMDGPU::OpName::src2_modifiers); + + MI.RemoveOperand(Src2ModIdx); + MI.RemoveOperand(Src1ModIdx); + MI.RemoveOperand(Src0ModIdx); +} + +bool SIInstrInfo::FoldImmediate(MachineInstr *UseMI, MachineInstr *DefMI, + unsigned Reg, MachineRegisterInfo *MRI) const { + if (!MRI->hasOneNonDBGUse(Reg)) + return false; + + unsigned Opc = UseMI->getOpcode(); + if (Opc == AMDGPU::V_MAD_F32) { + // Don't fold if we are using source modifiers. The new VOP2 instructions + // don't have them. + if (hasModifiersSet(*UseMI, AMDGPU::OpName::src0_modifiers) || + hasModifiersSet(*UseMI, AMDGPU::OpName::src1_modifiers) || + hasModifiersSet(*UseMI, AMDGPU::OpName::src2_modifiers)) { + return false; + } + + MachineOperand *Src0 = getNamedOperand(*UseMI, AMDGPU::OpName::src0); + MachineOperand *Src1 = getNamedOperand(*UseMI, AMDGPU::OpName::src1); + MachineOperand *Src2 = getNamedOperand(*UseMI, AMDGPU::OpName::src2); + + // The VOP2 src0 can't be an SGPR since the constant bus use will be the + // literal constant. + if (Src0->isReg() && RI.isSGPRClass(MRI->getRegClass(Src0->getReg()))) + return false; + + // Added part is the constant: Use v_madak_f32 + if (Src2->isReg() && Src2->getReg() == Reg) { + // Not allowed to use constant bus for another operand. + // We can however allow an inline immediate as src0. + if (!Src0->isImm() && + (Src0->isReg() && RI.isSGPRClass(MRI->getRegClass(Src0->getReg())))) + return false; + + if (!Src1->isReg() || + (Src1->isReg() && RI.isSGPRClass(MRI->getRegClass(Src1->getReg())))) + return false; + + const int64_t Imm = DefMI->getOperand(1).getImm(); + + // FIXME: This would be a lot easier if we could return a new instruction + // instead of having to modify in place. + + // Remove these first since they are at the end. + UseMI->RemoveOperand(AMDGPU::getNamedOperandIdx(AMDGPU::V_MAD_F32, + AMDGPU::OpName::omod)); + UseMI->RemoveOperand(AMDGPU::getNamedOperandIdx(AMDGPU::V_MAD_F32, + AMDGPU::OpName::clamp)); + + Src2->ChangeToImmediate(Imm); + + // These come before src2. + removeModOperands(*UseMI); + UseMI->setDesc(get(AMDGPU::V_MADAK_F32)); + + bool DeleteDef = MRI->hasOneNonDBGUse(Reg); + if (DeleteDef) + DefMI->eraseFromParent(); + + return true; + } + } + + return false; +} + bool SIInstrInfo::isTriviallyReMaterializable(const MachineInstr *MI, AliasAnalysis *AA) const { diff --git a/lib/Target/R600/SIInstrInfo.h b/lib/Target/R600/SIInstrInfo.h index 4d3371b1aec..12dc3f32c06 100644 --- a/lib/Target/R600/SIInstrInfo.h +++ b/lib/Target/R600/SIInstrInfo.h @@ -136,6 +136,9 @@ public: bool isSafeToMoveRegClassDefs(const TargetRegisterClass *RC) const override; + bool FoldImmediate(MachineInstr *UseMI, MachineInstr *DefMI, + unsigned Reg, MachineRegisterInfo *MRI) const final; + bool isSALU(uint16_t Opcode) const { return get(Opcode).TSFlags & SIInstrFlags::SALU; } diff --git a/test/CodeGen/R600/madak.ll b/test/CodeGen/R600/madak.ll new file mode 100644 index 00000000000..505a49bdf3d --- /dev/null +++ b/test/CodeGen/R600/madak.ll @@ -0,0 +1,193 @@ +; RUN: llc -march=amdgcn -verify-machineinstrs < %s | FileCheck -check-prefix=SI -check-prefix=GCN %s +; XUN: llc -march=amdgcn -mcpu=tonga -verify-machineinstrs < %s | FileCheck -check-prefix=VI -check-prefix=GCN %s + +; FIXME: Enable VI + +declare i32 @llvm.r600.read.tidig.x() nounwind readnone +declare float @llvm.fabs.f32(float) nounwind readnone + +; GCN-LABEL: {{^}}madak_f32: +; GCN: buffer_load_dword [[VA:v[0-9]+]] +; GCN: buffer_load_dword [[VB:v[0-9]+]] +; GCN: v_madak_f32 {{v[0-9]+}}, [[VB]], [[VA]], 0x41200000 +define void @madak_f32(float addrspace(1)* noalias %out, float addrspace(1)* noalias %in.a, float addrspace(1)* noalias %in.b) nounwind { + %tid = tail call i32 @llvm.r600.read.tidig.x() nounwind readnone + %in.a.gep = getelementptr float addrspace(1)* %in.a, i32 %tid + %in.b.gep = getelementptr float addrspace(1)* %in.b, i32 %tid + %out.gep = getelementptr float addrspace(1)* %out, i32 %tid + + %a = load float addrspace(1)* %in.a.gep, align 4 + %b = load float addrspace(1)* %in.b.gep, align 4 + + %mul = fmul float %a, %b + %madak = fadd float %mul, 10.0 + store float %madak, float addrspace(1)* %out.gep, align 4 + ret void +} + +; Make sure this is only folded with one use. This is a code size +; optimization and if we fold the immediate multiple times, we'll undo +; it. + +; GCN-LABEL: {{^}}madak_2_use_f32: +; GCN-DAG: buffer_load_dword [[VA:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64{{$}} +; GCN-DAG: buffer_load_dword [[VB:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:4 +; GCN-DAG: buffer_load_dword [[VC:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:8 +; GCN-DAG: v_mov_b32_e32 [[VK:v[0-9]+]], 0x41200000 +; GCN-DAG: v_mad_f32 {{v[0-9]+}}, [[VA]], [[VB]], [[VK]] +; GCN-DAG: v_mad_f32 {{v[0-9]+}}, [[VA]], [[VC]], [[VK]] +; GCN: s_endpgm +define void @madak_2_use_f32(float addrspace(1)* noalias %out, float addrspace(1)* noalias %in) nounwind { + %tid = tail call i32 @llvm.r600.read.tidig.x() nounwind readnone + + %in.gep.0 = getelementptr float addrspace(1)* %in, i32 %tid + %in.gep.1 = getelementptr float addrspace(1)* %in.gep.0, i32 1 + %in.gep.2 = getelementptr float addrspace(1)* %in.gep.0, i32 2 + + %out.gep.0 = getelementptr float addrspace(1)* %out, i32 %tid + %out.gep.1 = getelementptr float addrspace(1)* %in.gep.0, i32 1 + + %a = load float addrspace(1)* %in.gep.0, align 4 + %b = load float addrspace(1)* %in.gep.1, align 4 + %c = load float addrspace(1)* %in.gep.2, align 4 + + %mul0 = fmul float %a, %b + %mul1 = fmul float %a, %c + %madak0 = fadd float %mul0, 10.0 + %madak1 = fadd float %mul1, 10.0 + + store float %madak0, float addrspace(1)* %out.gep.0, align 4 + store float %madak1, float addrspace(1)* %out.gep.1, align 4 + ret void +} + +; GCN-LABEL: {{^}}madak_m_inline_imm_f32: +; GCN: buffer_load_dword [[VA:v[0-9]+]] +; GCN: v_madak_f32 {{v[0-9]+}}, 4.0, [[VA]], 0x41200000 +define void @madak_m_inline_imm_f32(float addrspace(1)* noalias %out, float addrspace(1)* noalias %in.a) nounwind { + %tid = tail call i32 @llvm.r600.read.tidig.x() nounwind readnone + %in.a.gep = getelementptr float addrspace(1)* %in.a, i32 %tid + %out.gep = getelementptr float addrspace(1)* %out, i32 %tid + + %a = load float addrspace(1)* %in.a.gep, align 4 + + %mul = fmul float 4.0, %a + %madak = fadd float %mul, 10.0 + store float %madak, float addrspace(1)* %out.gep, align 4 + ret void +} + +; Make sure nothing weird happens with a value that is also allowed as +; an inline immediate. + +; GCN-LABEL: {{^}}madak_inline_imm_f32: +; GCN: buffer_load_dword [[VA:v[0-9]+]] +; GCN: buffer_load_dword [[VB:v[0-9]+]] +; GCN: v_mad_f32 {{v[0-9]+}}, [[VA]], [[VB]], 4.0 +define void @madak_inline_imm_f32(float addrspace(1)* noalias %out, float addrspace(1)* noalias %in.a, float addrspace(1)* noalias %in.b) nounwind { + %tid = tail call i32 @llvm.r600.read.tidig.x() nounwind readnone + %in.a.gep = getelementptr float addrspace(1)* %in.a, i32 %tid + %in.b.gep = getelementptr float addrspace(1)* %in.b, i32 %tid + %out.gep = getelementptr float addrspace(1)* %out, i32 %tid + + %a = load float addrspace(1)* %in.a.gep, align 4 + %b = load float addrspace(1)* %in.b.gep, align 4 + + %mul = fmul float %a, %b + %madak = fadd float %mul, 4.0 + store float %madak, float addrspace(1)* %out.gep, align 4 + ret void +} + +; We can't use an SGPR when forming madak +; GCN-LABEL: {{^}}s_v_madak_f32: +; GCN: s_load_dword [[SB:s[0-9]+]] +; GCN-DAG: v_mov_b32_e32 [[VK:v[0-9]+]], 0x41200000 +; GCN-DAG: buffer_load_dword [[VA:v[0-9]+]] +; GCN-NOT: v_madak_f32 +; GCN: v_mad_f32 {{v[0-9]+}}, [[SB]], [[VA]], [[VK]] +define void @s_v_madak_f32(float addrspace(1)* noalias %out, float addrspace(1)* noalias %in.a, float %b) nounwind { + %tid = tail call i32 @llvm.r600.read.tidig.x() nounwind readnone + %in.a.gep = getelementptr float addrspace(1)* %in.a, i32 %tid + %out.gep = getelementptr float addrspace(1)* %out, i32 %tid + + %a = load float addrspace(1)* %in.a.gep, align 4 + + %mul = fmul float %a, %b + %madak = fadd float %mul, 10.0 + store float %madak, float addrspace(1)* %out.gep, align 4 + ret void +} + +; GCN-LABEL: @v_s_madak_f32 +; GCN-DAG: s_load_dword [[SB:s[0-9]+]] +; GCN-DAG: v_mov_b32_e32 [[VK:v[0-9]+]], 0x41200000 +; GCN-DAG: buffer_load_dword [[VA:v[0-9]+]] +; GCN-NOT: v_madak_f32 +; GCN: v_mad_f32 {{v[0-9]+}}, [[VA]], [[SB]], [[VK]] +define void @v_s_madak_f32(float addrspace(1)* noalias %out, float %a, float addrspace(1)* noalias %in.b) nounwind { + %tid = tail call i32 @llvm.r600.read.tidig.x() nounwind readnone + %in.b.gep = getelementptr float addrspace(1)* %in.b, i32 %tid + %out.gep = getelementptr float addrspace(1)* %out, i32 %tid + + %b = load float addrspace(1)* %in.b.gep, align 4 + + %mul = fmul float %a, %b + %madak = fadd float %mul, 10.0 + store float %madak, float addrspace(1)* %out.gep, align 4 + ret void +} + +; GCN-LABEL: {{^}}s_s_madak_f32: +; GCN-NOT: v_madak_f32 +; GCN: v_mad_f32 {{v[0-9]+}}, {{s[0-9]+}}, {{v[0-9]+}}, {{v[0-9]+}} +define void @s_s_madak_f32(float addrspace(1)* %out, float %a, float %b) nounwind { + %mul = fmul float %a, %b + %madak = fadd float %mul, 10.0 + store float %madak, float addrspace(1)* %out, align 4 + ret void +} + +; GCN-LABEL: {{^}}no_madak_src0_modifier_f32: +; GCN: buffer_load_dword [[VA:v[0-9]+]] +; GCN: buffer_load_dword [[VB:v[0-9]+]] +; GCN: v_mad_f32 {{v[0-9]+}}, |{{v[0-9]+}}|, {{v[0-9]+}}, {{[sv][0-9]+}} +; GCN: s_endpgm +define void @no_madak_src0_modifier_f32(float addrspace(1)* noalias %out, float addrspace(1)* noalias %in.a, float addrspace(1)* noalias %in.b) nounwind { + %tid = tail call i32 @llvm.r600.read.tidig.x() nounwind readnone + %in.a.gep = getelementptr float addrspace(1)* %in.a, i32 %tid + %in.b.gep = getelementptr float addrspace(1)* %in.b, i32 %tid + %out.gep = getelementptr float addrspace(1)* %out, i32 %tid + + %a = load float addrspace(1)* %in.a.gep, align 4 + %b = load float addrspace(1)* %in.b.gep, align 4 + + %a.fabs = call float @llvm.fabs.f32(float %a) nounwind readnone + + %mul = fmul float %a.fabs, %b + %madak = fadd float %mul, 10.0 + store float %madak, float addrspace(1)* %out.gep, align 4 + ret void +} + +; GCN-LABEL: {{^}}no_madak_src1_modifier_f32: +; GCN: buffer_load_dword [[VA:v[0-9]+]] +; GCN: buffer_load_dword [[VB:v[0-9]+]] +; GCN: v_mad_f32 {{v[0-9]+}}, {{v[0-9]+}}, |{{v[0-9]+}}|, {{[sv][0-9]+}} +; GCN: s_endpgm +define void @no_madak_src1_modifier_f32(float addrspace(1)* noalias %out, float addrspace(1)* noalias %in.a, float addrspace(1)* noalias %in.b) nounwind { + %tid = tail call i32 @llvm.r600.read.tidig.x() nounwind readnone + %in.a.gep = getelementptr float addrspace(1)* %in.a, i32 %tid + %in.b.gep = getelementptr float addrspace(1)* %in.b, i32 %tid + %out.gep = getelementptr float addrspace(1)* %out, i32 %tid + + %a = load float addrspace(1)* %in.a.gep, align 4 + %b = load float addrspace(1)* %in.b.gep, align 4 + + %b.fabs = call float @llvm.fabs.f32(float %b) nounwind readnone + + %mul = fmul float %a, %b.fabs + %madak = fadd float %mul, 10.0 + store float %madak, float addrspace(1)* %out.gep, align 4 + ret void +} -- 2.34.1