Skip to content

[HLSL] Implement frexp() - #235154

Open
danbrown-amd wants to merge 1 commit into
llvm:mainfrom
danbrown-amd:frexp
Open

danbrown-amd wants to merge 1 commit into
llvm:mainfrom
danbrown-amd:frexp

Conversation

@danbrown-amd

Copy link
Copy Markdown
Contributor

Resolves #99119, #220654

Assisted-by: Claude Opus 5

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 191101 tests passed
  • 5833 tests skipped

✅ The build succeeded and all tests passed.

@danbrown-amd
danbrown-amd force-pushed the frexp branch 5 times, most recently from 12cb599 to bc23ee6 Compare October 31, 2026 00:53
@danbrown-amd
danbrown-amd force-pushed the frexp branch 2 times, most recently from 380b96f to 81813f6 Compare November 6, 2026 02:54
Resolves llvm#99119, llvm#220654

Assisted-by: Claude Opus 5
@danbrown-amd
danbrown-amd marked this pull request as ready for review November 6, 2026 06:18
@llvmorg-github-actions llvmorg-github-actions Bot added backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics clang:codegen IR generation bugs: mangling, exceptions, etc. backend:DirectX HLSL HLSL Language Support backend:SPIR-V labels Nov 6, 2026
@llvmorg-github-actions

llvmorg-github-actions Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

@llvm/pr-subscribers-hlsl

@llvm/pr-subscribers-backend-x86

Author: Dan Brown (danbrown-amd)

Changes

Resolves #99119, #220654

Assisted-by: Claude Opus 5


Patch is 45.62 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/235154.diff

16 Files Affected:

  • (modified) clang/include/clang/Basic/Builtins.td (+6)
  • (modified) clang/lib/CodeGen/CGHLSLBuiltins.cpp (+31)
  • (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+31)
  • (modified) clang/lib/Sema/SemaHLSL.cpp (+17)
  • (added) clang/test/CodeGenHLSL/builtins/frexp.hlsl (+105)
  • (added) clang/test/CodeGenHLSL/builtins/frexp_mat.hlsl (+170)
  • (added) clang/test/SemaHLSL/BuiltIns/frexp-errors.hlsl (+70)
  • (added) clang/test/SemaHLSL/BuiltIns/frexp_mat-errors.hlsl (+53)
  • (modified) llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp (+65)
  • (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+1-1)
  • (modified) llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp (+8-2)
  • (added) llvm/test/CodeGen/DirectX/LongVector/frexp.ll (+16)
  • (added) llvm/test/CodeGen/DirectX/frexp.ll (+74)
  • (added) llvm/test/CodeGen/DirectX/frexp_error.ll (+10)
  • (added) llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/frexp.ll (+40)
  • (added) llvm/test/CodeGen/SPIRV/hlsl-intrinsics/frexp.ll (+61)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index d4d2393240433d..4ae54b68d4f132 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5957,6 +5957,12 @@ def HLSLBufferUpdateCounter : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "uint32_t(__hlsl_resource_t, int)";
 }
 
