Skip to content

[codegen] multi-driver / multi-decl: suspected symbol hygiene violation in generated verilog #2209

Closed
@cdleary

Description

@cdleary

Describe the bug
If you switch the multiprocess fuzzer to use p as the gensym prefix instead of x you observe a lot of problems quickly.

With this .x:

fn main(p0: u29, p1: u33, p2: u44, p3: u32, p4: u41, p5: u33, p6: u43) -> (u29, u45, u45, u29, u15, u32, u45, u33) {                                                                       
    { 
        let p7: u15 = u15:0x2000;                                                                                                                                                                                 
        let p8: u44 = !p2;
        let p9: u33 = -p5;
        let p10: u29 = ctz(p0);
        let p11: u44 = -p8;
        let p12: u29 = bit_slice_update(p0, p8, p7);                                                                                                                                                              
        let p13: u29 = signex(p1, p10);
        let p14: u45 = u45:0x682_1b1c_101d;
        let p15: u32 = p3[:];
        let p16: u45 = p14[0+:u45];                                                                                                                                                                               
        (p10, p14, p14, p12, p7, p15, p16, p9)                                                                                                                                                                    
    }
} 

We get the following opt IR:

package sample
    
file_number 0 "/tmp/temp_directory_8R9TAz/sample.x"                                                                                                                                                               
        
top fn __sample__main(p0: bits[29] id=1, p1: bits[33] id=2, p2: bits[44] id=3, p3: bits[32] id=4, p4: bits[41] id=5, p5: bits[33] id=6, p6: bits[43] id=7) -> (bits[29], bits[45], bits[45], bits[29], bits[15], bits[32], bits[45], bits[33]) {
  one_hot.11: bits[30] = one_hot(p0, lsb_prio=true, id=11, pos=[(0,5,26)])
  literal.29: bits[24] = literal(value=0, id=29, pos=[(0,5,26)])
  encode.12: bits[5] = encode(one_hot.11, id=12)
  p8: bits[44] = not(p2, id=9, pos=[(0,3,22)])
  p7: bits[15] = literal(value=8192, id=8, pos=[(0,2,22)])
  p10: bits[29] = concat(literal.29, encode.12, id=30, pos=[(0,5,26)])
  p12: bits[29] = bit_slice_update(p0, p8, p7, id=15, pos=[(0,7,39)])                                                                                                                                             
  p14: bits[45] = literal(value=7155870339101, id=17, pos=[(0,9,23)])                                                                                                                                             
  p9: bits[33] = neg(p5, id=10, pos=[(0,4,22)])
  ret tuple.21: (bits[29], bits[45], bits[45], bits[29], bits[15], bits[32], bits[45], bits[33]) = tuple(p10, p14, p14, p12, p7, p3, p14, p9, id=21, pos=[(0,12,8)])
}

and then we get the following in the .v:

  // ===== Pipe stage 5:
  wire [44:0] p5_p14_comb;                                                                                                                                                                                        
  wire [44:0] p5__1_comb;                                                                                                                                                                                         
  wire [14:0] p5__1_comb;                                                                                                                                                                                         
  wire [44:0] p5__2_comb;
  wire [272:0] p5_tuple_101_comb;

You can see there's a conflicting declaration for the width of p5__1_comb, pretty sure this is due to some mix of non-hygeinic gensym and perhaps some attempt to preserve names across optimizations -- first step is likely to add a verifier/validator that we don't get any collisions in module wire namespace to crash on these instead of passing to downstream tools that are happy to do "something".

To Reproduce

diff --git a/xls/fuzzer/ast_generator.cc b/xls/fuzzer/ast_generator.cc
index cc784ee4b..203a9e3b7 100644
--- a/xls/fuzzer/ast_generator.cc
+++ b/xls/fuzzer/ast_generator.cc
@@ -196,7 +196,7 @@ AstGenerator::Unzip(absl::Span<const TypedExpr> typed_exprs) {
 }
 
 std::string AstGenerator::GenSym() {
-  std::string result = absl::StrCat("x", next_name_index_++);
+  std::string result = absl::StrCat("p", next_name_index_++);
   VLOG(10) << "generated fresh symbol: " << result << " @ "
            << GetSymbolizedStackTraceAsString();
   return result;

at git ref d8b1db0
PiperOrigin-RevId: 759807560

bazel run -c opt //xls/fuzzer:run_fuzz_multiprocess -- --crash_path=/tmp/crashers-$(date +'%Y-%m-%d') --seed=0 --duration=12h --codegen=true --simulate=true --use_system_verilog=false

Environment (this can be helpful for troubleshooting):

  • OS: Ubuntu 24.04

Metadata

Metadata

Assignees

Labels

bugSomething isn't working or is incorrectcodegenRelated to emitting (System)Verilog.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions