https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/133405

>From 13833779faad62f95ef3fc0e2de3ed9b7c44d2f5 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhaf...@nvidia.com>
Date: Fri, 11 Apr 2025 17:46:00 +0200
Subject: [PATCH 1/2] [CIR] Upstream SelectOp and ShiftOp

Since SelectOp will only generated by a future pass that transforms a TernaryOp 
this only includes the lowering bits.

This patchs also improves the testing of the existing binary operators.
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  73 ++++
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp    |   9 +-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       |  43 +++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  87 +++++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h   |  20 ++
 clang/test/CIR/CodeGen/binop.cpp              | 317 +++++++++++++++++-
 clang/test/CIR/Lowering/select.cir            |  48 +++
 7 files changed, 579 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/CIR/Lowering/select.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 0d3c2065cd58c..22195477e0137 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1176,6 +1176,79 @@ def BinOp : CIR_Op<"binop", [Pure,
   let hasVerifier = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// ShiftOp
+//===----------------------------------------------------------------------===//
+
+def ShiftOp : CIR_Op<"shift", [Pure]> {
+  let summary = "Shift";
+  let description = [{
+    Shift `left` or `right`, according to the first operand. Second operand is
+    the shift target and the third the amount. Second and the thrid operand are
+    integers.
+
+    ```mlir
+    %7 = cir.shift(left, %1 : !u64i, %4 : !s32i) -> !u64i
+    ```
+  }];
+
+  // TODO(cir): Support vectors. CIR_IntType -> CIR_AnyIntOrVecOfInt. Also
+  // update the description above.
+  let results = (outs CIR_IntType:$result);
+  let arguments = (ins CIR_IntType:$value, CIR_IntType:$amount,
+                       UnitAttr:$isShiftleft);
+
+  let assemblyFormat = [{
+    `(`
+      (`left` $isShiftleft^) : (```right`)?
+      `,` $value `:` type($value)
+      `,` $amount `:` type($amount)
+    `)` `->` type($result) attr-dict
+  }];
+
+  let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// SelectOp
+//===----------------------------------------------------------------------===//
+
+def SelectOp : CIR_Op<"select", [Pure,
+    AllTypesMatch<["true_value", "false_value", "result"]>]> {
+  let summary = "Yield one of two values based on a boolean value";
+  let description = [{
+    The `cir.select` operation takes three operands. The first operand
+    `condition` is a boolean value of type `!cir.bool`. The second and the 
third
+    operand can be of any CIR types, but their types must be the same. If the
+    first operand is `true`, the operation yields its second operand. 
Otherwise,
+    the operation yields its third operand.
+
+    Example:
+
+    ```mlir
+    %0 = cir.const #cir.bool<true> : !cir.bool
+    %1 = cir.const #cir.int<42> : !s32i
+    %2 = cir.const #cir.int<72> : !s32i
+    %3 = cir.select if %0 then %1 else %2 : (!cir.bool, !s32i, !s32i) -> !s32i
+    ```
+  }];
+
+  let arguments = (ins CIR_BoolType:$condition, CIR_AnyType:$true_value,
+                       CIR_AnyType:$false_value);
+  let results = (outs CIR_AnyType:$result);
+
+  let assemblyFormat = [{
+    `if` $condition `then` $true_value `else` $false_value
+    `:` `(`
+      qualified(type($condition)) `,`
+      qualified(type($true_value)) `,`
+      qualified(type($false_value))
+    `)` `->` qualified(type($result)) attr-dict
+  }];
+
+  let hasFolder = 1;
+}
+
 
//===----------------------------------------------------------------------===//
 // GlobalOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 38104f8533c7d..7417df4407925 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1308,8 +1308,9 @@ mlir::Value ScalarExprEmitter::emitShl(const BinOpInfo 
&ops) {
            mlir::isa<cir::IntType>(ops.lhs.getType()))
     cgf.cgm.errorNYI("sanitizers");
 
-  cgf.cgm.errorNYI("shift ops");
-  return {};
+  return builder.create<cir::ShiftOp>(cgf.getLoc(ops.loc),
+                                      cgf.convertType(ops.fullType), ops.lhs,
+                                      ops.rhs, cgf.getBuilder().getUnitAttr());
 }
 
 mlir::Value ScalarExprEmitter::emitShr(const BinOpInfo &ops) {
@@ -1333,8 +1334,8 @@ mlir::Value ScalarExprEmitter::emitShr(const BinOpInfo 
&ops) {
 
   // Note that we don't need to distinguish unsigned treatment at this
   // point since it will be handled later by LLVM lowering.
-  cgf.cgm.errorNYI("shift ops");
-  return {};
+  return builder.create<cir::ShiftOp>(
+      cgf.getLoc(ops.loc), cgf.convertType(ops.fullType), ops.lhs, ops.rhs);
 }
 
 mlir::Value ScalarExprEmitter::emitAnd(const BinOpInfo &ops) {
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index f3e5e572653da..d25d6609a1aed 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -997,6 +997,9 @@ 
mlir::OpTrait::impl::verifySameFirstOperandAndResultType(Operation *op) {
 // been implemented yet.
 mlir::LogicalResult cir::FuncOp::verify() { return success(); }
 
+//===----------------------------------------------------------------------===//
+// BinOp
+//===----------------------------------------------------------------------===//
 LogicalResult cir::BinOp::verify() {
   bool noWrap = getNoUnsignedWrap() || getNoSignedWrap();
   bool saturated = getSaturated();
@@ -1028,6 +1031,46 @@ LogicalResult cir::BinOp::verify() {
   return mlir::success();
 }
 
+//===----------------------------------------------------------------------===//
+// ShiftOp
+//===----------------------------------------------------------------------===//
+LogicalResult cir::ShiftOp::verify() {
+  mlir::Operation *op = getOperation();
+  mlir::Type resType = getResult().getType();
+  assert(!cir::MissingFeatures::vectorType());
+  bool isOp0Vec = false;
+  bool isOp1Vec = false;
+  if (isOp0Vec != isOp1Vec)
+    return emitOpError() << "input types cannot be one vector and one scalar";
+  if (isOp1Vec && op->getOperand(1).getType() != resType) {
+    return emitOpError() << "shift amount must have the type of the result "
+                         << "if it is vector shift";
+  }
+  return mlir::success();
+}
+
+//===----------------------------------------------------------------------===//
+// SelectOp
+//===----------------------------------------------------------------------===//
+
+OpFoldResult cir::SelectOp::fold(FoldAdaptor adaptor) {
+  mlir::Attribute condition = adaptor.getCondition();
+  if (condition) {
+    bool conditionValue = mlir::cast<cir::BoolAttr>(condition).getValue();
+    return conditionValue ? getTrueValue() : getFalseValue();
+  }
+
+  // cir.select if %0 then x else x -> x
+  mlir::Attribute trueValue = adaptor.getTrueValue();
+  mlir::Attribute falseValue = adaptor.getFalseValue();
+  if (trueValue && trueValue == falseValue)
+    return trueValue;
+  if (getTrueValue() == getFalseValue())
+    return getTrueValue();
+
+  return {};
+}
+
 
//===----------------------------------------------------------------------===//
 // UnaryOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7159f89c93a53..7f0c056182af9 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1294,6 +1294,91 @@ mlir::LogicalResult 
CIRToLLVMCmpOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMShiftOpLowering::matchAndRewrite(
+    cir::ShiftOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  auto cirAmtTy = mlir::dyn_cast<cir::IntType>(op.getAmount().getType());
+  auto cirValTy = mlir::dyn_cast<cir::IntType>(op.getValue().getType());
+
+  // Operands could also be vector type
+  assert(!cir::MissingFeatures::vectorType());
+  mlir::Type llvmTy = getTypeConverter()->convertType(op.getType());
+  mlir::Value amt = adaptor.getAmount();
+  mlir::Value val = adaptor.getValue();
+
+  // TODO(cir): Assert for vector types
+  assert((cirValTy && cirAmtTy) &&
+         "shift input type must be integer or vector type, otherwise NYI");
+
+  assert((cirValTy == op.getType()) && "inconsistent operands' types NYI");
+
+  // Ensure shift amount is the same type as the value. Some undefined
+  // behavior might occur in the casts below as per [C99 6.5.7.3].
+  // Vector type shift amount needs no cast as type consistency is expected to
+  // be already be enforced at CIRGen.
+  if (cirAmtTy)
+    amt = getLLVMIntCast(rewriter, amt, mlir::cast<mlir::IntegerType>(llvmTy),
+                         !cirAmtTy.isSigned(), cirAmtTy.getWidth(),
+                         cirValTy.getWidth());
+
+  // Lower to the proper LLVM shift operation.
+  if (op.getIsShiftleft()) {
+    rewriter.replaceOpWithNewOp<mlir::LLVM::ShlOp>(op, llvmTy, val, amt);
+  } else {
+    assert(!cir::MissingFeatures::vectorType());
+    bool isUnsigned = !cirValTy.isSigned();
+    if (isUnsigned)
+      rewriter.replaceOpWithNewOp<mlir::LLVM::LShrOp>(op, llvmTy, val, amt);
+    else
+      rewriter.replaceOpWithNewOp<mlir::LLVM::AShrOp>(op, llvmTy, val, amt);
+  }
+
+  return mlir::success();
+}
+
+mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite(
+    cir::SelectOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  auto getConstantBool = [](mlir::Value value) -> std::optional<bool> {
+    auto definingOp =
+        mlir::dyn_cast_if_present<cir::ConstantOp>(value.getDefiningOp());
+    if (!definingOp)
+      return std::nullopt;
+
+    auto constValue = mlir::dyn_cast<cir::BoolAttr>(definingOp.getValue());
+    if (!constValue)
+      return std::nullopt;
+
+    return constValue.getValue();
+  };
+
+  // Two special cases in the LLVMIR codegen of select op:
+  // - select %0, %1, false => and %0, %1
+  // - select %0, true, %1 => or %0, %1
+  if (mlir::isa<cir::BoolType>(op.getTrueValue().getType())) {
+    std::optional<bool> trueValue = getConstantBool(op.getTrueValue());
+    std::optional<bool> falseValue = getConstantBool(op.getFalseValue());
+    if (falseValue.has_value() && !*falseValue) {
+      // select %0, %1, false => and %0, %1
+      rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(op, 
adaptor.getCondition(),
+                                                     adaptor.getTrueValue());
+      return mlir::success();
+    }
+    if (trueValue.has_value() && *trueValue) {
+      // select %0, true, %1 => or %0, %1
+      rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, adaptor.getCondition(),
+                                                    adaptor.getFalseValue());
+      return mlir::success();
+    }
+  }
+
+  mlir::Value llvmCondition = adaptor.getCondition();
+  rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(
+      op, llvmCondition, adaptor.getTrueValue(), adaptor.getFalseValue());
+
+  return mlir::success();
+}
+
 static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
                                  mlir::DataLayout &dataLayout) {
   converter.addConversion([&](cir::PointerType type) -> mlir::Type {
@@ -1439,6 +1524,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
                CIRToLLVMConstantOpLowering,
                CIRToLLVMFuncOpLowering,
                CIRToLLVMGetGlobalOpLowering,
+               CIRToLLVMSelectOpLowering,
+               CIRToLLVMShiftOpLowering,
                CIRToLLVMTrapOpLowering,
                CIRToLLVMUnaryOpLowering
       // clang-format on
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 1de6c9c56b485..acb872b200b55 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -209,6 +209,26 @@ class CIRToLLVMCmpOpLowering : public 
mlir::OpConversionPattern<cir::CmpOp> {
                   mlir::ConversionPatternRewriter &) const override;
 };
 
+class CIRToLLVMShiftOpLowering
+    : public mlir::OpConversionPattern<cir::ShiftOp> {
+public:
+  using mlir::OpConversionPattern<cir::ShiftOp>::OpConversionPattern;
+
+  mlir::LogicalResult
+  matchAndRewrite(cir::ShiftOp op, OpAdaptor,
+                  mlir::ConversionPatternRewriter &) const override;
+};
+
+class CIRToLLVMSelectOpLowering
+    : public mlir::OpConversionPattern<cir::SelectOp> {
+public:
+  using mlir::OpConversionPattern<cir::SelectOp>::OpConversionPattern;
+
+  mlir::LogicalResult
+  matchAndRewrite(cir::SelectOp op, OpAdaptor,
+                  mlir::ConversionPatternRewriter &) const override;
+};
+
 class CIRToLLVMBrOpLowering : public mlir::OpConversionPattern<cir::BrOp> {
 public:
   using mlir::OpConversionPattern<cir::BrOp>::OpConversionPattern;
diff --git a/clang/test/CIR/CodeGen/binop.cpp b/clang/test/CIR/CodeGen/binop.cpp
index 4c20f79600fac..22ee5d1cd1148 100644
--- a/clang/test/CIR/CodeGen/binop.cpp
+++ b/clang/test/CIR/CodeGen/binop.cpp
@@ -1,5 +1,9 @@
-// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -O1 
-Wno-unused-value -fclangir -emit-cir %s -o %t.cir
-// RUN: FileCheck --input-file=%t.cir %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu 
-Wno-unused-value -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++11 -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 -std=c++11 -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 b0(int a, int b) {
   int x = a * b;
@@ -12,22 +16,307 @@ void b0(int a, int b) {
   x = x | b;
 }
 
-// CHECK: %{{.+}} = cir.binop(mul, %{{.+}}, %{{.+}}) nsw : !s32i
-// CHECK: %{{.+}} = cir.binop(div, %{{.+}}, %{{.+}}) : !s32i
-// CHECK: %{{.+}} = cir.binop(rem, %{{.+}}, %{{.+}}) : !s32i
-// CHECK: %{{.+}} = cir.binop(add, %{{.+}}, %{{.+}}) nsw : !s32i
-// CHECK: %{{.+}} = cir.binop(sub, %{{.+}}, %{{.+}}) nsw : !s32i
-// CHECK: %{{.+}} = cir.binop(and, %{{.+}}, %{{.+}}) : !s32i
-// CHECK: %{{.+}} = cir.binop(xor, %{{.+}}, %{{.+}}) : !s32i
-// CHECK: %{{.+}} = cir.binop(or, %{{.+}}, %{{.+}}) : !s32i
+// CIR-LABEL: cir.func @b0(
+// CIR: %{{.+}} = cir.binop(mul, %{{.+}}, %{{.+}}) nsw : !s32i
+// CIR: %{{.+}} = cir.binop(div, %{{.+}}, %{{.+}}) : !s32i
+// CIR: %{{.+}} = cir.binop(rem, %{{.+}}, %{{.+}}) : !s32i
+// CIR: %{{.+}} = cir.binop(add, %{{.+}}, %{{.+}}) nsw : !s32i
+// CIR: %{{.+}} = cir.binop(sub, %{{.+}}, %{{.+}}) nsw : !s32i
+// CIR: %{{.+}} = cir.binop(and, %{{.+}}, %{{.+}}) : !s32i
+// CIR: %{{.+}} = cir.binop(xor, %{{.+}}, %{{.+}}) : !s32i
+// CIR: %{{.+}} = cir.binop(or, %{{.+}}, %{{.+}}) : !s32i
+// CIR: cir.return
+
+// LLVM-LABEL: define void @b0(
+// LLVM-SAME: i32 %[[A:.*]], i32 %[[B:.*]])
+// LLVM:         %[[A_ADDR:.*]] = alloca i32
+// LLVM:         %[[B_ADDR:.*]] = alloca i32
+// LLVM:         %[[X:.*]] = alloca i32
+// LLVM:         store i32 %[[A]], ptr %[[A_ADDR]]
+// LLVM:         store i32 %[[B]], ptr %[[B_ADDR]]
+
+// LLVM:         %[[A:.*]] = load i32, ptr %[[A_ADDR]]
+// LLVM:         %[[B:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[MUL:.*]] = mul nsw i32 %[[A]], %[[B]]
+// LLVM:         store i32 %[[MUL]], ptr %[[X]]
+
+// LLVM:         %[[X1:.*]] = load i32, ptr %[[X]]
+// LLVM:         %[[B1:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[DIV:.*]] = sdiv i32 %[[X1]], %[[B1]]
+// LLVM:         store i32 %[[DIV]], ptr %[[X]]
+
+// LLVM:         %[[X2:.*]] = load i32, ptr %[[X]]
+// LLVM:         %[[B2:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[REM:.*]] = srem i32 %[[X2]], %[[B2]]
+// LLVM:         store i32 %[[REM]], ptr %[[X]]
+
+// LLVM:         %[[X3:.*]] = load i32, ptr %[[X]]
+// LLVM:         %[[B3:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[ADD:.*]] = add nsw i32 %[[X3]], %[[B3]]
+// LLVM:         store i32 %[[ADD]], ptr %[[X]]
+
+// LLVM:         %[[X4:.*]] = load i32, ptr %[[X]]
+// LLVM:         %[[B4:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[SUB:.*]] = sub nsw i32 %[[X4]], %[[B4]]
+// LLVM:         store i32 %[[SUB]], ptr %[[X]]
+
+// LLVM:         %[[X5:.*]] = load i32, ptr %[[X]]
+// LLVM:         %[[B5:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[AND:.*]] = and i32 %[[X5]], %[[B5]]
+// LLVM:         store i32 %[[AND]], ptr %[[X]]
+
+// LLVM:         %[[X6:.*]] = load i32, ptr %[[X]]
+// LLVM:         %[[B6:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[XOR:.*]] = xor i32 %[[X6]], %[[B6]]
+// LLVM:         store i32 %[[XOR]], ptr %[[X]]
+
+// LLVM:         %[[X7:.*]] = load i32, ptr %[[X]]
+// LLVM:         %[[B7:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[OR:.*]] = or i32 %[[X7]], %[[B7]]
+// LLVM:         store i32 %[[OR]], ptr %[[X]]
+
+// LLVM:         ret void
+
+// OGCG-LABEL: define dso_local void @_Z2b0ii(i32 {{.*}} %a, i32 {{.*}} %b) 
{{.*}} { 
+// OGCG:         %[[A_ADDR:.*]] = alloca i32
+// OGCG:         %[[B_ADDR:.*]] = alloca i32
+// OGCG:         %[[X:.*]] = alloca i32
+// OGCG:         store i32 %a, ptr %[[A_ADDR]]
+// OGCG:         store i32 %b, ptr %[[B_ADDR]]
+
+// OGCG:         %[[A:.*]] = load i32, ptr %[[A_ADDR]]
+// OGCG:         %[[B:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[MUL:.*]] = mul nsw i32 %[[A]], %[[B]]
+// OGCG:         store i32 %[[MUL]], ptr %[[X]]
+
+// OGCG:         %[[X1:.*]] = load i32, ptr %[[X]]
+// OGCG:         %[[B1:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[DIV:.*]] = sdiv i32 %[[X1]], %[[B1]]
+// OGCG:         store i32 %[[DIV]], ptr %[[X]]
+
+// OGCG:         %[[X2:.*]] = load i32, ptr %[[X]]
+// OGCG:         %[[B2:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[REM:.*]] = srem i32 %[[X2]], %[[B2]]
+// OGCG:         store i32 %[[REM]], ptr %[[X]]
+
+// OGCG:         %[[X3:.*]] = load i32, ptr %[[X]]
+// OGCG:         %[[B3:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[ADD:.*]] = add nsw i32 %[[X3]], %[[B3]]
+// OGCG:         store i32 %[[ADD]], ptr %[[X]]
+
+// OGCG:         %[[X4:.*]] = load i32, ptr %[[X]]
+// OGCG:         %[[B4:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[SUB:.*]] = sub nsw i32 %[[X4]], %[[B4]]
+// OGCG:         store i32 %[[SUB]], ptr %[[X]]
+
+// OGCG:         %[[X5:.*]] = load i32, ptr %[[X]]
+// OGCG:         %[[B5:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[AND:.*]] = and i32 %[[X5]], %[[B5]]
+// OGCG:         store i32 %[[AND]], ptr %[[X]]
+
+// OGCG:         %[[X6:.*]] = load i32, ptr %[[X]]
+// OGCG:         %[[B6:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[XOR:.*]] = xor i32 %[[X6]], %[[B6]]
+// OGCG:         store i32 %[[XOR]], ptr %[[X]]
+
+// OGCG:         %[[X7:.*]] = load i32, ptr %[[X]]
+// OGCG:         %[[B7:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[OR:.*]] = or i32 %[[X7]], %[[B7]]
+// OGCG:         store i32 %[[OR]], ptr %[[X]]
+
+// OGCG:         ret void
 
 void testFloatingPointBinOps(float a, float b) {
   a * b;
-  // CHECK: cir.binop(mul, %{{.+}}, %{{.+}}) : !cir.float
   a / b;
-  // CHECK: cir.binop(div, %{{.+}}, %{{.+}}) : !cir.float
   a + b;
-  // CHECK: cir.binop(add, %{{.+}}, %{{.+}}) : !cir.float
   a - b;
-  // CHECK: cir.binop(sub, %{{.+}}, %{{.+}}) : !cir.float
 }
+
+// CIR-LABEL: cir.func @testFloatingPointBinOps(
+// CIR: cir.binop(mul, %{{.+}}, %{{.+}}) : !cir.float
+// CIR: cir.binop(div, %{{.+}}, %{{.+}}) : !cir.float
+// CIR: cir.binop(add, %{{.+}}, %{{.+}}) : !cir.float
+// CIR: cir.binop(sub, %{{.+}}, %{{.+}}) : !cir.float
+// CIR: cir.return
+
+// LLVM-LABEL: define void @testFloatingPointBinOps(
+// LLVM-SAME: float %[[A:.*]], float %[[B:.*]])
+// LLVM:         %[[A_ADDR:.*]] = alloca float, i64 1
+// LLVM:         %[[B_ADDR:.*]] = alloca float, i64 1
+// LLVM:         store float %[[A]], ptr %[[A_ADDR]]
+// LLVM:         store float %[[B]], ptr %[[B_ADDR]]
+
+// LLVM:         %[[A1:.*]] = load float, ptr %[[A_ADDR]]
+// LLVM:         %[[B1:.*]] = load float, ptr %[[B_ADDR]]
+// LLVM:         fmul float %[[A1]], %[[B1]]
+
+// LLVM:         %[[A2:.*]] = load float, ptr %[[A_ADDR]]
+// LLVM:         %[[B2:.*]] = load float, ptr %[[B_ADDR]]
+// LLVM:         fdiv float %[[A2]], %[[B2]]
+
+// LLVM:         %[[A3:.*]] = load float, ptr %[[A_ADDR]]
+// LLVM:         %[[B3:.*]] = load float, ptr %[[B_ADDR]]
+// LLVM:         fadd float %[[A3]], %[[B3]]
+
+// LLVM:         %[[A4:.*]] = load float, ptr %[[A_ADDR]]
+// LLVM:         %[[B4:.*]] = load float, ptr %[[B_ADDR]]
+// LLVM:         fsub float %[[A4]], %[[B4]]
+
+// LLVM:         ret void
+
+// OGCG-LABEL: define dso_local void @_Z23testFloatingPointBinOpsff(float 
{{.*}} %a, float {{.*}} %b)
+// OGCG:         %a.addr = alloca float
+// OGCG:         %b.addr = alloca float
+// OGCG:         store float %a, ptr %a.addr
+// OGCG:         store float %b, ptr %b.addr
+
+// OGCG:         %[[A1:.*]] = load float, ptr %a.addr
+// OGCG:         %[[B1:.*]] = load float, ptr %b.addr
+// OGCG:         fmul float %[[A1]], %[[B1]]
+
+// OGCG:         %[[A2:.*]] = load float, ptr %a.addr
+// OGCG:         %[[B2:.*]] = load float, ptr %b.addr
+// OGCG:         fdiv float %[[A2]], %[[B2]]
+
+// OGCG:         %[[A3:.*]] = load float, ptr %a.addr
+// OGCG:         %[[B3:.*]] = load float, ptr %b.addr
+// OGCG:         fadd float %[[A3]], %[[B3]]
+
+// OGCG:         %[[A4:.*]] = load float, ptr %a.addr
+// OGCG:         %[[B4:.*]] = load float, ptr %b.addr
+// OGCG:         fsub float %[[A4]], %[[B4]]
+
+// OGCG:         ret void
+
+void signed_shift(int a, int b) {
+  int x = a >> b;
+  x = a << b;
+}
+
+// CIR-LABEL: cir.func @signed_shift(
+// CIR-SAME: %[[ARG0:.*]]: !s32i{{.*}}, %[[ARG1:.*]]: !s32i{{.*}})
+// CIR: %[[A_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
+// CIR: %[[B_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init]
+// CIR: %[[X_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
+
+// CIR: cir.store %[[ARG0]], %[[A_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.store %[[ARG1]], %[[B_PTR]] : !s32i, !cir.ptr<!s32i>
+
+// CIR: %[[A1:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[B1:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[ASHR:.*]] = cir.shift(right, %[[A1]] : !s32i, %[[B1]] : !s32i) -> 
!s32i
+// CIR: cir.store %[[ASHR]], %[[X_PTR]] : !s32i, !cir.ptr<!s32i>
+
+// CIR: %[[A2:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[B2:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[SHL:.*]] = cir.shift(left, %[[A2]] : !s32i, %[[B2]] : !s32i) -> 
!s32i
+// CIR: cir.store %[[SHL]], %[[X_PTR]] : !s32i, !cir.ptr<!s32i>
+
+// CIR: cir.return
+
+// LLVM-LABEL: define void @signed_shift
+// LLVM-SAME: (i32 %[[A:.*]], i32 %[[B:.*]])
+// LLVM:         %[[A_ADDR:.*]] = alloca i32
+// LLVM:         %[[B_ADDR:.*]] = alloca i32
+// LLVM:         %[[X:.*]] = alloca i32
+// LLVM:         store i32 %[[A]], ptr %[[A_ADDR]]
+// LLVM:         store i32 %[[B]], ptr %[[B_ADDR]]
+
+// LLVM:         %[[A1:.*]] = load i32, ptr %[[A_ADDR]]
+// LLVM:         %[[B1:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[ASHR:.*]] = ashr i32 %[[A1]], %[[B1]]
+// LLVM:         store i32 %[[ASHR]], ptr %[[X]]
+
+// LLVM:         %[[A2:.*]] = load i32, ptr %[[A_ADDR]]
+// LLVM:         %[[B2:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[SHL:.*]] = shl i32 %[[A2]], %[[B2]]
+// LLVM:         store i32 %[[SHL]], ptr %[[X]]
+
+// LLVM:         ret void
+
+// OGCG-LABEL: define dso_local void @_Z12signed_shiftii
+// OGCG-SAME: (i32 {{.*}} %[[A:.*]], i32 {{.*}} %[[B:.*]])
+// OGCG:         %[[A_ADDR:.*]] = alloca i32
+// OGCG:         %[[B_ADDR:.*]] = alloca i32
+// OGCG:         %[[X:.*]] = alloca i32
+// OGCG:         store i32 %[[A]], ptr %[[A_ADDR]]
+// OGCG:         store i32 %[[B]], ptr %[[B_ADDR]]
+
+// OGCG:         %[[A1:.*]] = load i32, ptr %[[A_ADDR]]
+// OGCG:         %[[B1:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[ASHR:.*]] = ashr i32 %[[A1]], %[[B1]]
+// OGCG:         store i32 %[[ASHR]], ptr %[[X]]
+
+// OGCG:         %[[A2:.*]] = load i32, ptr %[[A_ADDR]]
+// OGCG:         %[[B2:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[SHL:.*]] = shl i32 %[[A2]], %[[B2]]
+// OGCG:         store i32 %[[SHL]], ptr %[[X]]
+
+// OGCG:         ret void
+
+void unsigned_shift(unsigned a, unsigned b) {
+  unsigned x = a >> b;
+  x = a << b;
+}
+
+// CIR-LABEL: cir.func @unsigned_shift(
+// CIR-SAME: %[[ARG0:.*]]: !u32i{{.*}}, %[[ARG1:.*]]: !u32i{{.*}})
+// CIR: %[[A_PTR:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["a", init]
+// CIR: %[[B_PTR:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["b", init]
+// CIR: %[[X_PTR:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["x", init]
+
+// CIR: cir.store %[[ARG0]], %[[A_PTR]] : !u32i, !cir.ptr<!u32i>
+// CIR: cir.store %[[ARG1]], %[[B_PTR]] : !u32i, !cir.ptr<!u32i>
+
+// CIR: %[[A1:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!u32i>, !u32i
+// CIR: %[[B1:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!u32i>, !u32i
+// CIR: %[[ASHR:.*]] = cir.shift(right, %[[A1]] : !u32i, %[[B1]] : !u32i) -> 
!u32i
+// CIR: cir.store %[[ASHR]], %[[X_PTR]] : !u32i, !cir.ptr<!u32i>
+
+// CIR: %[[A2:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!u32i>, !u32i
+// CIR: %[[B2:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!u32i>, !u32i
+// CIR: %[[SHL:.*]] = cir.shift(left, %[[A2]] : !u32i, %[[B2]] : !u32i) -> 
!u32i
+// CIR: cir.store %[[SHL]], %[[X_PTR]] : !u32i, !cir.ptr<!u32i>
+
+// CIR: cir.return
+
+// LLVM-LABEL: define void @unsigned_shift
+// LLVM-SAME: (i32 %[[A:.*]], i32 %[[B:.*]])
+// LLVM:         %[[A_ADDR:.*]] = alloca i32
+// LLVM:         %[[B_ADDR:.*]] = alloca i32
+// LLVM:         %[[X:.*]] = alloca i32
+// LLVM:         store i32 %[[A]], ptr %[[A_ADDR]]
+// LLVM:         store i32 %[[B]], ptr %[[B_ADDR]]
+
+// LLVM:         %[[A1:.*]] = load i32, ptr %[[A_ADDR]]
+// LLVM:         %[[B1:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[ASHR:.*]] = lshr i32 %[[A1]], %[[B1]]
+// LLVM:         store i32 %[[ASHR]], ptr %[[X]]
+
+// LLVM:         %[[A2:.*]] = load i32, ptr %[[A_ADDR]]
+// LLVM:         %[[B2:.*]] = load i32, ptr %[[B_ADDR]]
+// LLVM:         %[[SHL:.*]] = shl i32 %[[A2]], %[[B2]]
+// LLVM:         store i32 %[[SHL]], ptr %[[X]]
+
+// LLVM:         ret void
+
+// OGCG-LABEL: define dso_local void @_Z14unsigned_shiftjj
+// OGCG-SAME: (i32 {{.*}} %[[A:.*]], i32 {{.*}} %[[B:.*]])
+// OGCG:         %[[A_ADDR:.*]] = alloca i32
+// OGCG:         %[[B_ADDR:.*]] = alloca i32
+// OGCG:         %[[X:.*]] = alloca i32
+// OGCG:         store i32 %[[A]], ptr %[[A_ADDR]]
+// OGCG:         store i32 %[[B]], ptr %[[B_ADDR]]
+
+// OGCG:         %[[A1:.*]] = load i32, ptr %[[A_ADDR]]
+// OGCG:         %[[B1:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[ASHR:.*]] = lshr i32 %[[A1]], %[[B1]]
+// OGCG:         store i32 %[[ASHR]], ptr %[[X]]
+
+// OGCG:         %[[A2:.*]] = load i32, ptr %[[A_ADDR]]
+// OGCG:         %[[B2:.*]] = load i32, ptr %[[B_ADDR]]
+// OGCG:         %[[SHL:.*]] = shl i32 %[[A2]], %[[B2]]
+// OGCG:         store i32 %[[SHL]], ptr %[[X]]
+
+// OGCG:         ret void
diff --git a/clang/test/CIR/Lowering/select.cir 
b/clang/test/CIR/Lowering/select.cir
new file mode 100644
index 0000000000000..71ca79a390e8b
--- /dev/null
+++ b/clang/test/CIR/Lowering/select.cir
@@ -0,0 +1,48 @@
+// RUN: cir-translate -cir-to-llvmir --disable-cc-lowering -o %t.ll %s
+// RUN: FileCheck --input-file=%t.ll -check-prefix=LLVM %s
+
+!s32i = !cir.int<s, 32>
+
+module {
+  cir.func @select_int(%arg0 : !cir.bool, %arg1 : !s32i, %arg2 : !s32i) -> 
!s32i {
+    %0 = cir.select if %arg0 then %arg1 else %arg2 : (!cir.bool, !s32i, !s32i) 
-> !s32i
+    cir.return %0 : !s32i
+  }
+
+  //      LLVM: define i32 @select_int(i1 %[[#COND:]], i32 %[[#TV:]], i32 
%[[#FV:]])
+  // LLVM-NEXT:   %[[#RES:]] = select i1 %[[#COND]], i32 %[[#TV]], i32 %[[#FV]]
+  // LLVM-NEXT:   ret i32 %[[#RES]]
+  // LLVM-NEXT: }
+
+  cir.func @select_bool(%arg0 : !cir.bool, %arg1 : !cir.bool, %arg2 : 
!cir.bool) -> !cir.bool {
+    %0 = cir.select if %arg0 then %arg1 else %arg2 : (!cir.bool, !cir.bool, 
!cir.bool) -> !cir.bool
+    cir.return %0 : !cir.bool
+  }
+
+  //      LLVM: define i1 @select_bool(i1 %[[#COND:]], i1 %[[#TV:]], i1 
%[[#FV:]])
+  // LLVM-NEXT:   %[[#RES:]] = select i1 %[[#COND]], i1 %[[#TV]], i1 %[[#FV]]
+  // LLVM-NEXT:   ret i1 %[[#RES]]
+  // LLVM-NEXT: }
+
+  cir.func @logical_and(%arg0 : !cir.bool, %arg1 : !cir.bool) -> !cir.bool {
+    %0 = cir.const #cir.bool<false> : !cir.bool
+    %1 = cir.select if %arg0 then %arg1 else %0 : (!cir.bool, !cir.bool, 
!cir.bool) -> !cir.bool
+    cir.return %1 : !cir.bool
+  }
+
+  //      LLVM: define i1 @logical_and(i1 %[[#ARG0:]], i1 %[[#ARG1:]])
+  // LLVM-NEXT:   %[[#RES:]] = and i1 %[[#ARG0]], %[[#ARG1]]
+  // LLVM-NEXT:   ret i1 %[[#RES]]
+  // LLVM-NEXT: }
+
+  cir.func @logical_or(%arg0 : !cir.bool, %arg1 : !cir.bool) -> !cir.bool {
+    %0 = cir.const #cir.bool<true> : !cir.bool
+    %1 = cir.select if %arg0 then %0 else %arg1 : (!cir.bool, !cir.bool, 
!cir.bool) -> !cir.bool
+    cir.return %1 : !cir.bool
+  }
+
+  //      LLVM: define i1 @logical_or(i1 %[[#ARG0:]], i1 %[[#ARG1:]])
+  // LLVM-NEXT:   %[[#RES:]] = or i1 %[[#ARG0]], %[[#ARG1]]
+  // LLVM-NEXT:   ret i1 %[[#RES]]
+  // LLVM-NEXT: }
+}

>From 8199367b3221061c91d27bf91764be9cbc0ec188 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhaf...@nvidia.com>
Date: Mon, 14 Apr 2025 15:47:56 +0200
Subject: [PATCH 2/2] Address review feedback

- add createShift functions to CIRBuilder
- Rephrase ShiftOpn description comment
- Remove folding for now
- Always zero-extend instead of potentially sign-extend
- Tests with diffferently sized integral types
---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      |  38 +++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  10 +-
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp    |   7 +-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       |  22 --
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  21 +-
 clang/test/CIR/CodeGen/binop.cpp              | 220 ++++++++++++++++++
 6 files changed, 276 insertions(+), 42 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h 
b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 68a4505ca7a5a..55c6f658ea43b 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -353,6 +353,44 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     return create<cir::CmpOp>(loc, getBoolTy(), kind, lhs, rhs);
   }
 
+  mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
+                          bool isShiftLeft) {
+    return create<cir::ShiftOp>(loc, lhs.getType(), lhs, rhs, isShiftLeft);
+  }
+
+  mlir::Value createShift(mlir::Location loc, mlir::Value lhs,
+                          const llvm::APInt &rhs, bool isShiftLeft) {
+    return createShift(loc, lhs, getConstAPInt(loc, lhs.getType(), rhs),
+                       isShiftLeft);
+  }
+
+  mlir::Value createShift(mlir::Location loc, mlir::Value lhs, unsigned bits,
+                          bool isShiftLeft) {
+    auto width = mlir::dyn_cast<cir::IntType>(lhs.getType()).getWidth();
+    auto shift = llvm::APInt(width, bits);
+    return createShift(loc, lhs, shift, isShiftLeft);
+  }
+
+  mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs,
+                              unsigned bits) {
+    return createShift(loc, lhs, bits, true);
+  }
+
+  mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs,
+                               unsigned bits) {
+    return createShift(loc, lhs, bits, false);
+  }
+
+  mlir::Value createShiftLeft(mlir::Location loc, mlir::Value lhs,
+                              mlir::Value rhs) {
+    return createShift(loc, lhs, rhs, true);
+  }
+
+  mlir::Value createShiftRight(mlir::Location loc, mlir::Value lhs,
+                               mlir::Value rhs) {
+    return createShift(loc, lhs, rhs, false);
+  }
+
   //
   // Block handling helpers
   // ----------------------
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 22195477e0137..6b40ba20cd6a3 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1183,9 +1183,11 @@ def BinOp : CIR_Op<"binop", [Pure,
 def ShiftOp : CIR_Op<"shift", [Pure]> {
   let summary = "Shift";
   let description = [{
-    Shift `left` or `right`, according to the first operand. Second operand is
-    the shift target and the third the amount. Second and the thrid operand are
-    integers.
+    The `cir.shift` operation performs a bitwise shift, either to the left or 
to
+    the right, based on the first operand. The second operand specifies the
+    value to be shifted, and the third operand determines the number of
+    positions by which the shift is applied. Both the second and third operands
+    are required to be integers.
 
     ```mlir
     %7 = cir.shift(left, %1 : !u64i, %4 : !s32i) -> !u64i
@@ -1245,8 +1247,6 @@ def SelectOp : CIR_Op<"select", [Pure,
       qualified(type($false_value))
     `)` `->` qualified(type($result)) attr-dict
   }];
-
-  let hasFolder = 1;
 }
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 7417df4407925..2deb66b226145 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1308,9 +1308,7 @@ mlir::Value ScalarExprEmitter::emitShl(const BinOpInfo 
&ops) {
            mlir::isa<cir::IntType>(ops.lhs.getType()))
     cgf.cgm.errorNYI("sanitizers");
 
-  return builder.create<cir::ShiftOp>(cgf.getLoc(ops.loc),
-                                      cgf.convertType(ops.fullType), ops.lhs,
-                                      ops.rhs, cgf.getBuilder().getUnitAttr());
+  return builder.createShiftLeft(cgf.getLoc(ops.loc), ops.lhs, ops.rhs);
 }
 
 mlir::Value ScalarExprEmitter::emitShr(const BinOpInfo &ops) {
@@ -1334,8 +1332,7 @@ mlir::Value ScalarExprEmitter::emitShr(const BinOpInfo 
&ops) {
 
   // Note that we don't need to distinguish unsigned treatment at this
   // point since it will be handled later by LLVM lowering.
-  return builder.create<cir::ShiftOp>(
-      cgf.getLoc(ops.loc), cgf.convertType(ops.fullType), ops.lhs, ops.rhs);
+  return builder.createShiftRight(cgf.getLoc(ops.loc), ops.lhs, ops.rhs);
 }
 
 mlir::Value ScalarExprEmitter::emitAnd(const BinOpInfo &ops) {
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index d25d6609a1aed..bb85a8aead800 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1049,28 +1049,6 @@ LogicalResult cir::ShiftOp::verify() {
   return mlir::success();
 }
 
-//===----------------------------------------------------------------------===//
-// SelectOp
-//===----------------------------------------------------------------------===//
-
-OpFoldResult cir::SelectOp::fold(FoldAdaptor adaptor) {
-  mlir::Attribute condition = adaptor.getCondition();
-  if (condition) {
-    bool conditionValue = mlir::cast<cir::BoolAttr>(condition).getValue();
-    return conditionValue ? getTrueValue() : getFalseValue();
-  }
-
-  // cir.select if %0 then x else x -> x
-  mlir::Attribute trueValue = adaptor.getTrueValue();
-  mlir::Attribute falseValue = adaptor.getFalseValue();
-  if (trueValue && trueValue == falseValue)
-    return trueValue;
-  if (getTrueValue() == getFalseValue())
-    return getTrueValue();
-
-  return {};
-}
-
 
//===----------------------------------------------------------------------===//
 // UnaryOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7f0c056182af9..ec43b666830b8 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -19,6 +19,7 @@
 #include "mlir/Dialect/DLTI/DLTI.h"
 #include "mlir/Dialect/Func/IR/FuncOps.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/IR/BuiltinDialect.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/Types.h"
@@ -28,6 +29,7 @@
 #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
 #include "mlir/Target/LLVMIR/Export.h"
 #include "mlir/Transforms/DialectConversion.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/Passes.h"
 #include "clang/CIR/LoweringHelpers.h"
@@ -1318,8 +1320,7 @@ mlir::LogicalResult 
CIRToLLVMShiftOpLowering::matchAndRewrite(
   // be already be enforced at CIRGen.
   if (cirAmtTy)
     amt = getLLVMIntCast(rewriter, amt, mlir::cast<mlir::IntegerType>(llvmTy),
-                         !cirAmtTy.isSigned(), cirAmtTy.getWidth(),
-                         cirValTy.getWidth());
+                         true, cirAmtTy.getWidth(), cirValTy.getWidth());
 
   // Lower to the proper LLVM shift operation.
   if (op.getIsShiftleft()) {
@@ -1339,32 +1340,32 @@ mlir::LogicalResult 
CIRToLLVMShiftOpLowering::matchAndRewrite(
 mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite(
     cir::SelectOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
-  auto getConstantBool = [](mlir::Value value) -> std::optional<bool> {
+  auto getConstantBool = [](mlir::Value value) -> cir::BoolAttr {
     auto definingOp =
         mlir::dyn_cast_if_present<cir::ConstantOp>(value.getDefiningOp());
     if (!definingOp)
-      return std::nullopt;
+      return {};
 
     auto constValue = mlir::dyn_cast<cir::BoolAttr>(definingOp.getValue());
     if (!constValue)
-      return std::nullopt;
+      return {};
 
-    return constValue.getValue();
+    return constValue;
   };
 
   // Two special cases in the LLVMIR codegen of select op:
   // - select %0, %1, false => and %0, %1
   // - select %0, true, %1 => or %0, %1
   if (mlir::isa<cir::BoolType>(op.getTrueValue().getType())) {
-    std::optional<bool> trueValue = getConstantBool(op.getTrueValue());
-    std::optional<bool> falseValue = getConstantBool(op.getFalseValue());
-    if (falseValue.has_value() && !*falseValue) {
+    cir::BoolAttr trueValue = getConstantBool(op.getTrueValue());
+    cir::BoolAttr falseValue = getConstantBool(op.getFalseValue());
+    if (falseValue && !falseValue.getValue()) {
       // select %0, %1, false => and %0, %1
       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(op, 
adaptor.getCondition(),
                                                      adaptor.getTrueValue());
       return mlir::success();
     }
-    if (trueValue.has_value() && *trueValue) {
+    if (trueValue && trueValue.getValue()) {
       // select %0, true, %1 => or %0, %1
       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, adaptor.getCondition(),
                                                     adaptor.getFalseValue());
diff --git a/clang/test/CIR/CodeGen/binop.cpp b/clang/test/CIR/CodeGen/binop.cpp
index 22ee5d1cd1148..92816cd6b1f8a 100644
--- a/clang/test/CIR/CodeGen/binop.cpp
+++ b/clang/test/CIR/CodeGen/binop.cpp
@@ -320,3 +320,223 @@ void unsigned_shift(unsigned a, unsigned b) {
 // OGCG:         store i32 %[[SHL]], ptr %[[X]]
 
 // OGCG:         ret void
+
+void zext_shift_example(int a, unsigned char b) {
+  int x = a >> b;
+  x = a << b;
+}
+
+// CIR-LABEL: cir.func @zext_shift_example(
+// CIR-SAME: %[[ARG0:.*]]: !s32i{{.*}}, %[[ARG1:.*]]: !u8i{{.*}})
+// CIR: %[[A_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
+// CIR: %[[B_PTR:.*]] = cir.alloca !u8i, !cir.ptr<!u8i>, ["b", init]
+// CIR: %[[X_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
+
+// CIR: cir.store %[[ARG0]], %[[A_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.store %[[ARG1]], %[[B_PTR]] : !u8i, !cir.ptr<!u8i>
+
+// CIR: %[[A1:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[B1:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!u8i>, !u8i
+// CIR: %[[B1_EXT:.*]] = cir.cast(integral, %[[B1]] : !u8i), !s32i
+// CIR: %[[ASHR:.*]] = cir.shift(right, %[[A1]] : !s32i, %[[B1_EXT]] : !s32i) 
-> !s32i
+// CIR: cir.store %[[ASHR]], %[[X_PTR]] : !s32i, !cir.ptr<!s32i>
+
+// CIR: %[[A2:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[B2:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!u8i>, !u8i
+// CIR: %[[B2_EXT:.*]] = cir.cast(integral, %[[B2]] : !u8i), !s32i
+// CIR: %[[SHL:.*]] = cir.shift(left, %[[A2]] : !s32i, %[[B2_EXT]] : !s32i) -> 
!s32i
+// CIR: cir.store %[[SHL]], %[[X_PTR]] : !s32i, !cir.ptr<!s32i>
+
+// CIR: cir.return
+
+// LLVM-LABEL: define void @zext_shift_example
+// LLVM-SAME: (i32 %[[A:.*]], i8 %[[B:.*]])
+// LLVM:         %[[A_ADDR:.*]] = alloca i32
+// LLVM:         %[[B_ADDR:.*]] = alloca i8
+// LLVM:         %[[X:.*]] = alloca i32
+// LLVM:         store i32 %[[A]], ptr %[[A_ADDR]]
+// LLVM:         store i8 %[[B]], ptr %[[B_ADDR]]
+
+// LLVM:         %[[A1:.*]] = load i32, ptr %[[A_ADDR]]
+// LLVM:         %[[B1:.*]] = load i8, ptr %[[B_ADDR]]
+// LLVM:         %[[B1_EXT:.*]] = zext i8 %[[B1]] to i32
+// LLVM:         %[[ASHR:.*]] = ashr i32 %[[A1]], %[[B1_EXT]]
+// LLVM:         store i32 %[[ASHR]], ptr %[[X]]
+
+// LLVM:         %[[A2:.*]] = load i32, ptr %[[A_ADDR]]
+// LLVM:         %[[B2:.*]] = load i8, ptr %[[B_ADDR]]
+// LLVM:         %[[B2_EXT:.*]] = zext i8 %[[B2]] to i32
+// LLVM:         %[[SHL:.*]] = shl i32 %[[A2]], %[[B2_EXT]]
+// LLVM:         store i32 %[[SHL]], ptr %[[X]]
+
+// LLVM:         ret void
+
+// OGCG-LABEL: define dso_local void @_Z18zext_shift_exampleih
+// OGCG-SAME: (i32 {{.*}} %[[A:.*]], i8 {{.*}} %[[B:.*]])
+// OGCG:         %[[A_ADDR:.*]] = alloca i32
+// OGCG:         %[[B_ADDR:.*]] = alloca i8
+// OGCG:         %[[X:.*]] = alloca i32
+// OGCG:         store i32 %[[A]], ptr %[[A_ADDR]]
+// OGCG:         store i8 %[[B]], ptr %[[B_ADDR]]
+
+// OGCG:         %[[A1:.*]] = load i32, ptr %[[A_ADDR]]
+// OGCG:         %[[B1:.*]] = load i8, ptr %[[B_ADDR]]
+// OGCG:         %[[B1_EXT:.*]] = zext i8 %[[B1]] to i32
+// OGCG:         %[[ASHR:.*]] = ashr i32 %[[A1]], %[[B1_EXT]]
+// OGCG:         store i32 %[[ASHR]], ptr %[[X]]
+
+// OGCG:         %[[A2:.*]] = load i32, ptr %[[A_ADDR]]
+// OGCG:         %[[B2:.*]] = load i8, ptr %[[B_ADDR]]
+// OGCG:         %[[B2_EXT:.*]] = zext i8 %[[B2]] to i32
+// OGCG:         %[[SHL:.*]] = shl i32 %[[A2]], %[[B2_EXT]]
+// OGCG:         store i32 %[[SHL]], ptr %[[X]]
+
+// OGCG:         ret void
+
+void sext_shift_example(int a, signed char b) {
+  int x = a >> b;
+  x = a << b;
+}
+
+// CIR-LABEL: cir.func @sext_shift_example(
+// CIR-SAME: %[[ARG0:.*]]: !s32i{{.*}}, %[[ARG1:.*]]: !s8i{{.*}})
+// CIR: %[[A_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init]
+// CIR: %[[B_PTR:.*]] = cir.alloca !s8i, !cir.ptr<!s8i>, ["b", init]
+// CIR: %[[X_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
+
+// CIR: cir.store %[[ARG0]], %[[A_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.store %[[ARG1]], %[[B_PTR]] : !s8i, !cir.ptr<!s8i>
+
+// CIR: %[[A1:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[B1:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!s8i>, !s8i
+// CIR: %[[B1_EXT:.*]] = cir.cast(integral, %[[B1]] : !s8i), !s32i
+// CIR: %[[ASHR:.*]] = cir.shift(right, %[[A1]] : !s32i, %[[B1_EXT]] : !s32i) 
-> !s32i
+// CIR: cir.store %[[ASHR]], %[[X_PTR]] : !s32i, !cir.ptr<!s32i>
+
+// CIR: %[[A2:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[B2:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!s8i>, !s8i
+// CIR: %[[B2_EXT:.*]] = cir.cast(integral, %[[B2]] : !s8i), !s32i
+// CIR: %[[SHL:.*]] = cir.shift(left, %[[A2]] : !s32i, %[[B2_EXT]] : !s32i) -> 
!s32i
+// CIR: cir.store %[[SHL]], %[[X_PTR]] : !s32i, !cir.ptr<!s32i>
+
+// CIR: cir.return
+
+// LLVM-LABEL: define void @sext_shift_example
+// LLVM-SAME: (i32 %[[A:.*]], i8 %[[B:.*]])
+// LLVM:         %[[A_ADDR:.*]] = alloca i32
+// LLVM:         %[[B_ADDR:.*]] = alloca i8
+// LLVM:         %[[X:.*]] = alloca i32
+// LLVM:         store i32 %[[A]], ptr %[[A_ADDR]]
+// LLVM:         store i8 %[[B]], ptr %[[B_ADDR]]
+
+// LLVM:         %[[A1:.*]] = load i32, ptr %[[A_ADDR]]
+// LLVM:         %[[B1:.*]] = load i8, ptr %[[B_ADDR]]
+// LLVM:         %[[B1_EXT:.*]] = sext i8 %[[B1]] to i32
+// LLVM:         %[[ASHR:.*]] = ashr i32 %[[A1]], %[[B1_EXT]]
+// LLVM:         store i32 %[[ASHR]], ptr %[[X]]
+
+// LLVM:         %[[A2:.*]] = load i32, ptr %[[A_ADDR]]
+// LLVM:         %[[B2:.*]] = load i8, ptr %[[B_ADDR]]
+// LLVM:         %[[B2_EXT:.*]] = sext i8 %[[B2]] to i32
+// LLVM:         %[[SHL:.*]] = shl i32 %[[A2]], %[[B2_EXT]]
+// LLVM:         store i32 %[[SHL]], ptr %[[X]]
+
+// LLVM:         ret void
+
+// OGCG-LABEL: define dso_local void @_Z18sext_shift_exampleia
+// OGCG-SAME: (i32 {{.*}} %[[A:.*]], i8 {{.*}} %[[B:.*]])
+// OGCG:         %[[A_ADDR:.*]] = alloca i32
+// OGCG:         %[[B_ADDR:.*]] = alloca i8
+// OGCG:         %[[X:.*]] = alloca i32
+// OGCG:         store i32 %[[A]], ptr %[[A_ADDR]]
+// OGCG:         store i8 %[[B]], ptr %[[B_ADDR]]
+
+// OGCG:         %[[A1:.*]] = load i32, ptr %[[A_ADDR]]
+// OGCG:         %[[B1:.*]] = load i8, ptr %[[B_ADDR]]
+// OGCG:         %[[B1_EXT:.*]] = sext i8 %[[B1]] to i32
+// OGCG:         %[[ASHR:.*]] = ashr i32 %[[A1]], %[[B1_EXT]]
+// OGCG:         store i32 %[[ASHR]], ptr %[[X]]
+
+// OGCG:         %[[A2:.*]] = load i32, ptr %[[A_ADDR]]
+// OGCG:         %[[B2:.*]] = load i8, ptr %[[B_ADDR]]
+// OGCG:         %[[B2_EXT:.*]] = sext i8 %[[B2]] to i32
+// OGCG:         %[[SHL:.*]] = shl i32 %[[A2]], %[[B2_EXT]]
+// OGCG:         store i32 %[[SHL]], ptr %[[X]]
+
+// OGCG:         ret void
+
+void long_shift_example(long long a, short b) {
+  long long x = a >> b;
+  x = a << b;
+}
+
+// CIR-LABEL: cir.func @long_shift_example(
+// CIR-SAME: %[[ARG0:.*]]: !s64i{{.*}}, %[[ARG1:.*]]: !s16i{{.*}})
+// CIR: %[[A_PTR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["a", init]
+// CIR: %[[B_PTR:.*]] = cir.alloca !s16i, !cir.ptr<!s16i>, ["b", init]
+// CIR: %[[X_PTR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["x", init]
+
+// CIR: cir.store %[[ARG0]], %[[A_PTR]] : !s64i, !cir.ptr<!s64i>
+// CIR: cir.store %[[ARG1]], %[[B_PTR]] : !s16i, !cir.ptr<!s16i>
+
+// CIR: %[[A1:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!s64i>, !s64i
+// CIR: %[[B1:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!s16i>, !s16i
+// CIR: %[[B1_EXT:.*]] = cir.cast(integral, %[[B1]] : !s16i), !s32i
+// CIR: %[[ASHR:.*]] = cir.shift(right, %[[A1]] : !s64i, %[[B1_EXT]] : !s32i) 
-> !s64i
+// CIR: cir.store %[[ASHR]], %[[X_PTR]] : !s64i, !cir.ptr<!s64i>
+
+// CIR: %[[A2:.*]] = cir.load %[[A_PTR]] : !cir.ptr<!s64i>, !s64i
+// CIR: %[[B2:.*]] = cir.load %[[B_PTR]] : !cir.ptr<!s16i>, !s16i
+// CIR: %[[B2_EXT:.*]] = cir.cast(integral, %[[B2]] : !s16i), !s32i
+// CIR: %[[SHL:.*]] = cir.shift(left, %[[A2]] : !s64i, %[[B2_EXT]] : !s32i) -> 
!s64i
+// CIR: cir.store %[[SHL]], %[[X_PTR]] : !s64i, !cir.ptr<!s64i>
+
+// CIR: cir.return
+
+// LLVM-LABEL: define void @long_shift_example
+// LLVM-SAME: (i64 %[[A:.*]], i16 %[[B:.*]])
+// LLVM:         %[[A_ADDR:.*]] = alloca i64
+// LLVM:         %[[B_ADDR:.*]] = alloca i16
+// LLVM:         %[[X:.*]] = alloca i64
+// LLVM:         store i64 %[[A]], ptr %[[A_ADDR]]
+// LLVM:         store i16 %[[B]], ptr %[[B_ADDR]]
+
+// LLVM:         %[[A1:.*]] = load i64, ptr %[[A_ADDR]]
+// LLVM:         %[[B1:.*]] = load i16, ptr %[[B_ADDR]]
+// LLVM:         %[[B1_SEXT:.*]] = sext i16 %[[B1]] to i32
+// LLVM:         %[[B1_ZEXT:.*]] = zext i32 %[[B1_SEXT]] to i64
+// LLVM:         %[[ASHR:.*]] = ashr i64 %[[A1]], %[[B1_ZEXT]]
+// LLVM:         store i64 %[[ASHR]], ptr %[[X]]
+
+// LLVM:         %[[A2:.*]] = load i64, ptr %[[A_ADDR]]
+// LLVM:         %[[B2:.*]] = load i16, ptr %[[B_ADDR]]
+// LLVM:         %[[B2_SEXT:.*]] = sext i16 %[[B2]] to i32
+// LLVM:         %[[B2_ZEXT:.*]] = zext i32 %[[B2_SEXT]] to i64
+// LLVM:         %[[SHL:.*]] = shl i64 %[[A2]], %[[B2_ZEXT]]
+// LLVM:         store i64 %[[SHL]], ptr %[[X]]
+
+// LLVM:         ret void
+
+// OGCG-LABEL: define dso_local void @_Z18long_shift_examplexs
+// OGCG-SAME: (i64 {{.*}} %[[A:.*]], i16 {{.*}} %[[B:.*]])
+// OGCG:         %[[A_ADDR:.*]] = alloca i64
+// OGCG:         %[[B_ADDR:.*]] = alloca i16
+// OGCG:         %[[X:.*]] = alloca i64
+// OGCG:         store i64 %[[A]], ptr %[[A_ADDR]]
+// OGCG:         store i16 %[[B]], ptr %[[B_ADDR]]
+
+// OGCG:         %[[A1:.*]] = load i64, ptr %[[A_ADDR]]
+// OGCG:         %[[B1:.*]] = load i16, ptr %[[B_ADDR]]
+// OGCG:         %[[B1_SEXT:.*]] = sext i16 %[[B1]] to i32
+// OGCG:         %[[B1_ZEXT:.*]] = zext i32 %[[B1_SEXT]] to i64
+// OGCG:         %[[ASHR:.*]] = ashr i64 %[[A1]], %[[B1_ZEXT]]
+// OGCG:         store i64 %[[ASHR]], ptr %[[X]]
+
+// OGCG:         %[[A2:.*]] = load i64, ptr %[[A_ADDR]]
+// OGCG:         %[[B2:.*]] = load i16, ptr %[[B_ADDR]]
+// OGCG:         %[[B2_SEXT:.*]] = sext i16 %[[B2]] to i32
+// OGCG:         %[[B2_ZEXT:.*]] = zext i32 %[[B2_SEXT]] to i64
+// OGCG:         %[[SHL:.*]] = shl i64 %[[A2]], %[[B2_ZEXT]]
+// OGCG:         store i64 %[[SHL]], ptr %[[X]]
+
+// OGCG:         ret void

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to