Skip to content

Commit a96e075

Browse files
committed
[CIR] Generate the nsw flag correctly for unary ops
A previous checkin used a workaround to generate the nsw flag where needed for unary ops. This change upstreams a subsequent change that was made in the incubator to generate the flag correctly.
1 parent 32f2402 commit a96e075

File tree

5 files changed

+43
-28
lines changed

5 files changed

+43
-28
lines changed

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

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

704704
let results = (outs CIR_AnyType:$result);
705-
let arguments = (ins Arg<UnaryOpKind, "unary op kind">:$kind, Arg<CIR_AnyType>:$input);
705+
let arguments = (ins Arg<UnaryOpKind, "unary op kind">:$kind,
706+
Arg<CIR_AnyType>:$input,
707+
UnitAttr:$no_signed_wrap);
706708

707709
let assemblyFormat = [{
708-
`(` $kind `,` $input `)` `:` type($input) `,` type($result) attr-dict
710+
`(` $kind `,` $input `)`
711+
(`nsw` $no_signed_wrap^)?
712+
`:` type($input) `,` type($result) attr-dict
709713
}];
710714

711715
let hasVerifier = 1;

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ struct MissingFeatures {
7676
static bool opScopeCleanupRegion() { return false; }
7777

7878
// Unary operator handling
79-
static bool opUnarySignedOverflow() { return false; }
8079
static bool opUnaryPromotionType() { return false; }
8180

8281
// Clang early optimizations or things defered to LLVM lowering.

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
374374
cir::UnaryOpKind kind =
375375
e->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
376376
// NOTE(CIR): clang calls CreateAdd but folds this to a unary op
377-
value = emitUnaryOp(e, kind, input);
377+
value = emitUnaryOp(e, kind, input, /*nsw=*/false);
378378
}
379379
} else if (isa<PointerType>(type)) {
380380
cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec pointer");
@@ -429,19 +429,17 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
429429
mlir::Value emitIncDecConsiderOverflowBehavior(const UnaryOperator *e,
430430
mlir::Value inVal,
431431
bool isInc) {
432-
assert(!cir::MissingFeatures::opUnarySignedOverflow());
433432
cir::UnaryOpKind kind =
434433
e->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
435434
switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
436435
case LangOptions::SOB_Defined:
437-
return emitUnaryOp(e, kind, inVal);
436+
return emitUnaryOp(e, kind, inVal, /*nsw=*/false);
438437
case LangOptions::SOB_Undefined:
439438
assert(!cir::MissingFeatures::sanitizers());
440-
return emitUnaryOp(e, kind, inVal);
441-
break;
439+
return emitUnaryOp(e, kind, inVal, /*nsw=*/true);
442440
case LangOptions::SOB_Trapping:
443441
if (!e->canOverflow())
444-
return emitUnaryOp(e, kind, inVal);
442+
return emitUnaryOp(e, kind, inVal, /*nsw=*/true);
445443
cgf.cgm.errorNYI(e->getSourceRange(), "inc/def overflow SOB_Trapping");
446444
return {};
447445
}
@@ -473,18 +471,19 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
473471
assert(!cir::MissingFeatures::opUnaryPromotionType());
474472
mlir::Value operand = Visit(e->getSubExpr());
475473

476-
assert(!cir::MissingFeatures::opUnarySignedOverflow());
474+
bool nsw =
475+
kind == cir::UnaryOpKind::Minus && e->getType()->isSignedIntegerType();
477476

478477
// NOTE: LLVM codegen will lower this directly to either a FNeg
479478
// or a Sub instruction. In CIR this will be handled later in LowerToLLVM.
480-
return emitUnaryOp(e, kind, operand);
479+
return emitUnaryOp(e, kind, operand, nsw);
481480
}
482481

483482
mlir::Value emitUnaryOp(const UnaryOperator *e, cir::UnaryOpKind kind,
484-
mlir::Value input) {
483+
mlir::Value input, bool nsw = false) {
485484
return builder.create<cir::UnaryOp>(
486485
cgf.getLoc(e->getSourceRange().getBegin()), input.getType(), kind,
487-
input);
486+
input, nsw);
488487
}
489488

