[clang] [CIR] Upstream initial support for unary op (PR #131369)

via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 14 10:52:59 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Andy Kaylor (andykaylor)

<details>
<summary>Changes</summary>

This adds support for the cir.unary operation.

---

Patch is 40.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/131369.diff


11 Files Affected:

- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+49) 
- (modified) clang/include/clang/CIR/MissingFeatures.h (+9) 
- (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+48) 
- (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+223) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.cpp (+2) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+4) 
- (modified) clang/lib/CIR/CodeGen/CIRGenValue.h (+1) 
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+41) 
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+124-1) 
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h (+10) 
- (added) clang/test/CIR/CodeGen/unary.cpp (+392) 


``````````diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 77c43e5ace64a..52c78ffe42647 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -468,6 +468,55 @@ def BrOp : CIR_Op<"br",
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// UnaryOp
+//===----------------------------------------------------------------------===//
+
+def UnaryOpKind_Inc   : I32EnumAttrCase<"Inc",   1, "inc">;
+def UnaryOpKind_Dec   : I32EnumAttrCase<"Dec",   2, "dec">;
+def UnaryOpKind_Plus  : I32EnumAttrCase<"Plus",  3, "plus">;
+def UnaryOpKind_Minus : I32EnumAttrCase<"Minus", 4, "minus">;
+def UnaryOpKind_Not   : I32EnumAttrCase<"Not",   5, "not">;
+
+def UnaryOpKind : I32EnumAttr<
+    "UnaryOpKind",
+    "unary operation kind",
+    [UnaryOpKind_Inc,
+     UnaryOpKind_Dec,
+     UnaryOpKind_Plus,
+     UnaryOpKind_Minus,
+     UnaryOpKind_Not,
+     ]> {
+  let cppNamespace = "::cir";
+}
+
+// FIXME: Pure won't work when we add overloading.
+def UnaryOp : CIR_Op<"unary", [Pure, SameOperandsAndResultType]> {
+  let summary = "Unary operations";
+  let description = [{
+    `cir.unary` performs the unary operation according to
+    the specified opcode kind: [inc, dec, plus, minus, not].
+
+    It requires one input operand and has one result, both types
+    should be the same.
+
+    ```mlir
+    %7 = cir.unary(inc, %1) : i32 -> i32
+    %8 = cir.unary(dec, %2) : i32 -> i32
+    ```
+  }];
+
+  let results = (outs CIR_AnyType:$result);
+  let arguments = (ins Arg<UnaryOpKind, "unary op kind">:$kind, Arg<CIR_AnyType>:$input);
+
+  let assemblyFormat = [{
+      `(` $kind `,` $input `)` `:` type($input) `,` type($result) attr-dict
+  }];
+
+  let hasVerifier = 1;
+  let hasFolder = 1;
+}
+
 //===----------------------------------------------------------------------===//
 // GlobalOp
 //===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 6c3d74cf96c64..fcbb2ae3db6aa 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -72,6 +72,10 @@ struct MissingFeatures {
   static bool opFuncLinkage() { return false; }
   static bool opFuncVisibility() { return false; }
 
+  // Unary operator handling
+  static bool opUnarySignedOverflow() { return false; }
+  static bool opUnaryPromotionType() { return false; }
+
   // Misc
   static bool scalarConversionOpts() { return false; }
   static bool tryEmitAsConstant() { return false; }
@@ -86,6 +90,11 @@ struct MissingFeatures {
   static bool aggValueSlot() { return false; }
 
   static bool unsizedTypes() { return false; }
+  static bool sanitizers() { return false; }
+  static bool CGFPOptionsRAII() { return false; }
+
+  // Missing types
+  static bool vectorType() { return false; }
 };
 
 } // namespace cir
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 5b81fe172e645..24c0c8a18efd8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -165,6 +165,54 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
   return LValue();
 }
 
