Regression test from seed 135

mlir-stage-12-v1 · regression test PR · draft · ← all drafts

Add a regression test for mlir-stage-12-v1

This adds one LIT test covering 57 lines and 38 branch outcomes that the existing suite does not reach, across 3 source files, at 48615bc5925ef4b9db8b4550b5d4322933cf4b7b.

Coverage this test adds

Source file Newly covered lines Newly covered branch outcomes
lib/Dataflow/IR/DataflowDialect.cpp 32–33, 37 26:3–26:42 false; 32:3–32:37 true; 33:9–33:28 false
lib/Dataflow/IR/DataflowFunctionLikeOps.cpp 104–106, 109, 117–118, 121–122, 124–128, 130–131, 173–174, 180–182, 191, 194–197, 224–226, 230, 235–237, 239–245, 474, 542, 570–572, 576–577, 580, 656–658, 663–664, 668–669 105:7–105:27 true; 118:35–118:62 false; 118:7–118:31 false; 121:7–121:33 true; 122:38–122:62 false; 122:9–122:34 false; 127:63–127:69 false; 127:9–127:59 false; 127:9–128:38 false; 128:9–128:38 false; 172:12–172:26 true; 174:11–174:42 false; 182:14–182:62 false; 191:11–191:20 false; 219:9–219:16 false; 226:9–226:44 false; 230:9–230:37 false; 240:9–240:41 true; 331:15–331:23 true; 331:27–331:59 false; 473:12–473:50 true; 474:11–474:21 false; 541:13–541:22 true; 569:7–569:61 true; 572:9–572:33 false; 576:29–576:30 false; 576:29–576:30 true; 577:11–577:62 false; 657:7–657:43 false; 657:7–658:42 false; 658:7–658:42 false; 663:28–663:29 false; 663:28–663:29 true; 664:9–664:47 false
lib/Frontend/Lowering/LowerForallToThreadPass.cpp — 47:9–47:17 false

