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.
| 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 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:
48615bc5925ef4b9db8b4550b5d4322933cf4b7b.postcondition.spct, SHA-256 809bed02cdaa8a2f4755d8d167585869a7808f4be2a47a8ef5f48d6b268d0141).PBT mlir-stage-12-v1, run 20260911-083547, seed 135.
The property under test is anchored on documentation:
docs/spec-compiler-part-3-dfg.md lines 991–997 (output side)docs/spec-compiler-part-3-dfg.md lines 2052–2055 (input side)docs/spec-compiler-part-2-scf.md lines 934–937 (input side)docs/spec-compiler-part-3-dfg.md lines 2096–2100 (input side)docs/spec-compiler-part-3-dfg.md lines 2057–2061 (input side)docs/spec-compiler-part-2-scf.md lines 940–942 (input side)docs/spec-compiler-part-3-dfg.md lines 2008–2010 (input side)docs/spec-compiler-part-3-dfg.md lines 2017–2020 (input side)docs/spec-compiler-part-3-dfg.md lines 2022–2023 (input side)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