MikePopoloski / slang

SystemVerilog compiler and language services
MIT License
550 stars 117 forks source link

[Struct]When translating stuct expression and the memberaccess kind, member symbol is the same while clang will give the different symbol. #995

Closed mingzheTerapines closed 2 weeks ago

mingzheTerapines commented 2 weeks ago

Dear developer, I have some trouble with mapping different Ops with different symbol in CIRCT Project because different variables have the same symbol. I'll appreciate it if you can solve this problem. -slang version 6.0.49+a3721010. test.v is like this

module Foo;
  int x, y;
  always_comb begin
    typedef struct packed signed {int a, b;} int64;
    int64 ii;
    int64 bb;
    ii.b = x;
    bb.b = x;
  end
endmodule 

test.json will be like this

{
  "design": {
    "name": "$root",
    "kind": "Root",
    "addr": 2199024846272,
    "members": [
      {
        "name": "",
        "kind": "CompilationUnit",
        "addr": 2199025172240
      },
      {
        "name": "Foo",
        "kind": "Instance",
        "addr": 2199025174824,
        "body": {
          "name": "Foo",
          "kind": "InstanceBody",
          "addr": 2199025172632,
          "members": [
            {
              "name": "x",
              "kind": "Variable",
              "addr": 2199025172832,
              "type": "int",
              "lifetime": "Static"
            },
            {
              "name": "y",
              "kind": "Variable",
              "addr": 2199025173208,
              "type": "int",
              "lifetime": "Static"
            },
            {
              "name": "",
              "kind": "StatementBlock",
              "addr": 2199025173712,
              "members": [
                {
                  "name": "int64",
                  "kind": "TypeAlias",
                  "addr": 2199025173880,
                  "target": "struct packed signed{int a;int b;}Foo.s$1"
                },
                {
                  "name": "ii",
                  "kind": "Variable",
                  "addr": 2199025174064,
                  "type": "struct packed signed{int a;int b;}Foo.int64",
                  "lifetime": "Static"
                },
                {
                  "name": "bb",
                  "kind": "Variable",
                  "addr": 2199025174440,
                  "type": "struct packed signed{int a;int b;}Foo.int64",
                  "lifetime": "Static"
                }
              ]
            },
            {
              "name": "",
              "kind": "ProceduralBlock",
              "addr": 2199025173584,
              "procedureKind": "AlwaysComb",
              "body": {
                "kind": "Block",
                "blockKind": "Sequential",
                "block": "2199025173712 ",
                "body": {
                  "kind": "List",
                  "list": [
                    {
                      "kind": "VariableDeclaration",
                      "symbol": "2199025174064 ii"
                    },
                    {
                      "kind": "VariableDeclaration",
                      "symbol": "2199025174440 bb"
                    },
                    {
                      "kind": "ExpressionStatement",
                      "expr": {
                        "kind": "Assignment",
                        "type": "int",
                        "left": {
                          "kind": "MemberAccess",
                          "type": "int",
                          "member": "2199025176592 b",
                          "value": {
                            "kind": "NamedValue",
                            "type": "struct packed signed{int a;int b;}Foo.int64",
                            "symbol": "2199025174064 ii"
                          }
                        },
                        "right": {
                          "kind": "NamedValue",
                          "type": "int",
                          "symbol": "2199025172832 x"
                        },
                        "isNonBlocking": false
                      }
                    },
                    {
                      "kind": "ExpressionStatement",
                      "expr": {
                        "kind": "Assignment",
                        "type": "int",
                        "left": {
                          "kind": "MemberAccess",
                          "type": "int",
                          "member": "2199025176592 b",
                          "value": {
                            "kind": "NamedValue",
                            "type": "struct packed signed{int a;int b;}Foo.int64",
                            "symbol": "2199025174440 bb"
                          }
                        },
                        "right": {
                          "kind": "NamedValue",
                          "type": "int",
                          "symbol": "2199025172832 x"
                        },
                        "isNonBlocking": false
                      }
                    }
                  ]
                }
              }
            }
          ],
          "definition": "2199025221632 Foo"
        },
        "connections": [
        ]
      }
    ]
  },
  "definitions": [
    {
      "name": "Foo",
      "kind": "Definition",
      "addr": 2199025221632,
      "defaultNetType": "2199024843776 wire",
      "definitionKind": "Module",
      "defaultLifetime": "Static",
      "unconnectedDrive": "None"
    }
  ]
}
                       "kind": "MemberAccess",
                          "type": "int",
                          "member": "2199025176592 b",

As you can see, the symbol of different struct value's symbol which should be different but found the same. Here is an example what clang-18 do. test.c

typedef struct {
    int a;
    int b;
} Int64;
Int64 ii;
Int64 bb;
int y = ii.a;
int x = bb.a;

clang-18 -Xclang -ast-dump test.c

