https://github.com/badumbatish updated https://github.com/llvm/llvm-project/pull/171246
>From 40d3ddb8a9493563dba2858e07d19a78deb9326f Mon Sep 17 00:00:00 2001 From: Jasmine Tang <[email protected]> Date: Mon, 8 Dec 2025 05:00:55 -0800 Subject: [PATCH 1/2] Add switch case covered cirops.td --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 8 +++++- clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 2 ++ clang/test/CIR/IR/switch.cir | 30 ++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 9bd24cf0bcf27..d6099388886d7 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1047,6 +1047,11 @@ def CIR_SwitchOp : CIR_Op<"switch", [ conditionally executing multiple regions of code. The operand to an switch is an integral condition value. + Besides accepting an int type of condition and regions of cir code, it also accepts + a boolean allEnumCasesCovered indicating if all cases of an enum is covered. Note that + having a default CaseOp inside the switch doesn't imply allEnumCasesCovered, the OG AST switch + needs to have each case spelled out. + The set of `cir.case` operations and their enclosing `cir.switch` represent the semantics of a C/C++ switch statement. Users can use `collectCases(llvm::SmallVector<CaseOp> &cases)` to collect the `cir.case` @@ -1173,7 +1178,8 @@ def CIR_SwitchOp : CIR_Op<"switch", [ ``` }]; - let arguments = (ins CIR_IntType:$condition); + let arguments = (ins CIR_IntType:$condition, + DefaultValuedAttr<BoolAttr, "false">:$allEnumCasesCovered); let regions = (region AnyRegion:$body); diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index da7ab0691cb63..0ff19abaffc08 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -1105,6 +1105,8 @@ mlir::LogicalResult CIRGenFunction::emitSwitchStmt(const clang::SwitchStmt &s) { terminateBody(builder, caseOp.getCaseRegion(), caseOp.getLoc()); terminateBody(builder, swop.getBody(), swop.getLoc()); + swop.setAllEnumCasesCovered(s.isAllEnumCasesCovered()); + return res; } diff --git a/clang/test/CIR/IR/switch.cir b/clang/test/CIR/IR/switch.cir index 87d45bf1f5219..78c0273b8c97e 100644 --- a/clang/test/CIR/IR/switch.cir +++ b/clang/test/CIR/IR/switch.cir @@ -36,3 +36,33 @@ cir.func @s0() { // CHECK-NEXT: } // CHECK-NEXT: cir.yield // CHECK-NEXT: } + + +// Pretends that this is lowered from a C file and was tagged with allEnumCasesCovered = true +cir.func @s1(%1 : !s32i) { + cir.switch (%1 : !s32i) { + cir.case (default, []) { + cir.return + } + cir.case (equal, [#cir.int<1> : !s32i]) { + cir.yield + } + cir.case (equal, [#cir.int<2> : !s32i]) { + cir.yield + } + cir.yield + } { allEnumCasesCovered = true} + cir.return +} +// CHECK: cir.switch (%arg0 : !s32i) { +// CHECK-NEXT: cir.case(default, []) { +// CHECK-NEXT: cir.return +// CHECK-NEXT: } +// CHECK-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) { +// CHECK-NEXT: cir.yield +// CHECK-NEXT: } +// CHECK-NEXT: cir.case(equal, [#cir.int<2> : !s32i]) { +// CHECK-NEXT: cir.yield +// CHECK-NEXT: } +// CHECK-NEXT: cir.yield +// CHECK-NEXT: } {allEnumCasesCovered = true} >From 368fbbc587f998f4bf5675505620d61c803441a2 Mon Sep 17 00:00:00 2001 From: Jasmine Tang <[email protected]> Date: Wed, 10 Dec 2025 02:36:03 -0800 Subject: [PATCH 2/2] Resolve PR comments --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 21 +++++---- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 38 ---------------- clang/test/CIR/CodeGen/atomic.c | 6 +-- clang/test/CIR/CodeGen/switch.cpp | 48 ++++++++++++++------ clang/test/CIR/CodeGen/switch_flat_op.cpp | 2 +- clang/test/CIR/IR/switch.cir | 10 ++-- clang/test/CIR/Transforms/switch-fold.cir | 10 ++-- 7 files changed, 61 insertions(+), 74 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index d6099388886d7..e29f94b7eeb3e 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1047,10 +1047,11 @@ def CIR_SwitchOp : CIR_Op<"switch", [ conditionally executing multiple regions of code. The operand to an switch is an integral condition value. - Besides accepting an int type of condition and regions of cir code, it also accepts - a boolean allEnumCasesCovered indicating if all cases of an enum is covered. Note that - having a default CaseOp inside the switch doesn't imply allEnumCasesCovered, the OG AST switch - needs to have each case spelled out. + Besides taking an integer condition and CIR regions, it also accepts an + `all_enum_cases_covered` attribute indicating whether all enum cases are + handled by the operation. Note that the presence of a default CaseOp does + not imply `all_enum_cases_covered`. The original AST switch must explicitly list + every enum case. The set of `cir.case` operations and their enclosing `cir.switch` represent the semantics of a C/C++ switch statement. Users can use @@ -1178,8 +1179,10 @@ def CIR_SwitchOp : CIR_Op<"switch", [ ``` }]; - let arguments = (ins CIR_IntType:$condition, - DefaultValuedAttr<BoolAttr, "false">:$allEnumCasesCovered); + let arguments = (ins + CIR_IntType:$condition, + UnitAttr:$allEnumCasesCovered + ); let regions = (region AnyRegion:$body); @@ -1190,9 +1193,9 @@ def CIR_SwitchOp : CIR_Op<"switch", [ ]; let assemblyFormat = [{ - custom<SwitchOp>( - $body, $condition, type($condition) - ) + `(` $condition `:` qualified(type($condition)) `)` + (`allEnumCasesCovered` $allEnumCasesCovered^)? + $body attr-dict }]; diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index ec8cae62d6bc8..f2fee85dc501f 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1353,44 +1353,6 @@ void cir::CaseOp::build(OpBuilder &builder, OperationState &result, // SwitchOp //===----------------------------------------------------------------------===// -static ParseResult parseSwitchOp(OpAsmParser &parser, mlir::Region ®ions, - mlir::OpAsmParser::UnresolvedOperand &cond, - mlir::Type &condType) { - cir::IntType intCondType; - - if (parser.parseLParen()) - return mlir::failure(); - - if (parser.parseOperand(cond)) - return mlir::failure(); - if (parser.parseColon()) - return mlir::failure(); - if (parser.parseCustomTypeWithFallback(intCondType)) - return mlir::failure(); - condType = intCondType; - - if (parser.parseRParen()) - return mlir::failure(); - if (parser.parseRegion(regions, /*arguments=*/{}, /*argTypes=*/{})) - return failure(); - - return mlir::success(); -} - -static void printSwitchOp(OpAsmPrinter &p, cir::SwitchOp op, - mlir::Region &bodyRegion, mlir::Value condition, - mlir::Type condType) { - p << "("; - p << condition; - p << " : "; - p.printStrippedAttrOrType(condType); - p << ")"; - - p << ' '; - p.printRegion(bodyRegion, /*printEntryBlockArgs=*/false, - /*printBlockTerminators=*/true); -} - void cir::SwitchOp::getSuccessorRegions( mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> ®ion) { if (!point.isParent()) { diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c index 71cb1f1e164b3..065561a8e2fb7 100644 --- a/clang/test/CIR/CodeGen/atomic.c +++ b/clang/test/CIR/CodeGen/atomic.c @@ -1143,7 +1143,7 @@ int atomic_load_dynamic_order(int *ptr, int order) { // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> // CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i - // CIR-NEXT: cir.switch (%[[ORDER]] : !s32i) { + // CIR-NEXT: cir.switch(%[[ORDER]] : !s32i) { // CIR-NEXT: cir.case(default, []) { // CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(relaxed) %[[PTR]] : !cir.ptr<!s32i>, !s32i // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT:.+]] : !s32i, !cir.ptr<!s32i> @@ -1219,7 +1219,7 @@ void atomic_store_dynamic_order(int *ptr, int order) { // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> // CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i - // CIR: cir.switch (%[[ORDER]] : !s32i) { + // CIR: cir.switch(%[[ORDER]] : !s32i) { // CIR-NEXT: cir.case(default, []) { // CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i // CIR-NEXT: cir.store align(4) atomic(relaxed) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i> @@ -1288,7 +1288,7 @@ int atomic_load_and_store_dynamic_order(int *ptr, int order) { // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i> // CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i - // CIR: cir.switch (%[[ORDER]] : !s32i) { + // CIR: cir.switch(%[[ORDER]] : !s32i) { // CIR-NEXT: cir.case(default, []) { // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg relaxed %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i diff --git a/clang/test/CIR/CodeGen/switch.cpp b/clang/test/CIR/CodeGen/switch.cpp index 3824be0d08c2f..b7bd2da5e39b8 100644 --- a/clang/test/CIR/CodeGen/switch.cpp +++ b/clang/test/CIR/CodeGen/switch.cpp @@ -20,7 +20,7 @@ void sw1(int a) { } // CIR: cir.func{{.*}} @_Z3sw1i -// CIR: cir.switch (%[[COND:.*]] : !s32i) { +// CIR: cir.switch(%[[COND:.*]] : !s32i) { // CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) { // CIR: cir.break // CIR: cir.case(equal, [#cir.int<1> : !s32i]) { @@ -101,7 +101,7 @@ void sw2(int a) { // CIR: cir.scope { // CIR-NEXT: %[[YOLO:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["yolo", init] // CIR-NEXT: %[[FOMO:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["fomo", init] -// CIR: cir.switch (%[[COND:.*]] : !s32i) { +// CIR: cir.switch(%[[COND:.*]] : !s32i) { // CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) { // CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i // CIR-NEXT: cir.store{{.*}} %[[ZERO]], %[[FOMO]] : !s32i, !cir.ptr<!s32i> @@ -154,7 +154,7 @@ void sw3(int a) { // CIR: cir.func{{.*}} @_Z3sw3i // CIR: cir.scope { // CIR-NEXT: %[[COND:.*]] = cir.load{{.*}} %[[A:.*]] : !cir.ptr<!s32i>, !s32i -// CIR-NEXT: cir.switch (%[[COND]] : !s32i) { +// CIR-NEXT: cir.switch(%[[COND]] : !s32i) { // CIR-NEXT: cir.case(default, []) { // CIR-NEXT: cir.break // CIR-NEXT: } @@ -196,7 +196,7 @@ int sw4(int a) { } // CIR: cir.func{{.*}} @_Z3sw4i -// CIR: cir.switch (%[[COND:.*]] : !s32i) { +// CIR: cir.switch(%[[COND:.*]] : !s32i) { // CIR-NEXT: cir.case(equal, [#cir.int<42> : !s32i]) { // CIR-NEXT: cir.scope { // CIR-NEXT: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i @@ -264,7 +264,7 @@ void sw5(int a) { } // CIR: cir.func{{.*}} @_Z3sw5i -// CIR: cir.switch (%[[A:.*]] : !s32i) { +// CIR: cir.switch(%[[A:.*]] : !s32i) { // CIR-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) { // CIR-NEXT: cir.yield // CIR-NEXT: } @@ -314,7 +314,7 @@ void sw6(int a) { } // CIR: cir.func{{.*}} @_Z3sw6i -// CIR: cir.switch (%[[A:.*]] : !s32i) { +// CIR: cir.switch(%[[A:.*]] : !s32i) { // CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) { // CIR-NEXT: cir.yield // CIR-NEXT: } @@ -406,7 +406,7 @@ void sw7(int a) { // CIR: cir.func{{.*}} @_Z3sw7i // CIR: %[[X:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"] -// CIR: cir.switch (%[[A:.*]] : !s32i) +// CIR: cir.switch(%[[A:.*]] : !s32i) // CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) { // CIR-NEXT: cir.yield // CIR-NEXT: } @@ -499,7 +499,7 @@ void sw8(int a) { } // CIR: cir.func{{.*}} @_Z3sw8i -// CIR: cir.switch (%[[A:.*]] : !s32i) +// CIR: cir.switch(%[[A:.*]] : !s32i) // CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) { // CIR-NEXT: cir.break // CIR-NEXT: } @@ -557,7 +557,7 @@ void sw9(int a) { } // CIR: cir.func{{.*}} @_Z3sw9i -// CIR: cir.switch (%[[A:.*]] : !s32i) +// CIR: cir.switch(%[[A:.*]] : !s32i) // CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) { // CIR-NEXT: cir.break // CIR-NEXT: } @@ -616,7 +616,7 @@ void sw10(int a) { } // CIR: cir.func{{.*}} @_Z4sw10i -// CIR: cir.switch (%[[A:.*]] : !s32i) +// CIR: cir.switch(%[[A:.*]] : !s32i) // CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) { // CIR-NEXT: cir.break // CIR-NEXT: } @@ -688,7 +688,7 @@ void sw11(int a) { } // CIR: cir.func{{.*}} @_Z4sw11i -// CIR: cir.switch (%[[A:.*]] : !s32i) +// CIR: cir.switch(%[[A:.*]] : !s32i) // CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) { // CIR-NEXT: cir.break // CIR-NEXT: } @@ -1063,7 +1063,7 @@ int nested_switch(int a) { return 0; } -// CIR: cir.switch (%[[COND:.*]] : !s32i) { +// CIR: cir.switch(%[[COND:.*]] : !s32i) { // CIR: cir.case(equal, [#cir.int<0> : !s32i]) { // CIR: cir.yield // CIR: } @@ -1198,7 +1198,7 @@ int sw_return_multi_cases(int x) { } // CIR-LABEL: cir.func{{.*}} @_Z21sw_return_multi_casesi -// CIR: cir.switch (%{{.*}} : !s32i) { +// CIR: cir.switch(%{{.*}} : !s32i) { // CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) { // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i // CIR: cir.store{{.*}} %[[ZERO]], %{{.*}} : !s32i, !cir.ptr<!s32i> @@ -1270,3 +1270,25 @@ int sw_return_multi_cases(int x) { // OGCG: [[RETURN]]: // OGCG: %[[RETVAL_LOAD:.*]] = load i32, ptr %[[RETVAL]], align 4 // OGCG: ret i32 %[[RETVAL_LOAD]] + +enum M { + Six, + Seven +}; + +void testSwitchCoverAllCase(M m) { + switch (m) { + case Six:case Seven: + break; + } +} +// CIR: cir.switch(%[[ARG:.*]] : !s32i) allEnumCasesCovered { + +void testSwitchNotCoverAllCase(M m) { + switch (m) { + case Six: + default: + break; + } +} +// CIR: cir.switch(%[[ARG:.*]] : !s32i) { diff --git a/clang/test/CIR/CodeGen/switch_flat_op.cpp b/clang/test/CIR/CodeGen/switch_flat_op.cpp index a3ea7e7a15547..ba0a82da52c70 100644 --- a/clang/test/CIR/CodeGen/switch_flat_op.cpp +++ b/clang/test/CIR/CodeGen/switch_flat_op.cpp @@ -21,7 +21,7 @@ void swf(int a) { // BEFORE: cir.func{{.*}} @_Z3swfi // BEFORE: %[[VAR_B:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] {alignment = 4 : i64} // BEFORE: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i -// BEFORE: cir.switch (%[[COND:.*]] : !s32i) { +// BEFORE: cir.switch(%[[COND:.*]] : !s32i) { // BEFORE: cir.case(equal, [#cir.int<3> : !s32i]) { // BEFORE: %[[LOAD_B_EQ:.*]] = cir.load{{.*}} %[[VAR_B]] : !cir.ptr<!s32i>, !s32i // BEFORE: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i diff --git a/clang/test/CIR/IR/switch.cir b/clang/test/CIR/IR/switch.cir index 78c0273b8c97e..89614480e43cd 100644 --- a/clang/test/CIR/IR/switch.cir +++ b/clang/test/CIR/IR/switch.cir @@ -21,7 +21,7 @@ cir.func @s0() { cir.return } -// CHECK: cir.switch (%0 : !s32i) { +// CHECK: cir.switch(%0 : !s32i) { // CHECK-NEXT: cir.case(default, []) { // CHECK-NEXT: cir.return // CHECK-NEXT: } @@ -40,7 +40,7 @@ cir.func @s0() { // Pretends that this is lowered from a C file and was tagged with allEnumCasesCovered = true cir.func @s1(%1 : !s32i) { - cir.switch (%1 : !s32i) { + cir.switch (%1 : !s32i) allEnumCasesCovered { cir.case (default, []) { cir.return } @@ -51,10 +51,10 @@ cir.func @s1(%1 : !s32i) { cir.yield } cir.yield - } { allEnumCasesCovered = true} + } { } cir.return } -// CHECK: cir.switch (%arg0 : !s32i) { +// CHECK: cir.switch(%[[ARG:.*]] : !s32i) allEnumCasesCovered { // CHECK-NEXT: cir.case(default, []) { // CHECK-NEXT: cir.return // CHECK-NEXT: } @@ -65,4 +65,4 @@ cir.func @s1(%1 : !s32i) { // CHECK-NEXT: cir.yield // CHECK-NEXT: } // CHECK-NEXT: cir.yield -// CHECK-NEXT: } {allEnumCasesCovered = true} +// CHECK-NEXT: } diff --git a/clang/test/CIR/Transforms/switch-fold.cir b/clang/test/CIR/Transforms/switch-fold.cir index 62a94f4fde2c3..c348a05128671 100644 --- a/clang/test/CIR/Transforms/switch-fold.cir +++ b/clang/test/CIR/Transforms/switch-fold.cir @@ -27,7 +27,7 @@ module { cir.return } //CHECK: cir.func @foldCascade - //CHECK: cir.switch (%[[COND:.*]] : !s32i) { + //CHECK: cir.switch(%[[COND:.*]] : !s32i) { //CHECK-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i]) { //CHECK-NEXT: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i //CHECK-NEXT: cir.store %[[TWO]], %[[ARG0:.*]] : !s32i, !cir.ptr<!s32i> @@ -66,7 +66,7 @@ module { cir.return } //CHECK: @foldCascade2 - //CHECK: cir.switch (%[[COND2:.*]] : !s32i) { + //CHECK: cir.switch(%[[COND2:.*]] : !s32i) { //CHECK: cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<2> : !s32i, #cir.int<4> : !s32i]) { //CHECK: cir.break //cehck: } @@ -106,7 +106,7 @@ module { cir.return } //CHECK: cir.func @foldCascade3 - //CHECK: cir.switch (%[[COND3:.*]] : !s32i) { + //CHECK: cir.switch(%[[COND3:.*]] : !s32i) { //CHECK: cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i]) { //CHECK: cir.break //CHECK: } @@ -142,7 +142,7 @@ module { cir.return } //CHECK: cir.func @foldCascadeWithDefault - //CHECK: cir.switch (%[[COND:.*]] : !s32i) { + //CHECK: cir.switch(%[[COND:.*]] : !s32i) { //CHECK: cir.case(equal, [#cir.int<3> : !s32i]) { //CHECK: cir.break //CHECK: } @@ -187,7 +187,7 @@ module { cir.return } //CHECK: cir.func @foldAllCascade - //CHECK: cir.switch (%[[COND:.*]] : !s32i) { + //CHECK: cir.switch(%[[COND:.*]] : !s32i) { //CHECK: cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i]) { //CHECK: cir.yield //CHECK: } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
