diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 7ae28836d307..63390cbc2bf7 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -543,14 +543,18 @@ def ScopeOp : CIR_Op<"scope", [DeclareOpInterfaceMethods; -def UnaryOpKind_Dec : I32EnumAttrCase<"Dec", 2, "dec">; +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 : I32EnumAttr< "UnaryOpKind", "unary operation kind", [UnaryOpKind_Inc, - UnaryOpKind_Dec]> { + UnaryOpKind_Dec, + UnaryOpKind_Plus, + UnaryOpKind_Minus]> { let cppNamespace = "::mlir::cir"; } @@ -561,7 +565,7 @@ def UnaryOp : CIR_Op<"unary", let summary = "Unary operations"; let description = [{ `cir.unary` performs the unary operation according to - the specified opcode kind: [inc, dec]. + the specified opcode kind: [inc, dec, plus, minus]. Note for inc and dec: the operation corresponds only to the addition/subtraction, its input is expect to come from a load diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index ffa87a7fea28..59597df8a47f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -334,11 +334,44 @@ class ScalarExprEmitter : public StmtVisitor { llvm_unreachable("NYI"); } mlir::Value VisitUnaryPlus(const UnaryOperator *E) { - llvm_unreachable("NYI"); + // NOTE(cir): QualType function parameter still not used, so don´t replicate + // it here yet. + QualType promotionTy = getPromotionType(E->getSubExpr()->getType()); + auto result = VisitPlus(E, promotionTy); + if (result && !promotionTy.isNull()) + assert(0 && "not implemented yet"); + return buildUnaryOp(E, mlir::cir::UnaryOpKind::Plus, result); + } + + mlir::Value VisitPlus(const UnaryOperator *E, QualType PromotionType) { + // This differs from gcc, though, most likely due to a bug in gcc. + TestAndClearIgnoreResultAssign(); + if (!PromotionType.isNull()) + assert(0 && "scalar promotion not implemented yet"); + return Visit(E->getSubExpr()); } + mlir::Value VisitUnaryMinus(const UnaryOperator *E) { - llvm_unreachable("NYI"); + // NOTE(cir): QualType function parameter still not used, so don´t replicate + // it here yet. + QualType promotionTy = getPromotionType(E->getSubExpr()->getType()); + auto result = VisitMinus(E, promotionTy); + if (result && !promotionTy.isNull()) + assert(0 && "not implemented yet"); + return buildUnaryOp(E, mlir::cir::UnaryOpKind::Minus, result); + } + + mlir::Value VisitMinus(const UnaryOperator *E, QualType PromotionType) { + TestAndClearIgnoreResultAssign(); + if (!PromotionType.isNull()) + assert(0 && "scalar promotion not implemented yet"); + + // 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 Visit(E->getSubExpr()); } + mlir::Value VisitUnaryNot(const UnaryOperator *E) { llvm_unreachable("NYI"); } mlir::Value VisitUnaryLNot(const UnaryOperator *E) { llvm_unreachable("NYI"); @@ -592,6 +625,22 @@ class ScalarExprEmitter : public StmtVisitor { buildCompoundAssign(const CompoundAssignOperator *E, mlir::Value (ScalarExprEmitter::*F)(const BinOpInfo &)); + // TODO(cir): Candidate to be in a common AST helper between CIR and LLVM codegen. + QualType getPromotionType(QualType Ty) { + if (CGF.getContext() + .getTargetInfo() + .shouldEmitFloat16WithExcessPrecision()) { + if (Ty->isAnyComplexType()) { + QualType ElementType = Ty->castAs()->getElementType(); + if (ElementType->isFloat16Type()) + return CGF.getContext().getComplexType(CGF.getContext().FloatTy); + } + if (Ty->isFloat16Type()) + return CGF.getContext().FloatTy; + } + return QualType(); + } + // Binary operators and binary compound assignment operators. #define HANDLEBINOP(OP) \ mlir::Value VisitBin##OP(const BinaryOperator *E) { \ diff --git a/clang/lib/CIR/CodeGen/LowerToLLVM.cpp b/clang/lib/CIR/CodeGen/LowerToLLVM.cpp index a12d0af415b9..a1ce637301cb 100644 --- a/clang/lib/CIR/CodeGen/LowerToLLVM.cpp +++ b/clang/lib/CIR/CodeGen/LowerToLLVM.cpp @@ -232,6 +232,17 @@ class CIRUnaryOpLowering : public mlir::OpRewritePattern { op.getInput(), One); break; } + case mlir::cir::UnaryOpKind::Plus: { + rewriter.replaceOp(op, op.getInput()); + break; + } + case mlir::cir::UnaryOpKind::Minus: { + auto Zero = rewriter.create( + op.getLoc(), type, mlir::IntegerAttr::get(type, 0)); + rewriter.replaceOpWithNewOp(op, op.getType(), Zero, + op.getInput()); + break; + } } return mlir::LogicalResult::success(); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 2d333c8ac659..0955ac441f4d 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1314,6 +1314,12 @@ LogicalResult UnaryOp::verify() { return emitOpError() << "requires result to be used by a memory store " "to the same address as the input memory load"; } + case cir::UnaryOpKind::Plus: + // Nothing to verify. + return success(); + case cir::UnaryOpKind::Minus: + // Nothing to verify. + return success(); } llvm_unreachable("Unknown UnaryOp kind?"); diff --git a/clang/test/CIR/CIRToLLVM/unary-plus-minus.cir b/clang/test/CIR/CIRToLLVM/unary-plus-minus.cir new file mode 100644 index 000000000000..37a1d159ed1e --- /dev/null +++ b/clang/test/CIR/CIRToLLVM/unary-plus-minus.cir @@ -0,0 +1,29 @@ +// RUN: cir-tool %s -cir-to-func -cir-to-memref -o - | FileCheck %s -check-prefix=MLIR +// RUN: cir-tool %s -cir-to-func -cir-to-memref -cir-to-llvm -o - | mlir-translate -mlir-to-llvmir | FileCheck %s -check-prefix=LLVM + +module { + cir.func @foo() { + %0 = cir.alloca i32, cir.ptr , ["a", init] {alignment = 4 : i64} + %1 = cir.alloca i32, cir.ptr , ["b", init] {alignment = 4 : i64} + %2 = cir.cst(2 : i32) : i32 + cir.store %2, %0 : i32, cir.ptr + cir.store %2, %1 : i32, cir.ptr + + %3 = cir.load %0 : cir.ptr , i32 + %4 = cir.unary(plus, %3) : i32, i32 + cir.store %4, %0 : i32, cir.ptr + + %5 = cir.load %1 : cir.ptr , i32 + %6 = cir.unary(minus, %5) : i32, i32 + cir.store %6, %1 : i32, cir.ptr + cir.return + } +} + +// MLIR: %[[#INPUT_PLUS:]] = memref.load +// MLIR: memref.store %[[#INPUT_PLUS]] +// MLIR: %[[#INPUT_MINUS:]] = memref.load +// MLIR: %[[ZERO:[a-z0-9_]+]] = arith.constant 0 +// MLIR: arith.subi %[[ZERO]], %[[#INPUT_MINUS]] + +// LLVM: = sub i32 0, %[[#]] diff --git a/clang/test/CIR/CodeGen/unary.cpp b/clang/test/CIR/CodeGen/unary.cpp new file mode 100644 index 000000000000..8358e5976b46 --- /dev/null +++ b/clang/test/CIR/CodeGen/unary.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir-enable -Wno-unused-value -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +unsigned up0() { + unsigned a = 1; + return +a; +} + +// CHECK: cir.func @_Z3up0v() -> i32 { +// CHECK: %[[#RET:]] = cir.alloca i32, cir.ptr , ["__retval"] +// CHECK: %[[#A:]] = cir.alloca i32, cir.ptr , ["a", init] +// CHECK: %[[#INPUT:]] = cir.load %[[#A]] +// CHECK: %[[#OUTPUT:]] = cir.unary(plus, %[[#INPUT]]) +// CHECK: cir.store %[[#OUTPUT]], %[[#RET]] + +unsigned um0() { + unsigned a = 1; + return -a; +} + +// CHECK: cir.func @_Z3um0v() -> i32 { +// CHECK: %[[#RET:]] = cir.alloca i32, cir.ptr , ["__retval"] +// CHECK: %[[#A:]] = cir.alloca i32, cir.ptr , ["a", init] +// CHECK: %[[#INPUT:]] = cir.load %[[#A]] +// CHECK: %[[#OUTPUT:]] = cir.unary(minus, %[[#INPUT]]) +// CHECK: cir.store %[[#OUTPUT]], %[[#RET]]