TranslationUnitDecl 0x569514a47538 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x569514a47d68 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x569514a47b00 '__int128'
|-TypedefDecl 0x569514a47dd8 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x569514a47b20 'unsigned __int128'
|-TypedefDecl 0x569514a480e0 <<invalid sloc>> <invalid sloc> implicit __NSConstantString 'struct __NSConstantString_tag'
| `-RecordType 0x569514a47eb0 'struct __NSConstantString_tag'
|   `-Record 0x569514a47e30 '__NSConstantString_tag'
|-TypedefDecl 0x569514a48188 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x569514a48140 'char *'
|   `-BuiltinType 0x569514a475e0 'char'
|-TypedefDecl 0x569514a48480 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'struct __va_list_tag[1]'
| `-ConstantArrayType 0x569514a48420 'struct __va_list_tag[1]' 1 
|   `-RecordType 0x569514a48260 'struct __va_list_tag'
|     `-Record 0x569514a481e0 '__va_list_tag'
|-RecordDecl 0x569514aa7990 <test.c:1:9, line:4:1> line:1:9 struct definition
| |-FieldDecl 0x569514aa7a48 <line:2:5, col:9> col:9 referenced a 'int'
| `-FieldDecl 0x569514aa7ab0 <line:3:5, col:9> col:9 b 'int'
|-TypedefDecl 0x569514aa7b58 <line:1:1, line:4:3> col:3 referenced Int64 'struct Int64':'Int64'
| `-ElaboratedType 0x569514aa7b00 'struct Int64' sugar
|   `-RecordType 0x569514aa7a10 'Int64'
|     `-Record 0x569514aa7990 ''
|-VarDecl 0x569514aa7c40 <line:5:1, col:7> col:7 used ii 'Int64'
|-VarDecl 0x569514aa7d00 <line:6:1, col:7> col:7 used bb 'Int64'
|-VarDecl 0x569514aa7d80 <line:7:1, col:12> col:5 y 'int' cinit
| `-ImplicitCastExpr 0x569514aa7e38 <col:9, col:12> 'int' <LValueToRValue>
|   `-MemberExpr 0x569514aa7e08 <col:9, col:12> 'int' lvalue .a 0x569514aa7a48
|     `-DeclRefExpr 0x569514aa7de8 <col:9> 'Int64' lvalue Var 0x569514aa7c40 'ii' 'Int64'
`-VarDecl 0x569514aa7ec8 <line:8:1, col:12> col:5 x 'int' cinit
  `-ImplicitCastExpr 0x569514aa7f80 <col:9, col:12> 'int' <LValueToRValue>
    `-MemberExpr 0x569514aa7f50 <col:9, col:12> 'int' lvalue .a 0x569514aa7a48
      `-DeclRefExpr 0x569514aa7f30 <col:9> 'Int64' lvalue Var 0x569514aa7d00 'bb' 'Int64'
`-MemberExpr 0x569514aa7e08 <col:9, col:12> 'int' lvalue .a 0x569514aa7a48
  `-MemberExpr 0x569514aa7f50 <col:9, col:12> 'int' lvalue .a 0x569514aa7a48
cepheus69 commented 2 weeks ago

This is a good example of the obstacle of supporting Struct type in circt-verilog via slang frontend!

mingzheTerapines commented 2 weeks ago

BTW, the book of SV, has extra definition of structure. It says packed structure consists of bit fields, which are packed together in memory without gaps. Reffering IEEE Standard for SystemVerilog—Unified Hardware Design,Specification, and VerificationLanguage7.2.1 Packed structures

A packed structure is a mechanism for subdividing a vector into subfields, which can be conveniently accessed as members. Consequently, a packed structure consists of bit fields, which are packed together in memory without gaps. An unpacked structure has an implementation-dependent packing, normally matching the C compiler. A packed structure differs from an unpacked structure in that, when a packed structure appears as a primary, it shall be treated as a single vector.

"type": "struct packed signed{int a;int b;}Foo.int64", may be not proper. Variables a and b need to be delcared here before using them.

MikePopoloski commented 2 weeks ago

I'm not sure what the problem here is. Both variables have the same type and access the same member so of course the symbol has the same address. It appears from your example that clang-18 also does the same thing.

I also don't understand your followup message. I'm aware of what the LRM says. Do you have a question related to how packed structs work?

mingzheTerapines commented 2 weeks ago

"member": "2199025176592 b",

Thanks for your reply, what I mean is 2199025176592 in "member": "2199025176592 b", not the "b", which may means the addreess of member. In clang -MemberExpr 0x569514aa7e08 <col:9, col:12> 'int' lvalue .a 0x569514aa7a48 -MemberExpr 0x569514aa7f50 <col:9, col:12> 'int' lvalue .a 0x569514aa7a48 0x569514aa7e08 and 0x569514aa7f50 are different which can help me differ two different struct variable's same name member.

MikePopoloski commented 2 weeks ago

I believe you are highlighting the address of the expression itself. The address at the end of the line is the address of the member being accessed, which is the same in both cases just like it is in slang. The slang json doesn't print addresses for the expression objects because they aren't useful in cross referencing anything.

If you want to know which variable is being accessed you need to look deeper in the expression tree. In clang this is:

`-DeclRefExpr 0x569514aa7de8 <col:9> 'Int64' lvalue Var 0x569514aa7c40 'ii' 'Int64'

and in slang:

"value": {
                            "kind": "NamedValue",
                            "type": "struct packed signed{int a;int b;}Foo.int64",
                            "symbol": "2199025174064 ii"
                          }
mingzheTerapines commented 2 weeks ago

Thanks a lot, I will look deeper to differ.