+LValue CIRGenFunction::emitUnaryOpLValue(const UnaryOperator *e) {
+  UnaryOperatorKind op = e->getOpcode();
+
+  // __extension__ doesn't affect lvalue-ness.
+  if (op == UO_Extension)
+    return emitLValue(e->getSubExpr());
+
+  switch (op) {
+  case UO_Deref: {
+    cgm.errorNYI(e->getSourceRange(), "UnaryOp dereference");
+    return LValue();
+  }
+  case UO_Real:
+  case UO_Imag: {
+    cgm.errorNYI(e->getSourceRange(), "UnaryOp real/imag");
+    return LValue();
+  }
+  case UO_PreInc:
+  case UO_PreDec: {
+    bool isInc = e->isIncrementOp();
+    LValue lv = emitLValue(e->getSubExpr());
+
+    assert(e->isPrefix() && "Prefix operator in unexpected state!");
+
+    if (e->getType()->isAnyComplexType()) {
+      cgm.errorNYI(e->getSourceRange(), "UnaryOp complex inc/dec");
+      return LValue();
+    } else {
+      emitScalarPrePostIncDec(e, lv, isInc, /*isPre=*/true);
+    }
+
+    return lv;
+  }
+  case UO_Extension:
+    llvm_unreachable("UnaryOperator extension should be handled above!");
+  case UO_Plus:
+  case UO_Minus:
+  case UO_Not:
+  case UO_LNot:
+  case UO_AddrOf:
+  case UO_PostInc:
+  case UO_PostDec:
+  case UO_Coawait:
+    llvm_unreachable("UnaryOperator of non-lvalue kind!");
+  }
+  llvm_unreachable("Unknown unary operator kind!");
+}
+
 /// Emit code to compute the specified expression which
 /// can have any type.  The result is returned as an RValue struct.
 RValue CIRGenFunction::emitAnyExpr(const Expr *e) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index b9e56dc4123d6..b0d644faade17 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -92,6 +92,222 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
 
   mlir::Value VisitCastExpr(CastExpr *E);
 
