[clang] [AMDGPU][clang] provide device implementation for __builtin_logb and … (PR #129347)

via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 8 12:01:25 PDT 2025


https://github.com/choikwa updated https://github.com/llvm/llvm-project/pull/129347

>From 36bdf55ec26cfabd608548aa6fd6b703d2879d08 Mon Sep 17 00:00:00 2001
From: Kevin Choi <kevin.choi at amd.com>
Date: Fri, 28 Feb 2025 16:52:03 -0600
Subject: [PATCH] [AMDGPU][clang] provide device implementation for
 __builtin_logb and __builtin_scalbn

Clang generates library calls for __builtin_* functions which can be a problem for GPUs that cannot handle them.
This patch generates a device implementations for __builtin_logb and __builtin_scalbn by emitting LLVM IRs.
Only emit IRs when FP exceptions are disabled and math-errno is unset.
---
 clang/lib/CodeGen/CGBuiltin.cpp             |   35 +-
 clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp |   73 ++
 clang/test/CodeGen/logb_scalbn.c            | 1045 +++++++++++++++++++
 3 files changed, 1150 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CodeGen/logb_scalbn.c

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index fe55dfffc1cbe..941bd93b153ee 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -43,6 +43,33 @@ using namespace clang;
 using namespace CodeGen;
 using namespace llvm;
 
+/// Some builtins do not have library implementation on some targets and
+/// are instead emitted as LLVM IRs by some target builtin emitters.
+/// FIXME: Remove this when library support is added
+static bool shouldEmitBuiltinAsIR(unsigned BuiltinID,
+                                  const Builtin::Context &BI,
+                                  const CodeGenFunction &CGF) {
+  if (!CGF.CGM.getLangOpts().MathErrno &&
+      CGF.CurFPFeatures.getExceptionMode() ==
+          LangOptions::FPExceptionModeKind::FPE_Ignore &&
+      CGF.getTarget().getTriple().isAMDGCN()) {
+    switch (BuiltinID) {
+    default:
+      return false;
+    case Builtin::BIlogbf:
+    case Builtin::BI__builtin_logbf:
+    case Builtin::BIlogb:
+    case Builtin::BI__builtin_logb:
+    case Builtin::BIscalbnf:
+    case Builtin::BI__builtin_scalbnf:
+    case Builtin::BIscalbn:
+    case Builtin::BI__builtin_scalbn:
+      return true;
+    }
+  }
+  return false;
+}
+
 static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
                                         unsigned BuiltinID, const CallExpr *E,
                                         ReturnValueSlot ReturnValue,
@@ -2414,7 +2441,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
   // disabled.
   // Math intrinsics are generated only when math-errno is disabled. Any pragmas
   // or attributes that affect math-errno should prevent or allow math
-  // intrincs to be generated. Intrinsics are generated:
+  // intrinsics to be generated. Intrinsics are generated:
   //   1- In fast math mode, unless math-errno is overriden
   //      via '#pragma float_control(precise, on)', or via an
   //      'attribute__((optnone))'.
@@ -5999,13 +6026,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
   // If this is an alias for a lib function (e.g. __builtin_sin), emit
   // the call using the normal call path, but using the unmangled
   // version of the function name.
-  if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
+  const auto &BI = getContext().BuiltinInfo;
+  if (!shouldEmitBuiltinAsIR(BuiltinID, BI, *this) &&
+      BI.isLibFunction(BuiltinID))
     return emitLibraryCall(*this, FD, E,
                            CGM.getBuiltinLibFunction(FD, BuiltinID));
 
   // If this is a predefined lib function (e.g. malloc), emit the call
   // using exactly the normal call path.
-  if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+  if (BI.isPredefinedLibFunction(BuiltinID))
     return emitLibraryCall(*this, FD, E, CGM.getRawFunctionPointer(FD));
 
   // Check that a call to a target specific builtin has the correct target
diff --git a/clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp b/clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp
index b56b739094ff3..fb5f7ad6ec489 100644
--- a/clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp
@@ -23,6 +23,27 @@ using namespace CodeGen;
 using namespace llvm;
 
 namespace {
+
+// Has second type mangled argument.
+static Value *
+emitBinaryExpMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, const CallExpr *E,
+                                       Intrinsic::ID IntrinsicID,
+                                       Intrinsic::ID ConstrainedIntrinsicID) {
+  llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
+  llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
+
+  CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E);
+  if (CGF.Builder.getIsFPConstrained()) {
+    Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID,
+                                       {Src0->getType(), Src1->getType()});
+    return CGF.Builder.CreateConstrainedFPCall(F, {Src0, Src1});
+  }
+
+  Function *F =
+      CGF.CGM.getIntrinsic(IntrinsicID, {Src0->getType(), Src1->getType()});
+  return CGF.Builder.CreateCall(F, {Src0, Src1});
+}
+
 // If \p E is not null pointer, insert address space cast to match return
 // type of \p E if necessary.
 Value *EmitAMDGPUDispatchPtr(CodeGenFunction &CGF,
@@ -1142,6 +1163,58 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
   case AMDGPU::BI__builtin_amdgcn_s_prefetch_data:
     return emitBuiltinWithOneOverloadedType<2>(
         *this, E, Intrinsic::amdgcn_s_prefetch_data);
+  case Builtin::BIlogbf:
+  case Builtin::BI__builtin_logbf: {
+    Value *Src0 = EmitScalarExpr(E->getArg(0));
+    Function *FrExpFunc = CGM.getIntrinsic(
+        Intrinsic::frexp, {Src0->getType(), Builder.getInt32Ty()});
+    CallInst *FrExp = Builder.CreateCall(FrExpFunc, Src0);
+    Value *Exp = Builder.CreateExtractValue(FrExp, 1);
+    Value *Add = Builder.CreateAdd(
+        Exp, ConstantInt::getSigned(Exp->getType(), -1), "", false, true);
+    Value *SIToFP = Builder.CreateSIToFP(Add, Builder.getFloatTy());
+    Value *Fabs =
+        emitBuiltinWithOneOverloadedType<1>(*this, E, Intrinsic::fabs);
+    Value *FCmpONE = Builder.CreateFCmpONE(
+        Fabs, ConstantFP::getInfinity(Builder.getFloatTy()));
+    Value *Sel1 = Builder.CreateSelect(FCmpONE, SIToFP, Fabs);
+    Value *FCmpOEQ =
+        Builder.CreateFCmpOEQ(Src0, ConstantFP::getZero(Builder.getFloatTy()));
+    Value *Sel2 = Builder.CreateSelect(
+        FCmpOEQ,
+        ConstantFP::getInfinity(Builder.getFloatTy(), /*Negative=*/true),
+        Sel1);
+    return Sel2;
+  }
+  case Builtin::BIlogb:
+  case Builtin::BI__builtin_logb: {
+    Value *Src0 = EmitScalarExpr(E->getArg(0));
+    Function *FrExpFunc = CGM.getIntrinsic(
+        Intrinsic::frexp, {Src0->getType(), Builder.getInt32Ty()});
+    CallInst *FrExp = Builder.CreateCall(FrExpFunc, Src0);
+    Value *Exp = Builder.CreateExtractValue(FrExp, 1);
+    Value *Add = Builder.CreateAdd(
+        Exp, ConstantInt::getSigned(Exp->getType(), -1), "", false, true);
+    Value *SIToFP = Builder.CreateSIToFP(Add, Builder.getDoubleTy());
+    Value *Fabs =
+        emitBuiltinWithOneOverloadedType<1>(*this, E, Intrinsic::fabs);
+    Value *FCmpONE = Builder.CreateFCmpONE(
+        Fabs, ConstantFP::getInfinity(Builder.getDoubleTy()));
+    Value *Sel1 = Builder.CreateSelect(FCmpONE, SIToFP, Fabs);
+    Value *FCmpOEQ =
+        Builder.CreateFCmpOEQ(Src0, ConstantFP::getZero(Builder.getDoubleTy()));
+    Value *Sel2 = Builder.CreateSelect(
+        FCmpOEQ,
+        ConstantFP::getInfinity(Builder.getDoubleTy(), /*Negative=*/true),
+        Sel1);
+    return Sel2;
+  }
+  case Builtin::BIscalbnf:
+  case Builtin::BI__builtin_scalbnf:
+  case Builtin::BIscalbn:
+  case Builtin::BI__builtin_scalbn:
+    return emitBinaryExpMaybeConstrainedFPBuiltin(
+        *this, E, Intrinsic::ldexp, Intrinsic::experimental_constrained_ldexp);
   default:
     return nullptr;
   }
