Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[CIR] Upstream unary not for ComplexType#148857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
AmrDeveloper merged 3 commits intollvm:mainfromAmrDeveloper:cir_complex_unary_not
Jul 16, 2025

Conversation

AmrDeveloper
Copy link
Member

Upstream unary not for ComplexType

#141365

@llvmbotllvmbot added clangClang issues not falling into any other category ClangIRAnything related to the ClangIR project labelsJul 15, 2025
@llvmbot
Copy link
Member

@llvm/pr-subscribers-clang

Author: Amr Hesham (AmrDeveloper)

Changes

Upstream unary not for ComplexType

#141365


Full diff:https://github.com/llvm/llvm-project/pull/148857.diff

5 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h (+21)
  • (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.h (-16)
  • (modified) clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp (+6)
  • (modified) clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp (+56-1)
  • (added) clang/test/CIR/CodeGen/complex-unary.cpp (+48)
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.hindex 277c278fd38b7..25baf278bba38 100644--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h@@ -129,6 +129,22 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {   cir::BoolAttr getTrueAttr() { return getCIRBoolAttr(true); }   cir::BoolAttr getFalseAttr() { return getCIRBoolAttr(false); }+  mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,+                                  mlir::Value imag) {+    auto resultComplexTy = cir::ComplexType::get(real.getType());+    return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);+  }++  mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {+    auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());+    return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);+  }++  mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {+    auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());+    return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);+  }+   mlir::Value createNot(mlir::Value value) {     return create<cir::UnaryOp>(value.getLoc(), value.getType(),                                 cir::UnaryOpKind::Not, value);@@ -169,6 +185,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {     return create<cir::ContinueOp>(loc);   }+  mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind,+                            mlir::Value operand) {+    return create<cir::UnaryOp>(loc, kind, operand);+  }+   mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {     return cir::ConstPtrAttr::get(type, getI64IntegerAttr(value));   }diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.hindex 5bd53ebc52ab5..f855bdad2d7c3 100644--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h@@ -348,22 +348,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {     return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), align);   }-  mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,-                                  mlir::Value imag) {-    auto resultComplexTy = cir::ComplexType::get(real.getType());-    return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);-  }--  mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {-    auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());-    return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);-  }--  mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {-    auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());-    return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);-  }-   /// Create a cir.complex.real_ptr operation that derives a pointer to the real   /// part of the complex value pointed to by the specified pointer value.   mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cppindex 3273d9000771a..6663f5ea1e758 100644--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp@@ -57,6 +57,7 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {   mlir::Value   VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e);   mlir::Value VisitUnaryDeref(const Expr *e);+  mlir::Value VisitUnaryNot(const UnaryOperator *e);    struct BinOpInfo {     mlir::Location loc;@@ -338,6 +339,11 @@ mlir::Value ComplexExprEmitter::VisitUnaryDeref(const Expr *e) {   return emitLoadOfLValue(e); }+mlir::Value ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *e) {+  mlir::Value op = Visit(e->getSubExpr());+  return builder.createNot(op);+}+ mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e,                                              QualType promotionTy) {   e = e->IgnoreParens();diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cppindex 5493b86a0a321..788817006baa5 100644--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp@@ -8,7 +8,9 @@  #include "PassDetail.h" #include "clang/AST/ASTContext.h"+#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" #include "clang/CIR/Dialect/IR/CIRDialect.h"+#include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/Passes.h"  #include <memory>@@ -22,15 +24,68 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {   void runOnOperation() override;    void runOnOp(Operation *op);+  void lowerUnaryOp(UnaryOp op); };  } // namespace-void LoweringPreparePass::runOnOp(Operation *op) {}+void LoweringPreparePass::lowerUnaryOp(UnaryOp op) {+  mlir::Type ty = op.getType();+  if (!mlir::isa<cir::ComplexType>(ty))+    return;++  mlir::Location loc = op.getLoc();+  cir::UnaryOpKind opKind = op.getKind();++  CIRBaseBuilderTy builder(getContext());+  builder.setInsertionPointAfter(op);++  mlir::Value operand = op.getInput();+  mlir::Value operandReal = builder.createComplexReal(loc, operand);+  mlir::Value operandImag = builder.createComplexImag(loc, operand);++  mlir::Value resultReal;+  mlir::Value resultImag;++  switch (opKind) {+  case cir::UnaryOpKind::Inc:+  case cir::UnaryOpKind::Dec:+    llvm_unreachable("Complex unary Inc/Dec NYI");+    break;++  case cir::UnaryOpKind::Plus:+  case cir::UnaryOpKind::Minus:+    llvm_unreachable("Complex unary Plus/Minus NYI");+    break;++  case cir::UnaryOpKind::Not:+    resultReal = operandReal;+    resultImag =+        builder.createUnaryOp(loc, cir::UnaryOpKind::Minus, operandImag);+    break;+  }++  auto result = builder.createComplexCreate(loc, resultReal, resultImag);+  op.replaceAllUsesWith(result);+  op.erase();+}++void LoweringPreparePass::runOnOp(Operation *op) {+  if (auto unary = dyn_cast<UnaryOp>(op)) {+    lowerUnaryOp(unary);+  }+}  void LoweringPreparePass::runOnOperation() {+  mlir::Operation *op = getOperation();+   llvm::SmallVector<Operation *> opsToTransform;+  op->walk([&](Operation *op) {+    if (isa<UnaryOp>(op))+      opsToTransform.push_back(op);+  });+   for (auto *o : opsToTransform)     runOnOp(o); }diff --git a/clang/test/CIR/CodeGen/complex-unary.cpp b/clang/test/CIR/CodeGen/complex-unary.cppnew file mode 100644index 0000000000000..463c4dde47ed6--- /dev/null+++ b/clang/test/CIR/CodeGen/complex-unary.cpp@@ -0,0 +1,48 @@+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE %s+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare -o %t.cir %s 2>&1 | FileCheck --check-prefixes=CIR-AFTER %s+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG++void foo() {+  int _Complex a;+  int _Complex b = ~a;+}++// CIR-BEFORE: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]+// CIR-BEFORE: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]+// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>+// CIR-BEFORE: %[[COMPLEX_NOT:.*]] = cir.unary(not, %[[TMP]]) : !cir.complex<!s32i>, !cir.complex<!s32i>+// CIR-BEFORE: cir.store{{.*}} %[[COMPLEX_NOT]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>++// CIR-AFTER: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]+// CIR-AFTER: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]+// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>+// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %[[TMP]] : !cir.complex<!s32i> -> !s32i+// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %[[TMP]] : !cir.complex<!s32i> -> !s32i+// CIR-AFTER: %[[IMAG_MINUS:.*]] = cir.unary(minus, %[[IMAG]]) : !s32i, !s32i+// CIR-AFTER: %[[RESULT_VAL:.*]] = cir.complex.create %[[REAL]], %[[IMAG_MINUS]] : !s32i -> !cir.complex<!s32i>+// CIR-AFTER: cir.store{{.*}} %[[RESULT_VAL]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>++// LLVM: %[[COMPLEX:.*]] = alloca { i32, i32 }, i64 1, align 4+// LLVM: %[[RESULT:.*]] = alloca { i32, i32 }, i64 1, align 4+// LLVM: %[[TMP:.*]] = load { i32, i32 }, ptr %[[COMPLEX]], align 4+// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %[[TMP]], 0+// LLVM: %[[IMAG:.*]] = extractvalue { i32, i32 } %[[TMP]], 1+// LLVM: %[[IMAG_MINUS:.*]] = sub i32 0, %[[IMAG]]+// LLVM: %[[RESULT_TMP:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[REAL]], 0+// LLVM: %[[RESULT_VAL:.*]] = insertvalue { i32, i32 } %[[RESULT_TMP]], i32 %[[IMAG_MINUS]], 1+// LLVM: store { i32, i32 } %[[RESULT_VAL]], ptr %[[RESULT]], align 4++// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4+// OGCG: %[[RESULT:.*]] = alloca { i32, i32 }, align 4+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0+// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1+// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4+// OGCG: %[[A_IMAG_MINUS:.*]] = sub i32 0, %[[A_IMAG]]+// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 0+// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 1+// OGCG: store i32 %[[A_REAL]], ptr %[[RESULT_REAL_PTR]], align 4+// OGCG: store i32 %[[A_IMAG_MINUS]], ptr %[[RESULT_IMAG_PTR]], align 4

