[clang] [CIR] Lowering __builtin_stdc_* calls (PR #214931)

Bruno Cardoso Lopes via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 10 12:46:22 PDT 2026


================
@@ -111,6 +111,26 @@ static RValue emitBuiltinBitOpWithFallback(CIRGenFunction &cgf,
   return RValue::get(builder.createSelect(loc, isZero, fallbackValue, result));
 }
 
+static RValue emitStdcBitWidth(CIRGenFunction &cfg, const CallExpr *e) {
+  CIRGenBuilderTy &builder = cfg.getBuilder();
+  mlir::Location loc = cfg.getLoc(e->getSourceRange());
+
+  mlir::Value arg = cfg.emitScalarExpr(e->getArg(0));
+  auto argTy = mlir::cast<cir::IntType>(arg.getType());
+
+  mlir::Value lz =
+      createBuiltinBitOp<cir::BitClzOp>(cfg, e, arg, /*poisonZero=*/false);
----------------
bcardosolopes wrote:

I believe this will hit verifier failure for every type except `unsigned int`.

`createBuiltinBitOp` already casts its result to `convertType(e->getType())`, and that type is always `unsigned int` here (SemaChecking.cpp:4142 for the generic form, the stdbit.h prototypes for the typed ones). So `lz` comes back `!u32i` while `width` on the next line is built in `argTy`, and `cir.sub` is `SameOperandsAndResultType`. `stdc_bit_width_uc` gives you `cir.sub` of `!u32i` and `!u8i`, `ul`/`ull` give `!u32i` and `!u64i`. `unsigned int` is the only one that lines up and it is the only one in the test.

OG does the subtract in the argument type and casts once at the end (`emitStdcBitWidthMinus`, CGBuiltin.cpp:2565). Do the same: create the `cir::BitClzOp` directly instead of going through `createBuiltinBitOp`, subtract in `argTy`, and the cast you already have at the bottom finishes it. Keeps the IR matching OGCG too.

`cfg` -> `cgf` while you are in here.

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


More information about the cfe-commits mailing list