1// RUN: mlir-opt -allow-unregistered-dialect -split-input-file -verify-diagnostics %s | FileCheck %s 2 3//===----------------------------------------------------------------------===// 4// spv.Branch 5//===----------------------------------------------------------------------===// 6 7func @branch() -> () { 8 // CHECK: spv.Branch ^bb1 9 spv.Branch ^next 10^next: 11 spv.Return 12} 13 14// ----- 15 16func @branch_argument() -> () { 17 %zero = spv.constant 0 : i32 18 // CHECK: spv.Branch ^bb1(%{{.*}}, %{{.*}} : i32, i32) 19 spv.Branch ^next(%zero, %zero: i32, i32) 20^next(%arg0: i32, %arg1: i32): 21 spv.Return 22} 23 24// ----- 25 26func @missing_accessor() -> () { 27 // expected-error @+2 {{expected block name}} 28 spv.Branch 29} 30 31// ----- 32 33func @wrong_accessor_count() -> () { 34 %true = spv.constant true 35 // expected-error @+1 {{requires 1 successor but found 2}} 36 "spv.Branch"()[^one, ^two] : () -> () 37^one: 38 spv.Return 39^two: 40 spv.Return 41} 42 43// ----- 44 45//===----------------------------------------------------------------------===// 46// spv.BranchConditional 47//===----------------------------------------------------------------------===// 48 49func @cond_branch() -> () { 50 %true = spv.constant true 51 // CHECK: spv.BranchConditional %{{.*}}, ^bb1, ^bb2 52 spv.BranchConditional %true, ^one, ^two 53// CHECK: ^bb1 54^one: 55 spv.Return 56// CHECK: ^bb2 57^two: 58 spv.Return 59} 60 61// ----- 62 63func @cond_branch_argument() -> () { 64 %true = spv.constant true 65 %zero = spv.constant 0 : i32 66 // CHECK: spv.BranchConditional %{{.*}}, ^bb1(%{{.*}}, %{{.*}} : i32, i32), ^bb2 67 spv.BranchConditional %true, ^true1(%zero, %zero: i32, i32), ^false1 68^true1(%arg0: i32, %arg1: i32): 69 // CHECK: spv.BranchConditional %{{.*}}, ^bb3, ^bb4(%{{.*}}, %{{.*}} : i32, i32) 70 spv.BranchConditional %true, ^true2, ^false2(%zero, %zero: i32, i32) 71^false1: 72 spv.Return 73^true2: 74 spv.Return 75^false2(%arg3: i32, %arg4: i32): 76 spv.Return 77} 78 79// ----- 80 81func @cond_branch_with_weights() -> () { 82 %true = spv.constant true 83 // CHECK: spv.BranchConditional %{{.*}} [5, 10] 84 spv.BranchConditional %true [5, 10], ^one, ^two 85^one: 86 spv.Return 87^two: 88 spv.Return 89} 90 91// ----- 92 93func @missing_condition() -> () { 94 // expected-error @+1 {{expected SSA operand}} 95 spv.BranchConditional ^one, ^two 96^one: 97 spv.Return 98^two: 99 spv.Return 100} 101 102// ----- 103 104func @wrong_condition_type() -> () { 105 // expected-note @+1 {{prior use here}} 106 %zero = spv.constant 0 : i32 107 // expected-error @+1 {{use of value '%zero' expects different type than prior uses: 'i1' vs 'i32'}} 108 spv.BranchConditional %zero, ^one, ^two 109^one: 110 spv.Return 111^two: 112 spv.Return 113} 114 115// ----- 116 117func @wrong_accessor_count() -> () { 118 %true = spv.constant true 119 // expected-error @+1 {{requires 2 successors but found 1}} 120 "spv.BranchConditional"(%true)[^one] {operand_segment_sizes = dense<[1, 0, 0]>: vector<3xi32>} : (i1) -> () 121^one: 122 spv.Return 123^two: 124 spv.Return 125} 126 127// ----- 128 129func @wrong_number_of_weights() -> () { 130 %true = spv.constant true 131 // expected-error @+1 {{must have exactly two branch weights}} 132 "spv.BranchConditional"(%true)[^one, ^two] {branch_weights = [1 : i32, 2 : i32, 3 : i32], 133 operand_segment_sizes = dense<[1, 0, 0]>: vector<3xi32>} : (i1) -> () 134^one: 135 spv.Return 136^two: 137 spv.Return 138} 139 140// ----- 141 142func @weights_cannot_both_be_zero() -> () { 143 %true = spv.constant true 144 // expected-error @+1 {{branch weights cannot both be zero}} 145 spv.BranchConditional %true [0, 0], ^one, ^two 146^one: 147 spv.Return 148^two: 149 spv.Return 150} 151 152// ----- 153 154//===----------------------------------------------------------------------===// 155// spv.FunctionCall 156//===----------------------------------------------------------------------===// 157 158spv.module Logical GLSL450 { 159 spv.func @fmain(%arg0 : vector<4xf32>, %arg1 : vector<4xf32>, %arg2 : i32) -> i32 "None" { 160 // CHECK: {{%.*}} = spv.FunctionCall @f_0({{%.*}}, {{%.*}}) : (vector<4xf32>, vector<4xf32>) -> vector<4xf32> 161 %0 = spv.FunctionCall @f_0(%arg0, %arg1) : (vector<4xf32>, vector<4xf32>) -> vector<4xf32> 162 // CHECK: spv.FunctionCall @f_1({{%.*}}, {{%.*}}) : (vector<4xf32>, vector<4xf32>) -> () 163 spv.FunctionCall @f_1(%0, %arg1) : (vector<4xf32>, vector<4xf32>) -> () 164 // CHECK: spv.FunctionCall @f_2() : () -> () 165 spv.FunctionCall @f_2() : () -> () 166 // CHECK: {{%.*}} = spv.FunctionCall @f_3({{%.*}}) : (i32) -> i32 167 %1 = spv.FunctionCall @f_3(%arg2) : (i32) -> i32 168 spv.ReturnValue %1 : i32 169 } 170 171 spv.func @f_0(%arg0 : vector<4xf32>, %arg1 : vector<4xf32>) -> (vector<4xf32>) "None" { 172 spv.ReturnValue %arg0 : vector<4xf32> 173 } 174 175 spv.func @f_1(%arg0 : vector<4xf32>, %arg1 : vector<4xf32>) -> () "None" { 176 spv.Return 177 } 178 179 spv.func @f_2() -> () "None" { 180 spv.Return 181 } 182 183 spv.func @f_3(%arg0 : i32) -> (i32) "None" { 184 spv.ReturnValue %arg0 : i32 185 } 186} 187 188// ----- 189 190// Allow calling functions in other module-like ops 191spv.func @callee() "None" { 192 spv.Return 193} 194 195func @caller() { 196 // CHECK: spv.FunctionCall 197 spv.FunctionCall @callee() : () -> () 198 spv.Return 199} 200 201// ----- 202 203spv.module Logical GLSL450 { 204 spv.func @f_invalid_result_type(%arg0 : i32, %arg1 : i32) -> () "None" { 205 // expected-error @+1 {{result group starting at #0 requires 0 or 1 element, but found 2}} 206 %0:2 = spv.FunctionCall @f_invalid_result_type(%arg0, %arg1) : (i32, i32) -> (i32, i32) 207 spv.Return 208 } 209} 210 211// ----- 212 213spv.module Logical GLSL450 { 214 spv.func @f_result_type_mismatch(%arg0 : i32, %arg1 : i32) -> () "None" { 215 // expected-error @+1 {{has incorrect number of results has for callee: expected 0, but provided 1}} 216 %1 = spv.FunctionCall @f_result_type_mismatch(%arg0, %arg0) : (i32, i32) -> (i32) 217 spv.Return 218 } 219} 220 221// ----- 222 223spv.module Logical GLSL450 { 224 spv.func @f_type_mismatch(%arg0 : i32, %arg1 : i32) -> () "None" { 225 // expected-error @+1 {{has incorrect number of operands for callee: expected 2, but provided 1}} 226 spv.FunctionCall @f_type_mismatch(%arg0) : (i32) -> () 227 spv.Return 228 } 229} 230 231// ----- 232 233spv.module Logical GLSL450 { 234 spv.func @f_type_mismatch(%arg0 : i32, %arg1 : i32) -> () "None" { 235 %0 = spv.constant 2.0 : f32 236 // expected-error @+1 {{operand type mismatch: expected operand type 'i32', but provided 'f32' for operand number 1}} 237 spv.FunctionCall @f_type_mismatch(%arg0, %0) : (i32, f32) -> () 238 spv.Return 239 } 240} 241 242// ----- 243 244spv.module Logical GLSL450 { 245 spv.func @f_type_mismatch(%arg0 : i32, %arg1 : i32) -> i32 "None" { 246 %cst = spv.constant 0: i32 247 // expected-error @+1 {{result type mismatch: expected 'i32', but provided 'f32'}} 248 %0 = spv.FunctionCall @f_type_mismatch(%arg0, %arg0) : (i32, i32) -> f32 249 spv.ReturnValue %cst: i32 250 } 251} 252 253// ----- 254 255spv.module Logical GLSL450 { 256 spv.func @f_foo(%arg0 : i32, %arg1 : i32) -> i32 "None" { 257 // expected-error @+1 {{op callee function 'f_undefined' not found in nearest symbol table}} 258 %0 = spv.FunctionCall @f_undefined(%arg0, %arg0) : (i32, i32) -> i32 259 spv.ReturnValue %0: i32 260 } 261} 262 263// ----- 264 265//===----------------------------------------------------------------------===// 266// spv.loop 267//===----------------------------------------------------------------------===// 268 269// for (int i = 0; i < count; ++i) {} 270func @loop(%count : i32) -> () { 271 %zero = spv.constant 0: i32 272 %one = spv.constant 1: i32 273 %var = spv.Variable init(%zero) : !spv.ptr<i32, Function> 274 275 // CHECK: spv.loop { 276 spv.loop { 277 // CHECK-NEXT: spv.Branch ^bb1 278 spv.Branch ^header 279 280 // CHECK-NEXT: ^bb1: 281 ^header: 282 %val0 = spv.Load "Function" %var : i32 283 %cmp = spv.SLessThan %val0, %count : i32 284 // CHECK: spv.BranchConditional %{{.*}}, ^bb2, ^bb4 285 spv.BranchConditional %cmp, ^body, ^merge 286 287 // CHECK-NEXT: ^bb2: 288 ^body: 289 // Do nothing 290 // CHECK-NEXT: spv.Branch ^bb3 291 spv.Branch ^continue 292 293 // CHECK-NEXT: ^bb3: 294 ^continue: 295 %val1 = spv.Load "Function" %var : i32 296 %add = spv.IAdd %val1, %one : i32 297 spv.Store "Function" %var, %add : i32 298 // CHECK: spv.Branch ^bb1 299 spv.Branch ^header 300 301 // CHECK-NEXT: ^bb4: 302 ^merge: 303 spv.mlir.merge 304 } 305 return 306} 307 308// ----- 309 310// CHECK-LABEL: @empty_region 311func @empty_region() -> () { 312 // CHECK: spv.loop 313 spv.loop { 314 } 315 return 316} 317 318// ----- 319 320// CHECK-LABEL: @loop_with_control 321func @loop_with_control() -> () { 322 // CHECK: spv.loop control(Unroll) 323 spv.loop control(Unroll) { 324 } 325 return 326} 327 328// ----- 329 330func @wrong_merge_block() -> () { 331 // expected-error @+1 {{last block must be the merge block with only one 'spv.mlir.merge' op}} 332 spv.loop { 333 spv.Return 334 } 335 return 336} 337 338// ----- 339 340func @missing_entry_block() -> () { 341 // expected-error @+1 {{must have an entry block branching to the loop header block}} 342 spv.loop { 343 spv.mlir.merge 344 } 345 return 346} 347 348// ----- 349 350func @missing_header_block() -> () { 351 // expected-error @+1 {{must have a loop header block branched from the entry block}} 352 spv.loop { 353 ^entry: 354 spv.Branch ^merge 355 ^merge: 356 spv.mlir.merge 357 } 358 return 359} 360 361// ----- 362 363func @entry_should_branch_to_header() -> () { 364 // expected-error @+1 {{entry block must only have one 'spv.Branch' op to the second block}} 365 spv.loop { 366 ^entry: 367 spv.Branch ^merge 368 ^header: 369 spv.Branch ^merge 370 ^merge: 371 spv.mlir.merge 372 } 373 return 374} 375 376// ----- 377 378func @missing_continue_block() -> () { 379 // expected-error @+1 {{requires a loop continue block branching to the loop header block}} 380 spv.loop { 381 ^entry: 382 spv.Branch ^header 383 ^header: 384 spv.Branch ^merge 385 ^merge: 386 spv.mlir.merge 387 } 388 return 389} 390 391// ----- 392 393func @continue_should_branch_to_header() -> () { 394 // expected-error @+1 {{second to last block must be the loop continue block that branches to the loop header block}} 395 spv.loop { 396 ^entry: 397 spv.Branch ^header 398 ^header: 399 spv.Branch ^continue 400 ^continue: 401 spv.Branch ^merge 402 ^merge: 403 spv.mlir.merge 404 } 405 return 406} 407 408// ----- 409 410func @only_entry_and_continue_branch_to_header() -> () { 411 // expected-error @+1 {{can only have the entry and loop continue block branching to the loop header block}} 412 spv.loop { 413 ^entry: 414 spv.Branch ^header 415 ^header: 416 spv.Branch ^cont1 417 ^cont1: 418 spv.Branch ^header 419 ^cont2: 420 spv.Branch ^header 421 ^merge: 422 spv.mlir.merge 423 } 424 return 425} 426 427// ----- 428 429//===----------------------------------------------------------------------===// 430// spv.mlir.merge 431//===----------------------------------------------------------------------===// 432 433func @merge() -> () { 434 // expected-error @+1 {{expected parent op to be 'spv.selection' or 'spv.loop'}} 435 spv.mlir.merge 436} 437 438// ----- 439 440func @only_allowed_in_last_block(%cond : i1) -> () { 441 %zero = spv.constant 0: i32 442 %one = spv.constant 1: i32 443 %var = spv.Variable init(%zero) : !spv.ptr<i32, Function> 444 445 spv.selection { 446 spv.BranchConditional %cond, ^then, ^merge 447 448 ^then: 449 spv.Store "Function" %var, %one : i32 450 // expected-error @+1 {{can only be used in the last block of 'spv.selection' or 'spv.loop'}} 451 spv.mlir.merge 452 453 ^merge: 454 spv.mlir.merge 455 } 456 457 spv.Return 458} 459 460// ----- 461 462func @only_allowed_in_last_block() -> () { 463 %true = spv.constant true 464 spv.loop { 465 spv.Branch ^header 466 ^header: 467 spv.BranchConditional %true, ^body, ^merge 468 ^body: 469 // expected-error @+1 {{can only be used in the last block of 'spv.selection' or 'spv.loop'}} 470 spv.mlir.merge 471 ^continue: 472 spv.Branch ^header 473 ^merge: 474 spv.mlir.merge 475 } 476 return 477} 478 479// ----- 480 481//===----------------------------------------------------------------------===// 482// spv.Return 483//===----------------------------------------------------------------------===// 484 485// CHECK-LABEL: func @in_selection 486func @in_selection(%cond : i1) -> () { 487 spv.selection { 488 spv.BranchConditional %cond, ^then, ^merge 489 ^then: 490 // CHECK: spv.Return 491 spv.Return 492 ^merge: 493 spv.mlir.merge 494 } 495 spv.Return 496} 497 498// CHECK-LABEL: func @in_loop 499func @in_loop(%cond : i1) -> () { 500 spv.loop { 501 spv.Branch ^header 502 ^header: 503 spv.BranchConditional %cond, ^body, ^merge 504 ^body: 505 // CHECK: spv.Return 506 spv.Return 507 ^continue: 508 spv.Branch ^header 509 ^merge: 510 spv.mlir.merge 511 } 512 spv.Return 513} 514 515// CHECK-LABEL: in_other_func_like_op 516func @in_other_func_like_op() { 517 // CHECK: spv.Return 518 spv.Return 519} 520 521// ----- 522 523"foo.function"() ({ 524 // expected-error @+1 {{op must appear in a function-like op's block}} 525 spv.Return 526}) : () -> () 527 528// ----- 529 530// Return mismatches function signature 531spv.module Logical GLSL450 { 532 spv.func @work() -> (i32) "None" { 533 // expected-error @+1 {{cannot be used in functions returning value}} 534 spv.Return 535 } 536} 537 538// ----- 539 540spv.module Logical GLSL450 { 541 spv.func @in_nested_region(%cond: i1) -> (i32) "None" { 542 spv.selection { 543 spv.BranchConditional %cond, ^then, ^merge 544 ^then: 545 // expected-error @+1 {{cannot be used in functions returning value}} 546 spv.Return 547 ^merge: 548 spv.mlir.merge 549 } 550 551 %zero = spv.constant 0: i32 552 spv.ReturnValue %zero: i32 553 } 554} 555 556// ----- 557 558//===----------------------------------------------------------------------===// 559// spv.ReturnValue 560//===----------------------------------------------------------------------===// 561 562func @ret_val() -> (i32) { 563 %0 = spv.constant 42 : i32 564 // CHECK: spv.ReturnValue %{{.*}} : i32 565 spv.ReturnValue %0 : i32 566} 567 568// CHECK-LABEL: func @in_selection 569func @in_selection(%cond : i1) -> (i32) { 570 spv.selection { 571 spv.BranchConditional %cond, ^then, ^merge 572 ^then: 573 %zero = spv.constant 0 : i32 574 // CHECK: spv.ReturnValue 575 spv.ReturnValue %zero : i32 576 ^merge: 577 spv.mlir.merge 578 } 579 %one = spv.constant 1 : i32 580 spv.ReturnValue %one : i32 581} 582 583// CHECK-LABEL: func @in_loop 584func @in_loop(%cond : i1) -> (i32) { 585 spv.loop { 586 spv.Branch ^header 587 ^header: 588 spv.BranchConditional %cond, ^body, ^merge 589 ^body: 590 %zero = spv.constant 0 : i32 591 // CHECK: spv.ReturnValue 592 spv.ReturnValue %zero : i32 593 ^continue: 594 spv.Branch ^header 595 ^merge: 596 spv.mlir.merge 597 } 598 %one = spv.constant 1 : i32 599 spv.ReturnValue %one : i32 600} 601 602// CHECK-LABEL: in_other_func_like_op 603func @in_other_func_like_op(%arg: i32) -> i32 { 604 // CHECK: spv.ReturnValue 605 spv.ReturnValue %arg: i32 606} 607 608// ----- 609 610"foo.function"() ({ 611 %0 = spv.constant true 612 // expected-error @+1 {{op must appear in a function-like op's block}} 613 spv.ReturnValue %0 : i1 614}) : () -> () 615 616// ----- 617 618spv.module Logical GLSL450 { 619 spv.func @value_count_mismatch() -> () "None" { 620 %0 = spv.constant 42 : i32 621 // expected-error @+1 {{op returns 1 value but enclosing function requires 0 results}} 622 spv.ReturnValue %0 : i32 623 } 624} 625 626// ----- 627 628spv.module Logical GLSL450 { 629 spv.func @value_type_mismatch() -> (f32) "None" { 630 %0 = spv.constant 42 : i32 631 // expected-error @+1 {{return value's type ('i32') mismatch with function's result type ('f32')}} 632 spv.ReturnValue %0 : i32 633 } 634} 635 636// ----- 637 638spv.module Logical GLSL450 { 639 spv.func @in_nested_region(%cond: i1) -> () "None" { 640 spv.selection { 641 spv.BranchConditional %cond, ^then, ^merge 642 ^then: 643 %cst = spv.constant 0: i32 644 // expected-error @+1 {{op returns 1 value but enclosing function requires 0 results}} 645 spv.ReturnValue %cst: i32 646 ^merge: 647 spv.mlir.merge 648 } 649 650 spv.Return 651 } 652} 653 654// ----- 655 656//===----------------------------------------------------------------------===// 657// spv.selection 658//===----------------------------------------------------------------------===// 659 660func @selection(%cond: i1) -> () { 661 %zero = spv.constant 0: i32 662 %one = spv.constant 1: i32 663 %var = spv.Variable init(%zero) : !spv.ptr<i32, Function> 664 665 // CHECK: spv.selection { 666 spv.selection { 667 // CHECK-NEXT: spv.BranchConditional %{{.*}}, ^bb1, ^bb2 668 spv.BranchConditional %cond, ^then, ^merge 669 670 // CHECK: ^bb1 671 ^then: 672 spv.Store "Function" %var, %one : i32 673 // CHECK: spv.Branch ^bb2 674 spv.Branch ^merge 675 676 // CHECK: ^bb2 677 ^merge: 678 // CHECK-NEXT: spv.mlir.merge 679 spv.mlir.merge 680 } 681 682 spv.Return 683} 684 685// ----- 686 687func @selection(%cond: i1) -> () { 688 %zero = spv.constant 0: i32 689 %one = spv.constant 1: i32 690 %two = spv.constant 2: i32 691 %var = spv.Variable init(%zero) : !spv.ptr<i32, Function> 692 693 // CHECK: spv.selection { 694 spv.selection { 695 // CHECK-NEXT: spv.BranchConditional %{{.*}}, ^bb1, ^bb2 696 spv.BranchConditional %cond, ^then, ^else 697 698 // CHECK: ^bb1 699 ^then: 700 spv.Store "Function" %var, %one : i32 701 // CHECK: spv.Branch ^bb3 702 spv.Branch ^merge 703 704 // CHECK: ^bb2 705 ^else: 706 spv.Store "Function" %var, %two : i32 707 // CHECK: spv.Branch ^bb3 708 spv.Branch ^merge 709 710 // CHECK: ^bb3 711 ^merge: 712 // CHECK-NEXT: spv.mlir.merge 713 spv.mlir.merge 714 } 715 716 spv.Return 717} 718 719// ----- 720 721// CHECK-LABEL: @empty_region 722func @empty_region() -> () { 723 // CHECK: spv.selection 724 spv.selection { 725 } 726 return 727} 728 729// ----- 730 731// CHECK-LABEL: @selection_with_control 732func @selection_with_control() -> () { 733 // CHECK: spv.selection control(Flatten) 734 spv.selection control(Flatten) { 735 } 736 return 737} 738 739// ----- 740 741func @wrong_merge_block() -> () { 742 // expected-error @+1 {{last block must be the merge block with only one 'spv.mlir.merge' op}} 743 spv.selection { 744 spv.Return 745 } 746 return 747} 748 749// ----- 750 751func @missing_entry_block() -> () { 752 // expected-error @+1 {{must have a selection header block}} 753 spv.selection { 754 spv.mlir.merge 755 } 756 return 757} 758 759// ----- 760 761//===----------------------------------------------------------------------===// 762// spv.Unreachable 763//===----------------------------------------------------------------------===// 764 765// CHECK-LABEL: func @unreachable_no_pred 766func @unreachable_no_pred() { 767 spv.Return 768 769 ^next: 770 // CHECK: spv.Unreachable 771 spv.Unreachable 772} 773 774// CHECK-LABEL: func @unreachable_with_pred 775func @unreachable_with_pred() { 776 spv.Return 777 778 ^parent: 779 spv.Branch ^unreachable 780 781 ^unreachable: 782 // CHECK: spv.Unreachable 783 spv.Unreachable 784} 785 786// ----- 787 788func @unreachable() { 789 // expected-error @+1 {{cannot be used in reachable block}} 790 spv.Unreachable 791} 792