Index: clang/include/clang/Basic/Builtins.def =================================================================== --- clang/include/clang/Basic/Builtins.def +++ clang/include/clang/Basic/Builtins.def @@ -141,6 +141,7 @@ BUILTIN(__builtin_frexpf, "ffi*" , "Fn") BUILTIN(__builtin_frexpl, "LdLdi*", "Fn") BUILTIN(__builtin_frexpf128, "LLdLLdi*", "Fn") +BUILTIN(__builtin_frexpf16, "hhi*" , "Fn") BUILTIN(__builtin_huge_val, "d", "ncE") BUILTIN(__builtin_huge_valf, "f", "ncE") BUILTIN(__builtin_huge_vall, "Ld", "ncE") Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -646,6 +646,24 @@ } } +static Value *emitFrexpBuiltin(CodeGenFunction &CGF, const CallExpr *E, + llvm::Intrinsic::ID IntrinsicID) { + llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); + llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1)); + + QualType IntPtrTy = E->getArg(1)->getType()->getPointeeType(); + llvm::Type *IntTy = CGF.ConvertType(IntPtrTy); + llvm::Function *F = + CGF.CGM.getIntrinsic(IntrinsicID, {Src0->getType(), IntTy}); + llvm::Value *Call = CGF.Builder.CreateCall(F, Src0); + + llvm::Value *Exp = CGF.Builder.CreateExtractValue(Call, 1); + LValue LV = CGF.MakeNaturalAlignAddrLValue(Src1, IntPtrTy); + CGF.EmitStoreOfScalar(Exp, LV); + + return CGF.Builder.CreateExtractValue(Call, 0); +} + /// EmitFAbs - Emit a call to @llvm.fabs(). static Value *EmitFAbs(CodeGenFunction &CGF, Value *V) { Function *F = CGF.CGM.getIntrinsic(Intrinsic::fabs, V->getType()); @@ -2490,7 +2508,7 @@ return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, Intrinsic::roundeven, Intrinsic::experimental_constrained_roundeven)); - + case Builtin::BIsin: case Builtin::BIsinf: case Builtin::BIsinl: @@ -3060,6 +3078,12 @@ { Src0->getType(), Src1->getType() }); return RValue::get(Builder.CreateCall(F, { Src0, Src1 })); } + case Builtin::BI__builtin_frexp: + case Builtin::BI__builtin_frexpf: + case Builtin::BI__builtin_frexpl: + case Builtin::BI__builtin_frexpf128: + case Builtin::BI__builtin_frexpf16: + return RValue::get(emitFrexpBuiltin(*this, E, Intrinsic::frexp)); case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: case Builtin::BI__builtin_isless: Index: clang/test/CodeGen/aix-builtin-mapping.c =================================================================== --- clang/test/CodeGen/aix-builtin-mapping.c +++ clang/test/CodeGen/aix-builtin-mapping.c @@ -18,5 +18,5 @@ } // CHECK: %call = call double @modf(double noundef 1.000000e+00, ptr noundef %DummyLongDouble) #3 -// CHECK: %call1 = call double @frexp(double noundef 0.000000e+00, ptr noundef %DummyInt) #3 +// CHECK: %{{.+}} = call { double, i32 } @llvm.frexp.f64.i32(double 0.000000e+00) // CHECK: %{{.+}} = call double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 1) Index: clang/test/CodeGen/builtin-attributes.c =================================================================== --- clang/test/CodeGen/builtin-attributes.c +++ clang/test/CodeGen/builtin-attributes.c @@ -4,6 +4,10 @@ int printf(const char *, ...); void exit(int); +float frexpf(float, int*); +double frexp(double, int*); +long double frexpl(long double, int*); + // CHECK: declare i32 @printf(ptr noundef, ...) void f0() { printf("a\n"); @@ -49,9 +53,9 @@ // CHECK: ret int f3(double x) { int e; - __builtin_frexp(x, &e); - __builtin_frexpf(x, &e); - __builtin_frexpl(x, &e); + frexp(x, &e); + frexpf(x, &e); + frexpl(x, &e); __builtin_modf(x, &e); __builtin_modff(x, &e); __builtin_modfl(x, &e); Index: clang/test/CodeGen/math-builtins-long.c =================================================================== --- clang/test/CodeGen/math-builtins-long.c +++ clang/test/CodeGen/math-builtins-long.c @@ -34,10 +34,10 @@ // PPCF128: call fp128 @llvm.fabs.f128(fp128 %{{.+}}) __builtin_fabsl(f); - // F80: call x86_fp80 @frexpl(x86_fp80 noundef %{{.+}}, ptr noundef %{{.+}}) - // PPC: call ppc_fp128 @frexpl(ppc_fp128 noundef %{{.+}}, ptr noundef %{{.+}}) - // X86F128: call fp128 @frexpl(fp128 noundef %{{.+}}, ptr noundef %{{.+}}) - // PPCF128: call fp128 @frexpf128(fp128 noundef %{{.+}}, ptr noundef %{{.+}}) + // F80: call { x86_fp80, i32 } @llvm.frexp.f80.i32(x86_fp80 %{{.+}}) + // PPC: call { ppc_fp128, i32 } @llvm.frexp.ppcf128.i32(ppc_fp128 %{{.+}}) + // X86F128: call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %{{.+}}) + // PPCF128: call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %{{.+}}) __builtin_frexpl(f,i); // F80: store x86_fp80 0xK7FFF8000000000000000, ptr Index: clang/test/CodeGen/math-builtins.c =================================================================== --- clang/test/CodeGen/math-builtins.c +++ clang/test/CodeGen/math-builtins.c @@ -12,6 +12,30 @@ // NO__ERRNO: frem float // NO__ERRNO: frem x86_fp80 // NO__ERRNO: frem fp128 + +// NO__ERRNO: [[FREXP_F64:%.+]] = call { double, i32 } @llvm.frexp.f64.i32(double %{{.+}}) +// NO__ERRNO-NEXT: [[FREXP_F64_1:%.+]] = extractvalue { double, i32 } [[FREXP_F64]], 1 +// NO__ERRNO-NEXT: store i32 [[FREXP_F64_1]], ptr %{{.+}}, align 4 +// NO__ERRNO-NEXT: [[FREXP_F64_0:%.+]] = extractvalue { double, i32 } [[FREXP_F64]], 0 + +// NO__ERRNO: [[FREXP_F32:%.+]] = call { float, i32 } @llvm.frexp.f32.i32(float %{{.+}}) +// NO__ERRNO-NEXT: [[FREXP_F32_1:%.+]] = extractvalue { float, i32 } [[FREXP_F32]], 1 +// NO__ERRNO-NEXT: store i32 [[FREXP_F32_1]], ptr %{{.+}}, align 4 +// NO__ERRNO-NEXT: [[FREXP_F32_0:%.+]] = extractvalue { float, i32 } [[FREXP_F32]], 0 + + +// NO__ERRNO: [[FREXP_F80:%.+]] = call { x86_fp80, i32 } @llvm.frexp.f80.i32(x86_fp80 %{{.+}}) +// NO__ERRNO-NEXT: [[FREXP_F80_1:%.+]] = extractvalue { x86_fp80, i32 } [[FREXP_F80]], 1 +// NO__ERRNO-NEXT: store i32 [[FREXP_F80_1]], ptr %{{.+}}, align 4 +// NO__ERRNO-NEXT: [[FREXP_F80_0:%.+]] = extractvalue { x86_fp80, i32 } [[FREXP_F80]], 0 + + +// NO__ERRNO: [[FREXP_F128:%.+]] = call { fp128, i32 } @llvm.frexp.f128.i32(fp128 %{{.+}}) +// NO__ERRNO-NEXT: [[FREXP_F128_1:%.+]] = extractvalue { fp128, i32 } [[FREXP_F128]], 1 +// NO__ERRNO-NEXT: store i32 [[FREXP_F128_1]], ptr %{{.+}}, align 4 +// NO__ERRNO-NEXT: [[FREXP_F128_0:%.+]] = extractvalue { fp128, i32 } [[FREXP_F128]], 0 + + // HAS_ERRNO: declare double @fmod(double noundef, double noundef) [[NOT_READNONE:#[0-9]+]] // HAS_ERRNO: declare float @fmodf(float noundef, float noundef) [[NOT_READNONE]] // HAS_ERRNO: declare x86_fp80 @fmodl(x86_fp80 noundef, x86_fp80 noundef) [[NOT_READNONE]] @@ -52,14 +76,14 @@ __builtin_frexp(f,i); __builtin_frexpf(f,i); __builtin_frexpl(f,i); __builtin_frexpf128(f,i); -// NO__ERRNO: declare double @frexp(double noundef, ptr noundef) [[NOT_READNONE:#[0-9]+]] -// NO__ERRNO: declare float @frexpf(float noundef, ptr noundef) [[NOT_READNONE]] -// NO__ERRNO: declare x86_fp80 @frexpl(x86_fp80 noundef, ptr noundef) [[NOT_READNONE]] -// NO__ERRNO: declare fp128 @frexpf128(fp128 noundef, ptr noundef) [[NOT_READNONE]] -// HAS_ERRNO: declare double @frexp(double noundef, ptr noundef) [[NOT_READNONE]] -// HAS_ERRNO: declare float @frexpf(float noundef, ptr noundef) [[NOT_READNONE]] -// HAS_ERRNO: declare x86_fp80 @frexpl(x86_fp80 noundef, ptr noundef) [[NOT_READNONE]] -// HAS_ERRNO: declare fp128 @frexpf128(fp128 noundef, ptr noundef) [[NOT_READNONE]] +// NO__ERRNO: declare { double, i32 } @llvm.frexp.f64.i32(double) [[READNONE_INTRINSIC]] +// NO__ERRNO: declare { float, i32 } @llvm.frexp.f32.i32(float) [[READNONE_INTRINSIC]] +// NO__ERRNO: declare { x86_fp80, i32 } @llvm.frexp.f80.i32(x86_fp80) [[READNONE_INTRINSIC]] +// NO__ERRNO: declare { fp128, i32 } @llvm.frexp.f128.i32(fp128) [[READNONE_INTRINSIC]] +// HAS_ERRNO: declare { double, i32 } @llvm.frexp.f64.i32(double) [[READNONE_INTRINSIC]] +// HAS_ERRNO: declare { float, i32 } @llvm.frexp.f32.i32(float) [[READNONE_INTRINSIC]] +// HAS_ERRNO: declare { x86_fp80, i32 } @llvm.frexp.f80.i32(x86_fp80) [[READNONE_INTRINSIC]] +// HAS_ERRNO: declare { fp128, i32 } @llvm.frexp.f128.i32(fp128) [[READNONE_INTRINSIC]] __builtin_huge_val(); __builtin_huge_valf(); __builtin_huge_vall(); __builtin_huge_valf128(); @@ -88,7 +112,7 @@ __builtin_modf(f,d); __builtin_modff(f,fp); __builtin_modfl(f,l); __builtin_modff128(f,l); -// NO__ERRNO: declare double @modf(double noundef, ptr noundef) [[NOT_READNONE]] +// NO__ERRNO: declare double @modf(double noundef, ptr noundef) [[NOT_READNONE:#[0-9]+]] // NO__ERRNO: declare float @modff(float noundef, ptr noundef) [[NOT_READNONE]] // NO__ERRNO: declare x86_fp80 @modfl(x86_fp80 noundef, ptr noundef) [[NOT_READNONE]] // NO__ERRNO: declare fp128 @modff128(fp128 noundef, ptr noundef) [[NOT_READNONE]] Index: clang/test/CodeGenOpenCL/builtins-generic-amdgcn.cl =================================================================== --- clang/test/CodeGenOpenCL/builtins-generic-amdgcn.cl +++ clang/test/CodeGenOpenCL/builtins-generic-amdgcn.cl @@ -39,3 +39,18 @@ double test_builtin_ldexp(double v, int e) { return __builtin_ldexp(v, e); } + +// CHECK-LABEL: @test_builtin_frexpf16( +half test_builtin_frexpf16(half v, int* e) { + return __builtin_frexpf16(v, e); +} + +// CHECK-LABEL: @test_builtin_frexpf( +float test_builtin_frexpf(float v, int* e) { + return __builtin_frexpf(v, e); +} + +// CHECK-LABEL: @test_builtin_builtin_frexp( +double test_builtin_frexp(double v, int* e) { + return __builtin_frexp(v, e); +}