+  // Unary Operators.
+  mlir::Value VisitUnaryPostDec(const UnaryOperator *e) {
+    LValue lv = cgf.emitLValue(e->getSubExpr());
+    return emitScalarPrePostIncDec(e, lv, false, false);
+  }
+  mlir::Value VisitUnaryPostInc(const UnaryOperator *e) {
+    LValue lv = cgf.emitLValue(e->getSubExpr());
+    return emitScalarPrePostIncDec(e, lv, true, false);
+  }
+  mlir::Value VisitUnaryPreDec(const UnaryOperator *e) {
+    LValue lv = cgf.emitLValue(e->getSubExpr());
+    return emitScalarPrePostIncDec(e, lv, false, true);
+  }
+  mlir::Value VisitUnaryPreInc(const UnaryOperator *e) {
+    LValue lv = cgf.emitLValue(e->getSubExpr());
+    return emitScalarPrePostIncDec(e, lv, true, true);
+  }
+  mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv,
+                                      bool isInc, bool isPre) {
+    if (cgf.getLangOpts().OpenMP)
+      cgf.cgm.errorNYI(e->getSourceRange(), "inc/dec OpenMP");
+
+    QualType type = e->getSubExpr()->getType();
+
+    mlir::Value value;
+    mlir::Value input;
+
+    if (type->getAs<AtomicType>()) {
+      cgf.cgm.errorNYI(e->getSourceRange(), "Atomic inc/dec");
+      // TODO(cir): This is not correct, but it will produce reasonable code
+      // until atomic operations are implemented.
+      value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getScalarVal();
+      input = value;
+    } else {
+      value = cgf.emitLoadOfLValue(lv, e->getExprLoc()).getScalarVal();
+      input = value;
+    }
+
+    // NOTE: When possible, more frequent cases are handled first.
+
+    // Special case of integer increment that we have to check first: bool++.
+    // Due to promotion rules, we get:
+    //   bool++ -> bool = bool + 1
+    //          -> bool = (int)bool + 1
+    //          -> bool = ((int)bool + 1 != 0)
+    // An interesting aspect of this is that increment is always true.
+    // Decrement does not have this property.
+    if (isInc && type->isBooleanType()) {
+      value = builder.create<cir::ConstantOp>(cgf.getLoc(e->getExprLoc()),
+                                              cgf.convertType(type),
+                                              builder.getCIRBoolAttr(true));
+    } else if (type->isIntegerType()) {
+      QualType promotedType;
+      bool canPerformLossyDemotionCheck = false;
+      if (cgf.getContext().isPromotableIntegerType(type)) {
+        promotedType = cgf.getContext().getPromotedIntegerType(type);
+        assert(promotedType != type && "Shouldn't promote to the same type.");
+        canPerformLossyDemotionCheck = true;
+        canPerformLossyDemotionCheck &=
+            cgf.getContext().getCanonicalType(type) !=
+            cgf.getContext().getCanonicalType(promotedType);
+        canPerformLossyDemotionCheck &=
+            type->isIntegerType() && promotedType->isIntegerType();
+
+        // TODO(cir): Currently, we store bitwidths in CIR types only for
+        // integers. This might also be required for other types.
+        auto srcCirTy = mlir::dyn_cast<cir::IntType>(cgf.convertType(type));
+        auto promotedCirTy =
+            mlir::dyn_cast<cir::IntType>(cgf.convertType(type));
+        assert(srcCirTy && promotedCirTy && "Expected integer type");
+
+        assert(
+            (!canPerformLossyDemotionCheck ||
+             type->isSignedIntegerOrEnumerationType() ||
+             promotedType->isSignedIntegerOrEnumerationType() ||
+             srcCirTy.getWidth() == promotedCirTy.getWidth()) &&
+            "The following check expects that if we do promotion to different "
+            "underlying canonical type, at least one of the types (either "
+            "base or promoted) will be signed, or the bitwidths will match.");
+      }
+
+      assert(!cir::MissingFeatures::sanitizers());
+      if (e->canOverflow() && type->isSignedIntegerOrEnumerationType()) {
+        value = emitIncDecConsiderOverflowBehavior(e, value, isInc);
+      } else {
+        cir::UnaryOpKind 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);
+      }
+    } else if (const PointerType *ptr = type->getAs<PointerType>()) {
+      cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec pointer");
+      return {};
+    } else if (type->isVectorType()) {
+      cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec vector");
+      return {};
+    } else if (type->isRealFloatingType()) {
+      assert(!cir::MissingFeatures::CGFPOptionsRAII());
+
+      if (type->isHalfType() &&
+          !cgf.getContext().getLangOpts().NativeHalfType) {
+        cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec half");
+        return {};
+      }
+
+      if (mlir::isa<cir::SingleType, cir::DoubleType>(value.getType())) {
+        // Create the inc/dec operation.
+        // NOTE(CIR): clang calls CreateAdd but folds this to a unary op
+        cir::UnaryOpKind kind =
+            (isInc ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec);
+        value = emitUnaryOp(e, kind, value);
+      } else {
+        cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec other fp type");
+        return {};
+      }
+    } else if (type->isFixedPointType()) {
+      cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec other fixed point");
+      return {};
+    } else {
+      assert(type->castAs<ObjCObjectPointerType>());
+      cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec ObjectiveC pointer");
+      return {};
+    }
+
+    CIRGenFunction::SourceLocRAIIObject sourceloc{
+        cgf, cgf.getLoc(e->getSourceRange())};
+
+    // Store the updated result through the lvalue
+    if (lv.isBitField()) {
+      cgf.cgm.errorNYI(e->getSourceRange(), "Unary inc/dec bitfield");
+      return {};
+    } else {
+      cgf.emitStoreThroughLValue(RValue::get(value), lv);
+    }
+
+    // If this is a postinc, return the value read from memory, otherwise use
+    // the updated value.
+    return isPre ? value : input;
+  }
+
+  mlir::Value emitIncDecConsiderOverflowBehavior(const UnaryOperator *e,
+                                                 mlir::Value inVal,
+                                                 bool isInc) {
+    assert(!cir::MissingFeatures::opUnarySignedOverflow());
+    cir::UnaryOpKind kind =
+        e->isIncrementOp() ? cir::UnaryOpKind::Inc : cir::UnaryOpKind::Dec;
+    switch (cgf.getLangOpts().getSignedOverflowBehavior()) {
+    case LangOptions::SOB_Defined:
+      return emitUnaryOp(e, kind, inVal);
+    case LangOptions::SOB_Undefined:
+      assert(!cir::MissingFeatures::sanitizers());
+      return emitUnaryOp(e, kind, inVal);
+      break;
+    case LangOptions::SOB_Trapping:
+      if (!e->canOverflow())
+        return emitUnaryOp(e, kind, inVal);
+      cgf.cgm.errorNYI(e->getSourceRange(), "inc/def overflow SOB_Trapping");
+      return {};
+    }
+    llvm_unreachable("Unexpected signed overflow behavior kind");
+  }
+
+  mlir::Value VisitUnaryPlus(const UnaryOperator *e,
+                             QualType promotionType = QualType()) {
+    if (!promotionType.isNull())
+      cgf.cgm.errorNYI(e->getSourceRange(), "VisitUnaryPlus: promotionType");
+    assert(!cir::MissingFeatures::opUnaryPromotionType());
+    mlir::Value result = VisitPlus(e);
+    return result;
+  }
+
+  mlir::Value VisitPlus(const UnaryOperator *e) {
+    // This differs from gcc, though, most likely due to a bug in gcc.
+    ignoreResultAssign = false;
+
+    assert(!cir::MissingFeatures::opUnaryPromotionType());
+    mlir::Value operand = Visit(e->getSubExpr());
+
+    return emitUnaryOp(e, cir::UnaryOpKind::Plus, operand);
+  }
+
+  mlir::Value VisitUnaryMinus(const UnaryOperator *e,
+                              QualType promotionType = QualType()) {
+    if (!promotionType.isNull())
+      cgf.cgm.errorNYI(e->getSourceRange(), "VisitUnaryMinus: promotionType");
+    assert(!cir::MissingFeatures::opUnaryPromotionType());
+    mlir::Value result = VisitMinus(e);
+    return result;
+  }
+
+  mlir::Value VisitMinus(const UnaryOperator *e) {
+    ignoreResultAssign = false;
+
+    assert(!cir::MissingFeatures::opUnaryPromotionType());
+    mlir::Value operand = Visit(e->getSubExpr());
+
+    assert(!cir::MissingFeatures::opUnarySignedOverflow());
+
+    // 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);
+  }
+
+  mlir::Value emitUnaryOp(const UnaryOperator *e, cir::UnaryOpKind kind,
+                          mlir::Value input) {
+    return builder.create<cir::UnaryOp>(
+        cgf.getLoc(e->getSourceRange().getBegin()), input.getType(), kind,
+        input);
+  }
+
+  mlir::Value VisitUnaryNot(const UnaryOperator *e) {
+    ignoreResultAssign = false;
+    mlir::Value op = Visit(e->getSubExpr());
+    return emitUnaryOp(e, cir::UnaryOpKind::Not, op);
+  }
+
   /// Emit a conversion from the specified type to the specified destination
   /// type, both of which are CIR scalar types.
   /// TODO: do we need ScalarConversionOpts here? Should be done in another
