[clang] [CIR] Implement simple folding for unary operations (PR #174882)

Andy Kaylor via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 8 11:19:18 PST 2026


================
@@ -2479,6 +2479,39 @@ OpFoldResult cir::UnaryOp::fold(FoldAdaptor adaptor) {
       if (isBoolNot(previous))
         return previous.getInput();
 
+  // Fold constant unary operations.
+  if (auto srcConst = getInput().getDefiningOp<cir::ConstantOp>()) {
----------------
andykaylor wrote:

I implemented this change, and it looks much better for this PR, but I found that it leaves behind more dead constants when I use `createOrFold` during codegen. For instance, this:

```
short s = +(-3);
```

results in this before I explicitly delete the dead constants during canonicalization:
```
%19 = cir.const #cir.int<3> : !s32i
%20 = cir.const #cir.int<-3> : !s32i
%21 = cir.const #cir.int<-3> : !s32i
%22 = cir.const #cir.int<-3> : !s16i
cir.store align(2) %22, %1 : !s16i, !cir.ptr<!s16i>
```
This is because (1) we emit a constant 3 as the operand to the unary minus, (2) we fold the unary minus into a constant -3, (3) we fold the unary plus into another constant -3, and (4) we fold the implicit cast into the last constant -3. It all makes sense, but it was a bit shocking to see in the output.

My previous implementation did some of that, but it didn't introduce the duplicate constants in the cases where the folder is just returning the input value. If we return the actual input value, `createOrFold` will just use it, but if we return the attribute from the adaptor, it materializes a new constant. When the folder runs during the canonicalize pass, this isn't a problem because the folder doesn't materialize things in the middle of the process, but during codegen we materialize at each step.

I'm going to go with a hybrid approach where I look for the cases where we fold to the input value explicitly, and otherwise fold via the adaptor.

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


More information about the cfe-commits mailing list