@@ -340,7 +340,7 @@ std::string Mapper::mapTypeToC(mlir::Type t) const {
340340
341341 // Check for CIR bool type
342342 if (typeStr.find (" !cir.bool" ) != std::string::npos) {
343- return " int " ; // C89 compatible, or "bool" for C99+
343+ return " _Bool " ; // Emit C99 _Bool for true boolean values
344344 }
345345
346346 // Check for CIR integer types with size and signedness
@@ -425,7 +425,7 @@ std::string Mapper::mapTypeToC(mlir::Type t) const {
425425 } else if (elementTypeStr.find (" !cir.double" ) != std::string::npos) {
426426 ctype = " double" ;
427427 } else if (elementTypeStr.find (" !cir.bool" ) != std::string::npos) {
428- ctype = " int " ;
428+ ctype = " _Bool " ;
429429 }
430430 return ctype + " [" + sizeStr + " ]" ;
431431 }
@@ -629,6 +629,27 @@ bool Mapper::mapModule(ModuleOp module, std::ostream &out) {
629629 // collisions when demangling.
630630 prepareFunctionNames (module );
631631
632+ // Discover union record names from the textual IR so aliases (!rec_*)
633+ // that denote unions can be recognized without heuristics.
634+ std::set<std::string> unionRecordNames;
635+ {
636+ std::string irText;
637+ llvm::raw_string_ostream rso (irText);
638+ module .print (rso);
639+ rso.flush ();
640+ const std::string needle = " !cir.record<union \" " ;
641+ std::size_t pos = 0 ;
642+ while ((pos = irText.find (needle, pos)) != std::string::npos) {
643+ pos += needle.size ();
644+ auto end = irText.find (" \" " , pos);
645+ if (end == std::string::npos) break ;
646+ std::string name = irText.substr (pos, end - pos);
647+ std::replace (name.begin (), name.end (), ' .' , ' _' );
648+ unionRecordNames.insert (name);
649+ pos = end + 1 ;
650+ }
651+ }
652+
632653 // Auto-parse struct definitions by scanning member accesses.
633654 struct FieldInfo {
634655 std::string name; // field name
@@ -801,10 +822,7 @@ bool Mapper::mapModule(ModuleOp module, std::ostream &out) {
801822 }
802823 info.name = fname;
803824
804- // Heuristic: if we see a field named 'value' on a record, it's likely a union
805- if (fname == " value" ) {
806- isUnionContainer[structName] = true ;
807- }
825+ // Note: union detection is driven by IR-declared unions, not field names.
808826
809827 // Avoid duplicate entries for the same field name
810828 auto &vec = structFields[structName];
@@ -817,6 +835,14 @@ bool Mapper::mapModule(ModuleOp module, std::ostream &out) {
817835 // Kick off collection for top-level operations
818836 for (auto &op : module .getOps ()) collectFromOp (op);
819837
838+ // Mark union containers based on discovered union record names.
839+ for (auto &kv : structFields) {
840+ const auto &recName = kv.first ;
841+ if (unionRecordNames.count (recName)) {
842+ isUnionContainer[recName] = true ;
843+ }
844+ }
845+
820846 // Order structs to satisfy dependencies: if a struct references another
821847 // struct in its fields, emit the dependency first. Simple fixed-point topo.
822848 auto getDeps = [&](const std::string &sname){
0 commit comments