@@ -148,3 +364,10 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
   }
   return {};
 }
+
+mlir::Value CIRGenFunction::emitScalarPrePostIncDec(const UnaryOperator *E,
+                                                    LValue LV, bool isInc,
+                                                    bool isPre) {
+  return ScalarExprEmitter(*this, builder)
+      .emitScalarPrePostIncDec(E, LV, isInc, isPre);
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 47d296b70d789..2338ec9cd952a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -305,6 +305,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
                                std::string("l-value not implemented for '") +
                                    e->getStmtClassName() + "'");
     return LValue();
+  case Expr::UnaryOperatorClass:
+    return emitUnaryOpLValue(cast<UnaryOperator>(e));
   case Expr::DeclRefExprClass:
     return emitDeclRefLValue(cast<DeclRefExpr>(e));
   }
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 5ab882666f3e0..3542b6cafbc9c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -206,6 +206,7 @@ class CIRGenFunction : public CIRGenTypeCache {
                       LValue lvalue, bool capturedByInit = false);
 
   LValue emitDeclRefLValue(const clang::DeclRefExpr *e);
+  LValue emitUnaryOpLValue(const clang::UnaryOperator *e);
 
   /// Determine whether the given initializer is trivial in the sense
   /// that it requires no code to be generated.
@@ -305,6 +306,9 @@ class CIRGenFunction : public CIRGenTypeCache {
     // TODO: Add symbol table support
   }
 
