Build CallExpr to built-in functions during CodeGen

Hi everyone, I’m currently working on the frontend implementation of transactional memory support in C++ (N4923). Part of our implementation involves a new AST node and implicit calls to 2 new built-in functions. Here is how they work right now:

A transaction according to the spec is enclosed by an atomic do { ... } block, which is basically a compound statement prefixed with the atomic do keyword along with some special handling. During program execution, when a transaction is entered, a new libc++ built-in transaction_start() is called before anything in scope is evaluated, and when the program exits the transaction scope, the built-in transaction_end() is called as the last cleanup step. These 2 functions form the transaction’s boundary.

Currently in order to emit these 2 function calls, we first build a call expression to each of them in Sema and store them into AtomicStmt (a new Stmt class representing the atomic do block). They’re not accessible as child statements so they don’t show up as nodes when the AST is traversed. Then in CodeGen, we emit transaction_start() and add the emission of transaction_end() onto EHStack before emitting the transaction body.

Doing it this way achieves 2 of our goals:

  1. The function calls don’t show up in AST traversal, so the AST retains source fidelity.

  2. Objects created in a transaction have their destruction bounded within the transaction too, so we avoid a race condition.

However, storing built-in function CallExprs feels like a hack. It also wastes memory if there are multiple AtomicStmt instances each storing an identical pair of the CallExprs. I would like to avoid doing this, but so far I haven’t found a good way around it without carrying lots of information (such as AST context, pre-processor, and translation unit kind) for each transaction out of Parse and Sema into CodeGen.

I would really appreciate it if anyone has suggestions for how we might be able to build CallExprs to built-in functions on demand in CodeGen, or a pointer to some relevant documentation or similar things done in the past.

Typically this would be done at codegen time using CodeGenFunction/CodeGenModule CGF.EmitRuntimeCall(CGM.CreateRuntimeCall(..., not creating a CallExpr at all.

Stupid question: are transaction_start() and transaction_stop() in libc++ or in compiler-rt?

Right now they’re in libc++. For the time being, we have to assume that the user might replace them via LD_PRELOAD, and afaik this isn’t possible if they’re in compiler-rt.

Thanks for this info! I’ll give it a shot.