diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td index b4bc9eda4f50f..1fd6f3ed044ec 100644 --- a/llvm/lib/Target/DirectX/DXIL.td +++ b/llvm/lib/Target/DirectX/DXIL.td @@ -274,6 +274,9 @@ def Frac : DXILOpMapping<22, unary, int_dx_frac, "Returns a fraction from 0 to 1 that represents the " "decimal part of the input.", [llvm_halforfloat_ty, LLVMMatchType<0>]>; +def Log2 : DXILOpMapping<23, unary, int_log2, + "Returns the base-2 logarithm of the specified value.", + [llvm_halforfloat_ty, LLVMMatchType<0>]>; def Sqrt : DXILOpMapping<24, unary, int_sqrt, "Returns the square root of the specified floating-point" "value, per component.", diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp index b46564702c7aa..3cc375edabde9 100644 --- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp +++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp @@ -35,6 +35,8 @@ static bool isIntrinsicExpansion(Function &F) { switch (F.getIntrinsicID()) { case Intrinsic::abs: case Intrinsic::exp: + case Intrinsic::log: + case Intrinsic::log10: case Intrinsic::dx_any: case Intrinsic::dx_clamp: case Intrinsic::dx_uclamp: @@ -108,8 +110,8 @@ static bool expandExpIntrinsic(CallInst *Orig) { Ty->isVectorTy() ? ConstantVector::getSplat( ElementCount::getFixed( cast(Ty)->getNumElements()), - ConstantFP::get(EltTy, numbers::log2e)) - : ConstantFP::get(EltTy, numbers::log2e); + ConstantFP::get(EltTy, numbers::log2ef)) + : ConstantFP::get(EltTy, numbers::log2ef); Value *NewX = Builder.CreateFMul(Log2eConst, X); auto *Exp2Call = Builder.CreateIntrinsic(Ty, Intrinsic::exp2, {NewX}, nullptr, "dx.exp2"); @@ -169,6 +171,32 @@ static bool expandLerpIntrinsic(CallInst *Orig) { return true; } +static bool expandLogIntrinsic(CallInst *Orig, + float LogConstVal = numbers::ln2f) { + Value *X = Orig->getOperand(0); + IRBuilder<> Builder(Orig->getParent()); + Builder.SetInsertPoint(Orig); + Type *Ty = X->getType(); + Type *EltTy = Ty->getScalarType(); + Constant *Ln2Const = + Ty->isVectorTy() ? ConstantVector::getSplat( + ElementCount::getFixed( + cast(Ty)->getNumElements()), + ConstantFP::get(EltTy, LogConstVal)) + : ConstantFP::get(EltTy, LogConstVal); + auto *Log2Call = + Builder.CreateIntrinsic(Ty, Intrinsic::log2, {X}, nullptr, "elt.log2"); + Log2Call->setTailCall(Orig->isTailCall()); + Log2Call->setAttributes(Orig->getAttributes()); + auto *Result = Builder.CreateFMul(Ln2Const, Log2Call); + Orig->replaceAllUsesWith(Result); + Orig->eraseFromParent(); + return true; +} +static bool expandLog10Intrinsic(CallInst *Orig) { + return expandLogIntrinsic(Orig, numbers::ln2f / numbers::ln10f); +} + static bool expandRcpIntrinsic(CallInst *Orig) { Value *X = Orig->getOperand(0); IRBuilder<> Builder(Orig->getParent()); @@ -238,6 +266,10 @@ static bool expandIntrinsic(Function &F, CallInst *Orig) { return expandAbs(Orig); case Intrinsic::exp: return expandExpIntrinsic(Orig); + case Intrinsic::log: + return expandLogIntrinsic(Orig); + case Intrinsic::log10: + return expandLog10Intrinsic(Orig); case Intrinsic::dx_any: return expandAnyIntrinsic(Orig); case Intrinsic::dx_uclamp: diff --git a/llvm/test/CodeGen/DirectX/log-vec.ll b/llvm/test/CodeGen/DirectX/log-vec.ll new file mode 100644 index 0000000000000..4768fdd94b025 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/log-vec.ll @@ -0,0 +1,30 @@ +; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s + +; Make sure dxil operation function calls for log are generated for float and half. + +; CHECK-LABEL: log_float4 +; CHECK: call <4 x float> @llvm.log2.v4f32(<4 x float> %{{.*}}) +; CHECK: fmul <4 x float> , %{{.*}} +define noundef <4 x float> @log_float4(<4 x float> noundef %p0) { +entry: + %p0.addr = alloca <4 x float>, align 16 + store <4 x float> %p0, ptr %p0.addr, align 16 + %0 = load <4 x float>, ptr %p0.addr, align 16 + %elt.log = call <4 x float> @llvm.log.v4f32(<4 x float> %0) + ret <4 x float> %elt.log +} + +; CHECK-LABEL: log10_float4 +; CHECK: call <4 x float> @llvm.log2.v4f32(<4 x float> %{{.*}}) +; CHECK: fmul <4 x float> , %{{.*}} +define noundef <4 x float> @log10_float4(<4 x float> noundef %p0) { +entry: + %p0.addr = alloca <4 x float>, align 16 + store <4 x float> %p0, ptr %p0.addr, align 16 + %0 = load <4 x float>, ptr %p0.addr, align 16 + %elt.log10 = call <4 x float> @llvm.log10.v4f32(<4 x float> %0) + ret <4 x float> %elt.log10 +} + +declare <4 x float> @llvm.log.v4f32(<4 x float>) +declare <4 x float> @llvm.log10.v4f32(<4 x float>) diff --git a/llvm/test/CodeGen/DirectX/log.ll b/llvm/test/CodeGen/DirectX/log.ll new file mode 100644 index 0000000000000..172c3bfed3b77 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/log.ll @@ -0,0 +1,25 @@ +; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK +; RUN: opt -S -dxil-op-lower < %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK + +; Make sure dxil operation function calls for log are generated. + +define noundef float @log_float(float noundef %a) #0 { +entry: +; DOPCHECK: call float @dx.op.unary.f32(i32 23, float %{{.*}}) +; EXPCHECK: call float @llvm.log2.f32(float %a) +; CHECK: fmul float 0x3FE62E4300000000, %{{.*}} + %elt.log = call float @llvm.log.f32(float %a) + ret float %elt.log +} + +define noundef half @log_half(half noundef %a) #0 { +entry: +; DOPCHECK: call half @dx.op.unary.f16(i32 23, half %{{.*}}) +; EXPCHECK: call half @llvm.log2.f16(half %a) +; CHECK: fmul half 0xH398C, %{{.*}} + %elt.log = call half @llvm.log.f16(half %a) + ret half %elt.log +} + +declare half @llvm.log.f16(half) +declare float @llvm.log.f32(float) diff --git a/llvm/test/CodeGen/DirectX/log10.ll b/llvm/test/CodeGen/DirectX/log10.ll new file mode 100644 index 0000000000000..d4f827a0d1af8 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/log10.ll @@ -0,0 +1,25 @@ +; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK +; RUN: opt -S -dxil-op-lower < %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK + +; Make sure dxil operation function calls for log10 are generated. + +define noundef float @log10_float(float noundef %a) #0 { +entry: +; DOPCHECK: call float @dx.op.unary.f32(i32 23, float %{{.*}}) +; EXPCHECK: call float @llvm.log2.f32(float %a) +; CHECK: fmul float 0x3FD3441340000000, %{{.*}} + %elt.log10 = call float @llvm.log10.f32(float %a) + ret float %elt.log10 +} + +define noundef half @log10_half(half noundef %a) #0 { +entry: +; DOPCHECK: call half @dx.op.unary.f16(i32 23, half %{{.*}}) +; EXPCHECK: call half @llvm.log2.f16(half %a) +; CHECK: fmul half 0xH34D1, %{{.*}} + %elt.log10 = call half @llvm.log10.f16(half %a) + ret half %elt.log10 +} + +declare half @llvm.log10.f16(half) +declare float @llvm.log10.f32(float) diff --git a/llvm/test/CodeGen/DirectX/log2.ll b/llvm/test/CodeGen/DirectX/log2.ll new file mode 100644 index 0000000000000..2164d4db9396d --- /dev/null +++ b/llvm/test/CodeGen/DirectX/log2.ll @@ -0,0 +1,20 @@ +; RUN: opt -S -dxil-op-lower < %s | FileCheck %s + +; Make sure dxil operation function calls for log2 are generated for float and half. + +define noundef float @log2_float(float noundef %a) #0 { +entry: +; CHECK:call float @dx.op.unary.f32(i32 23, float %{{.*}}) + %elt.log2 = call float @llvm.log2.f32(float %a) + ret float %elt.log2 +} + +define noundef half @log2_half(half noundef %a) #0 { +entry: +; CHECK:call half @dx.op.unary.f16(i32 23, half %{{.*}}) + %elt.log2 = call half @llvm.log2.f16(half %a) + ret half %elt.log2 +} + +declare half @llvm.log2.f16(half) +declare float @llvm.log2.f32(float) diff --git a/llvm/test/CodeGen/DirectX/log2_error.ll b/llvm/test/CodeGen/DirectX/log2_error.ll new file mode 100644 index 0000000000000..a26f6e8c3117f --- /dev/null +++ b/llvm/test/CodeGen/DirectX/log2_error.ll @@ -0,0 +1,10 @@ +; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s + +; DXIL operation log2 does not support double overload type +; CHECK: LLVM ERROR: Invalid Overload Type + +define noundef double @log2_double(double noundef %a) { +entry: + %elt.log2 = call double @llvm.log2.f64(double %a) + ret double %elt.log2 +}