Skip to content

Commit e4e2f53

Browse files
authored
[clang] Add sincos builtin using llvm.sincos intrinsic (#114086)
This registers `sincos[f|l]` as a clang builtin and updates GCBuiltin to emit the `llvm.sincos.*` intrinsic when `-fno-math-errno` is set. Note: `llvm.sincos.*` is only emitted by `__builtin_sincos[f|l]` functions in this initial patch.
1 parent 4df366c commit e4e2f53

File tree

5 files changed

+134
-3
lines changed

5 files changed

+134
-3
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3568,6 +3568,19 @@ def Frexp : FPMathTemplate, LibBuiltin<"math.h"> {
35683568
let AddBuiltinPrefixedAlias = 1;
35693569
}
35703570

3571+
def Sincos : FPMathTemplate, GNULibBuiltin<"math.h"> {
3572+
let Spellings = ["sincos"];
3573+
let Attributes = [NoThrow];
3574+
let Prototype = "void(T, T*, T*)";
3575+
let AddBuiltinPrefixedAlias = 1;
3576+
}
3577+
3578+
def SincosF16F128 : F16F128MathTemplate, Builtin {
3579+
let Spellings = ["__builtin_sincos"];
3580+
let Attributes = [FunctionWithBuiltinPrefix, NoThrow];
3581+
let Prototype = "void(T, T*, T*)";
3582+
}
3583+
35713584
def Ldexp : FPMathTemplate, LibBuiltin<"math.h"> {
35723585
let Spellings = ["ldexp"];
35733586
let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions];

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,38 @@ static Value *emitFrexpBuiltin(CodeGenFunction &CGF, const CallExpr *E,
835835
return CGF.Builder.CreateExtractValue(Call, 0);
836836
}
837837

838+
static void emitSincosBuiltin(CodeGenFunction &CGF, const CallExpr *E,
839+
llvm::Intrinsic::ID IntrinsicID) {
840+
llvm::Value *Val = CGF.EmitScalarExpr(E->getArg(0));
841+
llvm::Value *Dest0 = CGF.EmitScalarExpr(E->getArg(1));
842+
llvm::Value *Dest1 = CGF.EmitScalarExpr(E->getArg(2));
843+
844+
llvm::Function *F = CGF.CGM.getIntrinsic(IntrinsicID, {Val->getType()});
845+
llvm::Value *Call = CGF.Builder.CreateCall(F, Val);
846+
847+
llvm::Value *SinResult = CGF.Builder.CreateExtractValue(Call, 0);
848+
llvm::Value *CosResult = CGF.Builder.CreateExtractValue(Call, 1);
849+
850+
QualType DestPtrType = E->getArg(1)->getType()->getPointeeType();
851+
LValue SinLV = CGF.MakeNaturalAlignAddrLValue(Dest0, DestPtrType);
852+
LValue CosLV = CGF.MakeNaturalAlignAddrLValue(Dest1, DestPtrType);
853+
854+
llvm::StoreInst *StoreSin =
855+
CGF.Builder.CreateStore(SinResult, SinLV.getAddress());
856+
llvm::StoreInst *StoreCos =
857+
CGF.Builder.CreateStore(CosResult, CosLV.getAddress());
858+
859+
// Mark the two stores as non-aliasing with each other. The order of stores
860+
// emitted by this builtin is arbitrary, enforcing a particular order will
861+
// prevent optimizations later on.
862+
llvm::MDBuilder MDHelper(CGF.getLLVMContext());
863+
MDNode *Domain = MDHelper.createAnonymousAliasScopeDomain();
864+
MDNode *AliasScope = MDHelper.createAnonymousAliasScope(Domain);
865+
MDNode *AliasScopeList = MDNode::get(Call->getContext(), AliasScope);
866+
StoreSin->setMetadata(LLVMContext::MD_alias_scope, AliasScopeList);
867+
StoreCos->setMetadata(LLVMContext::MD_noalias, AliasScopeList);
868+
}
869+
838870
/// EmitFAbs - Emit a call to @llvm.fabs().
839871
static Value *EmitFAbs(CodeGenFunction &CGF, Value *V) {
840872
Function *F = CGF.CGM.getIntrinsic(Intrinsic::fabs, V->getType());
@@ -3232,6 +3264,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
32323264
return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(
32333265
*this, E, Intrinsic::sinh, Intrinsic::experimental_constrained_sinh));
32343266

3267+
case Builtin::BI__builtin_sincos:
3268+
case Builtin::BI__builtin_sincosf:
3269+
case Builtin::BI__builtin_sincosf16:
3270+
case Builtin::BI__builtin_sincosl:
3271+
case Builtin::BI__builtin_sincosf128:
3272+
emitSincosBuiltin(*this, E, Intrinsic::sincos);
3273+
return RValue::get(nullptr);
3274+
32353275
case Builtin::BIsqrt:
32363276
case Builtin::BIsqrtf:
32373277
case Builtin::BIsqrtl:

clang/test/CodeGen/AArch64/sincos.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %clang_cc1 -triple=aarch64-gnu-linux -emit-llvm -O1 %s -o - | FileCheck --check-prefix=NO-MATH-ERRNO %s
2+
// RUN: %clang_cc1 -triple=aarch64-gnu-linux -emit-llvm -fmath-errno %s -o - | FileCheck --check-prefix=MATH-ERRNO %s
3+
4+
// NO-MATH-ERRNO-LABEL: @sincos_f32
5+
// NO-MATH-ERRNO: [[SINCOS:%.*]] = tail call { float, float } @llvm.sincos.f32(float {{.*}})
6+
// NO-MATH-ERRNO-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0
7+
// NO-MATH-ERRNO-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1
8+
// NO-MATH-ERRNO-NEXT: store float [[SIN]], ptr {{.*}}, align 4, !alias.scope [[SINCOS_ALIAS_SCOPE:![0-9]+]]
9+
// NO-MATH-ERRNO-NEXT: store float [[COS]], ptr {{.*}}, align 4, !noalias [[SINCOS_ALIAS_SCOPE]]
10+
//
11+
// MATH-ERRNO-LABEL: @sincos_f32
12+
// MATH-ERRNO: call void @sincosf(
13+
//
14+
void sincos_f32(float x, float* fp0, float* fp1) {
15+
__builtin_sincosf(x, fp0, fp1);
16+
}
17+
18+
// NO-MATH-ERRNO-LABEL: @sincos_f64
19+
// NO-MATH-ERRNO: [[SINCOS:%.*]] = tail call { double, double } @llvm.sincos.f64(double {{.*}})
20+
// NO-MATH-ERRNO-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0
21+
// NO-MATH-ERRNO-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1
22+
// NO-MATH-ERRNO-NEXT: store double [[SIN]], ptr {{.*}}, align 8, !alias.scope [[SINCOS_ALIAS_SCOPE:![0-9]+]]
23+
// NO-MATH-ERRNO-NEXT: store double [[COS]], ptr {{.*}}, align 8, !noalias [[SINCOS_ALIAS_SCOPE]]
24+
//
25+
// MATH-ERRNO-LABEL: @sincos_f64
26+
// MATH-ERRNO: call void @sincos(
27+
//
28+
void sincos_f64(double x, double* dp0, double* dp1) {
29+
__builtin_sincos(x, dp0, dp1);
30+
}
31+
32+
// NO-MATH-ERRNO-LABEL: @sincos_f128
33+
// NO-MATH-ERRNO: [[SINCOS:%.*]] = tail call { fp128, fp128 } @llvm.sincos.f128(fp128 {{.*}})
34+
// NO-MATH-ERRNO-NEXT: [[SIN:%.*]] = extractvalue { fp128, fp128 } [[SINCOS]], 0
35+
// NO-MATH-ERRNO-NEXT: [[COS:%.*]] = extractvalue { fp128, fp128 } [[SINCOS]], 1
36+
// NO-MATH-ERRNO-NEXT: store fp128 [[SIN]], ptr {{.*}}, align 16, !alias.scope [[SINCOS_ALIAS_SCOPE:![0-9]+]]
37+
// NO-MATH-ERRNO-NEXT: store fp128 [[COS]], ptr {{.*}}, align 16, !noalias [[SINCOS_ALIAS_SCOPE]]
38+
//
39+
// MATH-ERRNO-LABEL: @sincos_f128
40+
// MATH-ERRNO: call void @sincosl(
41+
//
42+
void sincos_f128(long double x, long double* ldp0, long double* ldp1) {
43+
__builtin_sincosl(x, ldp0, ldp1);
44+
}

clang/test/CodeGen/X86/math-builtins.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,31 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {
3838
// NO__ERRNO-NEXT: [[FREXP_F128_0:%.+]] = extractvalue { fp128, i32 } [[FREXP_F128]], 0
3939

4040

41+
// NO__ERRNO: [[SINCOS_F64:%.+]] = call { double, double } @llvm.sincos.f64(double %{{.+}})
42+
// NO__ERRNO-NEXT: [[SINCOS_F64_0:%.+]] = extractvalue { double, double } [[SINCOS_F64]], 0
43+
// NO__ERRNO-NEXT: [[SINCOS_F64_1:%.+]] = extractvalue { double, double } [[SINCOS_F64]], 1
44+
// NO__ERRNO-NEXT: store double [[SINCOS_F64_0]], ptr %{{.+}}, align 8
45+
// NO__ERRNO-NEXT: store double [[SINCOS_F64_1]], ptr %{{.+}}, align 8
46+
47+
// NO__ERRNO: [[SINCOS_F32:%.+]] = call { float, float } @llvm.sincos.f32(float %{{.+}})
48+
// NO__ERRNO-NEXT: [[SINCOS_F32_0:%.+]] = extractvalue { float, float } [[SINCOS_F32]], 0
49+
// NO__ERRNO-NEXT: [[SINCOS_F32_1:%.+]] = extractvalue { float, float } [[SINCOS_F32]], 1
50+
// NO__ERRNO-NEXT: store float [[SINCOS_F32_0]], ptr %{{.+}}, align 4
51+
// NO__ERRNO-NEXT: store float [[SINCOS_F32_1]], ptr %{{.+}}, align 4
52+
53+
// NO__ERRNO: [[SINCOS_F80:%.+]] = call { x86_fp80, x86_fp80 } @llvm.sincos.f80(x86_fp80 %{{.+}})
54+
// NO__ERRNO-NEXT: [[SINCOS_F80_0:%.+]] = extractvalue { x86_fp80, x86_fp80 } [[SINCOS_F80]], 0
55+
// NO__ERRNO-NEXT: [[SINCOS_F80_1:%.+]] = extractvalue { x86_fp80, x86_fp80 } [[SINCOS_F80]], 1
56+
// NO__ERRNO-NEXT: store x86_fp80 [[SINCOS_F80_0]], ptr %{{.+}}, align 16
57+
// NO__ERRNO-NEXT: store x86_fp80 [[SINCOS_F80_1]], ptr %{{.+}}, align 16
58+
59+
// NO__ERRNO: [[SINCOS_F128:%.+]] = call { fp128, fp128 } @llvm.sincos.f128(fp128 %{{.+}})
60+
// NO__ERRNO-NEXT: [[SINCOS_F128_0:%.+]] = extractvalue { fp128, fp128 } [[SINCOS_F128]], 0
61+
// NO__ERRNO-NEXT: [[SINCOS_F128_1:%.+]] = extractvalue { fp128, fp128 } [[SINCOS_F128]], 1
62+
// NO__ERRNO-NEXT: store fp128 [[SINCOS_F128_0]], ptr %{{.+}}, align 16
63+
// NO__ERRNO-NEXT: store fp128 [[SINCOS_F128_1]], ptr %{{.+}}, align 16
64+
65+
4166
// HAS_ERRNO: declare double @fmod(double noundef, double noundef) [[NOT_READNONE:#[0-9]+]]
4267
// HAS_ERRNO: declare float @fmodf(float noundef, float noundef) [[NOT_READNONE]]
4368
// HAS_ERRNO: declare x86_fp80 @fmodl(x86_fp80 noundef, x86_fp80 noundef) [[NOT_READNONE]]
@@ -665,6 +690,16 @@ __builtin_sinh(f); __builtin_sinhf(f); __builtin_sinhl(f); __builtin_
665690
// HAS_ERRNO: declare x86_fp80 @sinhl(x86_fp80 noundef) [[NOT_READNONE]]
666691
// HAS_ERRNO: declare fp128 @sinhf128(fp128 noundef) [[NOT_READNONE]]
667692

693+
__builtin_sincos(f,d,d); __builtin_sincosf(f,fp,fp); __builtin_sincosl(f,l,l); __builtin_sincosf128(f,l,l);
694+
// NO__ERRNO: declare { double, double } @llvm.sincos.f64(double) [[READNONE_INTRINSIC]]
695+
// NO__ERRNO: declare { float, float } @llvm.sincos.f32(float) [[READNONE_INTRINSIC]]
696+
// NO__ERRNO: declare { x86_fp80, x86_fp80 } @llvm.sincos.f80(x86_fp80) [[READNONE_INTRINSIC]]
697+
// NO__ERRNO: declare { fp128, fp128 } @llvm.sincos.f128(fp128) [[READNONE_INTRINSIC]]
698+
// HAS_ERRNO: declare void @sincos(double noundef, ptr noundef, ptr noundef) [[NOT_READNONE]]
699+
// HAS_ERRNO: declare void @sincosf(float noundef, ptr noundef, ptr noundef) [[NOT_READNONE]]
700+
// HAS_ERRNO: declare void @sincosl(x86_fp80 noundef, ptr noundef, ptr noundef) [[NOT_READNONE]]
701+
// HAS_ERRNO: declare void @sincosf128(fp128 noundef, ptr noundef, ptr noundef) [[NOT_READNONE]]
702+
668703
__builtin_sqrt(f); __builtin_sqrtf(f); __builtin_sqrtl(f); __builtin_sqrtf128(f);
669704

670705
// NO__ERRNO: declare double @llvm.sqrt.f64(double) [[READNONE_INTRINSIC]]
@@ -733,4 +768,3 @@ __builtin_trunc(f); __builtin_truncf(f); __builtin_truncl(f); __builtin
733768

734769
// HAS_ERRNO_GNU: attributes [[READNONE_INTRINSIC]] = { {{.*}}memory(none){{.*}} }
735770
// HAS_ERRNO_WIN: attributes [[READNONE_INTRINSIC]] = { {{.*}}memory(none){{.*}} }
736-

clang/test/OpenMP/declare_simd_aarch64.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// REQUIRES: aarch64-registered-target
22
// -fopemp and -fopenmp-simd behavior are expected to be the same.
33

4-
// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon -fopenmp -x c -emit-llvm %s -o - -femit-all-decls | FileCheck %s --check-prefix=AARCH64
5-
// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon -fopenmp-simd -x c -emit-llvm %s -o - -femit-all-decls | FileCheck %s --check-prefix=AARCH64
4+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon -fmath-errno -fopenmp -x c -emit-llvm %s -o - -femit-all-decls | FileCheck %s --check-prefix=AARCH64
5+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon -fmath-errno -fopenmp-simd -x c -emit-llvm %s -o - -femit-all-decls | FileCheck %s --check-prefix=AARCH64
66

77
#pragma omp declare simd
88
#pragma omp declare simd simdlen(2)

0 commit comments

Comments
 (0)