[clang] [CIR] Add Commutative/Idempotent traits to binary ops (PR #185163)
Henrich Lauko via cfe-commits
cfe-commits at lists.llvm.org
Sun Mar 8 07:03:28 PDT 2026
https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/185163
>From 1b8f6acec0a83383b174e430f05d5abff7f06037 Mon Sep 17 00:00:00 2001
From: xlauko <xlauko at mail.muni.cz>
Date: Sat, 7 Mar 2026 08:42:26 +0100
Subject: [PATCH] [CIR] Add Commutative/Idempotent traits to binary ops
Add missing MLIR traits to CIR binary operations, matching the arith
dialect conventions:
- AndOp, OrOp: Commutative, Idempotent (fixes FIXME)
- AddOp, MulOp, XorOp, MaxOp: Commutative
Add these ops to the CIRCanonicalize pass op list so trait-based
folding is exercised by applyOpPatternsGreedily.
Update testFloatingPointBinOps in binop.cpp to use computed values,
preventing DCE of the now-canonicalized ops.
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 22 ++++---
.../Dialect/Transforms/CIRCanonicalize.cpp | 11 ++--
clang/test/CIR/CodeGen/binop.cpp | 46 ++++++++-----
clang/test/CIR/CodeGen/new.cpp | 9 +--
clang/test/CIR/CodeGen/size-of-vla.cpp | 10 +--
clang/test/CIR/CodeGen/throws.cpp | 4 +-
clang/test/CIR/CodeGen/vla.c | 8 +--
clang/test/CIR/Transforms/binop-traits.cir | 65 +++++++++++++++++++
8 files changed, 125 insertions(+), 50 deletions(-)
create mode 100644 clang/test/CIR/Transforms/binop-traits.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7f52be17d30f8..8860d6df27a74 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2186,7 +2186,9 @@ class CIR_BinaryOpWithOverflowFlags<string mnemonic, Type type,
// AddOp
//===----------------------------------------------------------------------===//
-def CIR_AddOp : CIR_BinaryOpWithOverflowFlags<"add", CIR_AnyArithType> {
+def CIR_AddOp : CIR_BinaryOpWithOverflowFlags<"add", CIR_AnyArithType, [
+ Commutative
+]> {
let summary = "Integer or floating-point addition";
let description = [{
The `cir.add` operation performs addition on integer or floating-point
@@ -2241,7 +2243,7 @@ def CIR_SubOp : CIR_BinaryOpWithOverflowFlags<"sub", CIR_AnyArithType> {
// MulOp
//===----------------------------------------------------------------------===//
-def CIR_MulOp : CIR_BinaryOp<"mul", CIR_AnyArithType> {
+def CIR_MulOp : CIR_BinaryOp<"mul", CIR_AnyArithType, [Commutative]> {
let summary = "Integer or floating-point multiplication";
let description = [{
The `cir.mul` operation performs multiplication on integer or floating-point
@@ -2321,8 +2323,9 @@ def CIR_RemOp : CIR_BinaryOp<"rem", CIR_AnyArithType> {
// AndOp
//===----------------------------------------------------------------------===//
-// FIXME: Commutative, Idempotent traits
-def CIR_AndOp : CIR_BinaryOp<"and", CIR_AnyBitwiseType> {
+def CIR_AndOp : CIR_BinaryOp<"and", CIR_AnyBitwiseType, [
+ Commutative, Idempotent
+]> {
let summary = "Bitwise AND";
let description = [{
The `cir.and` operation performs a bitwise AND on integer operands.
@@ -2341,8 +2344,9 @@ def CIR_AndOp : CIR_BinaryOp<"and", CIR_AnyBitwiseType> {
// OrOp
//===----------------------------------------------------------------------===//
-// FIXME: Commutative, Idempotent traits
-def CIR_OrOp : CIR_BinaryOp<"or", CIR_AnyBitwiseType> {
+def CIR_OrOp : CIR_BinaryOp<"or", CIR_AnyBitwiseType, [
+ Commutative, Idempotent
+]> {
let summary = "Bitwise OR";
let description = [{
The `cir.or` operation performs a bitwise OR on integer operands.
@@ -2361,7 +2365,7 @@ def CIR_OrOp : CIR_BinaryOp<"or", CIR_AnyBitwiseType> {
// XorOp
//===----------------------------------------------------------------------===//
-def CIR_XorOp : CIR_BinaryOp<"xor", CIR_AnyBitwiseType> {
+def CIR_XorOp : CIR_BinaryOp<"xor", CIR_AnyBitwiseType, [Commutative]> {
let summary = "Bitwise XOR";
let description = [{
The `cir.xor` operation performs a bitwise XOR on integer operands.
@@ -2380,7 +2384,9 @@ def CIR_XorOp : CIR_BinaryOp<"xor", CIR_AnyBitwiseType> {
// MaxOp
//===----------------------------------------------------------------------===//
-def CIR_MaxOp : CIR_BinaryOp<"max", CIR_AnyIntOrVecOfIntType> {
+def CIR_MaxOp : CIR_BinaryOp<"max", CIR_AnyIntOrVecOfIntType, [
+ Commutative, Idempotent
+]> {
let summary = "Integer maximum";
let description = [{
The `cir.max` operation computes the maximum of two integer operands.
diff --git a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
index e9b825606a04e..46a8c011b320b 100644
--- a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
@@ -70,11 +70,12 @@ void CIRCanonicalizePass::runOnOperation() {
// Many operations are here to perform a manual `fold` in
// applyOpPatternsGreedily.
- if (isa<BrOp, BrCondOp, CastOp, ScopeOp, SwitchOp, SelectOp, UnaryOp,
- ComplexCreateOp, ComplexImagOp, ComplexRealOp, VecCmpOp,
- VecCreateOp, VecExtractOp, VecShuffleOp, VecShuffleDynamicOp,
- VecTernaryOp, BitClrsbOp, BitClzOp, BitCtzOp, BitFfsOp, BitParityOp,
- BitPopcountOp, BitReverseOp, ByteSwapOp, RotateOp, ConstantOp>(op))
+ if (isa<BrOp, BrCondOp, CastOp, ScopeOp, SwitchOp, SelectOp, UnaryOp, AddOp,
+ MulOp, AndOp, OrOp, XorOp, MaxOp, ComplexCreateOp, ComplexImagOp,
+ ComplexRealOp, VecCmpOp, VecCreateOp, VecExtractOp, VecShuffleOp,
+ VecShuffleDynamicOp, VecTernaryOp, BitClrsbOp, BitClzOp, BitCtzOp,
+ BitFfsOp, BitParityOp, BitPopcountOp, BitReverseOp, ByteSwapOp,
+ RotateOp, ConstantOp>(op))
ops.push_back(op);
});
diff --git a/clang/test/CIR/CodeGen/binop.cpp b/clang/test/CIR/CodeGen/binop.cpp
index 3d883f14acdc9..33498b90e3a42 100644
--- a/clang/test/CIR/CodeGen/binop.cpp
+++ b/clang/test/CIR/CodeGen/binop.cpp
@@ -127,10 +127,10 @@ void b0(int a, int b) {
// OGCG: ret void
void testFloatingPointBinOps(float a, float b) {
- a * b;
- a / b;
- a + b;
- a - b;
+ float x = a * b;
+ x = x / b;
+ x = x + b;
+ x = x - b;
}
// CIR-LABEL: cir.func{{.*}} @_Z23testFloatingPointBinOpsff(
@@ -144,48 +144,58 @@ void testFloatingPointBinOps(float a, float b) {
// LLVM-SAME: float {{.*}} %[[A:.*]], float {{.*}} %[[B:.*]])
// LLVM: %[[A_ADDR:.*]] = alloca float, i64 1
// LLVM: %[[B_ADDR:.*]] = alloca float, i64 1
+// LLVM: %[[X_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: %[[MUL:.*]] = fmul float %[[A1]], %[[B1]]
+// LLVM: store float %[[MUL]], ptr %[[X_ADDR]]
-// LLVM: %[[A2:.*]] = load float, ptr %[[A_ADDR]]
+// LLVM: %[[X1:.*]] = load float, ptr %[[X_ADDR]]
// LLVM: %[[B2:.*]] = load float, ptr %[[B_ADDR]]
-// LLVM: fdiv float %[[A2]], %[[B2]]
+// LLVM: %[[DIV:.*]] = fdiv float %[[X1]], %[[B2]]
+// LLVM: store float %[[DIV]], ptr %[[X_ADDR]]
-// LLVM: %[[A3:.*]] = load float, ptr %[[A_ADDR]]
+// LLVM: %[[X2:.*]] = load float, ptr %[[X_ADDR]]
// LLVM: %[[B3:.*]] = load float, ptr %[[B_ADDR]]
-// LLVM: fadd float %[[A3]], %[[B3]]
+// LLVM: %[[ADD:.*]] = fadd float %[[X2]], %[[B3]]
+// LLVM: store float %[[ADD]], ptr %[[X_ADDR]]
-// LLVM: %[[A4:.*]] = load float, ptr %[[A_ADDR]]
+// LLVM: %[[X3:.*]] = load float, ptr %[[X_ADDR]]
// LLVM: %[[B4:.*]] = load float, ptr %[[B_ADDR]]
-// LLVM: fsub float %[[A4]], %[[B4]]
+// LLVM: %[[SUB:.*]] = fsub float %[[X3]], %[[B4]]
+// LLVM: store float %[[SUB]], ptr %[[X_ADDR]]
// LLVM: ret void
// OGCG-LABEL: define{{.*}} void @_Z23testFloatingPointBinOpsff(float {{.*}} %a, float {{.*}} %b)
// OGCG: %a.addr = alloca float
// OGCG: %b.addr = alloca float
+// OGCG: %x = 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: %[[MUL:.*]] = fmul float %[[A1]], %[[B1]]
+// OGCG: store float %[[MUL]], ptr %x
-// OGCG: %[[A2:.*]] = load float, ptr %a.addr
+// OGCG: %[[X1:.*]] = load float, ptr %x
// OGCG: %[[B2:.*]] = load float, ptr %b.addr
-// OGCG: fdiv float %[[A2]], %[[B2]]
+// OGCG: %[[DIV:.*]] = fdiv float %[[X1]], %[[B2]]
+// OGCG: store float %[[DIV]], ptr %x
-// OGCG: %[[A3:.*]] = load float, ptr %a.addr
+// OGCG: %[[X2:.*]] = load float, ptr %x
// OGCG: %[[B3:.*]] = load float, ptr %b.addr
-// OGCG: fadd float %[[A3]], %[[B3]]
+// OGCG: %[[ADD:.*]] = fadd float %[[X2]], %[[B3]]
+// OGCG: store float %[[ADD]], ptr %x
-// OGCG: %[[A4:.*]] = load float, ptr %a.addr
+// OGCG: %[[X3:.*]] = load float, ptr %x
// OGCG: %[[B4:.*]] = load float, ptr %b.addr
-// OGCG: fsub float %[[A4]], %[[B4]]
+// OGCG: %[[SUB:.*]] = fsub float %[[X3]], %[[B4]]
+// OGCG: store float %[[SUB]], ptr %x
// OGCG: ret void
diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp
index 20fe26ac833e0..74aa74a8d51af 100644
--- a/clang/test/CIR/CodeGen/new.cpp
+++ b/clang/test/CIR/CodeGen/new.cpp
@@ -551,19 +551,14 @@ void t_new_var_size5(int n) {
auto p = new double[n][2][3];
}
-// NUM_ELEMENTS isn't used in this case because there is no cookie. It isn't
-// used in the allocation size because the allocation size is calculated with
-// the element size and the fixed size dimensions already combined (6 * 8 = 48).
-// We don't DCE NUM_ELEMENTS because it's not a constant, but later
-// optimizations will eliminate it.
+// The allocation size is calculated with the element size and the fixed size
+// dimensions already combined (6 * 8 = 48).
// CHECK: cir.func {{.*}} @_Z15t_new_var_size5i
// CHECK: %[[N:.*]] = cir.load{{.*}} %[[ARG_ALLOCA:.*]]
// CHECK: %[[N_SIZE_T:.*]] = cir.cast integral %[[N]] : !s32i -> !u64i
// CHECK: %[[ELEMENT_SIZE:.*]] = cir.const #cir.int<48> : !u64i
// CHECK: %[[RESULT:.*]], %[[OVERFLOW:.*]] = cir.binop.overflow(mul, %[[N_SIZE_T]], %[[ELEMENT_SIZE]]) : !u64i, (!u64i, !cir.bool)
-// CHECK: %[[NUM_ELEMENTS_MULTIPLIER:.*]] = cir.const #cir.int<6>
-// CHECK: %[[NUM_ELEMENTS:.*]] = cir.mul %[[N_SIZE_T]], %[[NUM_ELEMENTS_MULTIPLIER]] : !u64i
// CHECK: %[[ALL_ONES:.*]] = cir.const #cir.int<18446744073709551615> : !u64i
// CHECK: %[[ALLOC_SIZE:.*]] = cir.select if %[[OVERFLOW]] then %[[ALL_ONES]] else %[[RESULT]] : (!cir.bool, !u64i, !u64i)
// CHECK: %[[PTR:.*]] = cir.call @_Znam(%[[ALLOC_SIZE]]) {allocsize = array<i32: 0>} : (!u64i {llvm.noundef})
diff --git a/clang/test/CIR/CodeGen/size-of-vla.cpp b/clang/test/CIR/CodeGen/size-of-vla.cpp
index 789e97f40440b..3f9b2f5fecbbd 100644
--- a/clang/test/CIR/CodeGen/size-of-vla.cpp
+++ b/clang/test/CIR/CodeGen/size-of-vla.cpp
@@ -38,16 +38,16 @@ void vla_type_with_element_type_int() {
// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["size", init]
// CIR: %[[CONST_10:.*]] = cir.const #cir.int<10> : !u64i
// CIR: cir.store {{.*}} %[[CONST_10]], %[[N_ADDR]] : !u64i, !cir.ptr<!u64i>
-// CIR: %3 = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr<!u64i>, !u64i
+// CIR: %[[TMP_N:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr<!u64i>, !u64i
// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !u64i
-// CIR: %[[SIZE:.*]] = cir.mul nuw %[[CONST_4]], %3 : !u64i
+// CIR: %[[SIZE:.*]] = cir.mul nuw %[[TMP_N]], %[[CONST_4]] : !u64i
// CIR: cir.store {{.*}} %[[SIZE]], %[[SIZE_ADDR]] : !u64i, !cir.ptr<!u64i>
// LLVM: %[[N_ADDR:.*]] = alloca i64, i64 1, align 8
// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8
// LLVM: store i64 10, ptr %[[N_ADDR]], align 8
// LLVM: %[[TMP_N:.*]] = load i64, ptr %[[N_ADDR]], align 8
-// LLVM: %[[SIZE:.*]] = mul nuw i64 4, %[[TMP_N]]
+// LLVM: %[[SIZE:.*]] = mul nuw i64 %[[TMP_N]], 4
// LLVM: store i64 %[[SIZE]], ptr %[[SIZE_ADDR]], align 8
// OGCG: %[[N_ADDR:.*]] = alloca i64, align 8
@@ -126,7 +126,7 @@ void vla_expr_element_type_int() {
// CIR: cir.cleanup.scope {
// CIR: %[[ARR_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, %[[TMP_N]] : !u64i, ["arr"]
// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !u64i
-// CIR: %[[SIZE:.*]] = cir.mul nuw %[[CONST_4]], %[[TMP_N]] : !u64i
+// CIR: %[[SIZE:.*]] = cir.mul nuw %[[TMP_N]], %[[CONST_4]] : !u64i
// CIR: cir.store {{.*}} %[[SIZE]], %[[SIZE_ADDR]] : !u64i, !cir.ptr<!u64i>
// CIR: cir.yield
// CIR: } cleanup normal {
@@ -143,7 +143,7 @@ void vla_expr_element_type_int() {
// LLVM: %[[STACK_SAVE:.*]] = call ptr @llvm.stacksave.p0()
// LLVM: store ptr %[[STACK_SAVE]], ptr %[[SAVED_STACK_ADDR]], align 8
// LLVM: %[[ARR_ADDR:.*]] = alloca i32, i64 %[[TMP_N]], align 16
-// LLVM: %[[SIZE:.*]] = mul nuw i64 4, %[[TMP_N]]
+// LLVM: %[[SIZE:.*]] = mul nuw i64 %[[TMP_N]], 4
// LLVM: store i64 %[[SIZE]], ptr %[[SIZE_ADDR]], align 8
// LLVM: %[[TMP_SAVED_STACK:.*]] = load ptr, ptr %[[SAVED_STACK_ADDR]], align 8
// LLVM: call void @llvm.stackrestore.p0(ptr %[[TMP_SAVED_STACK]])
diff --git a/clang/test/CIR/CodeGen/throws.cpp b/clang/test/CIR/CodeGen/throws.cpp
index 64cf0f6d62b0a..14b1d1272217c 100644
--- a/clang/test/CIR/CodeGen/throws.cpp
+++ b/clang/test/CIR/CodeGen/throws.cpp
@@ -112,9 +112,7 @@ void paren_expr() { (throw 0, 1 + 2); }
// CIR: cir.throw %[[EXCEPTION_ADDR]] : !cir.ptr<!s32i>, @_ZTIi
// CIR: cir.unreachable
// CIR: ^bb1:
-// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i
-// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i
-// CIR: %[[ADD:.*]] = cir.add nsw %[[CONST_1]], %[[CONST_2]] : !s32i
+// CIR: cir.return
// LLVM: %[[EXCEPTION_ADDR:.*]] = call ptr @__cxa_allocate_exception(i64 4)
// LLVM: store i32 0, ptr %[[EXCEPTION_ADDR]], align 16
diff --git a/clang/test/CIR/CodeGen/vla.c b/clang/test/CIR/CodeGen/vla.c
index 2eb8d3c3814af..f30a438834660 100644
--- a/clang/test/CIR/CodeGen/vla.c
+++ b/clang/test/CIR/CodeGen/vla.c
@@ -62,7 +62,7 @@ void f1(int len) {
// CIR: %[[LEN_SIZE_T:.*]] = cir.cast integral %[[LEN]] : !s32i -> !u64i
// CIR: %[[STACK_PTR:.*]] = cir.stacksave
// CIR: cir.store{{.*}} %[[STACK_PTR]], %[[SAVED_STACK]]
-// CIR: %[[TOTAL_LEN:.*]] = cir.mul nuw %[[SIXTEEN]], %[[LEN_SIZE_T]]
+// CIR: %[[TOTAL_LEN:.*]] = cir.mul nuw %[[LEN_SIZE_T]], %[[SIXTEEN]]
// CIR: %[[ARR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, %[[TOTAL_LEN]] : !u64i, ["arr"]
// CIR: %[[STACK_RESTORE_PTR:.*]] = cir.load{{.*}} %[[SAVED_STACK]]
// CIR: cir.stackrestore %[[STACK_RESTORE_PTR]]
@@ -75,7 +75,7 @@ void f1(int len) {
// LLVM: %[[LEN_SIZE_T:.*]] = sext i32 %[[LEN]] to i64
// LLVM: %[[STACK_PTR:.*]] = call ptr @llvm.stacksave.p0()
// LLVM: store ptr %[[STACK_PTR]], ptr %[[SAVED_STACK]]
-// LLVM: %[[TOTAL_LEN:.*]] = mul nuw i64 16, %[[LEN_SIZE_T]]
+// LLVM: %[[TOTAL_LEN:.*]] = mul nuw i64 %[[LEN_SIZE_T]], 16
// LLVM: %[[ARR:.*]] = alloca i32, i64 %[[TOTAL_LEN]]
// LLVM: %[[STACK_RESTORE_PTR:.*]] = load ptr, ptr %[[SAVED_STACK]]
// LLVM: call void @llvm.stackrestore.p0(ptr %[[STACK_RESTORE_PTR]])
@@ -361,7 +361,7 @@ void vla_subscript_expr() {
// CIR: %[[COMPOUND_PTR:.*]] = cir.ptr_stride %[[TMP_COMPOUND]], %[[CONST_0]] : (!cir.ptr<!cir.ptr<!s32i>>, !s32i) -> !cir.ptr<!cir.ptr<!s32i>>
// CIR: %[[TMP_COMPOUND:.*]] = cir.load {{.*}} %10 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !u64i
-// CIR: %[[VLA_IDX:.*]] = cir.mul nsw %[[CONST_1]], %7 : !u64i
+// CIR: %[[VLA_IDX:.*]] = cir.mul nsw %[[TMP_N]], %[[CONST_1]] : !u64i
// CIR: %[[VLA_A_PTR:.*]] = cir.ptr_stride %[[TMP_COMPOUND]], %[[VLA_IDX]] : (!cir.ptr<!s32i>, !u64i) -> !cir.ptr<!s32i>
// CIR: %[[ELEM_5_PTR:.*]] = cir.ptr_stride %[[VLA_A_PTR]], %[[CONST_5]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
// CIR: cir.store {{.*}} %[[CONST_0_VAL]], %[[ELEM_5_PTR]] : !s32i, !cir.ptr<!s32i>
@@ -375,7 +375,7 @@ void vla_subscript_expr() {
// LLVM: %[[TMP_COMPOUND:.*]] = load ptr, ptr %[[COMPOUND_ADDR]], align 8
// LLVM: %[[COMPOUND_PTR:.*]] = getelementptr ptr, ptr %[[TMP_COMPOUND]], i64 0
// LLVM: %[[TMP_COMPOUND:.*]] = load ptr, ptr %[[COMPOUND_PTR]], align 8
-// LLVM: %[[VLA_IDX:.*]] = mul nsw i64 1, %[[TMP_N]]
+// LLVM: %[[VLA_IDX:.*]] = mul nsw i64 %[[TMP_N]], 1
// LLVM: %[[VLA_A_PTR:.*]] = getelementptr i32, ptr %[[TMP_COMPOUND]], i64 %[[VLA_IDX]]
// LLVM: %[[ELEM_5_PTR:.*]] = getelementptr i32, ptr %[[VLA_A_PTR]], i64 5
// LLVM: store i32 0, ptr %[[ELEM_5_PTR]], align 4
diff --git a/clang/test/CIR/Transforms/binop-traits.cir b/clang/test/CIR/Transforms/binop-traits.cir
new file mode 100644
index 0000000000000..df2b12cf9f178
--- /dev/null
+++ b/clang/test/CIR/Transforms/binop-traits.cir
@@ -0,0 +1,65 @@
+// RUN: cir-opt %s -cir-canonicalize -o - | FileCheck %s
+
+!s32i = !cir.int<s, 32>
+
+// CHECK-LABEL: @and_idempotent
+// CHECK-NEXT: cir.return %arg0
+cir.func @and_idempotent(%arg0 : !s32i) -> !s32i {
+ %0 = cir.and %arg0, %arg0 : !s32i
+ cir.return %0 : !s32i
+}
+
+// CHECK-LABEL: @or_idempotent
+// CHECK-NEXT: cir.return %arg0
+cir.func @or_idempotent(%arg0 : !s32i) -> !s32i {
+ %0 = cir.or %arg0, %arg0 : !s32i
+ cir.return %0 : !s32i
+}
+
+// CHECK-LABEL: @and_commutative
+// CHECK: cir.and %arg0, %{{.*}} : !s32i
+cir.func @and_commutative(%arg0 : !s32i) -> !s32i {
+ %0 = cir.const #cir.int<42> : !s32i
+ %1 = cir.and %0, %arg0 : !s32i
+ cir.return %1 : !s32i
+}
+
+// CHECK-LABEL: @or_commutative
+// CHECK: cir.or %arg0, %{{.*}} : !s32i
+cir.func @or_commutative(%arg0 : !s32i) -> !s32i {
+ %0 = cir.const #cir.int<42> : !s32i
+ %1 = cir.or %0, %arg0 : !s32i
+ cir.return %1 : !s32i
+}
+
+// CHECK-LABEL: @xor_commutative
+// CHECK: cir.xor %arg0, %{{.*}} : !s32i
+cir.func @xor_commutative(%arg0 : !s32i) -> !s32i {
+ %0 = cir.const #cir.int<42> : !s32i
+ %1 = cir.xor %0, %arg0 : !s32i
+ cir.return %1 : !s32i
+}
+
+// CHECK-LABEL: @add_commutative
+// CHECK: cir.add %arg0, %{{.*}} : !s32i
+cir.func @add_commutative(%arg0 : !s32i) -> !s32i {
+ %0 = cir.const #cir.int<42> : !s32i
+ %1 = cir.add %0, %arg0 : !s32i
+ cir.return %1 : !s32i
+}
+
+// CHECK-LABEL: @mul_commutative
+// CHECK: cir.mul %arg0, %{{.*}} : !s32i
+cir.func @mul_commutative(%arg0 : !s32i) -> !s32i {
+ %0 = cir.const #cir.int<42> : !s32i
+ %1 = cir.mul %0, %arg0 : !s32i
+ cir.return %1 : !s32i
+}
+
+// CHECK-LABEL: @max_commutative
+// CHECK: cir.max %arg0, %{{.*}} : !s32i
+cir.func @max_commutative(%arg0 : !s32i) -> !s32i {
+ %0 = cir.const #cir.int<42> : !s32i
+ %1 = cir.max %0, %arg0 : !s32i
+ cir.return %1 : !s32i
+}
More information about the cfe-commits
mailing list