Skip to content

Commit 6a3e881

Browse files
Lancernlanza
authored andcommitted
[CIR] Emit nsw flag for unary integer operations (#1485)
Resolves #1477 .
1 parent e810ed3 commit 6a3e881

File tree

12 files changed

+47
-41
lines changed

12 files changed

+47
-41
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,10 +1146,14 @@ def UnaryOp : CIR_Op<"unary", [Pure, SameOperandsAndResultType]> {
11461146
}];
11471147

11481148
let results = (outs CIR_AnyType:$result);
1149-
let arguments = (ins Arg<UnaryOpKind, "unary op kind">:$kind, Arg<CIR_AnyType>:$input);
1149+
let arguments = (ins Arg<UnaryOpKind, "unary op kind">:$kind,
1150+
Arg<CIR_AnyType>:$input,
1151+
UnitAttr:$no_signed_wrap);
11501152

11511153
let assemblyFormat = [{
1152-
`(` $kind `,` $input `)` `:` type($input) `,` type($result) attr-dict
1154+
`(` $kind `,` $input `)`
1155+
(`nsw` $no_signed_wrap^)?
1156+
`:` type($input) `,` type($result) attr-dict
11531157
}];
11541158

11551159
let hasVerifier = 1;

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
467467
auto Kind =
468468
E->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
469469
// NOTE(CIR): clang calls CreateAdd but folds this to a unary op
470-
value = emitUnaryOp(E, Kind, input);
470+
value = emitUnaryOp(E, Kind, input, /*nsw=*/false);
471471
}
472472
// Next most common: pointer increment.
473473
} else if (const PointerType *ptr = type->getAs<PointerType>()) {
@@ -580,22 +580,20 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
580580
mlir::Value emitIncDecConsiderOverflowBehavior(const UnaryOperator *E,
581581
mlir::Value InVal,
582582
bool IsInc) {
583-
// NOTE(CIR): The SignedOverflowBehavior is attached to the global ModuleOp
584-
// and the nsw behavior is handled during lowering.
585583
auto Kind =
586584
E->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
587585
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
588586
case LangOptions::SOB_Defined:
589-
return emitUnaryOp(E, Kind, InVal);
587+
return emitUnaryOp(E, Kind, InVal, /*nsw=*/false);
590588
case LangOptions::SOB_Undefined:
591589
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
592-
return emitUnaryOp(E, Kind, InVal);
590+
return emitUnaryOp(E, Kind, InVal, /*nsw=*/true);
593591
llvm_unreachable(
594592
"inc/dec overflow behavior SOB_Undefined not implemented yet");
595593
break;
596594
case LangOptions::SOB_Trapping:
597595
if (!E->canOverflow())
598-
return emitUnaryOp(E, Kind, InVal);
596+
return emitUnaryOp(E, Kind, InVal, /*nsw=*/true);
599597
llvm_unreachable(
600598
"inc/dec overflow behavior SOB_Trapping not implemented yet");
601599
break;
@@ -661,7 +659,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
661659

662660
// NOTE: LLVM codegen will lower this directly to either a FNeg
663661
// or a Sub instruction. In CIR this will be handled later in LowerToLLVM.
664-
return emitUnaryOp(E, cir::UnaryOpKind::Minus, operand);
662+
return emitUnaryOp(E, cir::UnaryOpKind::Minus, operand,
663+
/*nsw=*/E->getType()->isSignedIntegerType());
665664
}
666665

667666
mlir::Value VisitUnaryNot(const UnaryOperator *E) {
@@ -684,10 +683,10 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
684683
}
685684

686685
mlir::Value emitUnaryOp(const UnaryOperator *E, cir::UnaryOpKind kind,
687-
mlir::Value input) {
686+
mlir::Value input, bool nsw = false) {
688687
return Builder.create<cir::UnaryOp>(
689688
CGF.getLoc(E->getSourceRange().getBegin()), input.getType(), kind,
690-
input);
689+
input, nsw);
691690
}
692691

