1 // Check code generation 2 // RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 -emit-llvm %s -o - | FileCheck %s --check-prefix=IR 3 4 // Check same results after serialization round-trip 5 // RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 -emit-pch -o %t %s 6 // RUN: %clang_cc1 -no-opaque-pointers -verify -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 -include-pch %t -emit-llvm %s -o - | FileCheck %s --check-prefix=IR 7 // expected-no-diagnostics 8 9 #ifndef HEADER 10 #define HEADER 11 12 // placeholder for loop body code. 13 extern "C" void body(...) {} 14 15 16 // IR-LABEL: @func( 17 // IR-NEXT: [[ENTRY:.*]]: 18 // IR-NEXT: %[[START_ADDR:.+]] = alloca i32, align 4 19 // IR-NEXT: %[[END_ADDR:.+]] = alloca i32, align 4 20 // IR-NEXT: %[[STEP_ADDR:.+]] = alloca i32, align 4 21 // IR-NEXT: %[[DOTOMP_IV:.+]] = alloca i64, align 8 22 // IR-NEXT: %[[TMP:.+]] = alloca i32, align 4 23 // IR-NEXT: %[[TMP1:.+]] = alloca i32, align 4 24 // IR-NEXT: %[[DOTCAPTURE_EXPR_:.+]] = alloca i32, align 4 25 // IR-NEXT: %[[DOTCAPTURE_EXPR_2:.+]] = alloca i32, align 4 26 // IR-NEXT: %[[DOTCAPTURE_EXPR_3:.+]] = alloca i32, align 4 27 // IR-NEXT: %[[J:.+]] = alloca i32, align 4 28 // IR-NEXT: %[[DOTCAPTURE_EXPR_4:.+]] = alloca i32, align 4 29 // IR-NEXT: %[[DOTCAPTURE_EXPR_5:.+]] = alloca i32, align 4 30 // IR-NEXT: %[[DOTCAPTURE_EXPR_6:.+]] = alloca i32, align 4 31 // IR-NEXT: %[[DOTCAPTURE_EXPR_7:.+]] = alloca i32, align 4 32 // IR-NEXT: %[[DOTCAPTURE_EXPR_10:.+]] = alloca i32, align 4 33 // IR-NEXT: %[[DOTCAPTURE_EXPR_12:.+]] = alloca i64, align 8 34 // IR-NEXT: %[[I:.+]] = alloca i32, align 4 35 // IR-NEXT: %[[DOTUNROLLED_IV_J:.+]] = alloca i32, align 4 36 // IR-NEXT: %[[DOTOMP_LB:.+]] = alloca i64, align 8 37 // IR-NEXT: %[[DOTOMP_UB:.+]] = alloca i64, align 8 38 // IR-NEXT: %[[DOTOMP_STRIDE:.+]] = alloca i64, align 8 39 // IR-NEXT: %[[DOTOMP_IS_LAST:.+]] = alloca i32, align 4 40 // IR-NEXT: %[[I22:.+]] = alloca i32, align 4 41 // IR-NEXT: %[[DOTUNROLLED_IV_J23:.+]] = alloca i32, align 4 42 // IR-NEXT: %[[DOTUNROLL_INNER_IV_J:.+]] = alloca i32, align 4 43 // IR-NEXT: %[[TMP0:.+]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @2) 44 // IR-NEXT: store i32 %[[START:.+]], i32* %[[START_ADDR]], align 4 45 // IR-NEXT: store i32 %[[END:.+]], i32* %[[END_ADDR]], align 4 46 // IR-NEXT: store i32 %[[STEP:.+]], i32* %[[STEP_ADDR]], align 4 47 // IR-NEXT: %[[TMP1_1:.+]] = load i32, i32* %[[START_ADDR]], align 4 48 // IR-NEXT: store i32 %[[TMP1_1]], i32* %[[DOTCAPTURE_EXPR_]], align 4 49 // IR-NEXT: %[[TMP2:.+]] = load i32, i32* %[[END_ADDR]], align 4 50 // IR-NEXT: store i32 %[[TMP2]], i32* %[[DOTCAPTURE_EXPR_2]], align 4 51 // IR-NEXT: %[[TMP3:.+]] = load i32, i32* %[[STEP_ADDR]], align 4 52 // IR-NEXT: store i32 %[[TMP3]], i32* %[[DOTCAPTURE_EXPR_3]], align 4 53 // IR-NEXT: %[[TMP4:.+]] = load i32, i32* %[[START_ADDR]], align 4 54 // IR-NEXT: store i32 %[[TMP4]], i32* %[[J]], align 4 55 // IR-NEXT: %[[TMP5:.+]] = load i32, i32* %[[START_ADDR]], align 4 56 // IR-NEXT: store i32 %[[TMP5]], i32* %[[DOTCAPTURE_EXPR_4]], align 4 57 // IR-NEXT: %[[TMP6:.+]] = load i32, i32* %[[END_ADDR]], align 4 58 // IR-NEXT: store i32 %[[TMP6]], i32* %[[DOTCAPTURE_EXPR_5]], align 4 59 // IR-NEXT: %[[TMP7:.+]] = load i32, i32* %[[STEP_ADDR]], align 4 60 // IR-NEXT: store i32 %[[TMP7]], i32* %[[DOTCAPTURE_EXPR_6]], align 4 61 // IR-NEXT: %[[TMP8:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_5]], align 4 62 // IR-NEXT: %[[TMP9:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_4]], align 4 63 // IR-NEXT: %[[SUB:.+]] = sub i32 %[[TMP8]], %[[TMP9]] 64 // IR-NEXT: %[[SUB8:.+]] = sub i32 %[[SUB]], 1 65 // IR-NEXT: %[[TMP10:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_6]], align 4 66 // IR-NEXT: %[[ADD:.+]] = add i32 %[[SUB8]], %[[TMP10]] 67 // IR-NEXT: %[[TMP11:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_6]], align 4 68 // IR-NEXT: %[[DIV:.+]] = udiv i32 %[[ADD]], %[[TMP11]] 69 // IR-NEXT: %[[SUB9:.+]] = sub i32 %[[DIV]], 1 70 // IR-NEXT: store i32 %[[SUB9]], i32* %[[DOTCAPTURE_EXPR_7]], align 4 71 // IR-NEXT: %[[TMP12:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_7]], align 4 72 // IR-NEXT: %[[ADD11:.+]] = add i32 %[[TMP12]], 1 73 // IR-NEXT: store i32 %[[ADD11]], i32* %[[DOTCAPTURE_EXPR_10]], align 4 74 // IR-NEXT: %[[TMP13:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_2]], align 4 75 // IR-NEXT: %[[TMP14:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_]], align 4 76 // IR-NEXT: %[[SUB13:.+]] = sub i32 %[[TMP13]], %[[TMP14]] 77 // IR-NEXT: %[[SUB14:.+]] = sub i32 %[[SUB13]], 1 78 // IR-NEXT: %[[TMP15:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_3]], align 4 79 // IR-NEXT: %[[ADD15:.+]] = add i32 %[[SUB14]], %[[TMP15]] 80 // IR-NEXT: %[[TMP16:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_3]], align 4 81 // IR-NEXT: %[[DIV16:.+]] = udiv i32 %[[ADD15]], %[[TMP16]] 82 // IR-NEXT: %[[CONV:.+]] = zext i32 %[[DIV16]] to i64 83 // IR-NEXT: %[[TMP17:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_10]], align 4 84 // IR-NEXT: %[[SUB17:.+]] = sub i32 %[[TMP17]], -1 85 // IR-NEXT: %[[DIV18:.+]] = udiv i32 %[[SUB17]], 2 86 // IR-NEXT: %[[CONV19:.+]] = zext i32 %[[DIV18]] to i64 87 // IR-NEXT: %[[MUL:.+]] = mul nsw i64 %[[CONV]], %[[CONV19]] 88 // IR-NEXT: %[[SUB20:.+]] = sub nsw i64 %[[MUL]], 1 89 // IR-NEXT: store i64 %[[SUB20]], i64* %[[DOTCAPTURE_EXPR_12]], align 8 90 // IR-NEXT: %[[TMP18:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_]], align 4 91 // IR-NEXT: store i32 %[[TMP18]], i32* %[[I]], align 4 92 // IR-NEXT: store i32 0, i32* %[[DOTUNROLLED_IV_J]], align 4 93 // IR-NEXT: %[[TMP19:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_]], align 4 94 // IR-NEXT: %[[TMP20:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_2]], align 4 95 // IR-NEXT: %[[CMP:.+]] = icmp slt i32 %[[TMP19]], %[[TMP20]] 96 // IR-NEXT: br i1 %[[CMP]], label %[[LAND_LHS_TRUE:.+]], label %[[OMP_PRECOND_END:.+]] 97 // IR-EMPTY: 98 // IR-NEXT: [[LAND_LHS_TRUE]]: 99 // IR-NEXT: %[[TMP21:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_10]], align 4 100 // IR-NEXT: %[[CMP21:.+]] = icmp ult i32 0, %[[TMP21]] 101 // IR-NEXT: br i1 %[[CMP21]], label %[[OMP_PRECOND_THEN:.+]], label %[[OMP_PRECOND_END]] 102 // IR-EMPTY: 103 // IR-NEXT: [[OMP_PRECOND_THEN]]: 104 // IR-NEXT: store i64 0, i64* %[[DOTOMP_LB]], align 8 105 // IR-NEXT: %[[TMP22:.+]] = load i64, i64* %[[DOTCAPTURE_EXPR_12]], align 8 106 // IR-NEXT: store i64 %[[TMP22]], i64* %[[DOTOMP_UB]], align 8 107 // IR-NEXT: store i64 1, i64* %[[DOTOMP_STRIDE]], align 8 108 // IR-NEXT: store i32 0, i32* %[[DOTOMP_IS_LAST]], align 4 109 // IR-NEXT: call void @__kmpc_for_static_init_8(%struct.ident_t* @1, i32 %[[TMP0]], i32 34, i32* %[[DOTOMP_IS_LAST]], i64* %[[DOTOMP_LB]], i64* %[[DOTOMP_UB]], i64* %[[DOTOMP_STRIDE]], i64 1, i64 1) 110 // IR-NEXT: %[[TMP23:.+]] = load i64, i64* %[[DOTOMP_UB]], align 8 111 // IR-NEXT: %[[TMP24:.+]] = load i64, i64* %[[DOTCAPTURE_EXPR_12]], align 8 112 // IR-NEXT: %[[CMP24:.+]] = icmp sgt i64 %[[TMP23]], %[[TMP24]] 113 // IR-NEXT: br i1 %[[CMP24]], label %[[COND_TRUE:.+]], label %[[COND_FALSE:.+]] 114 // IR-EMPTY: 115 // IR-NEXT: [[COND_TRUE]]: 116 // IR-NEXT: %[[TMP25:.+]] = load i64, i64* %[[DOTCAPTURE_EXPR_12]], align 8 117 // IR-NEXT: br label %[[COND_END:.+]] 118 // IR-EMPTY: 119 // IR-NEXT: [[COND_FALSE]]: 120 // IR-NEXT: %[[TMP26:.+]] = load i64, i64* %[[DOTOMP_UB]], align 8 121 // IR-NEXT: br label %[[COND_END]] 122 // IR-EMPTY: 123 // IR-NEXT: [[COND_END]]: 124 // IR-NEXT: %[[COND:.+]] = phi i64 [ %[[TMP25]], %[[COND_TRUE]] ], [ %[[TMP26]], %[[COND_FALSE]] ] 125 // IR-NEXT: store i64 %[[COND]], i64* %[[DOTOMP_UB]], align 8 126 // IR-NEXT: %[[TMP27:.+]] = load i64, i64* %[[DOTOMP_LB]], align 8 127 // IR-NEXT: store i64 %[[TMP27]], i64* %[[DOTOMP_IV]], align 8 128 // IR-NEXT: br label %[[OMP_INNER_FOR_COND:.+]] 129 // IR-EMPTY: 130 // IR-NEXT: [[OMP_INNER_FOR_COND]]: 131 // IR-NEXT: %[[TMP28:.+]] = load i64, i64* %[[DOTOMP_IV]], align 8 132 // IR-NEXT: %[[TMP29:.+]] = load i64, i64* %[[DOTOMP_UB]], align 8 133 // IR-NEXT: %[[CMP25:.+]] = icmp sle i64 %[[TMP28]], %[[TMP29]] 134 // IR-NEXT: br i1 %[[CMP25]], label %[[OMP_INNER_FOR_BODY:.+]], label %[[OMP_INNER_FOR_END:.+]] 135 // IR-EMPTY: 136 // IR-NEXT: [[OMP_INNER_FOR_BODY]]: 137 // IR-NEXT: %[[TMP30:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_]], align 4 138 // IR-NEXT: %[[CONV26:.+]] = sext i32 %[[TMP30]] to i64 139 // IR-NEXT: %[[TMP31:.+]] = load i64, i64* %[[DOTOMP_IV]], align 8 140 // IR-NEXT: %[[TMP32:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_10]], align 4 141 // IR-NEXT: %[[SUB27:.+]] = sub i32 %[[TMP32]], -1 142 // IR-NEXT: %[[DIV28:.+]] = udiv i32 %[[SUB27]], 2 143 // IR-NEXT: %[[MUL29:.+]] = mul i32 1, %[[DIV28]] 144 // IR-NEXT: %[[CONV30:.+]] = zext i32 %[[MUL29]] to i64 145 // IR-NEXT: %[[DIV31:.+]] = sdiv i64 %[[TMP31]], %[[CONV30]] 146 // IR-NEXT: %[[TMP33:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_3]], align 4 147 // IR-NEXT: %[[CONV32:.+]] = sext i32 %[[TMP33]] to i64 148 // IR-NEXT: %[[MUL33:.+]] = mul nsw i64 %[[DIV31]], %[[CONV32]] 149 // IR-NEXT: %[[ADD34:.+]] = add nsw i64 %[[CONV26]], %[[MUL33]] 150 // IR-NEXT: %[[CONV35:.+]] = trunc i64 %[[ADD34]] to i32 151 // IR-NEXT: store i32 %[[CONV35]], i32* %[[I22]], align 4 152 // IR-NEXT: %[[TMP34:.+]] = load i64, i64* %[[DOTOMP_IV]], align 8 153 // IR-NEXT: %[[TMP35:.+]] = load i64, i64* %[[DOTOMP_IV]], align 8 154 // IR-NEXT: %[[TMP36:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_10]], align 4 155 // IR-NEXT: %[[SUB36:.+]] = sub i32 %[[TMP36]], -1 156 // IR-NEXT: %[[DIV37:.+]] = udiv i32 %[[SUB36]], 2 157 // IR-NEXT: %[[MUL38:.+]] = mul i32 1, %[[DIV37]] 158 // IR-NEXT: %[[CONV39:.+]] = zext i32 %[[MUL38]] to i64 159 // IR-NEXT: %[[DIV40:.+]] = sdiv i64 %[[TMP35]], %[[CONV39]] 160 // IR-NEXT: %[[TMP37:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_10]], align 4 161 // IR-NEXT: %[[SUB41:.+]] = sub i32 %[[TMP37]], -1 162 // IR-NEXT: %[[DIV42:.+]] = udiv i32 %[[SUB41]], 2 163 // IR-NEXT: %[[MUL43:.+]] = mul i32 1, %[[DIV42]] 164 // IR-NEXT: %[[CONV44:.+]] = zext i32 %[[MUL43]] to i64 165 // IR-NEXT: %[[MUL45:.+]] = mul nsw i64 %[[DIV40]], %[[CONV44]] 166 // IR-NEXT: %[[SUB46:.+]] = sub nsw i64 %[[TMP34]], %[[MUL45]] 167 // IR-NEXT: %[[MUL47:.+]] = mul nsw i64 %[[SUB46]], 2 168 // IR-NEXT: %[[ADD48:.+]] = add nsw i64 0, %[[MUL47]] 169 // IR-NEXT: %[[CONV49:.+]] = trunc i64 %[[ADD48]] to i32 170 // IR-NEXT: store i32 %[[CONV49]], i32* %[[DOTUNROLLED_IV_J23]], align 4 171 // IR-NEXT: %[[TMP38:.+]] = load i32, i32* %[[DOTUNROLLED_IV_J23]], align 4 172 // IR-NEXT: store i32 %[[TMP38]], i32* %[[DOTUNROLL_INNER_IV_J]], align 4 173 // IR-NEXT: br label %[[FOR_COND:.+]] 174 // IR-EMPTY: 175 // IR-NEXT: [[FOR_COND]]: 176 // IR-NEXT: %[[TMP39:.+]] = load i32, i32* %[[DOTUNROLL_INNER_IV_J]], align 4 177 // IR-NEXT: %[[TMP40:.+]] = load i32, i32* %[[DOTUNROLLED_IV_J23]], align 4 178 // IR-NEXT: %[[ADD50:.+]] = add i32 %[[TMP40]], 2 179 // IR-NEXT: %[[CMP51:.+]] = icmp ult i32 %[[TMP39]], %[[ADD50]] 180 // IR-NEXT: br i1 %[[CMP51]], label %[[LAND_RHS:.+]], label %[[LAND_END:.+]] 181 // IR-EMPTY: 182 // IR-NEXT: [[LAND_RHS]]: 183 // IR-NEXT: %[[TMP41:.+]] = load i32, i32* %[[DOTUNROLL_INNER_IV_J]], align 4 184 // IR-NEXT: %[[TMP42:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_7]], align 4 185 // IR-NEXT: %[[ADD52:.+]] = add i32 %[[TMP42]], 1 186 // IR-NEXT: %[[CMP53:.+]] = icmp ult i32 %[[TMP41]], %[[ADD52]] 187 // IR-NEXT: br label %[[LAND_END]] 188 // IR-EMPTY: 189 // IR-NEXT: [[LAND_END]]: 190 // IR-NEXT: %[[TMP43:.+]] = phi i1 [ false, %[[FOR_COND]] ], [ %[[CMP53]], %[[LAND_RHS]] ] 191 // IR-NEXT: br i1 %[[TMP43]], label %[[FOR_BODY:.+]], label %[[FOR_END:.+]] 192 // IR-EMPTY: 193 // IR-NEXT: [[FOR_BODY]]: 194 // IR-NEXT: %[[TMP44:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_4]], align 4 195 // IR-NEXT: %[[TMP45:.+]] = load i32, i32* %[[DOTUNROLL_INNER_IV_J]], align 4 196 // IR-NEXT: %[[TMP46:.+]] = load i32, i32* %[[DOTCAPTURE_EXPR_6]], align 4 197 // IR-NEXT: %[[MUL54:.+]] = mul i32 %[[TMP45]], %[[TMP46]] 198 // IR-NEXT: %[[ADD55:.+]] = add i32 %[[TMP44]], %[[MUL54]] 199 // IR-NEXT: store i32 %[[ADD55]], i32* %[[J]], align 4 200 // IR-NEXT: %[[TMP47:.+]] = load i32, i32* %[[START_ADDR]], align 4 201 // IR-NEXT: %[[TMP48:.+]] = load i32, i32* %[[END_ADDR]], align 4 202 // IR-NEXT: %[[TMP49:.+]] = load i32, i32* %[[STEP_ADDR]], align 4 203 // IR-NEXT: %[[TMP50:.+]] = load i32, i32* %[[I22]], align 4 204 // IR-NEXT: %[[TMP51:.+]] = load i32, i32* %[[J]], align 4 205 // IR-NEXT: call void (...) @body(i32 noundef %[[TMP47]], i32 noundef %[[TMP48]], i32 noundef %[[TMP49]], i32 noundef %[[TMP50]], i32 noundef %[[TMP51]]) 206 // IR-NEXT: br label %[[FOR_INC:.+]] 207 // IR-EMPTY: 208 // IR-NEXT: [[FOR_INC]]: 209 // IR-NEXT: %[[TMP52:.+]] = load i32, i32* %[[DOTUNROLL_INNER_IV_J]], align 4 210 // IR-NEXT: %[[INC:.+]] = add i32 %[[TMP52]], 1 211 // IR-NEXT: store i32 %[[INC]], i32* %[[DOTUNROLL_INNER_IV_J]], align 4 212 // IR-NEXT: br label %[[FOR_COND]], !llvm.loop ![[LOOP2:[0-9]+]] 213 // IR-EMPTY: 214 // IR-NEXT: [[FOR_END]]: 215 // IR-NEXT: br label %[[OMP_BODY_CONTINUE:.+]] 216 // IR-EMPTY: 217 // IR-NEXT: [[OMP_BODY_CONTINUE]]: 218 // IR-NEXT: br label %[[OMP_INNER_FOR_INC:.+]] 219 // IR-EMPTY: 220 // IR-NEXT: [[OMP_INNER_FOR_INC]]: 221 // IR-NEXT: %[[TMP53:.+]] = load i64, i64* %[[DOTOMP_IV]], align 8 222 // IR-NEXT: %[[ADD56:.+]] = add nsw i64 %[[TMP53]], 1 223 // IR-NEXT: store i64 %[[ADD56]], i64* %[[DOTOMP_IV]], align 8 224 // IR-NEXT: br label %[[OMP_INNER_FOR_COND]] 225 // IR-EMPTY: 226 // IR-NEXT: [[OMP_INNER_FOR_END]]: 227 // IR-NEXT: br label %[[OMP_LOOP_EXIT:.+]] 228 // IR-EMPTY: 229 // IR-NEXT: [[OMP_LOOP_EXIT]]: 230 // IR-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* @1, i32 %[[TMP0]]) 231 // IR-NEXT: br label %[[OMP_PRECOND_END]] 232 // IR-EMPTY: 233 // IR-NEXT: [[OMP_PRECOND_END]]: 234 // IR-NEXT: call void @__kmpc_barrier(%struct.ident_t* @3, i32 %[[TMP0]]) 235 // IR-NEXT: ret void 236 // IR-NEXT: } 237 extern "C" void func(int start, int end, int step) { 238 #pragma omp for collapse(2) 239 for (int i = start; i < end; i+=step) { 240 #pragma omp unroll partial 241 for (int j = start; j < end; j+=step) 242 body(start, end, step, i, j); 243 } 244 } 245 246 #endif /* HEADER */ 247 248 249 // IR: ![[LOOP2]] = distinct !{![[LOOP2]], ![[LOOPPROP3:[0-9]+]], ![[LOOPPROP4:[0-9]+]]} 250 // IR: ![[LOOPPROP3]] = !{!"llvm.loop.mustprogress"} 251 // IR: ![[LOOPPROP4]] = !{!"llvm.loop.unroll.count", i32 2} 252