@llvmbot
Copy link
Member

@llvm/pr-subscribers-clangir

Author: Amr Hesham (AmrDeveloper)

Changes

Upstream unary not for ComplexType

#141365


Full diff:https://github.com/llvm/llvm-project/pull/148857.diff

5 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h (+21)
  • (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.h (-16)
  • (modified) clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp (+6)
  • (modified) clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp (+56-1)
  • (added) clang/test/CIR/CodeGen/complex-unary.cpp (+48)
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.hindex 277c278fd38b7..25baf278bba38 100644--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h@@ -129,6 +129,22 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {   cir::BoolAttr getTrueAttr() { return getCIRBoolAttr(true); }   cir::BoolAttr getFalseAttr() { return getCIRBoolAttr(false); }+  mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,+                                  mlir::Value imag) {+    auto resultComplexTy = cir::ComplexType::get(real.getType());+    return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);+  }++  mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {+    auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());+    return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);+  }++  mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {+    auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());+    return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);+  }+   mlir::Value createNot(mlir::Value value) {     return create<cir::UnaryOp>(value.getLoc(), value.getType(),                                 cir::UnaryOpKind::Not, value);@@ -169,6 +185,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {     return create<cir::ContinueOp>(loc);   }+  mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind,+                            mlir::Value operand) {+    return create<cir::UnaryOp>(loc, kind, operand);+  }+   mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {     return cir::ConstPtrAttr::get(type, getI64IntegerAttr(value));   }diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.hindex 5bd53ebc52ab5..f855bdad2d7c3 100644--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h@@ -348,22 +348,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {     return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), align);   }-  mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,-                                  mlir::Value imag) {-    auto resultComplexTy = cir::ComplexType::get(real.getType());-    return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);-  }--  mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {-    auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());-    return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);-  }--  mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {-    auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());-    return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);-  }-   /// Create a cir.complex.real_ptr operation that derives a pointer to the real   /// part of the complex value pointed to by the specified pointer value.   mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cppindex 3273d9000771a..6663f5ea1e758 100644--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp@@ -57,6 +57,7 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {   mlir::Value   VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e);   mlir::Value VisitUnaryDeref(const Expr *e);+  mlir::Value VisitUnaryNot(const UnaryOperator *e);    struct BinOpInfo {     mlir::Location loc;@@ -338,6 +339,11 @@ mlir::Value ComplexExprEmitter::VisitUnaryDeref(const Expr *e) {   return emitLoadOfLValue(e); }+mlir::Value ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *e) {+  mlir::Value op = Visit(e->getSubExpr());+  return builder.createNot(op);+}+ mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e,                                              QualType promotionTy) {   e = e->IgnoreParens();diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cppindex 5493b86a0a321..788817006baa5 100644--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp@@ -8,7 +8,9 @@  #include "PassDetail.h" #include "clang/AST/ASTContext.h"+#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" #include "clang/CIR/Dialect/IR/CIRDialect.h"+#include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/Passes.h"  #include <memory>@@ -22,15 +24,68 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {   void runOnOperation() override;    void runOnOp(Operation *op);+  void lowerUnaryOp(UnaryOp op); };  } // namespace-void LoweringPreparePass::runOnOp(Operation *op) {}+void LoweringPreparePass::lowerUnaryOp(UnaryOp op) {+  mlir::Type ty = op.getType();+  if (!mlir::isa<cir::ComplexType>(ty))+    return;++  mlir::Location loc = op.getLoc();+  cir::UnaryOpKind opKind = op.getKind();++  CIRBaseBuilderTy builder(getContext());+  builder.setInsertionPointAfter(op);++  mlir::Value operand = op.getInput();+  mlir::Value operandReal = builder.createComplexReal(loc, operand);+  mlir::Value operandImag = builder.createComplexImag(loc, operand);++  mlir::Value resultReal;+  mlir::Value resultImag;++  switch (opKind) {+  case cir::UnaryOpKind::Inc:+  case cir::UnaryOpKind::Dec:+    llvm_unreachable("Complex unary Inc/Dec NYI");+    break;++  case cir::UnaryOpKind::Plus:+  case cir::UnaryOpKind::Minus:+    llvm_unreachable("Complex unary Plus/Minus NYI");+    break;++  case cir::UnaryOpKind::Not:+    resultReal = operandReal;+    resultImag =+        builder.createUnaryOp(loc, cir::UnaryOpKind::Minus, operandImag);+    break;+  }++  auto result = builder.createComplexCreate(loc, resultReal, resultImag);+  op.replaceAllUsesWith(result);+  op.erase();+}++void LoweringPreparePass::runOnOp(Operation *op) {+  if (auto unary = dyn_cast<UnaryOp>(op)) {+    lowerUnaryOp(unary);+  }+}  void LoweringPreparePass::runOnOperation() {+  mlir::Operation *op = getOperation();+   llvm::SmallVector<Operation *> opsToTransform;+  op->walk([&](Operation *op) {+    if (isa<UnaryOp>(op))+      opsToTransform.push_back(op);+  });+   for (auto *o : opsToTransform)     runOnOp(o); }diff --git a/clang/test/CIR/CodeGen/complex-unary.cpp b/clang/test/CIR/CodeGen/complex-unary.cppnew file mode 100644index 0000000000000..463c4dde47ed6--- /dev/null+++ b/clang/test/CIR/CodeGen/complex-unary.cpp@@ -0,0 +1,48 @@+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE %s+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare -o %t.cir %s 2>&1 | FileCheck --check-prefixes=CIR-AFTER %s+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG++void foo() {+  int _Complex a;+  int _Complex b = ~a;+}++// CIR-BEFORE: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]+// CIR-BEFORE: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]+// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>+// CIR-BEFORE: %[[COMPLEX_NOT:.*]] = cir.unary(not, %[[TMP]]) : !cir.complex<!s32i>, !cir.complex<!s32i>+// CIR-BEFORE: cir.store{{.*}} %[[COMPLEX_NOT]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>++// CIR-AFTER: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]+// CIR-AFTER: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]+// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>+// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %[[TMP]] : !cir.complex<!s32i> -> !s32i+// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %[[TMP]] : !cir.complex<!s32i> -> !s32i+// CIR-AFTER: %[[IMAG_MINUS:.*]] = cir.unary(minus, %[[IMAG]]) : !s32i, !s32i+// CIR-AFTER: %[[RESULT_VAL:.*]] = cir.complex.create %[[REAL]], %[[IMAG_MINUS]] : !s32i -> !cir.complex<!s32i>+// CIR-AFTER: cir.store{{.*}} %[[RESULT_VAL]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>++// LLVM: %[[COMPLEX:.*]] = alloca { i32, i32 }, i64 1, align 4+// LLVM: %[[RESULT:.*]] = alloca { i32, i32 }, i64 1, align 4+// LLVM: %[[TMP:.*]] = load { i32, i32 }, ptr %[[COMPLEX]], align 4+// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %[[TMP]], 0+// LLVM: %[[IMAG:.*]] = extractvalue { i32, i32 } %[[TMP]], 1+// LLVM: %[[IMAG_MINUS:.*]] = sub i32 0, %[[IMAG]]+// LLVM: %[[RESULT_TMP:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[REAL]], 0+// LLVM: %[[RESULT_VAL:.*]] = insertvalue { i32, i32 } %[[RESULT_TMP]], i32 %[[IMAG_MINUS]], 1+// LLVM: store { i32, i32 } %[[RESULT_VAL]], ptr %[[RESULT]], align 4++// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4+// OGCG: %[[RESULT:.*]] = alloca { i32, i32 }, align 4+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0+// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1+// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4+// OGCG: %[[A_IMAG_MINUS:.*]] = sub i32 0, %[[A_IMAG]]+// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 0+// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 1+// OGCG: store i32 %[[A_REAL]], ptr %[[RESULT_REAL_PTR]], align 4+// OGCG: store i32 %[[A_IMAG_MINUS]], ptr %[[RESULT_IMAG_PTR]], align 4

};

} // namespace

