From c093062447591991e3eacedaa111bb04b0f89fcb Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Sat, 15 Nov 2014 05:02:57 +0000 Subject: [PATCH] R600: Permute operands when selecting legacy min/max This gets the correct NaN behavior based on the compare type the hardware uses. This now passes the new piglit test I have for this on SI. Add stricter tests for the operand order. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222079 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/R600/AMDGPUISelLowering.cpp | 15 ++++--- test/CodeGen/R600/fmax_legacy.ll | 57 +++++++++++++++++++++---- test/CodeGen/R600/fmin_legacy.ll | 59 ++++++++++++++++++++++---- test/CodeGen/R600/pv.ll | 4 +- 4 files changed, 110 insertions(+), 25 deletions(-) diff --git a/lib/Target/R600/AMDGPUISelLowering.cpp b/lib/Target/R600/AMDGPUISelLowering.cpp index 26af397897e..2f95b74fcf7 100644 --- a/lib/Target/R600/AMDGPUISelLowering.cpp +++ b/lib/Target/R600/AMDGPUISelLowering.cpp @@ -1032,9 +1032,12 @@ SDValue AMDGPUTargetLowering::CombineFMinMax(SDLoc DL, case ISD::SETOLT: case ISD::SETLE: case ISD::SETLT: { - unsigned Opc - = (LHS == True) ? AMDGPUISD::FMIN_LEGACY : AMDGPUISD::FMAX_LEGACY; - return DAG.getNode(Opc, DL, VT, LHS, RHS); + // We need to permute the operands to get the correct NaN behavior. The + // selected operand is the second one based on the failing compare with NaN, + // so permute it based on the compare type the hardware uses. + if (LHS == True) + return DAG.getNode(AMDGPUISD::FMIN_LEGACY, DL, VT, RHS, LHS); + return DAG.getNode(AMDGPUISD::FMAX_LEGACY, DL, VT, LHS, RHS); } case ISD::SETGT: case ISD::SETGE: @@ -1042,9 +1045,9 @@ SDValue AMDGPUTargetLowering::CombineFMinMax(SDLoc DL, case ISD::SETOGE: case ISD::SETUGT: case ISD::SETOGT: { - unsigned Opc - = (LHS == True) ? AMDGPUISD::FMAX_LEGACY : AMDGPUISD::FMIN_LEGACY; - return DAG.getNode(Opc, DL, VT, LHS, RHS); + if (LHS == True) + return DAG.getNode(AMDGPUISD::FMAX_LEGACY, DL, VT, RHS, LHS); + return DAG.getNode(AMDGPUISD::FMIN_LEGACY, DL, VT, LHS, RHS); } case ISD::SETCC_INVALID: llvm_unreachable("Invalid setcc condcode!"); diff --git a/test/CodeGen/R600/fmax_legacy.ll b/test/CodeGen/R600/fmax_legacy.ll index 9bfff8a7d80..e9d837b0013 100644 --- a/test/CodeGen/R600/fmax_legacy.ll +++ b/test/CodeGen/R600/fmax_legacy.ll @@ -1,10 +1,21 @@ ; RUN: llc -march=r600 -mcpu=SI < %s | FileCheck -check-prefix=SI -check-prefix=FUNC %s ; RUN: llc -march=r600 -mcpu=redwood < %s | FileCheck -check-prefix=EG -check-prefix=FUNC %s +declare i32 @llvm.r600.read.tidig.x() #1 + ; FUNC-LABEL: @test_fmax_legacy_uge_f32 -; SI: v_max_legacy_f32_e32 +; SI: buffer_load_dword [[A:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64{{$}} +; SI: buffer_load_dword [[B:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:0x4 +; SI: v_max_legacy_f32_e32 {{v[0-9]+}}, [[A]], [[B]] ; EG: MAX -define void @test_fmax_legacy_uge_f32(float addrspace(1)* %out, float %a, float %b) nounwind { +define void @test_fmax_legacy_uge_f32(float addrspace(1)* %out, float addrspace(1)* %in) #0 { + %tid = call i32 @llvm.r600.read.tidig.x() #1 + %gep.0 = getelementptr float addrspace(1)* %in, i32 %tid + %gep.1 = getelementptr float addrspace(1)* %gep.0, i32 1 + + %a = load float addrspace(1)* %gep.0, align 4 + %b = load float addrspace(1)* %gep.1, align 4 + %cmp = fcmp uge float %a, %b %val = select i1 %cmp, float %a, float %b store float %val, float addrspace(1)* %out, align 4 @@ -12,9 +23,18 @@ define void @test_fmax_legacy_uge_f32(float addrspace(1)* %out, float %a, float } ; FUNC-LABEL: @test_fmax_legacy_oge_f32 -; SI: v_max_legacy_f32_e32 +; SI: buffer_load_dword [[A:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64{{$}} +; SI: buffer_load_dword [[B:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:0x4 +; SI: v_max_legacy_f32_e32 {{v[0-9]+}}, [[A]], [[B]] ; EG: MAX -define void @test_fmax_legacy_oge_f32(float addrspace(1)* %out, float %a, float %b) nounwind { +define void @test_fmax_legacy_oge_f32(float addrspace(1)* %out, float addrspace(1)* %in) #0 { + %tid = call i32 @llvm.r600.read.tidig.x() #1 + %gep.0 = getelementptr float addrspace(1)* %in, i32 %tid + %gep.1 = getelementptr float addrspace(1)* %gep.0, i32 1 + + %a = load float addrspace(1)* %gep.0, align 4 + %b = load float addrspace(1)* %gep.1, align 4 + %cmp = fcmp oge float %a, %b %val = select i1 %cmp, float %a, float %b store float %val, float addrspace(1)* %out, align 4 @@ -22,9 +42,18 @@ define void @test_fmax_legacy_oge_f32(float addrspace(1)* %out, float %a, float } ; FUNC-LABEL: @test_fmax_legacy_ugt_f32 -; SI: v_max_legacy_f32_e32 +; SI: buffer_load_dword [[A:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64{{$}} +; SI: buffer_load_dword [[B:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:0x4 +; SI: v_max_legacy_f32_e32 {{v[0-9]+}}, [[A]], [[B]] ; EG: MAX -define void @test_fmax_legacy_ugt_f32(float addrspace(1)* %out, float %a, float %b) nounwind { +define void @test_fmax_legacy_ugt_f32(float addrspace(1)* %out, float addrspace(1)* %in) #0 { + %tid = call i32 @llvm.r600.read.tidig.x() #1 + %gep.0 = getelementptr float addrspace(1)* %in, i32 %tid + %gep.1 = getelementptr float addrspace(1)* %gep.0, i32 1 + + %a = load float addrspace(1)* %gep.0, align 4 + %b = load float addrspace(1)* %gep.1, align 4 + %cmp = fcmp ugt float %a, %b %val = select i1 %cmp, float %a, float %b store float %val, float addrspace(1)* %out, align 4 @@ -32,11 +61,23 @@ define void @test_fmax_legacy_ugt_f32(float addrspace(1)* %out, float %a, float } ; FUNC-LABEL: @test_fmax_legacy_ogt_f32 -; SI: v_max_legacy_f32_e32 +; SI: buffer_load_dword [[A:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64{{$}} +; SI: buffer_load_dword [[B:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:0x4 +; SI: v_max_legacy_f32_e32 {{v[0-9]+}}, [[A]], [[B]] ; EG: MAX -define void @test_fmax_legacy_ogt_f32(float addrspace(1)* %out, float %a, float %b) nounwind { +define void @test_fmax_legacy_ogt_f32(float addrspace(1)* %out, float addrspace(1)* %in) #0 { + %tid = call i32 @llvm.r600.read.tidig.x() #1 + %gep.0 = getelementptr float addrspace(1)* %in, i32 %tid + %gep.1 = getelementptr float addrspace(1)* %gep.0, i32 1 + + %a = load float addrspace(1)* %gep.0, align 4 + %b = load float addrspace(1)* %gep.1, align 4 + %cmp = fcmp ogt float %a, %b %val = select i1 %cmp, float %a, float %b store float %val, float addrspace(1)* %out, align 4 ret void } + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone } diff --git a/test/CodeGen/R600/fmin_legacy.ll b/test/CodeGen/R600/fmin_legacy.ll index 5840e7ed45a..2fbdb6bb20c 100644 --- a/test/CodeGen/R600/fmin_legacy.ll +++ b/test/CodeGen/R600/fmin_legacy.ll @@ -1,10 +1,12 @@ ; RUN: llc -march=r600 -mcpu=SI < %s | FileCheck -check-prefix=SI -check-prefix=FUNC %s ; RUN: llc -march=r600 -mcpu=redwood < %s | FileCheck -check-prefix=EG -check-prefix=FUNC %s +declare i32 @llvm.r600.read.tidig.x() #1 + ; FUNC-LABEL: @test_fmin_legacy_f32 ; EG: MIN * ; SI: v_min_legacy_f32_e32 -define void @test_fmin_legacy_f32(<4 x float> addrspace(1)* %out, <4 x float> inreg %reg0) nounwind { +define void @test_fmin_legacy_f32(<4 x float> addrspace(1)* %out, <4 x float> inreg %reg0) #0 { %r0 = extractelement <4 x float> %reg0, i32 0 %r1 = extractelement <4 x float> %reg0, i32 1 %r2 = fcmp uge float %r0, %r1 @@ -15,8 +17,17 @@ define void @test_fmin_legacy_f32(<4 x float> addrspace(1)* %out, <4 x float> in } ; FUNC-LABEL: @test_fmin_legacy_ule_f32 -; SI: v_min_legacy_f32_e32 -define void @test_fmin_legacy_ule_f32(float addrspace(1)* %out, float %a, float %b) nounwind { +; SI: buffer_load_dword [[A:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64{{$}} +; SI: buffer_load_dword [[B:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:0x4 +; SI: v_min_legacy_f32_e32 {{v[0-9]+}}, [[A]], [[B]] +define void @test_fmin_legacy_ule_f32(float addrspace(1)* %out, float addrspace(1)* %in) #0 { + %tid = call i32 @llvm.r600.read.tidig.x() #1 + %gep.0 = getelementptr float addrspace(1)* %in, i32 %tid + %gep.1 = getelementptr float addrspace(1)* %gep.0, i32 1 + + %a = load float addrspace(1)* %gep.0, align 4 + %b = load float addrspace(1)* %gep.1, align 4 + %cmp = fcmp ule float %a, %b %val = select i1 %cmp, float %a, float %b store float %val, float addrspace(1)* %out, align 4 @@ -24,8 +35,17 @@ define void @test_fmin_legacy_ule_f32(float addrspace(1)* %out, float %a, float } ; FUNC-LABEL: @test_fmin_legacy_ole_f32 -; SI: v_min_legacy_f32_e32 -define void @test_fmin_legacy_ole_f32(float addrspace(1)* %out, float %a, float %b) nounwind { +; SI: buffer_load_dword [[A:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64{{$}} +; SI: buffer_load_dword [[B:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:0x4 +; SI: v_min_legacy_f32_e32 {{v[0-9]+}}, [[A]], [[B]] +define void @test_fmin_legacy_ole_f32(float addrspace(1)* %out, float addrspace(1)* %in) #0 { + %tid = call i32 @llvm.r600.read.tidig.x() #1 + %gep.0 = getelementptr float addrspace(1)* %in, i32 %tid + %gep.1 = getelementptr float addrspace(1)* %gep.0, i32 1 + + %a = load float addrspace(1)* %gep.0, align 4 + %b = load float addrspace(1)* %gep.1, align 4 + %cmp = fcmp ole float %a, %b %val = select i1 %cmp, float %a, float %b store float %val, float addrspace(1)* %out, align 4 @@ -33,8 +53,17 @@ define void @test_fmin_legacy_ole_f32(float addrspace(1)* %out, float %a, float } ; FUNC-LABEL: @test_fmin_legacy_olt_f32 -; SI: v_min_legacy_f32_e32 -define void @test_fmin_legacy_olt_f32(float addrspace(1)* %out, float %a, float %b) nounwind { +; SI: buffer_load_dword [[A:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64{{$}} +; SI: buffer_load_dword [[B:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:0x4 +; SI: v_min_legacy_f32_e32 {{v[0-9]+}}, [[A]], [[B]] +define void @test_fmin_legacy_olt_f32(float addrspace(1)* %out, float addrspace(1)* %in) #0 { + %tid = call i32 @llvm.r600.read.tidig.x() #1 + %gep.0 = getelementptr float addrspace(1)* %in, i32 %tid + %gep.1 = getelementptr float addrspace(1)* %gep.0, i32 1 + + %a = load float addrspace(1)* %gep.0, align 4 + %b = load float addrspace(1)* %gep.1, align 4 + %cmp = fcmp olt float %a, %b %val = select i1 %cmp, float %a, float %b store float %val, float addrspace(1)* %out, align 4 @@ -42,10 +71,22 @@ define void @test_fmin_legacy_olt_f32(float addrspace(1)* %out, float %a, float } ; FUNC-LABEL: @test_fmin_legacy_ult_f32 -; SI: v_min_legacy_f32_e32 -define void @test_fmin_legacy_ult_f32(float addrspace(1)* %out, float %a, float %b) nounwind { +; SI: buffer_load_dword [[A:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64{{$}} +; SI: buffer_load_dword [[B:v[0-9]+]], {{v\[[0-9]+:[0-9]+\]}}, {{s\[[0-9]+:[0-9]+\]}}, 0 addr64 offset:0x4 +; SI: v_min_legacy_f32_e32 {{v[0-9]+}}, [[A]], [[B]] +define void @test_fmin_legacy_ult_f32(float addrspace(1)* %out, float addrspace(1)* %in) #0 { + %tid = call i32 @llvm.r600.read.tidig.x() #1 + %gep.0 = getelementptr float addrspace(1)* %in, i32 %tid + %gep.1 = getelementptr float addrspace(1)* %gep.0, i32 1 + + %a = load float addrspace(1)* %gep.0, align 4 + %b = load float addrspace(1)* %gep.1, align 4 + %cmp = fcmp ult float %a, %b %val = select i1 %cmp, float %a, float %b store float %val, float addrspace(1)* %out, align 4 ret void } + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone } diff --git a/test/CodeGen/R600/pv.ll b/test/CodeGen/R600/pv.ll index 55eb56d3fb1..1908f15949a 100644 --- a/test/CodeGen/R600/pv.ll +++ b/test/CodeGen/R600/pv.ll @@ -1,7 +1,7 @@ ; RUN: llc < %s -march=r600 | FileCheck %s -;CHECK: DOT4 * T{{[0-9]\.W}} (MASKED) -;CHECK: MAX T{{[0-9].[XYZW]}}, PV.X, 0.0 +; CHECK: DOT4 * T{{[0-9]\.W}} (MASKED) +; CHECK: MAX T{{[0-9].[XYZW]}}, 0.0, PV.X define void @main(<4 x float> inreg %reg0, <4 x float> inreg %reg1, <4 x float> inreg %reg2, <4 x float> inreg %reg3, <4 x float> inreg %reg4, <4 x float> inreg %reg5, <4 x float> inreg %reg6, <4 x float> inreg %reg7) #0 { main_body: -- 2.34.1