@@ -1940,6 +1940,16 @@ std::string TaskCodeGenLLVM::init_offloaded_task_function(OffloadedStmt *stmt, s
19401940 func = llvm::Function::Create (task_function_type, llvm::Function::ExternalLinkage, task_kernel_name, module .get ());
19411941
19421942 current_task = std::make_unique<OffloadedTask>(task_kernel_name);
1943+ // Pre-register the per-task AdStackSizingInfo so the registry id is assigned BEFORE codegen visits any
1944+ // `AdStackPushStmt`. Metadata (allocated_max_sizes) is filled in at `finalize_offloaded_task_function`
1945+ // time after the alloca scan completes; the registry call is idempotent on the same `ad_stack_ptr` so
1946+ // the second call updates the entry in place. Skipping registration when `prog == nullptr` (C++-only
1947+ // tests) leaves `registry_id == 0`, which the codegen-emitted cmpxchg short-circuits.
1948+ if (prog != nullptr ) {
1949+ uint32_t id = prog->register_adstack_sizing_info (static_cast <const void *>(¤t_task->ad_stack ), kernel_name,
1950+ task_codegen_id, /* allocated_max_sizes=*/ {});
1951+ current_task->ad_stack .registry_id = id;
1952+ }
19431953
19441954 for (auto &arg : func->args ()) {
19451955 kernel_args.push_back (&arg);
@@ -2010,6 +2020,20 @@ void TaskCodeGenLLVM::finalize_offloaded_task_function() {
20102020 current_task->arr_writes .erase (std::unique (current_task->arr_writes .begin (), current_task->arr_writes .end ()),
20112021 current_task->arr_writes .end ());
20122022 }
2023+ // Register the per-task AdStackSizingInfo with the Program-side identity registry. The id is baked
2024+ // into the lazy-claim overflow path's `cmpxchg(0, id)` so the host raise site can name the offending
2025+ // kernel + task in its diagnostic message. Empty alloca list = no adstack pushes in this task; skip
2026+ // registration to keep the registry compact.
2027+ if (!current_task->ad_stack .allocas .empty () && prog != nullptr ) {
2028+ std::vector<int > allocated_max_sizes;
2029+ allocated_max_sizes.reserve (current_task->ad_stack .allocas .size ());
2030+ for (const auto &a : current_task->ad_stack .allocas ) {
2031+ allocated_max_sizes.push_back (static_cast <int >(a.max_size_compile_time ));
2032+ }
2033+ uint32_t id = prog->register_adstack_sizing_info (static_cast <const void *>(¤t_task->ad_stack ), kernel_name,
2034+ task_codegen_id, std::move (allocated_max_sizes));
2035+ current_task->ad_stack .registry_id = id;
2036+ }
20132037 }
20142038
20152039 // entry_block should jump to the body after all allocas are inserted
@@ -2464,10 +2488,12 @@ void TaskCodeGenLLVM::emit_ad_stack_row_claim_llvm() {
24642488 llvm::Value *clamped_row = builder->CreateSelect (cmp, clamp_upper, claimed_row);
24652489 builder->CreateStore (clamped_row, row_id_var);
24662490
2467- // Overflow signal: on `claimed_row > clamp_upper`, atomically OR 1 into the pinned-host overflow flag. The
2468- // condition is hoisted to a structured if so the not-overflowing fast path skips the atomic entirely - one
2469- // function call to fetch the flag pointer plus one CreateICmpUGT comparison, the same compare we already
2470- // emitted for the clamp.
2491+ // Overflow signal: on `claimed_row > clamp_upper`, atomically OR 1 into the pinned-host overflow flag and
2492+ // record the offending task identity in the companion `adstack_overflow_task_id_dev_ptr` slot via a
2493+ // `cmpxchg(0, registry_id)`. Only the FIRST overflowing thread's id sticks; subsequent threads observe
2494+ // a non-zero value and their cmpxchg fails harmlessly. The condition is hoisted to a structured if so
2495+ // the not-overflowing fast path skips both atomics entirely - one function call to fetch the pointers
2496+ // plus one CreateICmpUGT comparison (the same compare we already emitted for the clamp).
24712497 auto *current_function = builder->GetInsertBlock ()->getParent ();
24722498 auto *overflow_then_block = llvm::BasicBlock::Create (*llvm_context, " adstack_overflow_signal" , current_function);
24732499 auto *overflow_merge_block = llvm::BasicBlock::Create (*llvm_context, " adstack_overflow_merge" , current_function);
@@ -2479,6 +2505,17 @@ void TaskCodeGenLLVM::emit_ad_stack_row_claim_llvm() {
24792505 llvm::Value *one_i64 = llvm::ConstantInt::get (i64ty_local, 1 );
24802506 builder->CreateAtomicRMW (llvm::AtomicRMWInst::Or, flag_ptr, one_i64, llvm::MaybeAlign (),
24812507 llvm::AtomicOrdering::Monotonic);
2508+ // Record the registry id (0 means "not registered"; skip the cmpxchg in that case so the slot stays
2509+ // zero and the host raise site falls through to the generic dual-cause message). Each offload task
2510+ // emits its own lazy-claim block, so the immediate is task-local at codegen time.
2511+ if (current_task != nullptr && current_task->ad_stack .registry_id != 0 ) {
2512+ llvm::Value *task_id_ptr = call (" LLVMRuntime_get_adstack_overflow_task_id_dev_ptr" , get_runtime ());
2513+ llvm::Value *expected_zero = llvm::ConstantInt::get (i64ty_local, 0 );
2514+ llvm::Value *new_id =
2515+ llvm::ConstantInt::get (i64ty_local, static_cast <uint64_t >(current_task->ad_stack .registry_id ));
2516+ builder->CreateAtomicCmpXchg (task_id_ptr, expected_zero, new_id, llvm::MaybeAlign (),
2517+ llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Monotonic);
2518+ }
24822519 builder->CreateBr (overflow_merge_block);
24832520 }
24842521 builder->SetInsertPoint (overflow_merge_block);
@@ -2742,7 +2779,11 @@ void TaskCodeGenLLVM::visit(AdStackPushStmt *stmt) {
27422779 llvm::Value *max_size_addr = builder->CreateGEP (i64ty, ad_stack_max_sizes_ptr_llvm_, stack_id_i64);
27432780 llvm::Value *max_size = builder->CreateLoad (i64ty, max_size_addr);
27442781 llvm::Value *stack_base = get_ad_stack_base_llvm (stack);
2745- call (" stack_push" , get_runtime (), stack_base, max_size, tlctx->get_constant (stack->element_size_in_bytes ()));
2782+ auto *i64ty_local = llvm::Type::getInt64Ty (*llvm_context);
2783+ llvm::Value *registry_id_const = llvm::ConstantInt::get (
2784+ i64ty_local, current_task != nullptr ? static_cast <uint64_t >(current_task->ad_stack .registry_id ) : 0u );
2785+ call (" stack_push" , get_runtime (), stack_base, max_size, tlctx->get_constant (stack->element_size_in_bytes ()),
2786+ registry_id_const);
27462787 auto primal_ptr = call (" stack_top_primal" , stack_base, tlctx->get_constant (stack->element_size_in_bytes ()));
27472788 primal_ptr = builder->CreateBitCast (primal_ptr, llvm::PointerType::get (tlctx->get_data_type (stmt->ret_type ), 0 ));
27482789 builder->CreateStore (llvm_val[stmt->v ], primal_ptr);
0 commit comments