void LoweringPreparePass::runOnOp(Operation *op) {}
void LoweringPreparePass::lowerUnaryOp(UnaryOp op) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
voidLoweringPreparePass::lowerUnaryOp(UnaryOp op) {
voidLoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {

op.erase();
}

void LoweringPreparePass::runOnOp(Operation *op) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
voidLoweringPreparePass::runOnOp(Operation *op) {
voidLoweringPreparePass::runOnOp(mlir::Operation *op) {

Comment on lines 74 to 76
if (auto unary = dyn_cast<UnaryOp>(op)) {
lowerUnaryOp(unary);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
if (auto unary = dyn_cast<UnaryOp>(op)) {
lowerUnaryOp(unary);
}
if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op))
lowerUnaryOp(unary);

llvm::SmallVector<Operation *> opsToTransform;

op->walk([&](Operation *op) {
if (isa<UnaryOp>(op))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
if (isa<UnaryOp>(op))
if (mlir::isa<cir::UnaryOp>(op))

Copy link
Contributor

@andykaylorandykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

lgtm, with one nit about the test

// LLVM: %[[TMP:.*]] = load { i32, i32 }, ptr %[[COMPLEX]], align 4
// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %[[TMP]], 0
// LLVM: %[[IMAG:.*]] = extractvalue { i32, i32 } %[[TMP]], 1
// LLVM: %[[IMAG_MINUS:.*]] = sub i32 0, %[[IMAG]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Can you add a test case forfloat _Complex (or even just replace this one)? For floating point types, we should get anfneg rather thanfsub 0, i here. It's a subtle but important difference.

@AmrDeveloperAmrDeveloper merged commitbd0f9dd intollvm:mainJul 16, 2025
9 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@xlaukoxlaukoxlauko left review comments

@andykaylorandykaylorandykaylor approved these changes

@mmhammhaAwaiting requested review from mmha

@lanzalanzaAwaiting requested review from lanzalanza is a code owner

@bcardosolopesbcardosolopesAwaiting requested review from bcardosolopesbcardosolopes is a code owner

Assignees
No one assigned
Labels
clangClang issues not falling into any other categoryClangIRAnything related to the ClangIR project
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

4 participants
@AmrDeveloper@llvmbot@xlauko@andykaylor

[8]ページ先頭

©2009-2025 Movatter.jp