blob: d493002d1445d2adb6fd6174470b9d52521b127b [file] [log] [blame]
Kevin P. Neal20694032020-11-06 10:44:13 -05001// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s
3
4
5// Test that the constrained intrinsics are picking up the exception
6// metadata from the AST instead of the global default from the command line.
7// Include rounding metadata in the testing.
8// FIXME: All cases of "fpexcept.maytrap" in this test are wrong.
9// FIXME: All cases of "round.tonearest" in this test are wrong.
10
11#pragma float_control(except, on)
12#pragma STDC FENV_ROUND FE_UPWARD
13
14_Complex double g1, g2;
15_Complex float cf;
16double D;
17
18// CHECK-LABEL: @test3a(
19// CHECK-NEXT: entry:
20// CHECK-NEXT: [[TMP0:%.*]] = load double, double* @D, align 8
21// CHECK-NEXT: [[CF_REAL:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
22// CHECK-NEXT: [[CF_IMAG:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
23// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") [[ATTR2:#.*]]
24// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") [[ATTR2]]
25// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[CONV]], double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") [[ATTR2]]
26// CHECK-NEXT: [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[ADD_R]], metadata !"round.upward", metadata !"fpexcept.strict") [[ATTR2]]
27// CHECK-NEXT: [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[CONV1]], metadata !"round.upward", metadata !"fpexcept.strict") [[ATTR2]]
28// CHECK-NEXT: store float [[CONV2]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
29// CHECK-NEXT: store float [[CONV3]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
30// CHECK-NEXT: ret void
31//
32void test3a() {
33 cf += D;
34}
35
36// CHECK-LABEL: @test3b(
37// CHECK-NEXT: entry:
38// CHECK-NEXT: [[CF_REAL:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
39// CHECK-NEXT: [[CF_IMAG:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
40// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") [[ATTR2]]
41// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") [[ATTR2]]
42// CHECK-NEXT: [[TMP0:%.*]] = load double, double* @D, align 8
43// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[CONV]], metadata !"round.upward", metadata !"fpexcept.strict") [[ATTR2]]
44// CHECK-NEXT: store double [[ADD_R]], double* @D, align 8
45// CHECK-NEXT: ret void
46//
47void test3b() {
48 D += cf;
49}
50
51// CHECK-LABEL: @test3c(
52// CHECK-NEXT: entry:
53// CHECK-NEXT: [[G1_REAL:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 0), align 8
54// CHECK-NEXT: [[G1_IMAG:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 1), align 8
55// CHECK-NEXT: [[CF_REAL:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
56// CHECK-NEXT: [[CF_IMAG:%.*]] = load float, float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
57// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_REAL]], metadata !"fpexcept.strict") [[ATTR2]]
58// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float [[CF_IMAG]], metadata !"fpexcept.strict") [[ATTR2]]
59// CHECK-NEXT: [[CALL:%.*]] = call { double, double } @__divdc3(double [[CONV]], double [[CONV1]], double [[G1_REAL]], double [[G1_IMAG]]) [[ATTR3:#.*]]
60// CHECK-NEXT: [[TMP0:%.*]] = extractvalue { double, double } [[CALL]], 0
61// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[CALL]], 1
62// CHECK-NEXT: [[CONV2:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP0]], metadata !"round.upward", metadata !"fpexcept.strict") [[ATTR2]]
63// CHECK-NEXT: [[CONV3:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double [[TMP1]], metadata !"round.upward", metadata !"fpexcept.strict") [[ATTR2]]
64// CHECK-NEXT: store float [[CONV2]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
65// CHECK-NEXT: store float [[CONV3]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
66// CHECK-NEXT: ret void
67//
68void test3c() {
69 cf /= g1;
70}
71
72// CHECK-LABEL: @test3d(
73// CHECK-NEXT: entry:
74// CHECK-NEXT: [[G1_REAL:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 0), align 8
75// CHECK-NEXT: [[G1_IMAG:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 1), align 8
76// CHECK-NEXT: [[TMP0:%.*]] = load double, double* @D, align 8
77// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[G1_REAL]], double [[TMP0]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") [[ATTR2]]
78// CHECK-NEXT: store double [[ADD_R]], double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 0), align 8
79// CHECK-NEXT: store double [[G1_IMAG]], double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 1), align 8
80// CHECK-NEXT: ret void
81//
82void test3d() {
83 g1 = g1 + D;
84}
85
86// CHECK-LABEL: @test3e(
87// CHECK-NEXT: entry:
88// CHECK-NEXT: [[TMP0:%.*]] = load double, double* @D, align 8
89// CHECK-NEXT: [[G1_REAL:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 0), align 8
90// CHECK-NEXT: [[G1_IMAG:%.*]] = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 1), align 8
91// CHECK-NEXT: [[ADD_R:%.*]] = call double @llvm.experimental.constrained.fadd.f64(double [[TMP0]], double [[G1_REAL]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") [[ATTR2]]
92// CHECK-NEXT: store double [[ADD_R]], double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 0), align 8
93// CHECK-NEXT: store double [[G1_IMAG]], double* getelementptr inbounds ({ double, double }, { double, double }* @g1, i32 0, i32 1), align 8
94// CHECK-NEXT: ret void
95//
96void test3e() {
97 g1 = D + g1;
98}
99
100// CHECK-LABEL: @t1(
101// CHECK-NEXT: entry:
102// CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") [[ATTR2]]
103// CHECK-NEXT: store float [[CONV]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 0), align 4
104// CHECK-NEXT: ret void
105//
106void t1() {
107 (__real__ cf) = 4.0;
108}
109
110// CHECK-LABEL: @t2(
111// CHECK-NEXT: entry:
112// CHECK-NEXT: [[CONV:%.*]] = call float @llvm.experimental.constrained.fptrunc.f32.f64(double 4.000000e+00, metadata !"round.upward", metadata !"fpexcept.strict") [[ATTR2]]
113// CHECK-NEXT: store float [[CONV]], float* getelementptr inbounds ({ float, float }, { float, float }* @cf, i32 0, i32 1), align 4
114// CHECK-NEXT: ret void
115//
116void t2() {
117 (__imag__ cf) = 4.0;
118}
119
120// CHECK-LABEL: @t91(
121// CHECK-NEXT: entry:
122// CHECK-NEXT: [[C:%.*]] = alloca [0 x i8], align 1
123// CHECK-NEXT: br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
124// CHECK: cond.true:
125// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") [[ATTR2]]
126// CHECK-NEXT: br label [[COND_END:%.*]]
127// CHECK: cond.false:
128// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") [[ATTR2]]
129// CHECK-NEXT: br label [[COND_END]]
130// CHECK: cond.end:
131// CHECK-NEXT: [[COND_R:%.*]] = phi double [ [[CONV]], [[COND_TRUE]] ], [ [[CONV1]], [[COND_FALSE]] ]
132// CHECK-NEXT: [[COND_I:%.*]] = phi double [ 0.000000e+00, [[COND_TRUE]] ], [ 0.000000e+00, [[COND_FALSE]] ]
133// CHECK-NEXT: ret void
134//
135void t91() {
136 // Check for proper type promotion of conditional expression
137 char c[(int)(sizeof(typeof((0 ? 2.0f : (_Complex double) 2.0f))) - sizeof(_Complex double))];
138 // Check for proper codegen
139 (0 ? 2.0f : (_Complex double) 2.0f);
140}
141
142// CHECK-LABEL: @t92(
143// CHECK-NEXT: entry:
144// CHECK-NEXT: [[C:%.*]] = alloca [0 x i8], align 1
145// CHECK-NEXT: br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
146// CHECK: cond.true:
147// CHECK-NEXT: [[CONV:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") [[ATTR2]]
148// CHECK-NEXT: br label [[COND_END:%.*]]
149// CHECK: cond.false:
150// CHECK-NEXT: [[CONV1:%.*]] = call double @llvm.experimental.constrained.fpext.f64.f32(float 2.000000e+00, metadata !"fpexcept.strict") [[ATTR2]]
151// CHECK-NEXT: br label [[COND_END]]
152// CHECK: cond.end:
153// CHECK-NEXT: [[COND_R:%.*]] = phi double [ [[CONV]], [[COND_TRUE]] ], [ [[CONV1]], [[COND_FALSE]] ]
154// CHECK-NEXT: [[COND_I:%.*]] = phi double [ 0.000000e+00, [[COND_TRUE]] ], [ 0.000000e+00, [[COND_FALSE]] ]
155// CHECK-NEXT: ret void
156//
157void t92() {
158 // Check for proper type promotion of conditional expression
159 char c[(int)(sizeof(typeof((0 ? (_Complex double) 2.0f : 2.0f))) - sizeof(_Complex double))];
160 // Check for proper codegen
161 (0 ? (_Complex double) 2.0f : 2.0f);
162}
163