+  mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv,
+                                      bool isInc, bool isPre);
+
   /// Emit the computation of the specified expression of scalar type.
   mlir::Value emitScalarExpr(const clang::Expr *e);
   cir::FuncOp generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h
index d29646983fd30..c559e853aad39 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -93,6 +93,7 @@ class LValue {
 
 public:
   bool isSimple() const { return lvType == Simple; }
+  bool isBitField() const { return lvType == BitField; }
 
   // TODO: Add support for volatile
   bool isVolatile() const { return false; }
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index d041791770d82..faf8996434f74 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -457,6 +457,47 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
 // been implemented yet.
 mlir::LogicalResult cir::FuncOp::verify() { return success(); }
 
+//===----------------------------------------------------------------------===//
+// UnaryOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::UnaryOp::verify() {
+  switch (getKind()) {
+  case cir::UnaryOpKind::Inc:
+  case cir::UnaryOpKind::Dec:
+  case cir::UnaryOpKind::Plus:
+  case cir::UnaryOpKind::Minus:
+  case cir::UnaryOpKind::Not:
+    // Nothing to verify.
+    return success();
+  }
+
+  llvm_unreachable("Unknown UnaryOp kind?");
+}
+
+static bool isBoolNot(cir::UnaryOp op) {
+  return isa<cir::BoolType>(op.getInput().getType()) &&
+         op.getKind() == cir::UnaryOpKind::Not;
+}
+
+// This folder simplifies the sequential boolean not operations.
+// For instance, the next two unary operations will be eliminated:
+//
+// ```mlir
+// %1 = cir.unary(not, %0) : !cir.bool, !cir.bool
+// %2 = cir.unary(not, %1) : !cir.bool, !cir.bool
+// ```
+//
+// and the argument of the first one (%0) will be used instead.
+OpFoldResult cir::UnaryOp::fold(FoldAdaptor adaptor) {
+  if (isBoolNot(*this))
+    if (auto previous = dyn_cast_or_null<UnaryOp>(getInput().getDefiningOp()))
+      if (isBoolNot(previous))
+        return previous.getInput();
+
+  return {};
+}
+
 //===----------------------------------------------------------------------===//
 // TableGen'd op method definitions
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 0cd27ecf1a3bd..a126e1a29de13 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -568,6 +568,128 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMUnaryOpLowering::matchAndRewrite(
+    cir::UnaryOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  assert(op.getType() == op.getInput().getType() &&
+         "Unary operation's operand type and result type are different");
+  mlir::Type type = op.getType();
+  mlir::Type elementType = type;
+  bool isVector = false;
+  assert(!cir::MissingFeatures::vectorType());
+  mlir::Type llvmType = getTypeConverter()->convertType(type);
+  mlir::Location loc = op.getLoc();
+
+  auto createIntConstant = [&](int64_t value) -> mlir::Value {
+    return rewriter.create<mlir::LLVM::ConstantOp>(
+        loc, llvmType, mlir::IntegerAttr::get(llvmType, value));
+  };
+
+  auto createFloatConstant = [&](double value) -> mlir::Value {
+    mlir::FloatAttr attr = rewriter.getFloatAttr(llvmType, value);
+    return rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, attr);
+  };
+
+  // Integer unary operations: + - ~ ++ --
+  if (mlir::isa<cir::IntType>(elementType)) {
+    mlir::LLVM::IntegerOverflowFlags maybeNSW =
+        mlir::LLVM::IntegerOverflowFlags::none;
+    if (mlir::dyn_cast<cir::IntType>(elementType).isSigned()) {
+      assert(!cir::MissingFeatures::opUnarySignedOverflow...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/131369


More information about the cfe-commits mailing list