diff --git a/clang/test/CodeGen/logb_scalbn.c b/clang/test/CodeGen/logb_scalbn.c
new file mode 100644
index 0000000000000..be5e68b5fd4b0
--- /dev/null
+++ b/clang/test/CodeGen/logb_scalbn.c
@@ -0,0 +1,1045 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang -cc1 -triple amdgcn-amd-amdhsa -o - -emit-llvm %s | FileCheck %s -check-prefixes=DEFAULT
+// RUN: %clang -cc1 -triple amdgcn-amd-amdhsa -o - -ffp-exception-behavior=ignore -emit-llvm %s | FileCheck %s -check-prefixes=IGNORE
+// RUN: %clang -cc1 -triple amdgcn-amd-amdhsa -o - -ffp-exception-behavior=strict -emit-llvm %s | FileCheck %s -check-prefixes=STRICT
+// RUN: %clang -cc1 -triple amdgcn-amd-amdhsa -o - -ffp-exception-behavior=maytrap -emit-llvm %s | FileCheck %s -check-prefixes=MAYTRAP
+// RUN: %clang -cc1 -triple amdgcn-amd-amdhsa -o - -fmath-errno -emit-llvm %s | FileCheck %s -check-prefixes=ERRNO
+
+// DEFAULT-LABEL: define dso_local void @test_logbf(
+// DEFAULT-SAME: ) #[[ATTR0:[0-9]+]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    [[TMP0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0x40301999A0000000)
+// DEFAULT-NEXT:    [[TMP1:%.*]] = extractvalue { float, i32 } [[TMP0]], 1
+// DEFAULT-NEXT:    [[TMP2:%.*]] = add nsw i32 [[TMP1]], -1
+// DEFAULT-NEXT:    [[TMP3:%.*]] = sitofp i32 [[TMP2]] to float
+// DEFAULT-NEXT:    [[TMP4:%.*]] = call float @llvm.fabs.f32(float 0x40301999A0000000)
+// DEFAULT-NEXT:    [[TMP5:%.*]] = fcmp one float [[TMP4]], 0x7FF0000000000000
+// DEFAULT-NEXT:    [[TMP6:%.*]] = select i1 [[TMP5]], float [[TMP3]], float [[TMP4]]
+// DEFAULT-NEXT:    [[TMP7:%.*]] = select i1 false, float 0xFFF0000000000000, float [[TMP6]]
+// DEFAULT-NEXT:    store float [[TMP7]], ptr [[D1_ASCAST]], align 4
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_logbf(
+// IGNORE-SAME: ) #[[ATTR0:[0-9]+]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    [[TMP0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0x40301999A0000000)
+// IGNORE-NEXT:    [[TMP1:%.*]] = extractvalue { float, i32 } [[TMP0]], 1
+// IGNORE-NEXT:    [[TMP2:%.*]] = add nsw i32 [[TMP1]], -1
+// IGNORE-NEXT:    [[TMP3:%.*]] = sitofp i32 [[TMP2]] to float
+// IGNORE-NEXT:    [[TMP4:%.*]] = call float @llvm.fabs.f32(float 0x40301999A0000000)
+// IGNORE-NEXT:    [[TMP5:%.*]] = fcmp one float [[TMP4]], 0x7FF0000000000000
+// IGNORE-NEXT:    [[TMP6:%.*]] = select i1 [[TMP5]], float [[TMP3]], float [[TMP4]]
+// IGNORE-NEXT:    [[TMP7:%.*]] = select i1 false, float 0xFFF0000000000000, float [[TMP6]]
+// IGNORE-NEXT:    store float [[TMP7]], ptr [[D1_ASCAST]], align 4
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_logbf(
+// STRICT-SAME: ) #[[ATTR0:[0-9]+]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    [[TMP0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0x40301999A0000000)
+// STRICT-NEXT:    [[TMP1:%.*]] = extractvalue { float, i32 } [[TMP0]], 1
+// STRICT-NEXT:    [[TMP2:%.*]] = add nsw i32 [[TMP1]], -1
+// STRICT-NEXT:    [[TMP3:%.*]] = sitofp i32 [[TMP2]] to float
+// STRICT-NEXT:    [[TMP4:%.*]] = call float @llvm.fabs.f32(float 0x40301999A0000000)
+// STRICT-NEXT:    [[TMP5:%.*]] = fcmp one float [[TMP4]], 0x7FF0000000000000
+// STRICT-NEXT:    [[TMP6:%.*]] = select i1 [[TMP5]], float [[TMP3]], float [[TMP4]]
+// STRICT-NEXT:    [[TMP7:%.*]] = select i1 false, float 0xFFF0000000000000, float [[TMP6]]
+// STRICT-NEXT:    store float [[TMP7]], ptr [[D1_ASCAST]], align 4
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_logbf(
+// MAYTRAP-SAME: ) #[[ATTR0:[0-9]+]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0x40301999A0000000)
+// MAYTRAP-NEXT:    [[TMP1:%.*]] = extractvalue { float, i32 } [[TMP0]], 1
+// MAYTRAP-NEXT:    [[TMP2:%.*]] = add nsw i32 [[TMP1]], -1
+// MAYTRAP-NEXT:    [[TMP3:%.*]] = sitofp i32 [[TMP2]] to float
+// MAYTRAP-NEXT:    [[TMP4:%.*]] = call float @llvm.fabs.f32(float 0x40301999A0000000)
+// MAYTRAP-NEXT:    [[TMP5:%.*]] = fcmp one float [[TMP4]], 0x7FF0000000000000
+// MAYTRAP-NEXT:    [[TMP6:%.*]] = select i1 [[TMP5]], float [[TMP3]], float [[TMP4]]
+// MAYTRAP-NEXT:    [[TMP7:%.*]] = select i1 false, float 0xFFF0000000000000, float [[TMP6]]
+// MAYTRAP-NEXT:    store float [[TMP7]], ptr [[D1_ASCAST]], align 4
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_logbf(
+// ERRNO-SAME: ) #[[ATTR0:[0-9]+]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    [[CALL:%.*]] = call float @logbf(float noundef 0x40301999A0000000) #[[ATTR2:[0-9]+]]
+// ERRNO-NEXT:    store float [[CALL]], ptr [[D1_ASCAST]], align 4
+// ERRNO-NEXT:    ret void
+//
+void test_logbf() {
+  float D1 = __builtin_logbf(16.1f);
+}
+// DEFAULT-LABEL: define dso_local void @test_logbf_var(
+// DEFAULT-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP1:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[TMP0]])
+// DEFAULT-NEXT:    [[TMP2:%.*]] = extractvalue { float, i32 } [[TMP1]], 1
+// DEFAULT-NEXT:    [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1
+// DEFAULT-NEXT:    [[TMP4:%.*]] = sitofp i32 [[TMP3]] to float
+// DEFAULT-NEXT:    [[TMP5:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP6:%.*]] = call float @llvm.fabs.f32(float [[TMP5]])
+// DEFAULT-NEXT:    [[TMP7:%.*]] = fcmp one float [[TMP6]], 0x7FF0000000000000
+// DEFAULT-NEXT:    [[TMP8:%.*]] = select i1 [[TMP7]], float [[TMP4]], float [[TMP6]]
+// DEFAULT-NEXT:    [[TMP9:%.*]] = fcmp oeq float [[TMP0]], 0.000000e+00
+// DEFAULT-NEXT:    [[TMP10:%.*]] = select i1 [[TMP9]], float 0xFFF0000000000000, float [[TMP8]]
+// DEFAULT-NEXT:    store float [[TMP10]], ptr [[D1_ASCAST]], align 4
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_logbf_var(
+// IGNORE-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// IGNORE-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// IGNORE-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP1:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[TMP0]])
+// IGNORE-NEXT:    [[TMP2:%.*]] = extractvalue { float, i32 } [[TMP1]], 1
+// IGNORE-NEXT:    [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1
+// IGNORE-NEXT:    [[TMP4:%.*]] = sitofp i32 [[TMP3]] to float
+// IGNORE-NEXT:    [[TMP5:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP6:%.*]] = call float @llvm.fabs.f32(float [[TMP5]])
+// IGNORE-NEXT:    [[TMP7:%.*]] = fcmp one float [[TMP6]], 0x7FF0000000000000
+// IGNORE-NEXT:    [[TMP8:%.*]] = select i1 [[TMP7]], float [[TMP4]], float [[TMP6]]
+// IGNORE-NEXT:    [[TMP9:%.*]] = fcmp oeq float [[TMP0]], 0.000000e+00
+// IGNORE-NEXT:    [[TMP10:%.*]] = select i1 [[TMP9]], float 0xFFF0000000000000, float [[TMP8]]
+// IGNORE-NEXT:    store float [[TMP10]], ptr [[D1_ASCAST]], align 4
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_logbf_var(
+// STRICT-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// STRICT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// STRICT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP1:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[TMP0]])
+// STRICT-NEXT:    [[TMP2:%.*]] = extractvalue { float, i32 } [[TMP1]], 1
+// STRICT-NEXT:    [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1
+// STRICT-NEXT:    [[TMP4:%.*]] = sitofp i32 [[TMP3]] to float
+// STRICT-NEXT:    [[TMP5:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP6:%.*]] = call float @llvm.fabs.f32(float [[TMP5]])
+// STRICT-NEXT:    [[TMP7:%.*]] = fcmp one float [[TMP6]], 0x7FF0000000000000
+// STRICT-NEXT:    [[TMP8:%.*]] = select i1 [[TMP7]], float [[TMP4]], float [[TMP6]]
+// STRICT-NEXT:    [[TMP9:%.*]] = fcmp oeq float [[TMP0]], 0.000000e+00
+// STRICT-NEXT:    [[TMP10:%.*]] = select i1 [[TMP9]], float 0xFFF0000000000000, float [[TMP8]]
+// STRICT-NEXT:    store float [[TMP10]], ptr [[D1_ASCAST]], align 4
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_logbf_var(
+// MAYTRAP-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP1:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[TMP0]])
+// MAYTRAP-NEXT:    [[TMP2:%.*]] = extractvalue { float, i32 } [[TMP1]], 1
+// MAYTRAP-NEXT:    [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1
+// MAYTRAP-NEXT:    [[TMP4:%.*]] = sitofp i32 [[TMP3]] to float
+// MAYTRAP-NEXT:    [[TMP5:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP6:%.*]] = call float @llvm.fabs.f32(float [[TMP5]])
+// MAYTRAP-NEXT:    [[TMP7:%.*]] = fcmp one float [[TMP6]], 0x7FF0000000000000
+// MAYTRAP-NEXT:    [[TMP8:%.*]] = select i1 [[TMP7]], float [[TMP4]], float [[TMP6]]
+// MAYTRAP-NEXT:    [[TMP9:%.*]] = fcmp oeq float [[TMP0]], 0.000000e+00
+// MAYTRAP-NEXT:    [[TMP10:%.*]] = select i1 [[TMP9]], float 0xFFF0000000000000, float [[TMP8]]
+// MAYTRAP-NEXT:    store float [[TMP10]], ptr [[D1_ASCAST]], align 4
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_logbf_var(
+// ERRNO-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// ERRNO-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// ERRNO-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[CALL:%.*]] = call float @logbf(float noundef [[TMP0]]) #[[ATTR2]]
+// ERRNO-NEXT:    store float [[CALL]], ptr [[D1_ASCAST]], align 4
+// ERRNO-NEXT:    ret void
+//
+void test_logbf_var(float a) {
+  float D1 = __builtin_logbf(a);
+}
+// CHECK-LABEL: define dso_local void @test_logb(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// CHECK-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// CHECK-NEXT:    [[TMP0:%.*]] = call { double, i32 } @llvm.frexp.f64.i32(double 1.510000e+01)
+// CHECK-NEXT:    [[TMP1:%.*]] = extractvalue { double, i32 } [[TMP0]], 1
+// CHECK-NEXT:    [[TMP2:%.*]] = add nsw i32 [[TMP1]], -1
+// CHECK-NEXT:    [[TMP3:%.*]] = sitofp i32 [[TMP2]] to double
+// CHECK-NEXT:    [[TMP4:%.*]] = call double @llvm.fabs.f64(double 1.510000e+01)
+// CHECK-NEXT:    [[TMP5:%.*]] = fcmp one double [[TMP4]], 0x7FF0000000000000
+// CHECK-NEXT:    [[TMP6:%.*]] = select i1 [[TMP5]], double [[TMP3]], double [[TMP4]]
+// CHECK-NEXT:    [[TMP7:%.*]] = select i1 false, double 0xFFF0000000000000, double [[TMP6]]
+// CHECK-NEXT:    store double [[TMP7]], ptr [[D1_ASCAST]], align 8
+// CHECK-NEXT:    ret void
+// DEFAULT-LABEL: define dso_local void @test_logb(
+// DEFAULT-SAME: ) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    [[TMP0:%.*]] = call { double, i32 } @llvm.frexp.f64.i32(double 1.510000e+01)
+// DEFAULT-NEXT:    [[TMP1:%.*]] = extractvalue { double, i32 } [[TMP0]], 1
+// DEFAULT-NEXT:    [[TMP2:%.*]] = add nsw i32 [[TMP1]], -1
+// DEFAULT-NEXT:    [[TMP3:%.*]] = sitofp i32 [[TMP2]] to double
+// DEFAULT-NEXT:    [[TMP4:%.*]] = call double @llvm.fabs.f64(double 1.510000e+01)
+// DEFAULT-NEXT:    [[TMP5:%.*]] = fcmp one double [[TMP4]], 0x7FF0000000000000
+// DEFAULT-NEXT:    [[TMP6:%.*]] = select i1 [[TMP5]], double [[TMP3]], double [[TMP4]]
+// DEFAULT-NEXT:    [[TMP7:%.*]] = select i1 false, double 0xFFF0000000000000, double [[TMP6]]
+// DEFAULT-NEXT:    store double [[TMP7]], ptr [[D1_ASCAST]], align 8
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_logb(
+// IGNORE-SAME: ) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    [[TMP0:%.*]] = call { double, i32 } @llvm.frexp.f64.i32(double 1.510000e+01)
+// IGNORE-NEXT:    [[TMP1:%.*]] = extractvalue { double, i32 } [[TMP0]], 1
+// IGNORE-NEXT:    [[TMP2:%.*]] = add nsw i32 [[TMP1]], -1
+// IGNORE-NEXT:    [[TMP3:%.*]] = sitofp i32 [[TMP2]] to double
+// IGNORE-NEXT:    [[TMP4:%.*]] = call double @llvm.fabs.f64(double 1.510000e+01)
+// IGNORE-NEXT:    [[TMP5:%.*]] = fcmp one double [[TMP4]], 0x7FF0000000000000
+// IGNORE-NEXT:    [[TMP6:%.*]] = select i1 [[TMP5]], double [[TMP3]], double [[TMP4]]
+// IGNORE-NEXT:    [[TMP7:%.*]] = select i1 false, double 0xFFF0000000000000, double [[TMP6]]
+// IGNORE-NEXT:    store double [[TMP7]], ptr [[D1_ASCAST]], align 8
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_logb(
+// STRICT-SAME: ) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    [[TMP0:%.*]] = call { double, i32 } @llvm.frexp.f64.i32(double 1.510000e+01)
+// STRICT-NEXT:    [[TMP1:%.*]] = extractvalue { double, i32 } [[TMP0]], 1
+// STRICT-NEXT:    [[TMP2:%.*]] = add nsw i32 [[TMP1]], -1
+// STRICT-NEXT:    [[TMP3:%.*]] = sitofp i32 [[TMP2]] to double
+// STRICT-NEXT:    [[TMP4:%.*]] = call double @llvm.fabs.f64(double 1.510000e+01)
+// STRICT-NEXT:    [[TMP5:%.*]] = fcmp one double [[TMP4]], 0x7FF0000000000000
+// STRICT-NEXT:    [[TMP6:%.*]] = select i1 [[TMP5]], double [[TMP3]], double [[TMP4]]
+// STRICT-NEXT:    [[TMP7:%.*]] = select i1 false, double 0xFFF0000000000000, double [[TMP6]]
+// STRICT-NEXT:    store double [[TMP7]], ptr [[D1_ASCAST]], align 8
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_logb(
+// MAYTRAP-SAME: ) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = call { double, i32 } @llvm.frexp.f64.i32(double 1.510000e+01)
+// MAYTRAP-NEXT:    [[TMP1:%.*]] = extractvalue { double, i32 } [[TMP0]], 1
+// MAYTRAP-NEXT:    [[TMP2:%.*]] = add nsw i32 [[TMP1]], -1
+// MAYTRAP-NEXT:    [[TMP3:%.*]] = sitofp i32 [[TMP2]] to double
+// MAYTRAP-NEXT:    [[TMP4:%.*]] = call double @llvm.fabs.f64(double 1.510000e+01)
+// MAYTRAP-NEXT:    [[TMP5:%.*]] = fcmp one double [[TMP4]], 0x7FF0000000000000
+// MAYTRAP-NEXT:    [[TMP6:%.*]] = select i1 [[TMP5]], double [[TMP3]], double [[TMP4]]
+// MAYTRAP-NEXT:    [[TMP7:%.*]] = select i1 false, double 0xFFF0000000000000, double [[TMP6]]
+// MAYTRAP-NEXT:    store double [[TMP7]], ptr [[D1_ASCAST]], align 8
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_logb(
+// ERRNO-SAME: ) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    [[CALL:%.*]] = call double @logb(double noundef 1.510000e+01) #[[ATTR2]]
+// ERRNO-NEXT:    store double [[CALL]], ptr [[D1_ASCAST]], align 8
+// ERRNO-NEXT:    ret void
+//
+void test_logb() {
+  double D1 = __builtin_logb(15.1);
+}
+// CHECK-LABEL: define dso_local void @test_logb_var(
+// CHECK-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// CHECK-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// CHECK-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// CHECK-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// CHECK-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = call { double, i32 } @llvm.frexp.f64.i32(double [[TMP0]])
+// CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { double, i32 } [[TMP1]], 1
+// CHECK-NEXT:    [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1
+// CHECK-NEXT:    [[TMP4:%.*]] = sitofp i32 [[TMP3]] to double
+// CHECK-NEXT:    [[TMP5:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// CHECK-NEXT:    [[TMP6:%.*]] = call double @llvm.fabs.f64(double [[TMP5]])
+// CHECK-NEXT:    [[TMP7:%.*]] = fcmp one double [[TMP6]], 0x7FF0000000000000
+// CHECK-NEXT:    [[TMP8:%.*]] = select i1 [[TMP7]], double [[TMP4]], double [[TMP6]]
+// CHECK-NEXT:    [[TMP9:%.*]] = fcmp oeq double [[TMP0]], 0.000000e+00
+// CHECK-NEXT:    [[TMP10:%.*]] = select i1 [[TMP9]], double 0xFFF0000000000000, double [[TMP8]]
+// CHECK-NEXT:    store double [[TMP10]], ptr [[D1_ASCAST]], align 8
+// CHECK-NEXT:    ret void
+// DEFAULT-LABEL: define dso_local void @test_logb_var(
+// DEFAULT-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// DEFAULT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// DEFAULT-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// DEFAULT-NEXT:    [[TMP1:%.*]] = call { double, i32 } @llvm.frexp.f64.i32(double [[TMP0]])
+// DEFAULT-NEXT:    [[TMP2:%.*]] = extractvalue { double, i32 } [[TMP1]], 1
+// DEFAULT-NEXT:    [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1
+// DEFAULT-NEXT:    [[TMP4:%.*]] = sitofp i32 [[TMP3]] to double
+// DEFAULT-NEXT:    [[TMP5:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// DEFAULT-NEXT:    [[TMP6:%.*]] = call double @llvm.fabs.f64(double [[TMP5]])
+// DEFAULT-NEXT:    [[TMP7:%.*]] = fcmp one double [[TMP6]], 0x7FF0000000000000
+// DEFAULT-NEXT:    [[TMP8:%.*]] = select i1 [[TMP7]], double [[TMP4]], double [[TMP6]]
+// DEFAULT-NEXT:    [[TMP9:%.*]] = fcmp oeq double [[TMP0]], 0.000000e+00
+// DEFAULT-NEXT:    [[TMP10:%.*]] = select i1 [[TMP9]], double 0xFFF0000000000000, double [[TMP8]]
+// DEFAULT-NEXT:    store double [[TMP10]], ptr [[D1_ASCAST]], align 8
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_logb_var(
+// IGNORE-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// IGNORE-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// IGNORE-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IGNORE-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// IGNORE-NEXT:    [[TMP1:%.*]] = call { double, i32 } @llvm.frexp.f64.i32(double [[TMP0]])
+// IGNORE-NEXT:    [[TMP2:%.*]] = extractvalue { double, i32 } [[TMP1]], 1
+// IGNORE-NEXT:    [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1
+// IGNORE-NEXT:    [[TMP4:%.*]] = sitofp i32 [[TMP3]] to double
+// IGNORE-NEXT:    [[TMP5:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// IGNORE-NEXT:    [[TMP6:%.*]] = call double @llvm.fabs.f64(double [[TMP5]])
+// IGNORE-NEXT:    [[TMP7:%.*]] = fcmp one double [[TMP6]], 0x7FF0000000000000
+// IGNORE-NEXT:    [[TMP8:%.*]] = select i1 [[TMP7]], double [[TMP4]], double [[TMP6]]
+// IGNORE-NEXT:    [[TMP9:%.*]] = fcmp oeq double [[TMP0]], 0.000000e+00
+// IGNORE-NEXT:    [[TMP10:%.*]] = select i1 [[TMP9]], double 0xFFF0000000000000, double [[TMP8]]
+// IGNORE-NEXT:    store double [[TMP10]], ptr [[D1_ASCAST]], align 8
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_logb_var(
+// STRICT-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// STRICT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// STRICT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// STRICT-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// STRICT-NEXT:    [[TMP1:%.*]] = call { double, i32 } @llvm.frexp.f64.i32(double [[TMP0]])
+// STRICT-NEXT:    [[TMP2:%.*]] = extractvalue { double, i32 } [[TMP1]], 1
+// STRICT-NEXT:    [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1
+// STRICT-NEXT:    [[TMP4:%.*]] = sitofp i32 [[TMP3]] to double
+// STRICT-NEXT:    [[TMP5:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// STRICT-NEXT:    [[TMP6:%.*]] = call double @llvm.fabs.f64(double [[TMP5]])
+// STRICT-NEXT:    [[TMP7:%.*]] = fcmp one double [[TMP6]], 0x7FF0000000000000
+// STRICT-NEXT:    [[TMP8:%.*]] = select i1 [[TMP7]], double [[TMP4]], double [[TMP6]]
+// STRICT-NEXT:    [[TMP9:%.*]] = fcmp oeq double [[TMP0]], 0.000000e+00
+// STRICT-NEXT:    [[TMP10:%.*]] = select i1 [[TMP9]], double 0xFFF0000000000000, double [[TMP8]]
+// STRICT-NEXT:    store double [[TMP10]], ptr [[D1_ASCAST]], align 8
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_logb_var(
+// MAYTRAP-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// MAYTRAP-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// MAYTRAP-NEXT:    [[TMP1:%.*]] = call { double, i32 } @llvm.frexp.f64.i32(double [[TMP0]])
+// MAYTRAP-NEXT:    [[TMP2:%.*]] = extractvalue { double, i32 } [[TMP1]], 1
+// MAYTRAP-NEXT:    [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1
+// MAYTRAP-NEXT:    [[TMP4:%.*]] = sitofp i32 [[TMP3]] to double
+// MAYTRAP-NEXT:    [[TMP5:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// MAYTRAP-NEXT:    [[TMP6:%.*]] = call double @llvm.fabs.f64(double [[TMP5]])
+// MAYTRAP-NEXT:    [[TMP7:%.*]] = fcmp one double [[TMP6]], 0x7FF0000000000000
+// MAYTRAP-NEXT:    [[TMP8:%.*]] = select i1 [[TMP7]], double [[TMP4]], double [[TMP6]]
+// MAYTRAP-NEXT:    [[TMP9:%.*]] = fcmp oeq double [[TMP0]], 0.000000e+00
+// MAYTRAP-NEXT:    [[TMP10:%.*]] = select i1 [[TMP9]], double 0xFFF0000000000000, double [[TMP8]]
+// MAYTRAP-NEXT:    store double [[TMP10]], ptr [[D1_ASCAST]], align 8
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_logb_var(
+// ERRNO-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// ERRNO-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// ERRNO-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// ERRNO-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// ERRNO-NEXT:    [[CALL:%.*]] = call double @logb(double noundef [[TMP0]]) #[[ATTR2]]
+// ERRNO-NEXT:    store double [[CALL]], ptr [[D1_ASCAST]], align 8
+// ERRNO-NEXT:    ret void
+//
+void test_logb_var(double a) {
+  double D1 = __builtin_logb(a);
+}
+
+// CHECK-LABEL: define dso_local void @test_scalbnf(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// CHECK-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// CHECK-NEXT:    [[TMP0:%.*]] = call float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10)
+// CHECK-NEXT:    store float [[TMP0]], ptr [[D1_ASCAST]], align 4
+// CHECK-NEXT:    ret void
+// DEFAULT-LABEL: define dso_local void @test_scalbnf(
+// DEFAULT-SAME: ) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    [[TMP0:%.*]] = call float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10)
+// DEFAULT-NEXT:    store float [[TMP0]], ptr [[D1_ASCAST]], align 4
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_scalbnf(
+// IGNORE-SAME: ) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    [[TMP0:%.*]] = call float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10)
+// IGNORE-NEXT:    store float [[TMP0]], ptr [[D1_ASCAST]], align 4
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_scalbnf(
+// STRICT-SAME: ) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    [[TMP0:%.*]] = call float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10)
+// STRICT-NEXT:    store float [[TMP0]], ptr [[D1_ASCAST]], align 4
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_scalbnf(
+// MAYTRAP-SAME: ) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = call float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10)
+// MAYTRAP-NEXT:    store float [[TMP0]], ptr [[D1_ASCAST]], align 4
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_scalbnf(
+// ERRNO-SAME: ) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    [[CALL:%.*]] = call float @scalbnf(float noundef 0x4030B33340000000, i32 noundef 10) #[[ATTR2]]
+// ERRNO-NEXT:    store float [[CALL]], ptr [[D1_ASCAST]], align 4
+// ERRNO-NEXT:    ret void
+//
+void test_scalbnf() {
+  float D1 = __builtin_scalbnf(16.7f, 10);
+}
+// CHECK-LABEL: define dso_local void @test_scalbnf_var1(
+// CHECK-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// CHECK-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// CHECK-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// CHECK-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// CHECK-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP0]], i32 9)
+// CHECK-NEXT:    store float [[TMP1]], ptr [[D1_ASCAST]], align 4
+// CHECK-NEXT:    ret void
+// DEFAULT-LABEL: define dso_local void @test_scalbnf_var1(
+// DEFAULT-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP0]], i32 9)
+// DEFAULT-NEXT:    store float [[TMP1]], ptr [[D1_ASCAST]], align 4
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_scalbnf_var1(
+// IGNORE-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// IGNORE-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// IGNORE-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP0]], i32 9)
+// IGNORE-NEXT:    store float [[TMP1]], ptr [[D1_ASCAST]], align 4
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_scalbnf_var1(
+// STRICT-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// STRICT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// STRICT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP0]], i32 9)
+// STRICT-NEXT:    store float [[TMP1]], ptr [[D1_ASCAST]], align 4
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_scalbnf_var1(
+// MAYTRAP-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP0]], i32 9)
+// MAYTRAP-NEXT:    store float [[TMP1]], ptr [[D1_ASCAST]], align 4
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_scalbnf_var1(
+// ERRNO-SAME: float noundef [[A:%.*]]) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// ERRNO-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// ERRNO-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[CALL:%.*]] = call float @scalbnf(float noundef [[TMP0]], i32 noundef 9) #[[ATTR2]]
+// ERRNO-NEXT:    store float [[CALL]], ptr [[D1_ASCAST]], align 4
+// ERRNO-NEXT:    ret void
+//
+void test_scalbnf_var1(float a) {
+  float D1 = __builtin_scalbnf(a, 9);
+}
+// CHECK-LABEL: define dso_local void @test_scalbnf_var2(
+// CHECK-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// CHECK-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// CHECK-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// CHECK-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// CHECK-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float 0x402E666660000000, i32 [[TMP0]])
+// CHECK-NEXT:    store float [[TMP1]], ptr [[D1_ASCAST]], align 4
+// CHECK-NEXT:    ret void
+// DEFAULT-LABEL: define dso_local void @test_scalbnf_var2(
+// DEFAULT-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float 0x402E666660000000, i32 [[TMP0]])
+// DEFAULT-NEXT:    store float [[TMP1]], ptr [[D1_ASCAST]], align 4
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_scalbnf_var2(
+// IGNORE-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// IGNORE-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// IGNORE-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float 0x402E666660000000, i32 [[TMP0]])
+// IGNORE-NEXT:    store float [[TMP1]], ptr [[D1_ASCAST]], align 4
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_scalbnf_var2(
+// STRICT-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// STRICT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// STRICT-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float 0x402E666660000000, i32 [[TMP0]])
+// STRICT-NEXT:    store float [[TMP1]], ptr [[D1_ASCAST]], align 4
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_scalbnf_var2(
+// MAYTRAP-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float 0x402E666660000000, i32 [[TMP0]])
+// MAYTRAP-NEXT:    store float [[TMP1]], ptr [[D1_ASCAST]], align 4
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_scalbnf_var2(
+// ERRNO-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// ERRNO-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// ERRNO-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[CALL:%.*]] = call float @scalbnf(float noundef 0x402E666660000000, i32 noundef [[TMP0]]) #[[ATTR2]]
+// ERRNO-NEXT:    store float [[CALL]], ptr [[D1_ASCAST]], align 4
+// ERRNO-NEXT:    ret void
+//
+void test_scalbnf_var2(int b) {
+  float D1 = __builtin_scalbnf(15.2f, b);
+}
+// CHECK-LABEL: define dso_local void @test_scalbnf_var3(
+// CHECK-SAME: float noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// CHECK-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// CHECK-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// CHECK-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// CHECK-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// CHECK-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT:    store float [[TMP2]], ptr [[D1_ASCAST]], align 4
+// CHECK-NEXT:    ret void
+// DEFAULT-LABEL: define dso_local void @test_scalbnf_var3(
+// DEFAULT-SAME: float noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// DEFAULT-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP2:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP0]], i32 [[TMP1]])
+// DEFAULT-NEXT:    store float [[TMP2]], ptr [[D1_ASCAST]], align 4
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_scalbnf_var3(
+// IGNORE-SAME: float noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// IGNORE-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// IGNORE-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// IGNORE-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IGNORE-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP2:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP0]], i32 [[TMP1]])
+// IGNORE-NEXT:    store float [[TMP2]], ptr [[D1_ASCAST]], align 4
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_scalbnf_var3(
+// STRICT-SAME: float noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// STRICT-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// STRICT-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// STRICT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// STRICT-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP2:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP0]], i32 [[TMP1]])
+// STRICT-NEXT:    store float [[TMP2]], ptr [[D1_ASCAST]], align 4
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_scalbnf_var3(
+// MAYTRAP-SAME: float noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// MAYTRAP-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP2:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP0]], i32 [[TMP1]])
+// MAYTRAP-NEXT:    store float [[TMP2]], ptr [[D1_ASCAST]], align 4
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_scalbnf_var3(
+// ERRNO-SAME: float noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[A_ADDR:%.*]] = alloca float, align 4, addrspace(5)
+// ERRNO-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// ERRNO-NEXT:    [[D1:%.*]] = alloca float, align 4, addrspace(5)
+// ERRNO-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// ERRNO-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    store float [[A]], ptr [[A_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[TMP0:%.*]] = load float, ptr [[A_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[CALL:%.*]] = call float @scalbnf(float noundef [[TMP0]], i32 noundef [[TMP1]]) #[[ATTR2]]
+// ERRNO-NEXT:    store float [[CALL]], ptr [[D1_ASCAST]], align 4
+// ERRNO-NEXT:    ret void
+//
+void test_scalbnf_var3(float a, int b) {
+  float D1 = __builtin_scalbnf(a, b);
+}
+
+// CHECK-LABEL: define dso_local void @test_scalbn(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// CHECK-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// CHECK-NEXT:    [[TMP0:%.*]] = call double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10)
+// CHECK-NEXT:    store double [[TMP0]], ptr [[D1_ASCAST]], align 8
+// CHECK-NEXT:    ret void
+// DEFAULT-LABEL: define dso_local void @test_scalbn(
+// DEFAULT-SAME: ) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    [[TMP0:%.*]] = call double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10)
+// DEFAULT-NEXT:    store double [[TMP0]], ptr [[D1_ASCAST]], align 8
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_scalbn(
+// IGNORE-SAME: ) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    [[TMP0:%.*]] = call double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10)
+// IGNORE-NEXT:    store double [[TMP0]], ptr [[D1_ASCAST]], align 8
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_scalbn(
+// STRICT-SAME: ) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    [[TMP0:%.*]] = call double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10)
+// STRICT-NEXT:    store double [[TMP0]], ptr [[D1_ASCAST]], align 8
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_scalbn(
+// MAYTRAP-SAME: ) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = call double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10)
+// MAYTRAP-NEXT:    store double [[TMP0]], ptr [[D1_ASCAST]], align 8
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_scalbn(
+// ERRNO-SAME: ) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    [[CALL:%.*]] = call double @scalbn(double noundef 1.720000e+01, i32 noundef 10) #[[ATTR2]]
+// ERRNO-NEXT:    store double [[CALL]], ptr [[D1_ASCAST]], align 8
+// ERRNO-NEXT:    ret void
+//
+void test_scalbn() {
+  double D1 = __builtin_scalbn(17.2, 10);
+}
+// CHECK-LABEL: define dso_local void @test_scalbn_var1(
+// CHECK-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// CHECK-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// CHECK-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// CHECK-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// CHECK-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.ldexp.f64.i32(double [[TMP0]], i32 9)
+// CHECK-NEXT:    store double [[TMP1]], ptr [[D1_ASCAST]], align 8
+// CHECK-NEXT:    ret void
+// DEFAULT-LABEL: define dso_local void @test_scalbn_var1(
+// DEFAULT-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// DEFAULT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// DEFAULT-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// DEFAULT-NEXT:    [[TMP1:%.*]] = call double @llvm.ldexp.f64.i32(double [[TMP0]], i32 9)
+// DEFAULT-NEXT:    store double [[TMP1]], ptr [[D1_ASCAST]], align 8
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_scalbn_var1(
+// IGNORE-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// IGNORE-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// IGNORE-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IGNORE-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// IGNORE-NEXT:    [[TMP1:%.*]] = call double @llvm.ldexp.f64.i32(double [[TMP0]], i32 9)
+// IGNORE-NEXT:    store double [[TMP1]], ptr [[D1_ASCAST]], align 8
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_scalbn_var1(
+// STRICT-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// STRICT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// STRICT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// STRICT-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// STRICT-NEXT:    [[TMP1:%.*]] = call double @llvm.ldexp.f64.i32(double [[TMP0]], i32 9)
+// STRICT-NEXT:    store double [[TMP1]], ptr [[D1_ASCAST]], align 8
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_scalbn_var1(
+// MAYTRAP-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// MAYTRAP-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// MAYTRAP-NEXT:    [[TMP1:%.*]] = call double @llvm.ldexp.f64.i32(double [[TMP0]], i32 9)
+// MAYTRAP-NEXT:    store double [[TMP1]], ptr [[D1_ASCAST]], align 8
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_scalbn_var1(
+// ERRNO-SAME: double noundef [[A:%.*]]) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// ERRNO-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// ERRNO-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// ERRNO-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// ERRNO-NEXT:    [[CALL:%.*]] = call double @scalbn(double noundef [[TMP0]], i32 noundef 9) #[[ATTR2]]
+// ERRNO-NEXT:    store double [[CALL]], ptr [[D1_ASCAST]], align 8
+// ERRNO-NEXT:    ret void
+//
+void test_scalbn_var1(double a) {
+  double D1 = __builtin_scalbn(a, 9);
+}
+// CHECK-LABEL: define dso_local void @test_scalbn_var2(
+// CHECK-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// CHECK-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// CHECK-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// CHECK-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// CHECK-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = call double @llvm.ldexp.f64.i32(double 1.540000e+01, i32 [[TMP0]])
+// CHECK-NEXT:    store double [[TMP1]], ptr [[D1_ASCAST]], align 8
+// CHECK-NEXT:    ret void
+// DEFAULT-LABEL: define dso_local void @test_scalbn_var2(
+// DEFAULT-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// DEFAULT-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP1:%.*]] = call double @llvm.ldexp.f64.i32(double 1.540000e+01, i32 [[TMP0]])
+// DEFAULT-NEXT:    store double [[TMP1]], ptr [[D1_ASCAST]], align 8
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_scalbn_var2(
+// IGNORE-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// IGNORE-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// IGNORE-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP1:%.*]] = call double @llvm.ldexp.f64.i32(double 1.540000e+01, i32 [[TMP0]])
+// IGNORE-NEXT:    store double [[TMP1]], ptr [[D1_ASCAST]], align 8
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_scalbn_var2(
+// STRICT-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// STRICT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// STRICT-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP1:%.*]] = call double @llvm.ldexp.f64.i32(double 1.540000e+01, i32 [[TMP0]])
+// STRICT-NEXT:    store double [[TMP1]], ptr [[D1_ASCAST]], align 8
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_scalbn_var2(
+// MAYTRAP-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// MAYTRAP-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP1:%.*]] = call double @llvm.ldexp.f64.i32(double 1.540000e+01, i32 [[TMP0]])
+// MAYTRAP-NEXT:    store double [[TMP1]], ptr [[D1_ASCAST]], align 8
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_scalbn_var2(
+// ERRNO-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// ERRNO-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// ERRNO-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[TMP0:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[CALL:%.*]] = call double @scalbn(double noundef 1.540000e+01, i32 noundef [[TMP0]]) #[[ATTR2]]
+// ERRNO-NEXT:    store double [[CALL]], ptr [[D1_ASCAST]], align 8
+// ERRNO-NEXT:    ret void
+//
+void test_scalbn_var2(int b) {
+  double D1 = __builtin_scalbn(15.4, b);
+}
+// CHECK-LABEL: define dso_local void @test_scalbn_var3(
+// CHECK-SAME: double noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// CHECK-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// CHECK-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// CHECK-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// CHECK-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// CHECK-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// CHECK-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = call double @llvm.ldexp.f64.i32(double [[TMP0]], i32 [[TMP1]])
+// CHECK-NEXT:    store double [[TMP2]], ptr [[D1_ASCAST]], align 8
+// CHECK-NEXT:    ret void
+// DEFAULT-LABEL: define dso_local void @test_scalbn_var3(
+// DEFAULT-SAME: double noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// DEFAULT-NEXT:  [[ENTRY:.*:]]
+// DEFAULT-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// DEFAULT-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// DEFAULT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// DEFAULT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// DEFAULT-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// DEFAULT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// DEFAULT-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// DEFAULT-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// DEFAULT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// DEFAULT-NEXT:    [[TMP2:%.*]] = call double @llvm.ldexp.f64.i32(double [[TMP0]], i32 [[TMP1]])
+// DEFAULT-NEXT:    store double [[TMP2]], ptr [[D1_ASCAST]], align 8
+// DEFAULT-NEXT:    ret void
+//
+// IGNORE-LABEL: define dso_local void @test_scalbn_var3(
+// IGNORE-SAME: double noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// IGNORE-NEXT:  [[ENTRY:.*:]]
+// IGNORE-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// IGNORE-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// IGNORE-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// IGNORE-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IGNORE-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IGNORE-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// IGNORE-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IGNORE-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// IGNORE-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// IGNORE-NEXT:    [[TMP2:%.*]] = call double @llvm.ldexp.f64.i32(double [[TMP0]], i32 [[TMP1]])
+// IGNORE-NEXT:    store double [[TMP2]], ptr [[D1_ASCAST]], align 8
+// IGNORE-NEXT:    ret void
+//
+// STRICT-LABEL: define dso_local void @test_scalbn_var3(
+// STRICT-SAME: double noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// STRICT-NEXT:  [[ENTRY:.*:]]
+// STRICT-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// STRICT-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// STRICT-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// STRICT-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// STRICT-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// STRICT-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// STRICT-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// STRICT-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// STRICT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// STRICT-NEXT:    [[TMP2:%.*]] = call double @llvm.ldexp.f64.i32(double [[TMP0]], i32 [[TMP1]])
+// STRICT-NEXT:    store double [[TMP2]], ptr [[D1_ASCAST]], align 8
+// STRICT-NEXT:    ret void
+//
+// MAYTRAP-LABEL: define dso_local void @test_scalbn_var3(
+// MAYTRAP-SAME: double noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// MAYTRAP-NEXT:  [[ENTRY:.*:]]
+// MAYTRAP-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// MAYTRAP-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// MAYTRAP-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// MAYTRAP-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// MAYTRAP-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// MAYTRAP-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// MAYTRAP-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// MAYTRAP-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// MAYTRAP-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// MAYTRAP-NEXT:    [[TMP2:%.*]] = call double @llvm.ldexp.f64.i32(double [[TMP0]], i32 [[TMP1]])
+// MAYTRAP-NEXT:    store double [[TMP2]], ptr [[D1_ASCAST]], align 8
+// MAYTRAP-NEXT:    ret void
+//
+// ERRNO-LABEL: define dso_local void @test_scalbn_var3(
+// ERRNO-SAME: double noundef [[A:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] {
+// ERRNO-NEXT:  [[ENTRY:.*:]]
+// ERRNO-NEXT:    [[A_ADDR:%.*]] = alloca double, align 8, addrspace(5)
+// ERRNO-NEXT:    [[B_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// ERRNO-NEXT:    [[D1:%.*]] = alloca double, align 8, addrspace(5)
+// ERRNO-NEXT:    [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// ERRNO-NEXT:    [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// ERRNO-NEXT:    [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr
+// ERRNO-NEXT:    store double [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// ERRNO-NEXT:    store i32 [[B]], ptr [[B_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[TMP0:%.*]] = load double, ptr [[A_ADDR_ASCAST]], align 8
+// ERRNO-NEXT:    [[TMP1:%.*]] = load i32, ptr [[B_ADDR_ASCAST]], align 4
+// ERRNO-NEXT:    [[CALL:%.*]] = call double @scalbn(double noundef [[TMP0]], i32 noundef [[TMP1]]) #[[ATTR2]]
+// ERRNO-NEXT:    store double [[CALL]], ptr [[D1_ASCAST]], align 8
+// ERRNO-NEXT:    ret void
+//
+void test_scalbn_var3(double a, int b) {
+  double D1 = __builtin_scalbn(a, b);
+}



More information about the cfe-commits mailing list