How to understand the let statement in tablegen?

I have tried the code with llvm-tblgen like this:

class C <int x> {
  int Y = x;
  int Yplus1 = !add(Y, 1);
  int xplus1 = !add(x, 1);
}

let Y = 10 in {
  def rec1 : C<5> {
  }
}

def rec2 : C<5> {
  let Y = 10;
}

def rec3 : C<5> {
  int z = 8;
  let Y = z;
}

the result is:

------------- Classes -----------------
class C<int C:x = ?> {
  int Y = C:x;
  int Yplus1 = !add(Y, 1);
  int xplus1 = !add(C:x, 1);
}
------------- Defs -----------------
def rec1 {      // C
  int Y = 10;
  int Yplus1 = 11;
  int xplus1 = 6;
}
def rec2 {      // C
  int Y = 10;
  int Yplus1 = 11;
  int xplus1 = 6;
}
def rec3 {      // C
  int Y = 8;
  int Yplus1 = 9;
  int xplus1 = 6;
  int z = 8;
}

why the Yplus1 in rec2 is 11, in rec3 is 9,
according to explaination, " top-level let bindings to the record applied before fields to resolve"
so what is top-level let bindings, the let statement in rec3 is also a top-level binding?

Top level refers to the outermost “level” of the source code. It’s what C would call global scope, you’re not within any other scope or class or definition or whatever.

So in your example let Y = 10 in { is a top level let because it starts a new line with the let statement and isn’t inside any other construct. If you nested a second one in that one, it wouldn’t be “top level” because it’s within the first one.

let Y = z; is not top level because it is within the record def. The def itself would be a statement “at the top level”.

Maybe it helps to know what is allowed to be “top level” 1   TableGen Programmer’s Reference — LLVM 16.0.0git documentation. So for example, def is allowed but int is not so the body of a record or class is by definition not ever “top level”.

In general the reason the docs talk about top level is the scoping and to show how if two uses have equivalent scope they have equivalent results.