lib/Dataflow/IR/DataflowDialect.cpp

 24                           std::optional<uint64_t> workItemArgOrdinal) { 25    switch (kind) {+26    case ThreadDomainKind::DenseRectangular:    [false branch at 26:3] 27      if (workItemArgOrdinal) 28        return emitError()@@ 30                  "ordinal"; 31      return success();+32    case ThreadDomainKind::DynamicWork:    [true branch at 32:3]+33      if (!workItemArgOrdinal)    [false branch at 33:9] 34        return emitError() 35               << "dynamic-work thread domain requires a work-item argument " 36                  "ordinal";+37      return success(); 38    } 39    return emitError() << "unknown thread domain kind";

lib/Dataflow/IR/DataflowFunctionLikeOps.cpp

 102  enum class ExtentExprKind { Unsupported, Constant, AddI, IndexCast }; 103  +104  static bool isScalarNonzeroSignlessIntegerOrIndex(Type type) {+105    if (isa<IndexType>(type))    [true branch at 105:7]+106      return true; 107    auto integerType = dyn_cast<IntegerType>(type); 108    return integerType && integerType.isSignless() && integerType.getWidth() != 0;+109  } 110   111  static unsigned getScalarIntegerBitWidth(Type type) {@@ 115  } 116  +117  static ExtentExprKind classifyExtentExpr(Operation *op) {+118    if (op->getNumRegions() != 0 || op->getNumSuccessors() != 0)    [false branch at 118:35, false branch at 118:7] 119      return ExtentExprKind::Unsupported; 120  +121    if (isa<arith::ConstantOp>(op)) {    [true branch at 121:7]+122      if (op->getNumOperands() != 0 || op->getNumResults() != 1)    [false branch at 122:38, false branch at 122:9] 123        return ExtentExprKind::Unsupported;+124      Type resultType = op->getResult(0).getType();+125      auto value = dyn_cast_or_null<IntegerAttr>(+126          cast<arith::ConstantOp>(op).getProperties().value);+127      if (!isScalarNonzeroSignlessIntegerOrIndex(resultType) || !value ||    [false branch at 127:63, false branch at 127:9, false branch at 127:9]+128          value.getType() != resultType)    [false branch at 128:9] 129        return ExtentExprKind::Unsupported;+130      return ExtentExprKind::Constant;+131    } 132   133    if (isa<arith::AddIOp>(op)) {@@ 170      SmallVector<Frame> stack; 171      schedule(value, stack);+172      while (!stack.empty()) {    [true branch at 172:12]+173        Frame &frame = stack.back();+174        if (constants.contains(frame.value)) {    [false branch at 174:11] 175          active.erase(frame.value); 176          stack.pop_back();@@ 178        } 179  +180        Operation *definingOp = cast<OpResult>(frame.value).getOwner();+181        bool descended = false;+182        while (frame.nextOperand < definingOp->getNumOperands()) {    [false branch at 182:14] 183          Value operand = definingOp->getOperand(frame.nextOperand++); 184          if (constants.contains(operand))@@ 189          } 190        }+191        if (descended)    [false branch at 191:11] 192          continue; 193  +194        evaluateOperation(definingOp, frame.kind);+195        active.erase(frame.value);+196        stack.pop_back();+197      } 198   199      return constants.lookup(value);@@ 217   218      auto result = dyn_cast<OpResult>(value);+219      if (!result) {    [false branch at 219:9] 220        constants.try_emplace(value, Attribute{}); 221        return false; 222      } 223  +224      Operation *definingOp = result.getOwner();+225      ExtentExprKind kind = classifyExtentExpr(definingOp);+226      if (kind == ExtentExprKind::Unsupported) {    [false branch at 226:9] 227        cacheUnknown(definingOp); 228        return false; 229      }+230      if (!active.insert(value).second) {    [false branch at 230:9] 231        cacheUnknown(definingOp); 232        return false; 233      } 234  +235      stack.push_back({value, 0, kind});+236      return true;+237    } 238  +239    void evaluateOperation(Operation *op, ExtentExprKind kind) {+240      if (kind == ExtentExprKind::Constant) {    [true branch at 240:9]+241        constants.try_emplace(+242            op->getResult(0),+243            cast<IntegerAttr>(cast<arith::ConstantOp>(op).getProperties().value));+244        return;+245      } 246   247      auto operandConstant = [&](unsigned index) {@@ 329            auto constant = 330                dyn_cast_or_null<IntegerAttr>(evaluator.evaluate(extent));+331            if (constant && constant.getValue().isNegative()) {    [true branch at 331:15, false branch at 331:27] 332              launch.emitOpError("grid upper bound #") 333                  << index << " must be nonnegative";@@ 471      if (parseOne()) 472        return failure();+473      while (succeeded(parser.parseOptionalComma()))    [true branch at 473:12]+474        if (parseOne())    [false branch at 474:11] 475          return failure(); 476      return parser.parseRParen();@@ 539        p << " iv ("; 540        for (size_t i = N + 1, e = entry->getNumArguments(); i < e; ++i) {+541          if (i > N + 1)    [true branch at 541:13]+542            p << ", "; 543          p.printRegionArgument(entry->getArgument(i)); 544        }@@ 567      return emitOpError("must not declare function results"); 568  +569    if (getDomain().getKind() == ThreadDomainKind::DynamicWork) {    [true branch at 569:7]+570      uint64_t ordinal = *getDomain().getWorkItemArgOrdinal();+571      ArrayRef<Type> inputs = getFunctionType().getInputs();+572      if (ordinal >= inputs.size())    [false branch at 572:9] 573        return emitOpError("dynamic-work item argument ordinal ") 574               << ordinal << " is out of bounds for " << inputs.size() 575               << " thread inputs";+576      for (auto [index, type] : llvm::enumerate(inputs))    [false branch at 576:29, true branch at 576:29]+577        if (DataflowDialect::containsChannelOrThreadToken(type))    [false branch at 577:11] 578          return emitOpError("dynamic-work thread input #") 579                 << index << " must not contain a channel or thread token";+580    } 581    if (!ownsThreadLaunchExtentAnalysis(*this)) 582      return success();@@ 654  //===----------------------------------------------------------------------===// 655  +656  LogicalResult ThreadWaitOp::verify() {+657    if ((*this)->getParentOfType<ThreadOp>() ||    [false branch at 657:7, false branch at 657:7]+658        (*this)->getParentOfType<GraphOp>())    [false branch at 658:7] 659      return emitOpError( 660          "must appear outside any dataflow.thread or dataflow.graph " 661          "definition"); 662  +663    for (auto [index, token] : llvm::enumerate(getAsyncDependencies()))    [false branch at 663:28, true branch at 663:28]+664      if (!token.getDefiningOp<ThreadLaunchOp>())    [false branch at 664:9] 665        return emitOpError("operand #") << index 666                                        << " must be produced directly by " 667                                           "dataflow.thread.launch";+668    return success();+669  } 670   671  //===----------------------------------------------------------------------===//

The test

The input was reduced from 24 to 22 lines while keeping every covered line and branch outcome above, and while the compiler still accepted it. The CHECK lines are the compiler's exact output on this input at 48615bc5925ef4b9db8b4550b5d4322933cf4b7b.

// RUN: loom-raise-opt --loom-lower-forall-to-thread %s | FileCheck %s

dataflow.thread private @t_0 domain(#dataflow.thread_domain<dynamic_work, work_item_arg = 0>)(%arg_0: i32, %arg_1: f32) ctrl (%thread_ctrl: none) {
  dataflow.thread.yield %thread_ctrl : none
}

dataflow.thread private @t_1 domain(#dataflow.thread_domain<dense>)() ctrl (%thread_ctrl: none) iv (%coord_0: index, %coord_1: index) {
  dataflow.thread.yield
}

dataflow.thread private @t_2 domain(#dataflow.thread_domain<dynamic_work, work_item_arg = 0>)(%arg_0: index) ctrl (%thread_ctrl: none) {
  dataflow.thread.yield %thread_ctrl : none
}

func.func @host(%m_ref: memref<?xf32>) {
  %c_i32 = arith.constant 1 : i32
  %c_f32 = arith.constant 1.000000e+00 : f32
  %c_idx = arith.constant 4 : index
  %token_0 = dataflow.thread.launch @t_0(%c_i32, %c_f32) : (i32, f32) -> !dataflow.thread_token
  %token_1 = dataflow.thread.launch @t_1() grid(%c_idx, %c_idx) : () -> !dataflow.thread_token
  dataflow.thread.wait %token_1 : !dataflow.thread_token
  %token_2 = dataflow.thread.launch @t_2(%c_idx) : (index) -> !dataflow.thread_token
  return
}

// CHECK: module {
// CHECK-NEXT:   dataflow.thread private @t_0 domain(#dataflow.thread_domain<dynamic_work, work_item_arg = 0>)(%arg0: i32, %arg1: f32) ctrl (%arg2: none) {
// CHECK-NEXT:     dataflow.thread.yield %arg2 : none
// CHECK-NEXT:   }
// CHECK-NEXT:   dataflow.thread private @t_1 domain(#dataflow.thread_domain<dense>)() ctrl (%arg0: none) iv (%arg1: index, %arg2: index) {
// CHECK-NEXT:     dataflow.thread.yield
// CHECK-NEXT:   }
// CHECK-NEXT:   dataflow.thread private @t_2 domain(#dataflow.thread_domain<dynamic_work, work_item_arg = 0>)(%arg0: index) ctrl (%arg1: none) {
// CHECK-NEXT:     dataflow.thread.yield %arg1 : none
// CHECK-NEXT:   }
// CHECK-NEXT:   func.func @host(%arg0: memref<?xf32>) {
// CHECK-NEXT:     %c1_i32 = arith.constant 1 : i32
// CHECK-NEXT:     %cst = arith.constant 1.000000e+00 : f32
// CHECK-NEXT:     %c4 = arith.constant 4 : index
// CHECK-NEXT:     %0 = dataflow.thread.launch @t_0(%c1_i32, %cst) : (i32, f32) -> !dataflow.thread_token
// CHECK-NEXT:     %1 = dataflow.thread.launch @t_1() grid(%c4, %c4) : () -> !dataflow.thread_token
// CHECK-NEXT:     dataflow.thread.wait %1 : !dataflow.thread_token
// CHECK-NEXT:     %2 = dataflow.thread.launch @t_2(%c4) : (index) -> !dataflow.thread_token
// CHECK-NEXT:     return
// CHECK-NEXT:   }
// CHECK-NEXT: }
// CHECK-EMPTY:

Validation

  • Native compiler and FileCheck replay: passed at 48615bc5925ef4b9db8b4550b5d4322933cf4b7b.
  • Property checker verdict on the reduced pair: PASS (postcondition.spct, SHA-256 809bed02cdaa8a2f4755d8d167585869a7808f4be2a47a8ef5f48d6b268d0141).
  • Reduction criterion: accepted checker PASS and every original line/branch increment over the suite baseline; the original postcondition BDD decision path is unchanged; every original fast edge increment over its suite baseline.

Where this test came from

PBT mlir-stage-12-v1, run 20260911-083547, seed 135.

The property under test is anchored on documentation:

  • selected output: docs/spec-compiler-part-3-dfg.md lines 991–997 (output side)
  • linked input 4: docs/spec-compiler-part-3-dfg.md lines 2052–2055 (input side)
  • linked input 40: docs/spec-compiler-part-2-scf.md lines 934–937 (input side)
  • linked input 44: docs/spec-compiler-part-3-dfg.md lines 2096–2100 (input side)
  • linked input 49: docs/spec-compiler-part-3-dfg.md lines 2057–2061 (input side)
  • linked input 51: docs/spec-compiler-part-2-scf.md lines 940–942 (input side)
  • linked input 79: docs/spec-compiler-part-3-dfg.md lines 2008–2010 (input side)
  • linked input 139: docs/spec-compiler-part-3-dfg.md lines 2017–2020 (input side)
  • linked input 199: docs/spec-compiler-part-3-dfg.md lines 2022–2023 (input side)
  • linked input 208: docs/spec-compiler-part-3-dfg.md lines 2012–2013 (input side)

Coverage is measured against the recorded baseline suite at this revision, and counts unique mapped file locations including generated code. Reduction retains every added line or branch outcome and a passing property check; it is not a claim of global minimality, nor of a defect.

Originating PBT run · Seed 135

LIT test · PR patch · Native verification