693692
// C++

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2553,21 +2553,24 @@ mlir::LogicalResult CIRToLLVMUnaryOpLowering::matchAndRewrite(
25532553

25542554
// Integer unary operations: + - ~ ++ --
25552555
if (mlir::isa<cir::IntType>(elementType)) {
2556+
auto overflowFlags = op.getNoSignedWrap()
2557+
? mlir::LLVM::IntegerOverflowFlags::nsw
2558+
: mlir::LLVM::IntegerOverflowFlags::none;
25562559
switch (op.getKind()) {
25572560
case cir::UnaryOpKind::Inc: {
25582561
assert(!IsVector && "++ not allowed on vector types");
25592562
auto One = rewriter.create<mlir::LLVM::ConstantOp>(
25602563
loc, llvmType, mlir::IntegerAttr::get(llvmType, 1));
2561-
rewriter.replaceOpWithNewOp<mlir::LLVM::AddOp>(op, llvmType,
2562-
adaptor.getInput(), One);
2564+
rewriter.replaceOpWithNewOp<mlir::LLVM::AddOp>(
2565+
op, llvmType, adaptor.getInput(), One, overflowFlags);
25632566
return mlir::success();
25642567
}
25652568
case cir::UnaryOpKind::Dec: {
25662569
assert(!IsVector && "-- not allowed on vector types");
25672570
auto One = rewriter.create<mlir::LLVM::ConstantOp>(
25682571
loc, llvmType, mlir::IntegerAttr::get(llvmType, 1));
2569-
rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(op, llvmType,
2570-
adaptor.getInput(), One);
2572+
rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(
2573+
op, llvmType, adaptor.getInput(), One, overflowFlags);
25712574
return mlir::success();
25722575
}
25732576
case cir::UnaryOpKind::Plus: {
@@ -2581,8 +2584,8 @@ mlir::LogicalResult CIRToLLVMUnaryOpLowering::matchAndRewrite(
25812584
else
25822585
Zero = rewriter.create<mlir::LLVM::ConstantOp>(
25832586
loc, llvmType, mlir::IntegerAttr::get(llvmType, 0));
2584-
rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(op, llvmType, Zero,
2585-
adaptor.getInput());
2587+
rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(
2588+
op, llvmType, Zero, adaptor.getInput(), overflowFlags);
25862589
return mlir::success();
25872590
}
25882591
case cir::UnaryOpKind::Not: {

clang/test/CIR/CodeGen/bitfields.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ int load_field(S* s) {
8989
// CHECK: cir.func {{.*@unOp}}
9090
// CHECK: [[TMP0:%.*]] = cir.get_member {{.*}}[1] {name = "d"} : !cir.ptr<!ty_S> -> !cir.ptr<!cir.array<!u8i x 3>>
9191
// CHECK: [[TMP1:%.*]] = cir.get_bitfield(#bfi_d, [[TMP0]] : !cir.ptr<!cir.array<!u8i x 3>>) -> !s32i
92-
// CHECK: [[TMP2:%.*]] = cir.unary(inc, [[TMP1]]) : !s32i, !s32i
92+
// CHECK: [[TMP2:%.*]] = cir.unary(inc, [[TMP1]]) nsw : !s32i, !s32i
9393
// CHECK: cir.set_bitfield(#bfi_d, [[TMP0]] : !cir.ptr<!cir.array<!u8i x 3>>, [[TMP2]] : !s32i)
9494
void unOp(S* s) {
9595
s->d++;

clang/test/CIR/CodeGen/int128.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ unsigned __int128 test2(unsigned __int128 x) {
2626
// LLVM-LABEL: @_Z11unary_arithn
2727
__int128 unary_arith(__int128 x) {
2828
return ++x;
29-
// CHECK: %{{.+}} = cir.unary(inc, %{{.+}}) : !s128i, !s128i
30-
// LLVM: %{{.+}} = add i128 %{{.+}}, 1
29+
// CHECK: %{{.+}} = cir.unary(inc, %{{.+}}) nsw : !s128i, !s128i
30+
// LLVM: %{{.+}} = add nsw i128 %{{.+}}, 1
3131
}
3232

3333
// CHECK-LABEL: @_Z12binary_arithnn

clang/test/CIR/CodeGen/static-vars.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ void func1(void) {
2424
j++;
2525
// CHECK-DAG: %[[#V2:]] = cir.get_global @func1.j : !cir.ptr<!s32i>
2626
// CHECK-DAG: %[[#V3:]] = cir.load %[[#V2]] : !cir.ptr<!s32i>, !s32i
27-
// CHECK-DAG: %[[#V4:]] = cir.unary(inc, %[[#V3]]) : !s32i, !s32i
27+
// CHECK-DAG: %[[#V4:]] = cir.unary(inc, %[[#V3]]) nsw : !s32i, !s32i
2828
// CHECK-DAG: cir.store %[[#V4]], %[[#V2]] : !s32i, !cir.ptr<!s32i>
2929
}
3030

clang/test/CIR/CodeGen/static-vars.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ void func1(void) {
2626
j++;
2727
// CHECK-DAG: %[[#V2:]] = cir.get_global @_ZZ5func1vE1j : !cir.ptr<!s32i>
2828
// CHECK-DAG: %[[#V3:]] = cir.load %[[#V2]] : !cir.ptr<!s32i>, !s32i
29-
// CHECK-DAG: %[[#V4:]] = cir.unary(inc, %[[#V3]]) : !s32i, !s32i
29+
// CHECK-DAG: %[[#V4:]] = cir.unary(inc, %[[#V3]]) nsw : !s32i, !s32i
3030
// CHECK-DAG: cir.store %[[#V4]], %[[#V2]] : !s32i, !cir.ptr<!s32i>
3131
}
3232

clang/test/CIR/CodeGen/throw.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ void refoo1() {
5252
// CIR: } catch [type #cir.all {
5353
// CIR: %[[V3:.*]] = cir.catch_param -> !cir.ptr<!void>
5454
// CIR: %[[V4:.*]] = cir.load %[[V0]] : !cir.ptr<!s32i>, !s32i
55-
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) : !s32i, !s32i
55+
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) nsw : !s32i, !s32i
5656
// CIR: cir.store %[[V5]], %[[V0]] : !s32i, !cir.ptr<!s32i>
5757
// CIR: cir.yield
5858
// CIR: }]
@@ -91,7 +91,7 @@ void refoo1() {
9191
// LLVM: %[[V16:.*]] = phi ptr [ %[[V9]], %[[B7]] ], [ %[[V13]], %[[B11]] ]
9292
// LLVM: %[[V17:.*]] = call ptr @__cxa_begin_catch(ptr %[[V16]])
9393
// LLVM: %[[V18:.*]] = load i32, ptr %[[V2]], align 4
94-
// LLVM: %[[V19:.*]] = add i32 %[[V18]], 1
94+
// LLVM: %[[V19:.*]] = add nsw i32 %[[V18]], 1
9595
// LLVM: store i32 %[[V19]], ptr %[[V2]], align 4
9696
// LLVM: call void @__cxa_end_catch()
9797

@@ -136,7 +136,7 @@ void refoo2() {
136136
// CIR: cir.yield
137137
// CIR: } step {
138138
// CIR: %[[V5:.*]] = cir.load %[[V3]] : !cir.ptr<!s32i>, !s32i
139-
// CIR: %[[V6:.*]] = cir.unary(inc, %[[V5]]) : !s32i, !s32i
139+
// CIR: %[[V6:.*]] = cir.unary(inc, %[[V5]]) nsw : !s32i, !s32i
140140
// CIR: cir.store %[[V6]], %[[V3]] : !s32i, !cir.ptr<!s32i>
141141
// CIR: cir.yield
142142
// CIR: }
@@ -146,7 +146,7 @@ void refoo2() {
146146
// CIR: } catch [type #cir.all {
147147
// CIR: %[[V3:.*]] = cir.catch_param -> !cir.ptr<!void>
148148
// CIR: %[[V4:.*]] = cir.load %[[V0]] : !cir.ptr<!s32i>, !s32i
149-
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) : !s32i, !s32i
149+
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) nsw : !s32i, !s32i
150150
// CIR: cir.store %[[V5]], %[[V0]] : !s32i, !cir.ptr<!s32i>
151151
// CIR: cir.yield
152152
// CIR: }]
@@ -166,7 +166,7 @@ void refoo2() {
166166
// LLVM: br label %[[B16:.*]]
167167
// LLVM: [[B16]]:
168168
// LLVM: %[[V17]] = load i32, ptr {{.*}}, align 4
169-
// LLVM: %[[V18]] = add i32 %[[V17]], 1
169+
// LLVM: %[[V18]] = add nsw i32 %[[V17]], 1
170170
// LLVM: store i32 %[[V18]], ptr {{.*}}, align 4
171171
// LLVM: br label {{.*}}
172172
// LLVM: %[[B19:.*]]
@@ -198,7 +198,7 @@ void refoo2() {
198198
// LLVM: %[[V35:.*]] = phi ptr [ %[[V32]], %[[B30]] ], [ %[[V24]], %[[B22]] ], [ %[[V28]], %[[B26]] ]
199199
// LLVM: %[[V36:.*]] = call ptr @__cxa_begin_catch(ptr %[[V35]])
200200
// LLVM: %[[V37:.*]] = load i32, ptr {{.*}}, align 4
201-
// LLVM: %[[V38:.*]] = add i32 %[[V37]], 1
201+
// LLVM: %[[V38:.*]] = add nsw i32 %[[V37]], 1
202202
// LLVM: store i32 %[[V38]], ptr {{.*}}, align 4
203203
// LLVM: call void @__cxa_end_catch()
204204
// LLVM: br label {{.*}}
@@ -228,7 +228,7 @@ void refoo3() {
228228
// CIR: } catch [type #cir.all {
229229
// CIR: %[[V3:.*]] = cir.catch_param -> !cir.ptr<!void>
230230
// CIR: %[[V4:.*]] = cir.load %[[V0]] : !cir.ptr<!s32i>, !s32i
231-
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) : !s32i, !s32i
231+
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) nsw : !s32i, !s32i
232232
// CIR: cir.store %[[V5]], %[[V0]] : !s32i, !cir.ptr<!s32i>
233233
// CIR: cir.yield
234234
// CIR: }]
@@ -261,7 +261,7 @@ void refoo3() {
261261
// LLVM: %[[V17:.*]] = phi ptr [ %[[V14]], %[[B12]] ], [ %[[V10]], %[[B8]] ]
262262
// LLVM: %[[V18:.*]] = call ptr @__cxa_begin_catch(ptr %[[V17]])
263263
// LLVM: %[[V19:.*]] = load i32, ptr {{.*}}, align 4
264-
// LLVM: %[[V20:.*]] = add i32 %[[V19]], 1
264+
// LLVM: %[[V20:.*]] = add nsw i32 %[[V19]], 1
265265
// LLVM: store i32 %[[V20]], ptr {{.*}}, align 4
266266
// LLVM: call void @__cxa_end_catch()
267267
// LLVM: br label %[[B21]]

clang/test/CIR/CodeGen/try-catch.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ void tc6() {
144144
// CHECK: cir.return
145145
// CHECK: ^bb1: // no predecessors
146146
// CHECK: %[[V2:.*]] = cir.load {{.*}} : !cir.ptr<!s32i>, !s32i
147-
// CHECK: %[[V3:.*]] = cir.unary(inc, %[[V2]]) : !s32i, !s32i
147+
// CHECK: %[[V3:.*]] = cir.unary(inc, %[[V2]]) nsw : !s32i, !s32i
148148
// CHECK: cir.store %[[V3]], {{.*}} : !s32i, !cir.ptr<!s32i>
149149
// CHECK: cir.yield
150150
// CHECK: }

clang/test/CIR/CodeGen/unary.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ int inc0() {
4949
// CHECK: %[[#ATMP:]] = cir.const #cir.int<1> : !s32i
5050
// CHECK: cir.store %[[#ATMP]], %[[#A]] : !s32i
5151
// CHECK: %[[#INPUT:]] = cir.load %[[#A]]
52-
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#INPUT]])
52+
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#INPUT]]) nsw
5353
// CHECK: cir.store %[[#INCREMENTED]], %[[#A]]
5454
// CHECK: %[[#A_TO_OUTPUT:]] = cir.load %[[#A]]
5555
// CHECK: cir.store %[[#A_TO_OUTPUT]], %[[#RET]]
@@ -68,7 +68,7 @@ int dec0() {
6868
// CHECK: %[[#ATMP:]] = cir.const #cir.int<1> : !s32i
6969
// CHECK: cir.store %[[#ATMP]], %[[#A]] : !s32i
7070
// CHECK: %[[#INPUT:]] = cir.load %[[#A]]
71-
// CHECK: %[[#INCREMENTED:]] = cir.unary(dec, %[[#INPUT]])
71+
// CHECK: %[[#INCREMENTED:]] = cir.unary(dec, %[[#INPUT]]) nsw
7272
// CHECK: cir.store %[[#INCREMENTED]], %[[#A]]
7373
// CHECK: %[[#A_TO_OUTPUT:]] = cir.load %[[#A]]
7474
// CHECK: cir.store %[[#A_TO_OUTPUT]], %[[#RET]]
@@ -88,7 +88,7 @@ int inc1() {
8888
// CHECK: %[[#ATMP:]] = cir.const #cir.int<1> : !s32i
8989
// CHECK: cir.store %[[#ATMP]], %[[#A]] : !s32i
9090
// CHECK: %[[#INPUT:]] = cir.load %[[#A]]
91-
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#INPUT]])
91+
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#INPUT]]) nsw
9292
// CHECK: cir.store %[[#INCREMENTED]], %[[#A]]
9393
// CHECK: %[[#A_TO_OUTPUT:]] = cir.load %[[#A]]
9494
// CHECK: cir.store %[[#A_TO_OUTPUT]], %[[#RET]]
@@ -107,7 +107,7 @@ int dec1() {
107107
// CHECK: %[[#ATMP:]] = cir.const #cir.int<1> : !s32i
108108
// CHECK: cir.store %[[#ATMP]], %[[#A]] : !s32i
109109
// CHECK: %[[#INPUT:]] = cir.load %[[#A]]
110-
// CHECK: %[[#INCREMENTED:]] = cir.unary(dec, %[[#INPUT]])
110+
// CHECK: %[[#INCREMENTED:]] = cir.unary(dec, %[[#INPUT]]) nsw
111111
// CHECK: cir.store %[[#INCREMENTED]], %[[#A]]
112112
// CHECK: %[[#A_TO_OUTPUT:]] = cir.load %[[#A]]
113113
// CHECK: cir.store %[[#A_TO_OUTPUT]], %[[#RET]]
@@ -128,7 +128,7 @@ int inc2() {
128128
// CHECK: %[[#ATMP:]] = cir.const #cir.int<1> : !s32i
129129
// CHECK: cir.store %[[#ATMP]], %[[#A]] : !s32i
130130
// CHECK: %[[#ATOB:]] = cir.load %[[#A]]
131-
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#ATOB]])
131+
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#ATOB]]) nsw
132132
// CHECK: cir.store %[[#INCREMENTED]], %[[#A]]
133133
// CHECK: cir.store %[[#ATOB]], %[[#B]]
134134
// CHECK: %[[#B_TO_OUTPUT:]] = cir.load %[[#B]]
@@ -218,7 +218,7 @@ void chars(char c) {
218218
// CHECK: cir.unary(plus, %[[#PROMO]]) : !s32i, !s32i
219219
int c2 = -c;
220220
// CHECK: %[[#PROMO:]] = cir.cast(integral, %{{.+}} : !s8i), !s32i
221-
// CHECK: cir.unary(minus, %[[#PROMO]]) : !s32i, !s32i
221+
// CHECK: cir.unary(minus, %[[#PROMO]]) nsw : !s32i, !s32i
222222

223223
// Chars can go through some integer promotion codegen paths even when not promoted.
224224
++c; // CHECK: cir.unary(inc, %10) : !s8i, !s8i

0 commit comments

Comments
 (0)