Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1146,10 +1146,14 @@ def UnaryOp : CIR_Op<"unary", [Pure, SameOperandsAndResultType]> {
}];

let results = (outs CIR_AnyType:$result);
let arguments = (ins Arg<UnaryOpKind, "unary op kind">:$kind, Arg<CIR_AnyType>:$input);
let arguments = (ins Arg<UnaryOpKind, "unary op kind">:$kind,
Arg<CIR_AnyType>:$input,
UnitAttr:$no_signed_wrap);

let assemblyFormat = [{
`(` $kind `,` $input `)` `:` type($input) `,` type($result) attr-dict
`(` $kind `,` $input `)`
(`nsw` $no_signed_wrap^)?
`:` type($input) `,` type($result) attr-dict
}];

let hasVerifier = 1;
Expand Down
17 changes: 8 additions & 9 deletions clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
auto Kind =
E->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
// NOTE(CIR): clang calls CreateAdd but folds this to a unary op
value = emitUnaryOp(E, Kind, input);
value = emitUnaryOp(E, Kind, input, /*nsw=*/false);
}
// Next most common: pointer increment.
} else if (const PointerType *ptr = type->getAs<PointerType>()) {
Expand Down Expand Up @@ -580,22 +580,20 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
mlir::Value emitIncDecConsiderOverflowBehavior(const UnaryOperator *E,
mlir::Value InVal,
bool IsInc) {
// NOTE(CIR): The SignedOverflowBehavior is attached to the global ModuleOp
// and the nsw behavior is handled during lowering.
auto Kind =
E->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return emitUnaryOp(E, Kind, InVal);
return emitUnaryOp(E, Kind, InVal, /*nsw=*/false);
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return emitUnaryOp(E, Kind, InVal);
return emitUnaryOp(E, Kind, InVal, /*nsw=*/true);
llvm_unreachable(
"inc/dec overflow behavior SOB_Undefined not implemented yet");
break;
case LangOptions::SOB_Trapping:
if (!E->canOverflow())
return emitUnaryOp(E, Kind, InVal);
return emitUnaryOp(E, Kind, InVal, /*nsw=*/true);
llvm_unreachable(
"inc/dec overflow behavior SOB_Trapping not implemented yet");
break;
Expand Down Expand Up @@ -661,7 +659,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {

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

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

mlir::Value emitUnaryOp(const UnaryOperator *E, cir::UnaryOpKind kind,
mlir::Value input) {
mlir::Value input, bool nsw = false) {
return Builder.create<cir::UnaryOp>(
CGF.getLoc(E->getSourceRange().getBegin()), input.getType(), kind,
input);
input, nsw);
}

// C++
Expand Down
15 changes: 9 additions & 6 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2553,21 +2553,24 @@ mlir::LogicalResult CIRToLLVMUnaryOpLowering::matchAndRewrite(

// Integer unary operations: + - ~ ++ --
if (mlir::isa<cir::IntType>(elementType)) {
auto overflowFlags = op.getNoSignedWrap()
? mlir::LLVM::IntegerOverflowFlags::nsw
: mlir::LLVM::IntegerOverflowFlags::none;
switch (op.getKind()) {
case cir::UnaryOpKind::Inc: {
assert(!IsVector && "++ not allowed on vector types");
auto One = rewriter.create<mlir::LLVM::ConstantOp>(
loc, llvmType, mlir::IntegerAttr::get(llvmType, 1));
rewriter.replaceOpWithNewOp<mlir::LLVM::AddOp>(op, llvmType,
adaptor.getInput(), One);
rewriter.replaceOpWithNewOp<mlir::LLVM::AddOp>(
op, llvmType, adaptor.getInput(), One, overflowFlags);
return mlir::success();
}
case cir::UnaryOpKind::Dec: {
assert(!IsVector && "-- not allowed on vector types");
auto One = rewriter.create<mlir::LLVM::ConstantOp>(
loc, llvmType, mlir::IntegerAttr::get(llvmType, 1));
rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(op, llvmType,
adaptor.getInput(), One);
rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(
op, llvmType, adaptor.getInput(), One, overflowFlags);
return mlir::success();
}
case cir::UnaryOpKind::Plus: {
Expand All @@ -2581,8 +2584,8 @@ mlir::LogicalResult CIRToLLVMUnaryOpLowering::matchAndRewrite(
else
Zero = rewriter.create<mlir::LLVM::ConstantOp>(
loc, llvmType, mlir::IntegerAttr::get(llvmType, 0));
rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(op, llvmType, Zero,
adaptor.getInput());
rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(
op, llvmType, Zero, adaptor.getInput(), overflowFlags);
return mlir::success();
}
case cir::UnaryOpKind::Not: {
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CIR/CodeGen/bitfields.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ int load_field(S* s) {
// CHECK: cir.func {{.*@unOp}}
// CHECK: [[TMP0:%.*]] = cir.get_member {{.*}}[1] {name = "d"} : !cir.ptr<!ty_S> -> !cir.ptr<!cir.array<!u8i x 3>>
// CHECK: [[TMP1:%.*]] = cir.get_bitfield(#bfi_d, [[TMP0]] : !cir.ptr<!cir.array<!u8i x 3>>) -> !s32i
// CHECK: [[TMP2:%.*]] = cir.unary(inc, [[TMP1]]) : !s32i, !s32i
// CHECK: [[TMP2:%.*]] = cir.unary(inc, [[TMP1]]) nsw : !s32i, !s32i
// CHECK: cir.set_bitfield(#bfi_d, [[TMP0]] : !cir.ptr<!cir.array<!u8i x 3>>, [[TMP2]] : !s32i)
void unOp(S* s) {
s->d++;
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CIR/CodeGen/int128.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ unsigned __int128 test2(unsigned __int128 x) {
// LLVM-LABEL: @_Z11unary_arithn
__int128 unary_arith(__int128 x) {
return ++x;
// CHECK: %{{.+}} = cir.unary(inc, %{{.+}}) : !s128i, !s128i
// LLVM: %{{.+}} = add i128 %{{.+}}, 1
// CHECK: %{{.+}} = cir.unary(inc, %{{.+}}) nsw : !s128i, !s128i
// LLVM: %{{.+}} = add nsw i128 %{{.+}}, 1
}

// CHECK-LABEL: @_Z12binary_arithnn
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CIR/CodeGen/static-vars.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ void func1(void) {
j++;
// CHECK-DAG: %[[#V2:]] = cir.get_global @func1.j : !cir.ptr<!s32i>
// CHECK-DAG: %[[#V3:]] = cir.load %[[#V2]] : !cir.ptr<!s32i>, !s32i
// CHECK-DAG: %[[#V4:]] = cir.unary(inc, %[[#V3]]) : !s32i, !s32i
// CHECK-DAG: %[[#V4:]] = cir.unary(inc, %[[#V3]]) nsw : !s32i, !s32i
// CHECK-DAG: cir.store %[[#V4]], %[[#V2]] : !s32i, !cir.ptr<!s32i>
}

Expand Down
2 changes: 1 addition & 1 deletion clang/test/CIR/CodeGen/static-vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void func1(void) {
j++;
// CHECK-DAG: %[[#V2:]] = cir.get_global @_ZZ5func1vE1j : !cir.ptr<!s32i>
// CHECK-DAG: %[[#V3:]] = cir.load %[[#V2]] : !cir.ptr<!s32i>, !s32i
// CHECK-DAG: %[[#V4:]] = cir.unary(inc, %[[#V3]]) : !s32i, !s32i
// CHECK-DAG: %[[#V4:]] = cir.unary(inc, %[[#V3]]) nsw : !s32i, !s32i
// CHECK-DAG: cir.store %[[#V4]], %[[#V2]] : !s32i, !cir.ptr<!s32i>
}

Expand Down
16 changes: 8 additions & 8 deletions clang/test/CIR/CodeGen/throw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ void refoo1() {
// CIR: } catch [type #cir.all {
// CIR: %[[V3:.*]] = cir.catch_param -> !cir.ptr<!void>
// CIR: %[[V4:.*]] = cir.load %[[V0]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) : !s32i, !s32i
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) nsw : !s32i, !s32i
// CIR: cir.store %[[V5]], %[[V0]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: }]
Expand Down Expand Up @@ -91,7 +91,7 @@ void refoo1() {
// LLVM: %[[V16:.*]] = phi ptr [ %[[V9]], %[[B7]] ], [ %[[V13]], %[[B11]] ]
// LLVM: %[[V17:.*]] = call ptr @__cxa_begin_catch(ptr %[[V16]])
// LLVM: %[[V18:.*]] = load i32, ptr %[[V2]], align 4
// LLVM: %[[V19:.*]] = add i32 %[[V18]], 1
// LLVM: %[[V19:.*]] = add nsw i32 %[[V18]], 1
// LLVM: store i32 %[[V19]], ptr %[[V2]], align 4
// LLVM: call void @__cxa_end_catch()

Expand Down Expand Up @@ -136,7 +136,7 @@ void refoo2() {
// CIR: cir.yield
// CIR: } step {
// CIR: %[[V5:.*]] = cir.load %[[V3]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[V6:.*]] = cir.unary(inc, %[[V5]]) : !s32i, !s32i
// CIR: %[[V6:.*]] = cir.unary(inc, %[[V5]]) nsw : !s32i, !s32i
// CIR: cir.store %[[V6]], %[[V3]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: }
Expand All @@ -146,7 +146,7 @@ void refoo2() {
// CIR: } catch [type #cir.all {
// CIR: %[[V3:.*]] = cir.catch_param -> !cir.ptr<!void>
// CIR: %[[V4:.*]] = cir.load %[[V0]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) : !s32i, !s32i
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) nsw : !s32i, !s32i
// CIR: cir.store %[[V5]], %[[V0]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: }]
Expand All @@ -166,7 +166,7 @@ void refoo2() {
// LLVM: br label %[[B16:.*]]
// LLVM: [[B16]]:
// LLVM: %[[V17]] = load i32, ptr {{.*}}, align 4
// LLVM: %[[V18]] = add i32 %[[V17]], 1
// LLVM: %[[V18]] = add nsw i32 %[[V17]], 1
// LLVM: store i32 %[[V18]], ptr {{.*}}, align 4
// LLVM: br label {{.*}}
// LLVM: %[[B19:.*]]
Expand Down Expand Up @@ -198,7 +198,7 @@ void refoo2() {
// LLVM: %[[V35:.*]] = phi ptr [ %[[V32]], %[[B30]] ], [ %[[V24]], %[[B22]] ], [ %[[V28]], %[[B26]] ]
// LLVM: %[[V36:.*]] = call ptr @__cxa_begin_catch(ptr %[[V35]])
// LLVM: %[[V37:.*]] = load i32, ptr {{.*}}, align 4
// LLVM: %[[V38:.*]] = add i32 %[[V37]], 1
// LLVM: %[[V38:.*]] = add nsw i32 %[[V37]], 1
// LLVM: store i32 %[[V38]], ptr {{.*}}, align 4
// LLVM: call void @__cxa_end_catch()
// LLVM: br label {{.*}}
Expand Down Expand Up @@ -228,7 +228,7 @@ void refoo3() {
// CIR: } catch [type #cir.all {
// CIR: %[[V3:.*]] = cir.catch_param -> !cir.ptr<!void>
// CIR: %[[V4:.*]] = cir.load %[[V0]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) : !s32i, !s32i
// CIR: %[[V5:.*]] = cir.unary(inc, %[[V4]]) nsw : !s32i, !s32i
// CIR: cir.store %[[V5]], %[[V0]] : !s32i, !cir.ptr<!s32i>
// CIR: cir.yield
// CIR: }]
Expand Down Expand Up @@ -261,7 +261,7 @@ void refoo3() {
// LLVM: %[[V17:.*]] = phi ptr [ %[[V14]], %[[B12]] ], [ %[[V10]], %[[B8]] ]
// LLVM: %[[V18:.*]] = call ptr @__cxa_begin_catch(ptr %[[V17]])
// LLVM: %[[V19:.*]] = load i32, ptr {{.*}}, align 4
// LLVM: %[[V20:.*]] = add i32 %[[V19]], 1
// LLVM: %[[V20:.*]] = add nsw i32 %[[V19]], 1
// LLVM: store i32 %[[V20]], ptr {{.*}}, align 4
// LLVM: call void @__cxa_end_catch()
// LLVM: br label %[[B21]]
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CIR/CodeGen/try-catch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ void tc6() {
// CHECK: cir.return
// CHECK: ^bb1: // no predecessors
// CHECK: %[[V2:.*]] = cir.load {{.*}} : !cir.ptr<!s32i>, !s32i
// CHECK: %[[V3:.*]] = cir.unary(inc, %[[V2]]) : !s32i, !s32i
// CHECK: %[[V3:.*]] = cir.unary(inc, %[[V2]]) nsw : !s32i, !s32i
// CHECK: cir.store %[[V3]], {{.*}} : !s32i, !cir.ptr<!s32i>
// CHECK: cir.yield
// CHECK: }
Expand Down
12 changes: 6 additions & 6 deletions clang/test/CIR/CodeGen/unary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ int inc0() {
// CHECK: %[[#ATMP:]] = cir.const #cir.int<1> : !s32i
// CHECK: cir.store %[[#ATMP]], %[[#A]] : !s32i
// CHECK: %[[#INPUT:]] = cir.load %[[#A]]
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#INPUT]])
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#INPUT]]) nsw
// CHECK: cir.store %[[#INCREMENTED]], %[[#A]]
// CHECK: %[[#A_TO_OUTPUT:]] = cir.load %[[#A]]
// CHECK: cir.store %[[#A_TO_OUTPUT]], %[[#RET]]
Expand All @@ -68,7 +68,7 @@ int dec0() {
// CHECK: %[[#ATMP:]] = cir.const #cir.int<1> : !s32i
// CHECK: cir.store %[[#ATMP]], %[[#A]] : !s32i
// CHECK: %[[#INPUT:]] = cir.load %[[#A]]
// CHECK: %[[#INCREMENTED:]] = cir.unary(dec, %[[#INPUT]])
// CHECK: %[[#INCREMENTED:]] = cir.unary(dec, %[[#INPUT]]) nsw
// CHECK: cir.store %[[#INCREMENTED]], %[[#A]]
// CHECK: %[[#A_TO_OUTPUT:]] = cir.load %[[#A]]
// CHECK: cir.store %[[#A_TO_OUTPUT]], %[[#RET]]
Expand All @@ -88,7 +88,7 @@ int inc1() {
// CHECK: %[[#ATMP:]] = cir.const #cir.int<1> : !s32i
// CHECK: cir.store %[[#ATMP]], %[[#A]] : !s32i
// CHECK: %[[#INPUT:]] = cir.load %[[#A]]
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#INPUT]])
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#INPUT]]) nsw
// CHECK: cir.store %[[#INCREMENTED]], %[[#A]]
// CHECK: %[[#A_TO_OUTPUT:]] = cir.load %[[#A]]
// CHECK: cir.store %[[#A_TO_OUTPUT]], %[[#RET]]
Expand All @@ -107,7 +107,7 @@ int dec1() {
// CHECK: %[[#ATMP:]] = cir.const #cir.int<1> : !s32i
// CHECK: cir.store %[[#ATMP]], %[[#A]] : !s32i
// CHECK: %[[#INPUT:]] = cir.load %[[#A]]
// CHECK: %[[#INCREMENTED:]] = cir.unary(dec, %[[#INPUT]])
// CHECK: %[[#INCREMENTED:]] = cir.unary(dec, %[[#INPUT]]) nsw
// CHECK: cir.store %[[#INCREMENTED]], %[[#A]]
// CHECK: %[[#A_TO_OUTPUT:]] = cir.load %[[#A]]
// CHECK: cir.store %[[#A_TO_OUTPUT]], %[[#RET]]
Expand All @@ -128,7 +128,7 @@ int inc2() {
// CHECK: %[[#ATMP:]] = cir.const #cir.int<1> : !s32i
// CHECK: cir.store %[[#ATMP]], %[[#A]] : !s32i
// CHECK: %[[#ATOB:]] = cir.load %[[#A]]
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#ATOB]])
// CHECK: %[[#INCREMENTED:]] = cir.unary(inc, %[[#ATOB]]) nsw
// CHECK: cir.store %[[#INCREMENTED]], %[[#A]]
// CHECK: cir.store %[[#ATOB]], %[[#B]]
// CHECK: %[[#B_TO_OUTPUT:]] = cir.load %[[#B]]
Expand Down Expand Up @@ -218,7 +218,7 @@ void chars(char c) {
// CHECK: cir.unary(plus, %[[#PROMO]]) : !s32i, !s32i
int c2 = -c;
// CHECK: %[[#PROMO:]] = cir.cast(integral, %{{.+}} : !s8i), !s32i
// CHECK: cir.unary(minus, %[[#PROMO]]) : !s32i, !s32i
// CHECK: cir.unary(minus, %[[#PROMO]]) nsw : !s32i, !s32i

// Chars can go through some integer promotion codegen paths even when not promoted.
++c; // CHECK: cir.unary(inc, %10) : !s8i, !s8i
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CIR/Lowering/switch-while.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ int f(int a, int cond) {
// CHECK: br label %[[LOOP_HEADER:.+]]
//
// CHECK: [[LOOP_HEADER]]:
// CHECK: add i32 %{{.*}}, 1
// CHECK: add nsw i32 %{{.*}}, 1
// CHECK: br label %[[DEFAULT_BB:.+]]
//
// CHECK: [[DEFAULT_BB]]:
Expand All @@ -61,7 +61,7 @@ int f(int a, int cond) {
// CHECK: add nsw i32 %[[V1]], %[[V2]]
//
// CHECK: [[TWO_BB]]:
// CHECK: add i32 %{{.*}}, 1
// CHECK: add nsw i32 %{{.*}}, 1
// CHECK: br label %[[FALLTHOUGH_BB:.+]]
//
// CHECK: [[FALLTHOUGH_BB]]:
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CIR/Transforms/mem2reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void alloca_in_loop(int* ar, int n) {
// BEFORE: cir.yield
// BEFORE: } step {
// BEFORE: %4 = cir.load %2 : !cir.ptr<!s32i>, !s32i
// BEFORE: %5 = cir.unary(inc, %4) : !s32i, !s32i
// BEFORE: %5 = cir.unary(inc, %4) nsw : !s32i, !s32i
// BEFORE: cir.store %5, %2 : !s32i, !cir.ptr<!s32i>
// BEFORE: cir.yield
// BEFORE: }
Expand All @@ -82,7 +82,7 @@ void alloca_in_loop(int* ar, int n) {
// MEM2REG: ^bb5: // pred: ^bb4
// MEM2REG: cir.br ^bb6
// MEM2REG: ^bb6: // pred: ^bb5
// MEM2REG: %5 = cir.unary(inc, %1) : !s32i, !s32i
// MEM2REG: %5 = cir.unary(inc, %1) nsw : !s32i, !s32i
// MEM2REG: cir.br ^bb2(%5 : !s32i)
// MEM2REG: ^bb7: // pred: ^bb2
// MEM2REG: cir.br ^bb8
Expand Down
Loading