Index: lib/Target/R600/AMDGPUISelLowering.h =================================================================== --- lib/Target/R600/AMDGPUISelLowering.h +++ lib/Target/R600/AMDGPUISelLowering.h @@ -146,6 +146,10 @@ SDValue CombineMinMax(SDNode *N, SelectionDAG &DAG) const; const char* getTargetNodeName(unsigned Opcode) const override; + SDValue getRsqrtEstimate(SDValue Operand, + DAGCombinerInfo &DCI, + unsigned &RefinementSteps) const override; + virtual SDNode *PostISelFolding(MachineSDNode *N, SelectionDAG &DAG) const { return N; Index: lib/Target/R600/AMDGPUISelLowering.cpp =================================================================== --- lib/Target/R600/AMDGPUISelLowering.cpp +++ lib/Target/R600/AMDGPUISelLowering.cpp @@ -2325,6 +2325,23 @@ } } +SDValue AMDGPUTargetLowering::getRsqrtEstimate(SDValue Operand, + DAGCombinerInfo &DCI, + unsigned &RefinementSteps) const { + SelectionDAG &DAG = DCI.DAG; + EVT VT = Operand.getValueType(); + + if (VT == MVT::f32) { + RefinementSteps = 0; + return DAG.getNode(AMDGPUISD::RSQ, SDLoc(Operand), VT, Operand); + } + + // TODO: There is also f64 rsq instruction, but the documentation is less + // clear on its precision. + + return SDValue(); +} + static void computeKnownBitsForMinMax(const SDValue Op0, const SDValue Op1, APInt &KnownZero, Index: test/CodeGen/R600/fsqrt.ll =================================================================== --- test/CodeGen/R600/fsqrt.ll +++ test/CodeGen/R600/fsqrt.ll @@ -1,4 +1,7 @@ -; RUN: llc < %s -march=r600 -mcpu=tahiti -verify-machineinstrs | FileCheck %s +; RUN: llc -march=r600 -mcpu=tahiti -verify-machineinstrs < %s | FileCheck %s +; RUN: llc -march=r600 -mcpu=tahiti -verify-machineinstrs -enable-unsafe-fp-math < %s | FileCheck %s + +; Run with unsafe-fp-math to make sure nothing tries to turn this into 1 / rsqrt(x) ; CHECK: {{^}}fsqrt_f32: ; CHECK: V_SQRT_F32_e32 {{v[0-9]+, v[0-9]+}} Index: test/CodeGen/R600/rsq.ll =================================================================== --- test/CodeGen/R600/rsq.ll +++ test/CodeGen/R600/rsq.ll @@ -1,6 +1,7 @@ ; RUN: llc -march=r600 -mcpu=SI -mattr=-fp32-denormals -verify-machineinstrs -enable-unsafe-fp-math < %s | FileCheck -check-prefix=SI-UNSAFE -check-prefix=SI %s ; RUN: llc -march=r600 -mcpu=SI -mattr=-fp32-denormals -verify-machineinstrs < %s | FileCheck -check-prefix=SI-SAFE -check-prefix=SI %s +declare i32 @llvm.r600.read.tidig.x() nounwind readnone declare float @llvm.sqrt.f32(float) nounwind readnone declare double @llvm.sqrt.f64(double) nounwind readnone @@ -36,3 +37,38 @@ store float %div, float addrspace(1)* %out, align 4 ret void } + +; Recognize that this is rsqrt(a) * rcp(b) * c, +; not 1 / ( 1 / sqrt(a)) * rcp(b) * c. + +; SI-LABEL: @rsqrt_fmul +; SI-DAG: BUFFER_LOAD_DWORD [[A:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64{{$}} +; SI-DAG: BUFFER_LOAD_DWORD [[B:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:0x4 +; SI-DAG: BUFFER_LOAD_DWORD [[C:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:0x8 + +; SI-UNSAFE-DAG: V_RSQ_F32_e32 [[RSQA:v[0-9]+]], [[A]] +; SI-UNSAFE-DAG: V_RCP_F32_e32 [[RCPB:v[0-9]+]], [[B]] +; SI-UNSAFE-DAG: V_MUL_F32_e32 [[TMP:v[0-9]+]], [[RCPB]], [[RSQA]] +; SI-UNSAFE: V_MUL_F32_e32 [[RESULT:v[0-9]+]], [[TMP]], [[C]] +; SI-UNSAFE: BUFFER_STORE_DWORD [[RESULT]] + +; SI-SAFE-NOT: V_RSQ_F32 + +; SI: S_ENDPGM +define void @rsqrt_fmul(float addrspace(1)* %out, float addrspace(1)* %in) { + %tid = call i32 @llvm.r600.read.tidig.x() nounwind readnone + %out.gep = getelementptr float addrspace(1)* %out, i32 %tid + %gep.0 = getelementptr float addrspace(1)* %in, i32 %tid + %gep.1 = getelementptr float addrspace(1)* %gep.0, i32 1 + %gep.2 = getelementptr float addrspace(1)* %gep.0, i32 2 + + %a = load float addrspace(1)* %gep.0 + %b = load float addrspace(1)* %gep.1 + %c = load float addrspace(1)* %gep.2 + + %x = call float @llvm.sqrt.f32(float %a) + %y = fmul float %x, %b + %z = fdiv float %c, %y + store float %z, float addrspace(1)* %out.gep + ret void +}