2222#include < clang/Basic/LangOptions.h>
2323#include < clang/Basic/SourceLocation.h>
2424#include < clang/Basic/Specifiers.h>
25+ #include < clang/Sema/Lookup.h>
2526#include < clang/Sema/Sema.h>
2627#include < llvm/ADT/APInt.h>
2728#include < llvm/Support/Casting.h>
@@ -89,6 +90,42 @@ namespace patchestry::ast {
8990 }
9091 }
9192
93+ /* *
94+ * Helper function to create a builtin call expression.
95+ */
96+ clang::Expr *create_builtin_call (
97+ const clang::ASTContext &ctx, clang::Sema &sema,
98+ const clang::Builtin::ID builtin_id, std::vector< clang::Expr * > &args,
99+ const clang::SourceLocation loc
100+ ) {
101+ // Get the builtin name and create a lookup result
102+ const auto name = ctx.BuiltinInfo .getName (builtin_id);
103+ const clang::LookupResult r (
104+ sema, &ctx.Idents .get (name), loc, clang::Sema::LookupOrdinaryName
105+ );
106+ auto *II = r.getLookupName ().getAsIdentifierInfo ();
107+
108+ // Get the builtin type
109+ clang::ASTContext::GetBuiltinTypeError error{};
110+ const auto ty = ctx.GetBuiltinType (builtin_id, error);
111+ assert (!error && " Failed to get builtin type" );
112+
113+ // Create the builtin declaration
114+ auto *builtin_decl = sema.CreateBuiltin (II , ty, builtin_id, loc);
115+
116+ // Create a DeclRefExpr for the builtin
117+ auto *decl_ref = clang::DeclRefExpr::Create (
118+ ctx, clang::NestedNameSpecifierLoc (), clang::SourceLocation (), builtin_decl,
119+ false , loc, builtin_decl->getType (), clang::VK_PRValue
120+ );
121+
122+ // Build the call expression
123+ auto result = sema.BuildCallExpr (nullptr , decl_ref, loc, args, loc);
124+ assert (!result.isInvalid () && " Failed to build builtin call expr" );
125+
126+ return result.getAs < clang::Expr >();
127+ }
128+
92129 } // namespace
93130
94131 /* *
@@ -1215,6 +1252,34 @@ namespace patchestry::ast {
12151252 return create_builtin_call_expr (ctx, function, op, clang::Builtin::BIroundf);
12161253 }
12171254
1255+ std::pair< clang::Stmt *, bool > OpBuilder::create_popcount (
1256+ clang::ASTContext &ctx, const Function &function, const Operation &op
1257+ ) {
1258+ if (op.inputs .size () != 1U || op.mnemonic != Mnemonic::OP_POPCOUNT ) {
1259+ LOG (ERROR ) << " POPCOUNT operation is invalid or has invalid input operand. key: "
1260+ << op.key << " \n " ;
1261+ return {};
1262+ }
1263+
1264+ // Use __builtin_popcount for population count
1265+ return create_builtin_call_expr (
1266+ ctx, function, op, clang::Builtin::BI__builtin_popcount
1267+ );
1268+ }
1269+
1270+ std::pair< clang::Stmt *, bool > OpBuilder::create_lzcount (
1271+ clang::ASTContext &ctx, const Function &function, const Operation &op
1272+ ) {
1273+ if (op.inputs .size () != 1U || op.mnemonic != Mnemonic::OP_LZCOUNT ) {
1274+ LOG (ERROR ) << " LZCOUNT operation is invalid or has invalid input operand. key: "
1275+ << op.key << " \n " ;
1276+ return {};
1277+ }
1278+
1279+ // Use __builtin_clz for count leading zeros
1280+ return create_builtin_call_expr (ctx, function, op, clang::Builtin::BI__builtin_clz);
1281+ }
1282+
12181283 std::pair< clang::Stmt *, bool > OpBuilder::create_builtin_call_expr (
12191284 clang::ASTContext &ctx, const Function &function, const Operation &op,
12201285 clang::Builtin::ID id
@@ -1224,7 +1289,9 @@ namespace patchestry::ast {
12241289 auto *input_expr =
12251290 clang::dyn_cast< clang::Expr >(create_varnode (ctx, function, op.inputs [0 ]));
12261291
1227- auto *call_expr = sema ().BuildBuiltinCallExpr (op_loc, id, { input_expr });
1292+ std::vector args = { input_expr };
1293+ auto *call_expr = create_builtin_call (ctx, sema (), id, args, op_loc);
1294+
12281295 if (op.output .has_value ()) {
12291296 return { call_expr, true };
12301297 }
0 commit comments