+def HLSLFrexp : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_elementwise_frexp"];
+  let Attributes = [NoThrow, Const, CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
 def HLSLSplitDouble: LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_elementwise_splitdouble"];
   let Attributes = [NoThrow, Const];
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index be680b259b9039..48c930eb5df559 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -119,6 +119,32 @@ static Value *handleHlslClip(const CallExpr *E, CodeGenFunction *CGF) {
   return LastInstr;
 }
 
+static Value *handleHlslFrexp(const CallExpr *E, CodeGenFunction *CGF) {
+  Value *X = CGF->EmitScalarExpr(E->getArg(0));
+
+  // Calls through the frexp overloads wrap the exponent in an HLSLOutArgExpr;
+  // direct calls to the builtin pass a plain lvalue.
+  CallArgList Args;
+  LValue ExpLValue;
+  if (const auto *OutArg = dyn_cast<HLSLOutArgExpr>(E->getArg(1)))
+    ExpLValue = CGF->EmitHLSLOutArgExpr(OutArg, Args, OutArg->getType());
+  else
+    ExpLValue = CGF->EmitLValue(E->getArg(1));
+
+  // llvm.frexp returns {mantissa, integer exponent}; HLSL wants the exponent
+  // as a float of the same shape as X.
+  llvm::Type *ExpIntTy = X->getType()->getWithNewType(CGF->Int32Ty);
+  Value *Frexp = CGF->Builder.CreateIntrinsic(
+      Intrinsic::frexp, {X->getType(), ExpIntTy}, {X}, nullptr, "hlsl.frexp");
+  Value *Mantissa = CGF->Builder.CreateExtractValue(Frexp, 0);
+  Value *Exp = CGF->Builder.CreateSIToFP(
+      CGF->Builder.CreateExtractValue(Frexp, 1), X->getType());
+
+  CGF->EmitStoreThroughLValue(RValue::get(Exp), ExpLValue);
+  CGF->EmitWritebacks(Args);
+  return Mantissa;
+}
+
 static Value *handleHlslSplitdouble(const CallExpr *E, CodeGenFunction *CGF) {
   Value *Op0 = CGF->EmitScalarExpr(E->getArg(0));
   const auto *OutArg1 = dyn_cast<HLSLOutArgExpr>(E->getArg(1));
@@ -1818,6 +1844,11 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
         CGM.getHLSLRuntime().getBufferUpdateCounterIntrinsic(),
         ArrayRef<Value *>{ResHandle, OffsetI8}, nullptr);
   }
+  case Builtin::BI__builtin_hlsl_elementwise_frexp:
+    assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+           E->getArg(1)->getType()->hasFloatingRepresentation() &&
+           "frexp operands types mismatch");
+    return handleHlslFrexp(E, this);
   case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
 
     assert((E->getArg(0)->getType()->hasFloatingRepresentation() &&
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index a86fc7dc0988bb..bce5fec19558b9 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -220,6 +220,37 @@ firstbithigh(vector<T, N> X) {
   return __detail::firstbithigh_impl<vector<uint, N>, vector<T, N>, 64>(X);
 }
 
+//===----------------------------------------------------------------------===//
+// frexp builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn T frexp(T X, out T Exp)
+/// \brief Returns the mantissa and exponent of the specified floating-point
+/// value.
+/// \param X The specified floating-point value.
+/// \param Exp The returned exponent of X.
+///
+/// The mantissa has the same sign as X and an absolute value in [0.5, 1), such
+/// that X = mantissa * 2^Exp. If X is 0, both the mantissa and the exponent
+/// are 0.
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_frexp)
+float frexp(float, out float);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_frexp)
+float2 frexp(float2, out float2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_frexp)
+float3 frexp(float3, out float3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_frexp)
+float4 frexp(float4, out float4);
+template <int N>
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_frexp)
+vector<__detail::enable_if_t<(N > 4), float>, N> frexp(
+    vector<__detail::enable_if_t<(N > 4), float>, N>,
+    out __detail::type_identity_t<vector<float, N>>);
+template <int R, int C>
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_frexp)
+matrix<float, R, C> frexp(matrix<float, R, C>,
+                          out __detail::type_identity_t<matrix<float, R, C>>);
+
 //===----------------------------------------------------------------------===//
 // mul builtins
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index eb6fce49d87083..9fb19de94df284 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -5432,6 +5432,23 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
     TheCall->setType(ArgTyExpr);
     break;
   }
+  case Builtin::BI__builtin_hlsl_elementwise_frexp: {
+    if (SemaRef.checkArgCount(TheCall, 2))
+      return true;
+
+    if (CheckScalarOrVectorOrMatrix(&SemaRef, TheCall, SemaRef.Context.FloatTy,
+                                    0) ||
+        CheckScalarOrVectorOrMatrix(&SemaRef, TheCall, SemaRef.Context.FloatTy,
+                                    1) ||
+        CheckAllArgsHaveSameType(&SemaRef, TheCall))
+      return true;
+
+    if (CheckModifiableLValue(&SemaRef, TheCall, 1))
+      return true;
+
+    TheCall->setType(TheCall->getArg(0)->getType());
+    break;
+  }
   case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
     if (SemaRef.checkArgCount(TheCall, 3))
       return true;
