diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index 108baab73..1803489b9 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -407,6 +407,10 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { // Pass 3: clobbers // Only the Scratch group. Unpinned register scratch was already emitted as an // output in Pass 1, so it is skipped here. + StringSet emitted_reg_clobbers = {}; + string_set_init(&emitted_reg_clobbers); + defer (string_set_destroy(&emitted_reg_clobbers)); + for (isize i = 0; i < ops->count; i++) { AsmTemplateEntityDecl const &e = (*ops)[i]; @@ -425,6 +429,7 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { case AsmTemplateEntityDecl_Register: // pinned -> real clobber GB_ASSERT(e.pin.len != 0); raw("~{"); put(e.pin); raw("}"); + string_set_update(&emitted_reg_clobbers, e.pin); break; case AsmTemplateEntityDecl_Memory: // general memory clobber raw("~{memory}"); @@ -435,6 +440,17 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } } + // Explicit register clobbers from #clobber , deduped against the pinned + // scratch clobbers already emitted above. + for (String const ® : tmpl_entity->AsmTemplate.clobber_registers_set) { + if (string_set_exists(&emitted_reg_clobbers, reg)) { + continue; // already clobbered as a pinned scratch; don't double-emit + } + sep(); + raw("~{"); put(reg); raw("}"); + string_set_update(&emitted_reg_clobbers, reg); + } + // Template-level clobbers derived from #clobber cc / #clobber memory. if (tmpl_entity->AsmTemplate.clobber_cc) { sep(); @@ -444,7 +460,7 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { raw("~{cc}"); // AArch64 uses ~{cc} } } - if (tmpl_entity->AsmTemplate.clobber_memory && memory_clobbered_already) { + if (tmpl_entity->AsmTemplate.clobber_memory && !memory_clobbered_already) { sep(); raw("~{memory}"); }