From 2fe4fbc1843019d804b33117bc006a2a8ba89f6a Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Wed, 30 Mar 2016 22:28:52 +0000 Subject: [PATCH] AMDGPU: Add frexp_exp intrinsic llvm-svn: 264944 --- llvm/include/llvm/IR/IntrinsicsAMDGPU.td | 4 + llvm/lib/Target/AMDGPU/SIInstructions.td | 4 +- .../Transforms/InstCombine/InstCombineCalls.cpp | 21 ++- llvm/test/CodeGen/AMDGPU/llvm.amdgcn.frexp.exp.ll | 64 ++++++++ .../Transforms/InstCombine/amdgcn-intrinsics.ll | 162 +++++++++++++++++++++ 5 files changed, 248 insertions(+), 7 deletions(-) create mode 100644 llvm/test/CodeGen/AMDGPU/llvm.amdgcn.frexp.exp.ll diff --git a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td index 89ea798..393a1ba 100644 --- a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td +++ b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td @@ -123,6 +123,10 @@ def int_amdgcn_frexp_mant : Intrinsic< [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] >; +def int_amdgcn_frexp_exp : Intrinsic< + [llvm_i32_ty], [llvm_anyfloat_ty], [IntrNoMem] +>; + def int_amdgcn_class : Intrinsic< [llvm_i1_ty], [llvm_anyfloat_ty, llvm_i32_ty], [IntrNoMem] >; diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td index 2f7f908..bc0afa0 100644 --- a/llvm/lib/Target/AMDGPU/SIInstructions.td +++ b/llvm/lib/Target/AMDGPU/SIInstructions.td @@ -1344,7 +1344,7 @@ defm V_FFBH_U32 : VOP1Inst , "v_ffbh_u32", VOP_I32_I32>; defm V_FFBL_B32 : VOP1Inst , "v_ffbl_b32", VOP_I32_I32>; defm V_FFBH_I32 : VOP1Inst , "v_ffbh_i32", VOP_I32_I32>; defm V_FREXP_EXP_I32_F64 : VOP1Inst , "v_frexp_exp_i32_f64", - VOP_I32_F64 + VOP_I32_F64, int_amdgcn_frexp_exp >; let SchedRW = [WriteDoubleAdd] in { @@ -1359,7 +1359,7 @@ defm V_FRACT_F64 : VOP1Inst , "v_fract_f64", defm V_FREXP_EXP_I32_F32 : VOP1Inst , "v_frexp_exp_i32_f32", - VOP_I32_F32 + VOP_I32_F32, int_amdgcn_frexp_exp >; defm V_FREXP_MANT_F32 : VOP1Inst , "v_frexp_mant_f32", VOP_F32_F32, int_amdgcn_frexp_mant diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 19d81fa..3132fe8 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1846,17 +1846,28 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { break; } - case Intrinsic::amdgcn_frexp_mant: { + case Intrinsic::amdgcn_frexp_mant: + case Intrinsic::amdgcn_frexp_exp: { Value *Src = II->getArgOperand(0); if (const ConstantFP *C = dyn_cast(Src)) { int Exp; APFloat Significand = frexp(C->getValueAPF(), Exp, APFloat::rmNearestTiesToEven); - return replaceInstUsesWith(CI, ConstantFP::get(II->getContext(), - Significand)); - } else if (isa(Src)) - return replaceInstUsesWith(CI, Src); + if (II->getIntrinsicID() == Intrinsic::amdgcn_frexp_mant) { + return replaceInstUsesWith(CI, ConstantFP::get(II->getContext(), + Significand)); + } + + // Match instruction special case behavior. + if (Exp == APFloat::IEK_NaN || Exp == APFloat::IEK_Inf) + Exp = 0; + + return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), Exp)); + } + + if (isa(Src)) + return replaceInstUsesWith(CI, UndefValue::get(II->getType())); break; } diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.frexp.exp.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.frexp.exp.ll new file mode 100644 index 0000000..728a6b5 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.frexp.exp.ll @@ -0,0 +1,64 @@ +; RUN: llc -march=amdgcn -verify-machineinstrs < %s | FileCheck -check-prefix=GCN %s +; RUN: llc -march=amdgcn -mcpu=tonga -verify-machineinstrs < %s | FileCheck -check-prefix=GCN %s + +declare float @llvm.fabs.f32(float) #0 +declare double @llvm.fabs.f64(double) #0 +declare i32 @llvm.amdgcn.frexp.exp.f32(float) #0 +declare i32 @llvm.amdgcn.frexp.exp.f64(double) #0 + +; GCN-LABEL: {{^}}s_test_frexp_exp_f32: +; GCN: v_frexp_exp_i32_f32_e32 {{v[0-9]+}}, {{s[0-9]+}} +define void @s_test_frexp_exp_f32(i32 addrspace(1)* %out, float %src) #1 { + %frexp.exp = call i32 @llvm.amdgcn.frexp.exp.f32(float %src) + store i32 %frexp.exp, i32 addrspace(1)* %out + ret void +} + +; GCN-LABEL: {{^}}s_test_fabs_frexp_exp_f32: +; GCN: v_frexp_exp_i32_f32_e64 {{v[0-9]+}}, |{{s[0-9]+}}| +define void @s_test_fabs_frexp_exp_f32(i32 addrspace(1)* %out, float %src) #1 { + %fabs.src = call float @llvm.fabs.f32(float %src) + %frexp.exp = call i32 @llvm.amdgcn.frexp.exp.f32(float %fabs.src) + store i32 %frexp.exp, i32 addrspace(1)* %out + ret void +} + +; GCN-LABEL: {{^}}s_test_fneg_fabs_frexp_exp_f32: +; GCN: v_frexp_exp_i32_f32_e64 {{v[0-9]+}}, -|{{s[0-9]+}}| +define void @s_test_fneg_fabs_frexp_exp_f32(i32 addrspace(1)* %out, float %src) #1 { + %fabs.src = call float @llvm.fabs.f32(float %src) + %fneg.fabs.src = fsub float -0.0, %fabs.src + %frexp.exp = call i32 @llvm.amdgcn.frexp.exp.f32(float %fneg.fabs.src) + store i32 %frexp.exp, i32 addrspace(1)* %out + ret void +} + +; GCN-LABEL: {{^}}s_test_frexp_exp_f64: +; GCN: v_frexp_exp_i32_f64_e32 {{v[0-9]+}}, {{s\[[0-9]+:[0-9]+\]}} +define void @s_test_frexp_exp_f64(i32 addrspace(1)* %out, double %src) #1 { + %frexp.exp = call i32 @llvm.amdgcn.frexp.exp.f64(double %src) + store i32 %frexp.exp, i32 addrspace(1)* %out + ret void +} + +; GCN-LABEL: {{^}}s_test_fabs_frexp_exp_f64: +; GCN: v_frexp_exp_i32_f64_e64 {{v[0-9]+}}, |{{s\[[0-9]+:[0-9]+\]}}| +define void @s_test_fabs_frexp_exp_f64(i32 addrspace(1)* %out, double %src) #1 { + %fabs.src = call double @llvm.fabs.f64(double %src) + %frexp.exp = call i32 @llvm.amdgcn.frexp.exp.f64(double %fabs.src) + store i32 %frexp.exp, i32 addrspace(1)* %out + ret void +} + +; GCN-LABEL: {{^}}s_test_fneg_fabs_frexp_exp_f64: +; GCN: v_frexp_exp_i32_f64_e64 {{v[0-9]+}}, -|{{s\[[0-9]+:[0-9]+\]}}| +define void @s_test_fneg_fabs_frexp_exp_f64(i32 addrspace(1)* %out, double %src) #1 { + %fabs.src = call double @llvm.fabs.f64(double %src) + %fneg.fabs.src = fsub double -0.0, %fabs.src + %frexp.exp = call i32 @llvm.amdgcn.frexp.exp.f64(double %fneg.fabs.src) + store i32 %frexp.exp, i32 addrspace(1)* %out + ret void +} + +attributes #0 = { nounwind readnone } +attributes #1 = { nounwind } diff --git a/llvm/test/Transforms/InstCombine/amdgcn-intrinsics.ll b/llvm/test/Transforms/InstCombine/amdgcn-intrinsics.ll index 32f8bed..a734924 100644 --- a/llvm/test/Transforms/InstCombine/amdgcn-intrinsics.ll +++ b/llvm/test/Transforms/InstCombine/amdgcn-intrinsics.ll @@ -200,3 +200,165 @@ define double @test_constant_fold_frexp_mant_f64_min_num() nounwind { ret double %val } + +; -------------------------------------------------------------------- +; llvm.amdgcn.frexp.exp +; -------------------------------------------------------------------- + +declare i32 @llvm.amdgcn.frexp.exp.f32(float) nounwind readnone +declare i32 @llvm.amdgcn.frexp.exp.f64(double) nounwind readnone + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_undef( +; CHECK-NEXT: ret i32 undef +define i32 @test_constant_fold_frexp_exp_f32_undef() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float undef) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_undef( +; CHECK-NEXT: ret i32 undef +define i32 @test_constant_fold_frexp_exp_f64_undef() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double undef) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_0( +; CHECK-NEXT: ret i32 0 +define i32 @test_constant_fold_frexp_exp_f32_0() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float 0.0) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_0( +; CHECK-NEXT: ret i32 0 +define i32 @test_constant_fold_frexp_exp_f64_0() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double 0.0) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_n0( +; CHECK-NEXT: ret i32 0 +define i32 @test_constant_fold_frexp_exp_f32_n0() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float -0.0) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_n0( +; CHECK-NEXT: ret i32 0 +define i32 @test_constant_fold_frexp_exp_f64_n0() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double -0.0) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_1024( +; CHECK-NEXT: ret i32 11 +define i32 @test_constant_fold_frexp_exp_f32_1024() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float 1024.0) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_1024( +; CHECK-NEXT: ret i32 11 +define i32 @test_constant_fold_frexp_exp_f64_1024() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double 1024.0) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_n1024( +; CHECK-NEXT: ret i32 11 +define i32 @test_constant_fold_frexp_exp_f32_n1024() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float -1024.0) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_n1024( +; CHECK-NEXT: ret i32 11 +define i32 @test_constant_fold_frexp_exp_f64_n1024() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double -1024.0) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_1_1024( +; CHECK-NEXT: ret i32 -9 +define i32 @test_constant_fold_frexp_exp_f32_1_1024() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float 0.0009765625) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_1_1024( +; CHECK-NEXT: ret i32 -9 +define i32 @test_constant_fold_frexp_exp_f64_1_1024() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double 0.0009765625) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_nan( +; CHECK-NEXT: ret i32 0 +define i32 @test_constant_fold_frexp_exp_f32_nan() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float 0x7FF8000000000000) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_nan( +; CHECK-NEXT: ret i32 0 +define i32 @test_constant_fold_frexp_exp_f64_nan() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double 0x7FF8000000000000) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_inf( +; CHECK-NEXT: ret i32 0 +define i32 @test_constant_fold_frexp_exp_f32_inf() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float 0x7FF0000000000000) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_inf( +; CHECK-NEXT: ret i32 0 +define i32 @test_constant_fold_frexp_exp_f64_inf() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double 0x7FF0000000000000) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_ninf( +; CHECK-NEXT: ret i32 0 +define i32 @test_constant_fold_frexp_exp_f32_ninf() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float 0xFFF0000000000000) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_ninf( +; CHECK-NEXT: ret i32 0 +define i32 @test_constant_fold_frexp_exp_f64_ninf() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double 0xFFF0000000000000) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_max_num( +; CHECK-NEXT: ret i32 128 +define i32 @test_constant_fold_frexp_exp_f32_max_num() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float 0x47EFFFFFE0000000) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_max_num( +; CHECK-NEXT: ret i32 1024 +define i32 @test_constant_fold_frexp_exp_f64_max_num() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double 0x7FEFFFFFFFFFFFFF) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f32_min_num( +; CHECK-NEXT: ret i32 -148 +define i32 @test_constant_fold_frexp_exp_f32_min_num() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f32(float 0x36A0000000000000) + ret i32 %val +} + +; CHECK-LABEL: @test_constant_fold_frexp_exp_f64_min_num( +; CHECK-NEXT: ret i32 -1073 +define i32 @test_constant_fold_frexp_exp_f64_min_num() nounwind { + %val = call i32 @llvm.amdgcn.frexp.exp.f64(double 4.940656e-324) + ret i32 %val +} + -- 2.7.4