diff --git a/clang/test/CodeGenHLSL/builtins/frexp.hlsl b/clang/test/CodeGenHLSL/builtins/frexp.hlsl
new file mode 100644
index 00000000000000..4043fd145b8f88
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/frexp.hlsl
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
+// RUN:   -o - | FileCheck %s --check-prefixes=CHECK,DXCHECK
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   spirv-unknown-vulkan-library %s -emit-llvm -disable-llvm-passes \
+// RUN:   -o - | FileCheck %s --check-prefixes=CHECK,SPVCHECK
+
+// The only difference between the targets is the calling convention on the
+// definitions. It is captured once, in the first function, as [[FN_TYPE]].
+
+// DXCHECK: define hidden [[FN_TYPE:]]noundef nofpclass(nan inf) float @_Z12test_frexp_ffRf(
+// SPVCHECK: define hidden [[FN_TYPE:spir_func ]]noundef nofpclass(nan inf) float @_Z12test_frexp_ffRf(
+// CHECK:      [[X:%.*]] = load float, ptr %{{.*}}
+// CHECK:      [[FREXP:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]])
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { float, i32 } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { float, i32 } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}i32 [[EXPI]] to float
+// CHECK-NEXT: store float [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK-NEXT: [[WB:%.*]] = load float, ptr [[TMP]], align 4
+// CHECK-NEXT: store float [[WB]], ptr %{{.*}}, align 4
+// CHECK:      ret float [[MANT]]
+float test_frexp_f(float X, out float E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <2 x float> @_Z13test_frexp_f2Dv2_fRS_(
+// CHECK:      [[FREXP:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <2 x float>, <2 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <2 x float>, <2 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<2 x i32> [[EXPI]] to <2 x float>
+// CHECK-NEXT: store <2 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <2 x float> [[MANT]]
+float2 test_frexp_f2(float2 X, out float2 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <3 x float> @_Z13test_frexp_f3Dv3_fRS_(
+// CHECK:      [[FREXP:%.*]] = call { <3 x float>, <3 x i32> } @llvm.frexp.v3f32.v3i32(<3 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <3 x float>, <3 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <3 x float>, <3 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<3 x i32> [[EXPI]] to <3 x float>
+// CHECK-NEXT: store <3 x float> [[EXPF]], ptr [[TMP:%.*]]
+// CHECK:      ret <3 x float> [[MANT]]
+float3 test_frexp_f3(float3 X, out float3 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <4 x float> @_Z13test_frexp_f4Dv4_fRS_(
+// CHECK:      [[FREXP:%.*]] = call { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <4 x float>, <4 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <4 x float>, <4 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<4 x i32> [[EXPI]] to <4 x float>
+// CHECK-NEXT: store <4 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <4 x float> [[MANT]]
+float4 test_frexp_f4(float4 X, out float4 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <5 x float> @_Z13test_frexp_f5Dv5_fRS_(
+// CHECK:      [[FREXP:%.*]] = call { <5 x float>, <5 x i32> } @llvm.frexp.v5f32.v5i32(<5 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <5 x float>, <5 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <5 x float>, <5 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<5 x i32> [[EXPI]] to <5 x float>
+// CHECK-NEXT: store <5 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <5 x float> [[MANT]]
+vector<float, 5> test_frexp_f5(vector<float, 5> X, out vector<float, 5> E) {
+  return frexp(X, E);
+}
+
+// Direct calls to the builtin store the exponent straight to the lvalue.
+// CHECK-LABEL: test_frexp_builtin
+// CHECK:      [[FREXP:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { float, i32 } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { float, i32 } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}i32 [[EXPI]] to float
+// CHECK-NEXT: store float [[EXPF]], ptr %{{.*}}, align 4
+// CHECK-NEXT: store float [[MANT]], ptr %{{.*}}, align 4
+float2 test_frexp_builtin(float X) {
+  float E;
+  float M = __builtin_hlsl_elementwise_frexp(X, E);
+  return float2(M, E);
+}
+
+// The exponent can also be an integer, as with DXC. It is computed as a float
+// and converted when it is written back.
+
+// CHECK-LABEL: define {{.*}}test_frexp_int_exp_scalar
+// CHECK:      [[FREXP:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { float, i32 } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { float, i32 } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}i32 [[EXPI]] to float
+// CHECK-NEXT: store float [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK-NEXT: [[LOAD:%.*]] = load float, ptr [[TMP]], align 4
+// CHECK-NEXT: [[CONV:%.*]] = fptosi float [[LOAD]] to i32
+// CHECK-NEXT: store i32 [[CONV]], ptr %{{.*}}, align 4
+// CHECK:      ret float [[MANT]]
+float test_frexp_int_exp_scalar(float X, out int E) { return frexp(X, E); }
+
+// CHECK-LABEL: define {{.*}}test_frexp_int_exp_long
+// CHECK:      [[FREXP:%.*]] = call { <8 x float>, <8 x i32> } @llvm.frexp.v8f32.v8i32(<8 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <8 x float>, <8 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <8 x float>, <8 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<8 x i32> [[EXPI]] to <8 x float>
+// CHECK-NEXT: store <8 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK-NEXT: [[LOAD:%.*]] = load <8 x float>, ptr [[TMP]], align 4
+// CHECK-NEXT: [[CONV:%.*]] = fptosi <8 x float> [[LOAD]] to <8 x i32>
+// CHECK-NEXT: store <8 x i32> [[CONV]], ptr %{{.*}}, align 4
+// CHECK:      ret <8 x float> [[MANT]]
+vector<float, 8> test_frexp_int_exp_long(vector<float, 8> X,
+                                         out vector<int, 8> E) {
+  return frexp(X, E);
+}
+
diff --git a/clang/test/CodeGenHLSL/builtins/frexp_mat.hlsl b/clang/test/CodeGenHLSL/builtins/frexp_mat.hlsl
new file mode 100644
index 00000000000000..699082e0c5982b
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/frexp_mat.hlsl
@@ -0,0 +1,170 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
+// RUN:   -o - | FileCheck %s --check-prefixes=CHECK,DXCHECK
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   spirv-unknown-vulkan-library %s -emit-llvm -disable-llvm-passes \
+// RUN:   -o - | FileCheck %s --check-prefixes=CHECK,SPVCHECK
+
+// DXCHECK: define hidden [[FN_TYPE:]]noundef nofpclass(nan inf) <2 x float> @{{.*}}test_frexp_f1x2{{.*}}(
+// SPVCHECK: define hidden [[FN_TYPE:spir_func ]]noundef nofpclass(nan inf) <2 x float> @{{.*}}test_frexp_f1x2{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <2 x float>, <2 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <2 x float>, <2 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<2 x i32> [[EXPI]] to <2 x float>
+// CHECK-NEXT: store <2 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <2 x float> [[MANT]]
+float1x2 test_frexp_f1x2(float1x2 X, out float1x2 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <3 x float> @{{.*}}test_frexp_f1x3{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <3 x float>, <3 x i32> } @llvm.frexp.v3f32.v3i32(<3 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <3 x float>, <3 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <3 x float>, <3 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<3 x i32> [[EXPI]] to <3 x float>
+// CHECK-NEXT: store <3 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <3 x float> [[MANT]]
+float1x3 test_frexp_f1x3(float1x3 X, out float1x3 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <4 x float> @{{.*}}test_frexp_f1x4{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <4 x float>, <4 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <4 x float>, <4 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<4 x i32> [[EXPI]] to <4 x float>
+// CHECK-NEXT: store <4 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <4 x float> [[MANT]]
+float1x4 test_frexp_f1x4(float1x4 X, out float1x4 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <2 x float> @{{.*}}test_frexp_f2x1{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <2 x float>, <2 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <2 x float>, <2 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<2 x i32> [[EXPI]] to <2 x float>
+// CHECK-NEXT: store <2 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <2 x float> [[MANT]]
+float2x1 test_frexp_f2x1(float2x1 X, out float2x1 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <4 x float> @{{.*}}test_frexp_f2x2{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <4 x float>, <4 x i32> } @llvm.frexp.v4f32.v4i32(<4 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <4 x float>, <4 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <4 x float>, <4 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<4 x i32> [[EXPI]] to <4 x float>
+// CHECK-NEXT: store <4 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <4 x float> [[MANT]]
+float2x2 test_frexp_f2x2(float2x2 X, out float2x2 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <6 x float> @{{.*}}test_frexp_f2x3{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <6 x float>, <6 x i32> } @llvm.frexp.v6f32.v6i32(<6 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <6 x float>, <6 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <6 x float>, <6 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<6 x i32> [[EXPI]] to <6 x float>
+// CHECK-NEXT: store <6 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <6 x float> [[MANT]]
+float2x3 test_frexp_f2x3(float2x3 X, out float2x3 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <8 x float> @{{.*}}test_frexp_f2x4{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <8 x float>, <8 x i32> } @llvm.frexp.v8f32.v8i32(<8 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <8 x float>, <8 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <8 x float>, <8 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<8 x i32> [[EXPI]] to <8 x float>
+// CHECK-NEXT: store <8 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <8 x float> [[MANT]]
+float2x4 test_frexp_f2x4(float2x4 X, out float2x4 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <3 x float> @{{.*}}test_frexp_f3x1{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <3 x float>, <3 x i32> } @llvm.frexp.v3f32.v3i32(<3 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <3 x float>, <3 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <3 x float>, <3 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<3 x i32> [[EXPI]] to <3 x float>
+// CHECK-NEXT: store <3 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <3 x float> [[MANT]]
+float3x1 test_frexp_f3x1(float3x1 X, out float3x1 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <6 x float> @{{.*}}test_frexp_f3x2{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <6 x float>, <6 x i32> } @llvm.frexp.v6f32.v6i32(<6 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <6 x float>, <6 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <6 x float>, <6 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<6 x i32> [[EXPI]] to <6 x float>
+// CHECK-NEXT: store <6 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <6 x float> [[MANT]]
+float3x2 test_frexp_f3x2(float3x2 X, out float3x2 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <9 x float> @{{.*}}test_frexp_f3x3{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <9 x float>, <9 x i32> } @llvm.frexp.v9f32.v9i32(<9 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <9 x float>, <9 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <9 x float>, <9 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<9 x i32> [[EXPI]] to <9 x float>
+// CHECK-NEXT: store <9 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <9 x float> [[MANT]]
+float3x3 test_frexp_f3x3(float3x3 X, out float3x3 E) { return frexp(X, E); }
+
+// CHECK: define hidden [[FN_TYPE]]noundef nofpclass(nan inf) <12 x float> @{{.*}}test_frexp_f3x4{{.*}}(
+// CHECK:      [[FREXP:%.*]] = call { <12 x float>, <12 x i32> } @llvm.frexp.v12f32.v12i32(<12 x float> %{{.*}})
+// CHECK-NEXT: [[MANT:%.*]] = extractvalue { <12 x float>, <12 x i32> } [[FREXP]], 0
+// CHECK-NEXT: [[EXPI:%.*]] = extractvalue { <12 x float>, <12 x i32> } [[FREXP]], 1
+// CHECK-NEXT: [[EXPF:%.*]] = sitofp {{.*}}<12 x i32> [[EXPI]] to <12 x float>
+// CHECK-NEXT: store <12 x float> [[EXPF]], ptr [[TMP:%.*]], align 4
+// CHECK:      ret <12 x float> [[MANT]]
+float3x4 test_frexp_f3x4(float3x4 X, out float3x4 E)...
[truncated]

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:DirectX backend:SPIR-V backend:X86 clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:headers Headers provided by Clang, e.g. for intrinsics HLSL HLSL Language Support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement the frexp HLSL Function

1 participant