1// RUN: mlir-opt -allow-unregistered-dialect %s -split-input-file -verify-diagnostics 2 3func @loop_for_lb(%arg0: f32, %arg1: index) { 4 // expected-error@+1 {{operand #0 must be index}} 5 "scf.for"(%arg0, %arg1, %arg1) ({}) : (f32, index, index) -> () 6 return 7} 8 9// ----- 10 11func @loop_for_ub(%arg0: f32, %arg1: index) { 12 // expected-error@+1 {{operand #1 must be index}} 13 "scf.for"(%arg1, %arg0, %arg1) ({}) : (index, f32, index) -> () 14 return 15} 16 17// ----- 18 19func @loop_for_step(%arg0: f32, %arg1: index) { 20 // expected-error@+1 {{operand #2 must be index}} 21 "scf.for"(%arg1, %arg1, %arg0) ({}) : (index, index, f32) -> () 22 return 23} 24 25// ----- 26 27func @loop_for_step_positive(%arg0: index) { 28 // expected-error@+2 {{constant step operand must be positive}} 29 %c0 = constant 0 : index 30 "scf.for"(%arg0, %arg0, %c0) ({ 31 ^bb0(%arg1: index): 32 scf.yield 33 }) : (index, index, index) -> () 34 return 35} 36 37// ----- 38 39func @loop_for_one_region(%arg0: index) { 40 // expected-error@+1 {{requires one region}} 41 "scf.for"(%arg0, %arg0, %arg0) ( 42 {scf.yield}, 43 {scf.yield} 44 ) : (index, index, index) -> () 45 return 46} 47 48// ----- 49 50func @loop_for_single_block(%arg0: index) { 51 // expected-error@+1 {{expects region #0 to have 0 or 1 blocks}} 52 "scf.for"(%arg0, %arg0, %arg0) ( 53 { 54 ^bb1: 55 scf.yield 56 ^bb2: 57 scf.yield 58 } 59 ) : (index, index, index) -> () 60 return 61} 62 63// ----- 64 65func @loop_for_single_index_argument(%arg0: index) { 66 // expected-error@+1 {{op expected body first argument to be an index argument for the induction variable}} 67 "scf.for"(%arg0, %arg0, %arg0) ( 68 { 69 ^bb0(%i0 : f32): 70 scf.yield 71 } 72 ) : (index, index, index) -> () 73 return 74} 75 76// ----- 77 78func @loop_if_not_i1(%arg0: index) { 79 // expected-error@+1 {{operand #0 must be 1-bit signless integer}} 80 "scf.if"(%arg0) ({}, {}) : (index) -> () 81 return 82} 83 84// ----- 85 86func @loop_if_more_than_2_regions(%arg0: i1) { 87 // expected-error@+1 {{expected 2 regions}} 88 "scf.if"(%arg0) ({}, {}, {}): (i1) -> () 89 return 90} 91 92// ----- 93 94func @loop_if_not_one_block_per_region(%arg0: i1) { 95 // expected-error@+1 {{expects region #0 to have 0 or 1 blocks}} 96 "scf.if"(%arg0) ({ 97 ^bb0: 98 scf.yield 99 ^bb1: 100 scf.yield 101 }, {}): (i1) -> () 102 return 103} 104 105// ----- 106 107func @loop_if_illegal_block_argument(%arg0: i1) { 108 // expected-error@+1 {{region #0 should have no arguments}} 109 "scf.if"(%arg0) ({ 110 ^bb0(%0 : index): 111 scf.yield 112 }, {}): (i1) -> () 113 return 114} 115 116// ----- 117 118func @parallel_arguments_different_tuple_size( 119 %arg0: index, %arg1: index, %arg2: index) { 120 // expected-error@+1 {{custom op 'scf.parallel' expected 1 operands}} 121 scf.parallel (%i0) = (%arg0) to (%arg1, %arg2) step () { 122 } 123 return 124} 125 126// ----- 127 128func @parallel_body_arguments_wrong_type( 129 %arg0: index, %arg1: index, %arg2: index) { 130 // expected-error@+1 {{'scf.parallel' op expects arguments for the induction variable to be of index type}} 131 "scf.parallel"(%arg0, %arg1, %arg2) ({ 132 ^bb0(%i0: f32): 133 scf.yield 134 }) {operand_segment_sizes = dense<[1, 1, 1, 0]>: vector<4xi32>}: (index, index, index) -> () 135 return 136} 137 138// ----- 139 140func @parallel_body_wrong_number_of_arguments( 141 %arg0: index, %arg1: index, %arg2: index) { 142 // expected-error@+1 {{'scf.parallel' op expects the same number of induction variables: 2 as bound and step values: 1}} 143 "scf.parallel"(%arg0, %arg1, %arg2) ({ 144 ^bb0(%i0: index, %i1: index): 145 scf.yield 146 }) {operand_segment_sizes = dense<[1, 1, 1, 0]>: vector<4xi32>}: (index, index, index) -> () 147 return 148} 149 150// ----- 151 152func @parallel_no_tuple_elements() { 153 // expected-error@+1 {{'scf.parallel' op needs at least one tuple element for lowerBound, upperBound and step}} 154 scf.parallel () = () to () step () { 155 } 156 return 157} 158 159// ----- 160 161func @parallel_step_not_positive( 162 %arg0: index, %arg1: index, %arg2: index, %arg3: index) { 163 // expected-error@+3 {{constant step operand must be positive}} 164 %c0 = constant 1 : index 165 %c1 = constant 0 : index 166 scf.parallel (%i0, %i1) = (%arg0, %arg1) to (%arg2, %arg3) step (%c0, %c1) { 167 } 168 return 169} 170 171// ----- 172 173func @parallel_fewer_results_than_reduces( 174 %arg0 : index, %arg1: index, %arg2: index) { 175 // expected-error@+1 {{expects number of results: 0 to be the same as number of reductions: 1}} 176 scf.parallel (%i0) = (%arg0) to (%arg1) step (%arg2) { 177 %c0 = constant 1.0 : f32 178 scf.reduce(%c0) : f32 { 179 ^bb0(%lhs: f32, %rhs: f32): 180 scf.reduce.return %lhs : f32 181 } 182 } 183 return 184} 185 186// ----- 187 188func @parallel_more_results_than_reduces( 189 %arg0 : index, %arg1 : index, %arg2 : index) { 190 // expected-error@+2 {{expects number of results: 1 to be the same as number of reductions: 0}} 191 %zero = constant 1.0 : f32 192 %res = scf.parallel (%i0) = (%arg0) to (%arg1) step (%arg2) init (%zero) -> f32 { 193 } 194 195 return 196} 197 198// ----- 199 200func @parallel_more_results_than_initial_values( 201 %arg0 : index, %arg1: index, %arg2: index) { 202 // expected-error@+1 {{expects number of results: 1 to be the same as number of initial values: 0}} 203 %res = scf.parallel (%i0) = (%arg0) to (%arg1) step (%arg2) -> f32 { 204 scf.reduce(%arg0) : index { 205 ^bb0(%lhs: index, %rhs: index): 206 scf.reduce.return %lhs : index 207 } 208 } 209} 210 211// ----- 212 213func @parallel_different_types_of_results_and_reduces( 214 %arg0 : index, %arg1: index, %arg2: index) { 215 %zero = constant 0.0 : f32 216 %res = scf.parallel (%i0) = (%arg0) to (%arg1) 217 step (%arg2) init (%zero) -> f32 { 218 // expected-error@+1 {{expects type of reduce: 'index' to be the same as result type: 'f32'}} 219 scf.reduce(%arg0) : index { 220 ^bb0(%lhs: index, %rhs: index): 221 scf.reduce.return %lhs : index 222 } 223 } 224 return 225} 226 227// ----- 228 229func @top_level_reduce(%arg0 : f32) { 230 // expected-error@+1 {{expects parent op 'scf.parallel'}} 231 scf.reduce(%arg0) : f32 { 232 ^bb0(%lhs : f32, %rhs : f32): 233 scf.reduce.return %lhs : f32 234 } 235 return 236} 237 238// ----- 239 240func @reduce_empty_block(%arg0 : index, %arg1 : f32) { 241 %zero = constant 0.0 : f32 242 %res = scf.parallel (%i0) = (%arg0) to (%arg0) 243 step (%arg0) init (%zero) -> f32 { 244 // expected-error@+1 {{the block inside reduce should not be empty}} 245 scf.reduce(%arg1) : f32 { 246 ^bb0(%lhs : f32, %rhs : f32): 247 } 248 } 249 return 250} 251 252// ----- 253 254func @reduce_too_many_args(%arg0 : index, %arg1 : f32) { 255 %zero = constant 0.0 : f32 256 %res = scf.parallel (%i0) = (%arg0) to (%arg0) 257 step (%arg0) init (%zero) -> f32 { 258 // expected-error@+1 {{expects two arguments to reduce block of type 'f32'}} 259 scf.reduce(%arg1) : f32 { 260 ^bb0(%lhs : f32, %rhs : f32, %other : f32): 261 scf.reduce.return %lhs : f32 262 } 263 } 264 return 265} 266 267// ----- 268 269func @reduce_wrong_args(%arg0 : index, %arg1 : f32) { 270 %zero = constant 0.0 : f32 271 %res = scf.parallel (%i0) = (%arg0) to (%arg0) 272 step (%arg0) init (%zero) -> f32 { 273 // expected-error@+1 {{expects two arguments to reduce block of type 'f32'}} 274 scf.reduce(%arg1) : f32 { 275 ^bb0(%lhs : f32, %rhs : i32): 276 scf.reduce.return %lhs : f32 277 } 278 } 279 return 280} 281 282 283// ----- 284 285func @reduce_wrong_terminator(%arg0 : index, %arg1 : f32) { 286 %zero = constant 0.0 : f32 287 %res = scf.parallel (%i0) = (%arg0) to (%arg0) 288 step (%arg0) init (%zero) -> f32 { 289 // expected-error@+1 {{the block inside reduce should be terminated with a 'scf.reduce.return' op}} 290 scf.reduce(%arg1) : f32 { 291 ^bb0(%lhs : f32, %rhs : f32): 292 scf.yield 293 } 294 } 295 return 296} 297 298// ----- 299 300func @reduceReturn_wrong_type(%arg0 : index, %arg1: f32) { 301 %zero = constant 0.0 : f32 302 %res = scf.parallel (%i0) = (%arg0) to (%arg0) 303 step (%arg0) init (%zero) -> f32 { 304 scf.reduce(%arg1) : f32 { 305 ^bb0(%lhs : f32, %rhs : f32): 306 %c0 = constant 1 : index 307 // expected-error@+1 {{needs to have type 'f32' (the type of the enclosing ReduceOp)}} 308 scf.reduce.return %c0 : index 309 } 310 } 311 return 312} 313 314// ----- 315 316func @reduceReturn_not_inside_reduce(%arg0 : f32) { 317 "foo.region"() ({ 318 // expected-error@+1 {{expects parent op 'scf.reduce'}} 319 scf.reduce.return %arg0 : f32 320 }): () -> () 321 return 322} 323 324// ----- 325 326func @std_if_incorrect_yield(%arg0: i1, %arg1: f32) 327{ 328 // expected-error@+1 {{region control flow edge from Region #0 to parent results: source has 1 operands, but target successor needs 2}} 329 %x, %y = scf.if %arg0 -> (f32, f32) { 330 %0 = addf %arg1, %arg1 : f32 331 scf.yield %0 : f32 332 } else { 333 %0 = subf %arg1, %arg1 : f32 334 scf.yield %0, %0 : f32, f32 335 } 336 return 337} 338 339// ----- 340 341func @std_if_missing_else(%arg0: i1, %arg1: f32) 342{ 343 // expected-error@+1 {{must have an else block if defining values}} 344 %x = scf.if %arg0 -> (f32) { 345 %0 = addf %arg1, %arg1 : f32 346 scf.yield %0 : f32 347 } 348 return 349} 350 351// ----- 352 353func @std_for_operands_mismatch(%arg0 : index, %arg1 : index, %arg2 : index) { 354 %s0 = constant 0.0 : f32 355 %t0 = constant 1 : i32 356 // expected-error@+1 {{mismatch in number of loop-carried values and defined values}} 357 %result1:3 = scf.for %i0 = %arg0 to %arg1 step %arg2 358 iter_args(%si = %s0, %ti = %t0) -> (f32, i32, f32) { 359 %sn = addf %si, %si : f32 360 %tn = addi %ti, %ti : i32 361 scf.yield %sn, %tn, %sn : f32, i32, f32 362 } 363 return 364} 365 366// ----- 367 368func @std_for_operands_mismatch_2(%arg0 : index, %arg1 : index, %arg2 : index) { 369 %s0 = constant 0.0 : f32 370 %t0 = constant 1 : i32 371 %u0 = constant 1.0 : f32 372 // expected-error@+1 {{mismatch in number of loop-carried values and defined values}} 373 %result1:2 = scf.for %i0 = %arg0 to %arg1 step %arg2 374 iter_args(%si = %s0, %ti = %t0, %ui = %u0) -> (f32, i32) { 375 %sn = addf %si, %si : f32 376 %tn = addi %ti, %ti : i32 377 %un = subf %ui, %ui : f32 378 scf.yield %sn, %tn, %un : f32, i32, f32 379 } 380 return 381} 382 383// ----- 384 385func @std_for_operands_mismatch_3(%arg0 : index, %arg1 : index, %arg2 : index) { 386 // expected-note@+1 {{prior use here}} 387 %s0 = constant 0.0 : f32 388 %t0 = constant 1.0 : f32 389 // expected-error@+2 {{expects different type than prior uses: 'i32' vs 'f32'}} 390 %result1:2 = scf.for %i0 = %arg0 to %arg1 step %arg2 391 iter_args(%si = %s0, %ti = %t0) -> (i32, i32) { 392 %sn = addf %si, %si : i32 393 %tn = addf %ti, %ti : i32 394 scf.yield %sn, %tn : i32, i32 395 } 396 return 397} 398 399// ----- 400 401func @std_for_operands_mismatch_4(%arg0 : index, %arg1 : index, %arg2 : index) { 402 %s0 = constant 0.0 : f32 403 %t0 = constant 1.0 : f32 404 // expected-error @+1 {{along control flow edge from Region #0 to Region #0: source type #1 'i32' should match input type #1 'f32'}} 405 %result1:2 = scf.for %i0 = %arg0 to %arg1 step %arg2 406 iter_args(%si = %s0, %ti = %t0) -> (f32, f32) { 407 %sn = addf %si, %si : f32 408 %ic = constant 1 : i32 409 scf.yield %sn, %ic : f32, i32 410 } 411 return 412} 413 414 415// ----- 416 417func @parallel_invalid_yield( 418 %arg0: index, %arg1: index, %arg2: index) { 419 scf.parallel (%i0) = (%arg0) to (%arg1) step (%arg2) { 420 %c0 = constant 1.0 : f32 421 // expected-error@+1 {{'scf.yield' op not allowed to have operands inside 'scf.parallel'}} 422 scf.yield %c0 : f32 423 } 424 return 425} 426 427// ----- 428 429func @yield_invalid_parent_op() { 430 "my.op"() ({ 431 // expected-error@+1 {{'scf.yield' op expects parent op to be one of 'scf.if, scf.for, scf.parallel, scf.while'}} 432 scf.yield 433 }) : () -> () 434 return 435} 436 437// ----- 438 439func @while_parser_type_mismatch() { 440 %true = constant true 441 // expected-error@+1 {{expected as many input types as operands (expected 0 got 1)}} 442 scf.while : (i32) -> () { 443 scf.condition(%true) 444 } do { 445 scf.yield 446 } 447} 448 449// ----- 450 451func @while_bad_terminator() { 452 // expected-error@+1 {{expects the 'before' region to terminate with 'scf.condition'}} 453 scf.while : () -> () { 454 // expected-note@+1 {{terminator here}} 455 "some.other_terminator"() : () -> () 456 } do { 457 scf.yield 458 } 459} 460 461// ----- 462 463func @while_cross_region_type_mismatch() { 464 %true = constant true 465 // expected-error@+1 {{expects the same number of trailing operands of the 'before' block terminator and 'after' region arguments}} 466 scf.while : () -> () { 467 scf.condition(%true) 468 } do { 469 ^bb0(%arg0: i32): 470 scf.yield 471 } 472} 473 474// ----- 475 476func @while_cross_region_type_mismatch() { 477 %true = constant true 478 // expected-error@+2 {{expects the same types for trailing operands of the 'before' block terminator and 'after' region arguments}} 479 // expected-note@+1 {{for argument 0, found 'i1' and 'i32}} 480 scf.while : () -> () { 481 scf.condition(%true) %true : i1 482 } do { 483 ^bb0(%arg0: i32): 484 scf.yield 485 } 486} 487 488// ----- 489 490func @while_result_type_mismatch() { 491 %true = constant true 492 // expected-error@+1 {{expects the same number of trailing operands of the 'before' block terminator and op results}} 493 scf.while : () -> () { 494 scf.condition(%true) %true : i1 495 } do { 496 ^bb0(%arg0: i1): 497 scf.yield 498 } 499} 500 501// ----- 502 503func @while_bad_terminator() { 504 %true = constant true 505 // expected-error@+1 {{expects the 'after' region to terminate with 'scf.yield'}} 506 scf.while : () -> () { 507 scf.condition(%true) 508 } do { 509 // expected-note@+1 {{terminator here}} 510 "some.other_terminator"() : () -> () 511 } 512} 513