490489
mlir::Value VisitUnaryNot(const UnaryOperator *e) {

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

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -860,14 +860,8 @@ mlir::LogicalResult CIRToLLVMUnaryOpLowering::matchAndRewrite(
860860
// Integer unary operations: + - ~ ++ --
861861
if (mlir::isa<cir::IntType>(elementType)) {
862862
mlir::LLVM::IntegerOverflowFlags maybeNSW =
863-
mlir::LLVM::IntegerOverflowFlags::none;
864-
if (mlir::dyn_cast<cir::IntType>(elementType).isSigned()) {
865-
assert(!cir::MissingFeatures::opUnarySignedOverflow());
866-
// TODO: For now, assume signed overflow is undefined. We'll need to add
867-
// an attribute to the unary op to control this.
868-
maybeNSW = mlir::LLVM::IntegerOverflowFlags::nsw;
869-
}
870-
863+
op.getNoSignedWrap() ? mlir::LLVM::IntegerOverflowFlags::nsw
864+
: mlir::LLVM::IntegerOverflowFlags::none;
871865
switch (op.getKind()) {
872866
case cir::UnaryOpKind::Inc: {
873867
assert(!isVector && "++ not allowed on vector types");

clang/test/CIR/CodeGen/unary.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ int inc0() {
8383
// CHECK: %[[ATMP:.*]] = cir.const #cir.int<1> : !s32i
8484
// CHECK: cir.store %[[ATMP]], %[[A]] : !s32i
8585
// CHECK: %[[INPUT:.*]] = cir.load %[[A]]
86-
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[INPUT]])
86+
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[INPUT]]) nsw
8787
// CHECK: cir.store %[[INCREMENTED]], %[[A]]
8888
// CHECK: %[[A_TO_OUTPUT:.*]] = cir.load %[[A]]
8989

@@ -111,8 +111,8 @@ int dec0() {
111111
// CHECK: %[[ATMP:.*]] = cir.const #cir.int<1> : !s32i
112112
// CHECK: cir.store %[[ATMP]], %[[A]] : !s32i
113113
// CHECK: %[[INPUT:.*]] = cir.load %[[A]]
114-
// CHECK: %[[INCREMENTED:.*]] = cir.unary(dec, %[[INPUT]])
115-
// CHECK: cir.store %[[INCREMENTED]], %[[A]]
114+
// CHECK: %[[DECREMENTED:.*]] = cir.unary(dec, %[[INPUT]]) nsw
115+
// CHECK: cir.store %[[DECREMENTED]], %[[A]]
116116
// CHECK: %[[A_TO_OUTPUT:.*]] = cir.load %[[A]]
117117

118118
// LLVM: define i32 @dec0()
@@ -139,7 +139,7 @@ int inc1() {
139139
// CHECK: %[[ATMP:.*]] = cir.const #cir.int<1> : !s32i
140140
// CHECK: cir.store %[[ATMP]], %[[A]] : !s32i
141141
// CHECK: %[[INPUT:.*]] = cir.load %[[A]]
142-
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[INPUT]])
142+
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[INPUT]]) nsw
143143
// CHECK: cir.store %[[INCREMENTED]], %[[A]]
144144
// CHECK: %[[A_TO_OUTPUT:.*]] = cir.load %[[A]]
145145

@@ -167,8 +167,8 @@ int dec1() {
167167
// CHECK: %[[ATMP:.*]] = cir.const #cir.int<1> : !s32i
168168
// CHECK: cir.store %[[ATMP]], %[[A]] : !s32i
169169
// CHECK: %[[INPUT:.*]] = cir.load %[[A]]
170-
// CHECK: %[[INCREMENTED:.*]] = cir.unary(dec, %[[INPUT]])
171-
// CHECK: cir.store %[[INCREMENTED]], %[[A]]
170+
// CHECK: %[[DECREMENTED:.*]] = cir.unary(dec, %[[INPUT]]) nsw
171+
// CHECK: cir.store %[[DECREMENTED]], %[[A]]
172172
// CHECK: %[[A_TO_OUTPUT:.*]] = cir.load %[[A]]
173173

174174
// LLVM: define i32 @dec1()
@@ -197,7 +197,7 @@ int inc2() {
197197
// CHECK: %[[ATMP:.*]] = cir.const #cir.int<1> : !s32i
198198
// CHECK: cir.store %[[ATMP]], %[[A]] : !s32i
199199
// CHECK: %[[ATOB:.*]] = cir.load %[[A]]
200-
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[ATOB]])
200+
// CHECK: %[[INCREMENTED:.*]] = cir.unary(inc, %[[ATOB]]) nsw
201201
// CHECK: cir.store %[[INCREMENTED]], %[[A]]
202202
// CHECK: cir.store %[[ATOB]], %[[B]]
203203
// CHECK: %[[B_TO_OUTPUT:.*]] = cir.load %[[B]]
@@ -405,3 +405,22 @@ float fpPostInc2() {
405405
// OGCG: store float %[[A_INC]], ptr %[[A]], align 4
406406
// OGCG: store float %[[A_LOAD]], ptr %[[B]], align 4
407407
// OGCG: %[[B_TO_OUTPUT:.*]] = load float, ptr %[[B]], align 4
408+
409+
void chars(char c) {
410+
// CHECK: cir.func @chars
411+
412+
int c1 = +c;
413+
// CHECK: %[[PROMO:.*]] = cir.cast(integral, %{{.+}} : !s8i), !s32i
414+
// CHECK: cir.unary(plus, %[[PROMO]]) : !s32i, !s32i
415+
int c2 = -c;
416+
// CHECK: %[[PROMO:.*]] = cir.cast(integral, %{{.+}} : !s8i), !s32i
417+
// CHECK: cir.unary(minus, %[[PROMO]]) nsw : !s32i, !s32i
418+
419+
// Chars can go through some integer promotion codegen paths even when not promoted.
420+
// These should not have nsw attributes because the intermediate promotion makes the
421+
// overflow defined behavior.
422+
++c; // CHECK: cir.unary(inc, %{{.+}}) : !s8i, !s8i
423+
--c; // CHECK: cir.unary(dec, %{{.+}}) : !s8i, !s8i
424+
c++; // CHECK: cir.unary(inc, %{{.+}}) : !s8i, !s8i
425+
c--; // CHECK: cir.unary(dec, %{{.+}}) : !s8i, !s8i
426+
}

0 commit comments

Comments
 (0)