2020年 2月 13日 コンパイラ読み回

2020年 2月 13日 コンパイラ読み回

今回はGCCとLLVMを読んでいきます

# 環境構築

mercurialのoriginalのソースコードをそれぞれ最新版にする

  • GCC
  • LLVM

# コンパイラのバージョンアップ方法

  1. とりあえず古いリポジトリにあるファイルをrm -rfする
  • 最新版を持ってきたときに競合する
  1. 最新版を持ってくる

  2. hg add *する

  3. hg statusを書き出す

  4. egrepで egrep '^!' /tmp/hg_status.logとかして、消えたファイルを確認する

  5. !がついてたファイルを削除する

  • vimで%s/..//とかすると便利
  1. hg commit してpushする

# gccの最新版

なんかGitになったらしい

1
$ git clone git://gcc.gnu.org/git/gcc.git

# llvmの最新版

これはGitHubになったみたい

1
$ git clone https://github.com/llvm/llvm-project

# gccのビルド

あたたかみのあるConfigure

1
2
3
$ ~/src/CbC_gcc/configure CFLAGS="-g3 -O0" --prefix=$PWD \                  
 --disable-nls --disable-bootstrap --enable-languages=c \                
    --enable-checking=tree,rtl,assert,types

# llvmのビルド

cmake+ninjaを使う

  • libstd関連でエラーが出るのでrpathを指定しておく
1
$cmake3 -G Ninja -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:PATH=/usr/local/llvm  -DLLVM_ENABLE_PROJECTS="clang;libgcc;libcxx;libcxxabi" -DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,/usr/local/gcc9/lib64 -L/usr/local/gcc9/lib64"  ~/src/LLVM_original/llvm

# LLVMのデバッグをするとき

起動する

1
lldb -- "/mnt/dalmore-home/one/build/build_llvm_origin/bin/clang-11" -cc1 -triple x86_64-unknown-linux-gnu -S -disable-free -main-file-name hello.c -mrelocation-model static -mthread-model posix -mframe-pointer=all -fmath-errno -fdenormal-fp-math=ieee,ieee -fdenormal-fp-math-f32=ieee,ieee -ffp-contract=on -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -v -resource-dir /mnt/dalmore-home/one/build/build_llvm_origin/lib/clang/11.0.0 -internal-isystem /usr/local/include -internal-isystem /mnt/dalmore-home/one/build/build_llvm_origin/lib/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /mnt/dalmore-home/one/build/build_llvm_origin -ferror-limit 19 -fmessage-length 0 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -fcolor-diagnostics -faddrsig -o hello.s -x c /mnt/dalmore-home//one/src/test/hello.c

なんかlldbだとおもすぎて駄目なのでgdbにした

例えばこういうコードををデバッグしたい時

//clang/lib/Parse/ParseStmt.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
/// Parse an expression statement.
StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) {
  // If a case keyword is missing, this is where it should be inserted.
  Token OldToken = Tok;

  ExprStatementTokLoc = Tok.getLocation();

  // expression[opt] ';'
  ExprResult Expr(ParseExpression());
  if (Expr.isInvalid()) {
    // If the expression is invalid, skip ahead to the next semicolon or '}'.
    // Not doing this opens us up to the possibility of infinite loops if
    // ParseExpression does not consume any tokens.
    SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
    if (Tok.is(tok::semi))
      ConsumeToken();
    return Actions.ActOnExprStmtError();

何故か Parser::ParseExpr...ではbreak pointに設定出来ない。

このParser::ParseExprStatementをbreakpointにしたい場合はclang::Parser::ParseExprStatementをbreak pointにする

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#0  clang::Parser::ParseExprStatement (this=0xe696330, StmtCtx=clang::Parser::Compound)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/ParseStmt.cpp:428
#1  0x0000000005a39e80 in clang::Parser::ParseStatementOrDeclarationAfterAttributes (this=0xe696330, Stmts=..., StmtCtx=clang::Parser::Compound,
    TrailingElseLoc=0x0, Attrs=...) at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/ParseStmt.cpp:233
#2  0x0000000005a3965c in clang::Parser::ParseStatementOrDeclaration (this=0xe696330, Stmts=..., StmtCtx=clang::Parser::Compound, TrailingElseLoc=0x0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/ParseStmt.cpp:107
#3  0x0000000005a3cec9 in clang::Parser::ParseCompoundStatementBody (this=0xe696330, isStmtExpr=false)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/ParseStmt.cpp:1079
#4  0x0000000005a411fb in clang::Parser::ParseFunctionStatementBody (this=0xe696330, Decl=0xe6bda30, BodyScope=...)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/ParseStmt.cpp:2204
#5  0x0000000005977d9f in clang::Parser::ParseFunctionDefinition (this=0xe696330, D=..., TemplateInfo=..., LateParsedAttrs=0x7fffffff9a80)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/Parser.cpp:1349
#6  0x00000000059941d8 in clang::Parser::ParseDeclGroup (this=0xe696330, DS=..., Context=clang::FileContext, DeclEnd=0x0, FRI=0x0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/ParseDecl.cpp:2068
#7  0x0000000005976df4 in clang::Parser::ParseDeclOrFunctionDefInternal (this=0xe696330, attrs=..., DS=..., AS=clang::AS_none)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/Parser.cpp:1109
#8  0x0000000005976eae in clang::Parser::ParseDeclarationOrFunctionDefinition (this=0xe696330, attrs=..., DS=0x0, AS=clang::AS_none)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/Parser.cpp:1125
#9  0x0000000005976391 in clang::Parser::ParseExternalDeclaration (this=0xe696330, attrs=..., DS=0x0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/Parser.cpp:945
#10 0x0000000005975419 in clang::Parser::ParseTopLevelDecl (this=0xe696330, Result=..., IsFirstDecl=false)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/Parser.cpp:696
#11 0x0000000005970f3a in clang::ParseAST (S=..., PrintStats=false, SkipFunctionBodies=false)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/ParseAST.cpp:158
#12 0x0000000003ce5a91 in clang::ASTFrontendAction::ExecuteAction (this=0xe63c1a0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Frontend/FrontendAction.cpp:1047
#13 0x0000000004572303 in clang::CodeGenAction::ExecuteAction (this=0xe63c1a0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CodeGenAction.cpp:1176
#14 0x0000000003ce53fd in clang::FrontendAction::Execute (this=0xe63c1a0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Frontend/FrontendAction.cpp:940
#15 0x0000000003c7db31 in clang::CompilerInstance::ExecuteAction (this=0xe6381d0, Act=...)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Frontend/CompilerInstance.cpp:969
#16 0x0000000003e40b1d in clang::ExecuteCompilerInvocation (Clang=0xe6381d0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:292

# GCC

c_parser_expr_no_commasで止めてみる

  • この関数自体は再帰下降でパースが実行されている最中に呼び出される
  • テストコードがexternから始まっていたので、c_parser_external_declarationから呼び出されているみたい
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
(gdb) bt
#0  c_parser_expr_no_commas (parser=parser@entry=0x7ffff7ff8ab0,
    after=after@entry=0x0, omp_atomic_lhs=omp_atomic_lhs@entry=0x0)
    at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:7557
#1  0x000000000083fc05 in c_parser_expression (
    parser=parser@entry=0x7ffff7ff8ab0)
    at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:10630
#2  0x000000000084046c in c_parser_expression_conv (
    parser=parser@entry=0x7ffff7ff8ab0)
    at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:10663
#3  0x000000000085b72a in c_parser_statement_after_labels (
    parser=parser@entry=0x7ffff7ff8ab0, if_p=if_p@entry=0x0,
    chain=chain@entry=0x0)
at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:6294
#4  0x0000000000856d04 in c_parser_compound_statement_nostart (
parser=parser@entry=0x7ffff7ff8ab0)
at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:5800
#5  0x00000000008572d7 in c_parser_compound_statement (
parser=parser@entry=0x7ffff7ff8ab0)
at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:5616
#6  0x0000000000858c56 in c_parser_declaration_or_fndef (
parser=parser@entry=0x7ffff7ff8ab0, fndef_ok=fndef_ok@entry=true,
static_assert_ok=static_assert_ok@entry=true,
empty_ok=empty_ok@entry=true, nested=nested@entry=false,
start_attr_ok=start_attr_ok@entry=true,
objc_foreach_object_declaration=objc_foreach_object_declaration@entry=0x0, omp_declare_simd_clauses=..., omp_declare_simd_clauses@entry=...,
have_attrs=<optimized out>, have_attrs@entry=false,
attrs=attrs@entry=0x0, oacc_routine_data=oacc_routine_data@entry=0x0,
fallthru_attr_p=fallthru_attr_p@entry=0x0)
at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:2504
#7  0x0000000000861c81 in c_parser_external_declaration (
parser=0x7ffff7ff8ab0)
at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:1747
#8  0x0000000000862872 in c_parser_translation_unit (
parser=0x7ffff7ff8ab0)
at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:1619
#9  c_parse_file ()
---Type <return> to continue, or q <return> to quit---
at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:21710
#10 0x00000000008c708b in c_common_parse_file ()
at /mnt/dalmore-home//one/src/GCC_original/gcc/c-family/c-opts.c:1186
#11 0x0000000000ebad8f in compile_file ()
at /mnt/dalmore-home//one/src/GCC_original/gcc/toplev.c:458
#12 0x0000000000742efd in do_compile ()
at /mnt/dalmore-home//one/src/GCC_original/gcc/toplev.c:2273
#13 toplev::main (this=this@entry=0x7fffffffde70, argc=argc@entry=2,
argv=argv@entry=0x7fffffffdf78)
at /mnt/dalmore-home//one/src/GCC_original/gcc/toplev.c:2412
#14 0x00000000007c1527 in main (argc=2, argv=0x7fffffffdf78)
at /mnt/dalmore-home//one/src/GCC_original/gcc/main.c:39

# 2020/02/14 (2日目)

午前中はgccから

# テストコード

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
extern int printf(const char*, ...);

extern void g(int* p);

int f(int arg) {
    int loq;
    g(&loq);
}

int main() {
    f(3);
    return 0;
}

# gcc

build したディレクトリに移動

# gdb起動

1
$ gdb --args gcc/cc1 ~/src/test/hello.c

# break point

昨日と同じところから

1
#0  c_parser_expr_no_commas (parser=parser@entry=0x7ffff7ff8ab0,
  • ソースコード的にはgcc/c/c-parser.cを読んでいく世界観

# C言語のおさらい

C言語でstaticがついている関数は自分自身のファイルだけからしか参照できない関数

c_parserがGCCのパース関連の色々入っている構造体っぽい

  • lhs
    • 代入される側
  • rhs
    • 代入する側

# parser 構造体

  • なんかtokensのアドレスとか、tokenのbufとかが入っている
  • この時点でソースコードのlocationが知りたい

https://gcc.gnu.org/onlinedocs/gccint/Guidelines-for-Diagnostics.html#Location-Information

  • このドキュメント読んだけど微妙だった

# c_parser_conditional_expression

  • なんか途中でgcc_assertとかしている
    • 多分抜けそう

# c_parser_binary_expression

  • 引数はparser, after, omp_atomic_lhs
  • 今は extern void g();g()を見てそう
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
static struct c_expr
c_parser_binary_expression (c_parser *parser, struct c_expr *after,
                            tree omp_atomic_lhs)
{
  /* A binary expression is parsed using operator-precedence parsing,
     with the operands being cast expressions.  All the binary
     operators are left-associative.  Thus a binary expression is of
     form:

     E0 op1 E1 op2 E2 ...

     which we represent on a stack.  On the stack, the precedence
     levels are strictly increasing.  When a new operator is
     encountered of higher precedence than that at the top of the
     stack, it is pushed; its LHS is the top expression, and its RHS
     is everything parsed until it is popped.  When a new operator is
     encountered with precedence less than or equal to that at the top
     of the stack, triples E[i-1] op[i] E[i] are popped and replaced
     by the result of the operation until the operator at the top of
     the stack has lower precedence than the new operator or there is
     only one element on the stack; then the top expression is the LHS
     of the new operator.  In the case of logical AND and OR
     expressions, we also need to adjust c_inhibit_evaluation_warnings
     as appropriate when the operators are pushed and popped.  */

  struct {
    /* The expression at this stack level.  */
    struct c_expr expr;
    /* The precedence of the operator on its left, PREC_NONE at the
       bottom of the stack.  */
    enum c_parser_prec prec;
    /* The operation on its left.  */
    enum tree_code op;
    /* The source location of this operation.  */
    location_t loc;
    /* The sizeof argument if expr.original_code == SIZEOF_EXPR.  */
    tree sizeof_arg;
  } stack[NUM_PRECS];
  int sp;
  /* Location of the binary operator.  */
  location_t binary_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */

left-associative

  • 1+2+3と来た場合 
  • (1+2)+3に変換するやつ
  • 再帰下降と相性が悪い(無限ループするので), whileに書き直すオペレーションが入る

#define POP

  • 最近GCCはマクロに書く方針でやり始めたらしい
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define POP                                                                   \
  do {                                                                        \
    switch (stack[sp].op)                                                     \
      {                                                                       \
      case TRUTH_ANDIF_EXPR:                                                  \
        c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value            \
                                          == truthvalue_false_node);          \
....
            & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) | (1 << PREC_BITAND)    \
               | (1 << PREC_SHIFT) | (1 << PREC_ADD) | (1 << PREC_MULT)))     \
        && stack[sp].op != TRUNC_MOD_EXPR                                     \
        && stack[0].expr.value != error_mark_node                             \
        && stack[1].expr.value != error_mark_node                             \
        && (c_tree_equal (stack[0].expr.value, omp_atomic_lhs)                \
            || c_tree_equal (stack[1].expr.value, omp_atomic_lhs)))           \
      stack[0].expr.value                                                     \
        = build2 (stack[1].op, TREE_TYPE (stack[0].expr.value),               \
                  stack[0].expr.value, stack[1].expr.value);                  \
    else                                                                      \
      stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc,             \
                                                   stack[sp].op,              \
                                                   stack[sp - 1].expr,        \
                                                   stack[sp].expr);           \
    sp--;                                                                     \
  } while (0)

stackに代入するタイミングでc_parser_cast_expressionが呼ばれていそう

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
/* Parse a cast expression (C90 6.3.4, C99 6.5.4, C11 6.5.4).  If AFTER
   is not NULL then it is an Objective-C message expression which is the
   primary-expression starting the expression as an initializer.

   cast-expression:
     unary-expression
     ( type-name ) unary-expression
*/

static struct c_expr
c_parser_cast_expression (c_parser *parser, struct c_expr *after)
{
  location_t cast_loc = c_parser_peek_token (parser)->location;
  gcc_assert (!after || c_dialect_objc ());
  if (after)
    return c_parser_postfix_expression_after_primary (parser,
                                                      cast_loc, *after);

下のifで処理されるのは次のケースみたい

  • (int )0.1
    • キャスト
  • j = ({ i = 1;})
    • compound literal
1
2
3
4
5
6
7
8
 /* If the expression begins with a parenthesized type name, it may
    be either a cast or a compound literal; we need to see whether
    the next character is '{' to tell the difference.  If not, it is
    an unary expression.  Full detection of unknown typenames here
    would require a 3-token lookahead.  */
 if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
     && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
   {

次にここを読む

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* Parse an unary expression (C90 6.3.3, C99 6.5.3, C11 6.5.3).

   unary-expression:
     postfix-expression
     ++ unary-expression
     -- unary-expression
     unary-operator cast-expression
     sizeof unary-expression
     sizeof ( type-name )

   unary-operator: one of
     & * + - ~ !

   GNU extensions:

   unary-expression:
     __alignof__ unary-expression
     __alignof__ ( type-name )
     && identifier

   (C11 permits _Alignof with type names only.)

   unary-operator: one of
     __extension__ __real__ __imag__

   Transactional Memory:

   unary-expression:
     transaction-expression

   In addition, the GNU syntax treats ++ and -- as unary operators, so
   they may be applied to cast expressions with errors for non-lvalues
   given later.  */

static struct c_expr
c_parser_unary_expression (c_parser *parser)
{
  int ext;
  struct c_expr ret, op;
  location_t op_loc = c_parser_peek_token (parser)->location;
  location_t exp_loc;
  location_t finish;
  ret.original_code = ERROR_MARK;
  ret.original_type = NULL;
  switch (c_parser_peek_token (parser)->type)

例えばこのcaseは++iのとき

1
2
3
4
5
6
7
8
9
  switch (c_parser_peek_token (parser)->type)
   {
   case CPP_PLUS_PLUS:
     c_parser_consume_token (parser);
     exp_loc = c_parser_peek_token (parser)->location;
     op = c_parser_cast_expression (parser, NULL);

     op = default_function_array_read_conversion (exp_loc, op);
     return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op);

# c_parser_peek_token(parser)をgdbで読む

p c_parser_peek_token(parser)するとポインタが返ってくる

p *c_parser_peek_token(parser)とかすると中身が見れる

このあたりのデバッグサポートライブラリはConfigureで指定するとリンクされて使えるようになるらしい

p *c_parser_peek_token(parser)したところ、fieldにvalueがある

  • 多分unionっぽい

# c_parser_postfix_expression

8983行目くらい

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

static struct c_expr
c_parser_postfix_expression (c_parser *parser)
{
  struct c_expr expr, e1;
  struct c_type_name *t1, *t2;
  location_t loc = c_parser_peek_token (parser)->location;
  source_range tok_range = c_parser_peek_token (parser)->get_range ();
  expr.original_code = ERROR_MARK;
  expr.original_type = NULL;
  switch (c_parser_peek_token (parser)->type)
    {
    case CPP_NUMBER:
      expr.value = c_parser_peek_token (parser)->value;
      set_c_expr_source_range (&expr, tok_range);
      loc = c_parser_peek_token (parser)->location;
      c_parser_consume_token (parser);
      if (TREE_CODE (expr.value) == FIXED_CST
          && !targetm.fixed_point_supported_p ())
        {
          error_at (loc, "fixed-point types not supported for this target");
          expr.set_error ();
        }
      break;
    case CPP_CHAR:
    case CPP_CHAR16:
    case CPP_CHAR32:
    case CPP_UTF8CHAR:
    case CPP_WCHAR:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 case CPP_NAME:
   switch (c_parser_peek_token (parser)->id_kind)
     {
     case C_ID_ID:
       {
         tree id = c_parser_peek_token (parser)->value;
         c_parser_consume_token (parser);
         expr.value = build_external_ref (loc, id,
                                          (c_parser_peek_token (parser)->type
                                           == CPP_OPEN_PAREN),
                                          &expr.original_type);
         set_c_expr_source_range (&expr, tok_range);
         break;
       }
     case C_ID_CLASSNAME:
       {
         /* Here we parse the Objective-C 2.0 Class.name dot
            syntax.  */
         tree class_name = c_parser_peek_token (parser)->value;
         tree component;
         c_parser_consume_token (parser);
         gcc_assert (c_dialect_objc ());
         if (!c_parser_require (parser, CPP_DOT, "expected %<.%>"))
           {
             expr.set_error ();
             break;
           }
         if (c_parser_next_token_is_not (parser, CPP_NAME))
           {
             c_parser_error (parser, "expected identifier");
             expr.set_error ();
             break;
           }

C言語だとreturnで値がコピーされるので、ローカル変数の構造体をそのまま返すことができる

# build_external_ref (location_t loc, tree id, bool fun, tree *type)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* Build an external reference to identifier ID.  FUN indicates
   whether this will be used for a function call.  LOC is the source
   location of the identifier.  This sets *TYPE to the type of the
   identifier, which is not the same as the type of the returned value
   for CONST_DECLs defined as enum constants.  If the type of the
   identifier is not available, *TYPE is set to NULL.  */
tree
build_external_ref (location_t loc, tree id, bool fun, tree *type)
{
  tree ref;
  tree decl = lookup_name (id);

  /* In Objective-C, an instance variable (ivar) may be preferred to
     whatever lookup_name() found.  */
  decl = objc_lookup_ivar (decl, id);

  *type = NULL;
  if (decl && decl != error_mark_node)
    {
      ref = decl;
      *type = TREE_TYPE (ref);
    }
  else if (fun)
    /* Implicit function declaration.  */
    ref = implicitly_declare (loc, id);
  else if (decl == error_mark_node)
    /* Don't complain about something that's already been
       complained about.  */
    return error_mark_node;
  else
    {
      undeclared_variable (loc, id);
      return error_mark_node;
    }

  if (TREE_TYPE (ref) == error_mark_node)
    return error_mark_node;

  if (TREE_DEPRECATED (ref))
    warn_deprecated_use (ref, NULL_TREE);

  /* Recursive call does not count as usage.  */
  if (ref != current_function_decl)
    {
      TREE_USED (ref) = 1;

昔のCは型を定義しないで名前を定義して、後から型を定義できるようになっていた

  • その名残?

ここまではIDが来ていて、具体的にすでに登録されているかの確認はしていない

  • tree decl = lookup_name (id);で確認していそう
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  #0  build_external_ref (loc=loc@entry=184896, id=id@entry=0x7ffff64518c0, 
    fun=<optimized out>, type=type@entry=0x7fffffffd010)
    at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-typeck.c:2744
#1  0x0000000000830a63 in c_parser_postfix_expression (
    parser=parser@entry=0x7ffff7ff8ab0)
    at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:9043
#2  0x000000000083c8d3 in c_parser_unary_expression (
    parser=parser@entry=0x7ffff7ff8ab0)
    at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:8269
#3  0x000000000083db87 in c_parser_cast_expression (
    parser=parser@entry=0x7ffff7ff8ab0, after=0x0)
    at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:8108
#4  0x000000000083de3d in c_parser_binary_expression (
    parser=parser@entry=0x7ffff7ff8ab0, after=<optimized out>, 
    omp_atomic_lhs=0x0)
    at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:7911
#5  0x000000000083f186 in c_parser_conditional_expression (
    parser=parser@entry=0x7ffff7ff8ab0, after=<optimized out>, 
    omp_atomic_lhs=<optimized out>)
    at /mnt/dalmore-home//one/src/GCC_original/gcc/c/c-parser.c:7645
#6  0x000000000083f971 in c_parser_expr_no_commas (
    parser=parser@entry=0x7ffff7ff8ab0, after=after@entry=0x0, 
    omp_atomic_lhs=omp_atomic_lhs@entry=0x0)

# 午後

午後はCbCのupgradeをしていきます

# CbC_gccのupgrade

1
2
$ cd ~/src/CbC_gcc
$ hg pull  ../GCC_original
1
2
$hg updat -C 145
$hg resolve

conflictしたやつ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
merging gcc/c-family/c-common.c
merging gcc/c/c-decl.c
merging gcc/c/c-parser.c
merging gcc/calls.c
merging gcc/config/i386/i386.c
merging gcc/gimple.c
merging gcc/ipa-inline.c
3 files to edit
merging gcc/c-family/c-common.c failed!
3 files to edit
merging gcc/c/c-decl.c failed!
3 files to edit
merging gcc/c/c-parser.c failed!
3 files to edit
merging gcc/calls.c failed!
3 files to edit
merging gcc/config/i386/i386.c failed!
3 files to edit
merging gcc/gimple.c failed!
3 files to edit
merging gcc/ipa-inline.c failed!

変更点を探して、中のCbCの記述を探す

1
2
3
4
$hg diff gcc/c-family/c-common.c -r -1
$grep CbC gcc/c-family/c-common.c
$hg cat -r 145 gcc/c-family/c-common.c > gcc/c-family/c-common.c
$hg diff  gcc/c-family/c-common.c

あとはvimを使っていい感じに修正する

1
$hg resolve -m gcc/c-family/c-common.c

なんか直前のcommitが最新になっていて、今のcommitが古いやつになっていた。 なので一回pullしてupdate -r 145して、直前の古い状態に戻しておく

# なおしたところ

  • __code -> void への関数型の変換部分(function declaration)

# LLVM側のupdate

新しいのをpullしてきて、新しい方にupdateする

  • 古い方をmergeする

vimdiffが起動したら:cqで抜けられるらしい

  • 今回はファイルに>>>> ==== <<<<は書き出さない
1
2
3
4
5
6
$cd ~/CbC_llvm
$hg log | less
$hg pull ../LLVM_original
$hg log | less
$hg update -r 150 -C
$hg merge -r 149 

was deleted in local

これみたいなエラーが出たら、 d で消しちゃっていい

# llvm側で変数の寿命を管理しているとこを見てみる

clang/lib/Parse/ParseExpr.cppを見ていく

  • とりあえずfuncとかでgrep

llvmのcppはまぁ正気なcppらしい

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
    // Function designators are allowed to be undeclared (C99 6.5.1p2), so we
    // need to know whether or not this identifier is a function designator or
    // not.
    UnqualifiedId Name;
    CXXScopeSpec ScopeSpec;
    SourceLocation TemplateKWLoc;
    Token Replacement;
    CastExpressionIdValidator Validator(
        /*Next=*/Tok,
        /*AllowTypes=*/isTypeCast != NotTypeCast,
        /*AllowNonTypes=*/isTypeCast != IsTypeCast);
    Validator.IsAddressOfOperand = isAddressOfOperand;
    if (Tok.isOneOf(tok::periodstar, tok::arrowstar)) {
      Validator.WantExpressionKeywords = false;
      Validator.WantRemainingKeywords = false;
    } else {
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/// Once the leading part of a postfix-expression is parsed, this
/// method parses any suffixes that apply.
///
/// \verbatim
///       postfix-expression: [C99 6.5.2]
///         primary-expression
///         postfix-expression '[' expression ']'
///         postfix-expression '[' braced-init-list ']'
///         postfix-expression '(' argument-expression-list[opt] ')'
///         postfix-expression '.' identifier
///         postfix-expression '->' identifier
///         postfix-expression '++'
///         postfix-expression '--'
///         '(' type-name ')' '{' initializer-list '}'
///         '(' type-name ')' '{' initializer-list ',' '}'
///
///       argument-expression-list: [C99 6.5.2]
///         argument-expression ...[opt]
///         argument-expression-list ',' assignment-expression ...[opt]
/// \endverbatim
ExprResult
Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
  // Now that the primary-expression piece of the postfix-expression has been
  // parsed, see if there are any postfix-expression pieces here.
  SourceLocation Loc;
  auto SavedType = PreferredType;
  while (1) {
    // Each iteration relies on preferred type for the whole expression.
    PreferredType = SavedType;
    switch (Tok.getKind()) {
    case tok::code_completion:
      if (InMessageExpression)
        return LHS;

      Actions.CodeCompletePostfixExpression(
          getCurScope(), LHS, PreferredType.get(Tok.getLocation()));
      cutOffParsing();
      return ExprError();
  • 大文字Tokが先読み部分っぽい
    • さらに大域変数?
    • debug traceしたらインスタンス変数だった
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

    case tok::l_paren:         // p-e: p-e '(' argument-expression-list[opt] ')'
    case tok::lesslessless: {  // p-e: p-e '<<<' argument-expression-list '>>>'
                               //   '(' argument-expression-list[opt] ')'
      tok::TokenKind OpKind = Tok.getKind();
      InMessageExpressionRAIIObject InMessage(*this, false);

      Expr *ExecConfig = nullptr;

      BalancedDelimiterTracker PT(*this, tok::l_paren);

      if (OpKind == tok::lesslessless) {
        ExprVector ExecConfigExprs;
        CommaLocsTy ExecConfigCommaLocs;
        SourceLocation OpenLoc = ConsumeToken();

        if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) {
          (void)Actions.CorrectDelayedTyposInExpr(LHS);
          LHS = ExprError();
        }

        SourceLocation CloseLoc;
        if (TryConsumeToken(tok::greatergreatergreater, CloseLoc)) {
        } else if (LHS.isInvalid()) {
          SkipUntil(tok::greatergreatergreater, StopAtSemi);
        } else {
          // There was an error closing the brackets
          Diag(Tok, diag::err_expected) << tok::greatergreatergreater;
          Diag(OpenLoc, diag::note_matching) << tok::lesslessless;
          SkipUntil(tok::greatergreatergreater, StopAtSemi);
          LHS = ExprError();
        }

        if (!LHS.isInvalid()) {
          if (ExpectAndConsume(tok::l_paren))
            LHS = ExprError();
          else

たぶん上のが関数呼び出し部分っぽい気がする

  • というわけで Parser::ParsePostfixExpressionSuffix(ExprResult LHS) をbreak pointに設定する

# Parser::ParsePostfixExpressionSuffix(ExprResult LHS)

  • b clang::Parser::ParsePostfixExpressionSuffixでbreak point設定
  • llvmはthisが色々入っている環境っぽい
  • この関数自体は関数化なんなのかをチェックしているので、必ずしも関数の場合に突入してない
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1895       ExprVector ArgExprs;
1896       CommaLocsTy CommaLocs;
1897       auto RunSignatureHelp = [&]() -> QualType {
1898         QualType PreferredType = Actions.ProduceCallSignatureHelp(
1899             getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation());
1900         CalledSignatureHelp = true;
1901         return PreferredType;
1902       };
1903       if (OpKind == tok::l_paren || !LHS.isInvalid()) {
1904         if (Tok.isNot(tok::r_paren)) {
1905           if (ParseExpressionList(ArgExprs, CommaLocs, [&] {
1906                 PreferredType.enterFunctionArgument(Tok.getLocation(),
1907                                                     RunSignatureHelp);
1908               })) {
1909             (void)Actions.CorrectDelayedTyposInExpr(LHS);
1910             // If we got an error when parsing expression list, we don't call
1911             // the CodeCompleteCall handler inside the parser. So call it here
1912             // to make sure we get overload suggestions even when we are in the
1913             // middle of a parameter.
1914             if (PP.isCodeCompletionReached() && !CalledSignatureHelp)
1915               RunSignatureHelp();
1916             LHS = ExprError();
1917           } else if (LHS.isInvalid()) {
1918             for (auto &E : ArgExprs)
1919               Actions.CorrectDelayedTyposInExpr(E);
1920           }
1921         }
1922       }
1923

このあたりで引数を設定していそうだが…

1
2
3
4
1905           if (ParseExpressionList(ArgExprs, CommaLocs, [&] {
1906                 PreferredType.enterFunctionArgument(Tok.getLocation(),
1907                                                     RunSignatureHelp);
1908               })) {
  • このParseExpressionListが,区切りの引数のリストがきていそう

# llvmIRを出力してみる

1
$clang -S -emit-llvm hello.c
  • IRレベルでは変数の寿命は入ってない?

# 2020/02/15(3日目)

今日は変数のライフタイム/コード生成を追っていきます

# LLVMのselectionと呼ばれるところ

  • clangレベルでIRを出力しているところ
  • IRからnativeを吐き出しているところ

コード生成を追うことに

# clangレベルのコード生成っぽいところを探す

clang/lib/CodeGenがそれっぽい

  • *selectionを探す
    • なさそう?
  • ./lib/CodeGen/CGExpr.cppを読んで見る
    • 194:RValue CodeGenFunction::EmitAnyExpr(const Expr *E,をbreak pointにする

# LLVMのdebug

こういうシェルスクリプトが生まれたので使う

1
gdb --args "/mnt/dalmore-home/one/build/build_llvm_origin/bin/clang-11" -cc1 -triple x86_64-unknown-linux-gnu -S -disable-free -main-file-name hello.c -mrelocation-model static -mthread-model posix -mframe-pointer=all -fmath-errno -fdenormal-fp-math=ieee,ieee -fdenormal-fp-math-f32=ieee,ieee -ffp-contract=on -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -v -resource-dir /mnt/dalmore-home/one/build/build_llvm_origin/lib/clang/11.0.0 -internal-isystem /usr/local/include -internal-isystem /mnt/dalmore-home/one/build/build_llvm_origin/lib/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /mnt/dalmore-home/one/build/build_llvm_origin -ferror-limit 19 -fmessage-length 0 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -fcolor-diagnostics -faddrsig -o hello.s -x c /mnt/dalmore-home//one/src/test/hello.c

# CodeGenFunction::EmitAnyExpr

clang::CodeGen::CodeGenFunction::EmitAnyExprをbreak pointにする

  • CGExpr.cppの先頭にnamespaceが切られているので、これの通りに先頭につける必要があるらしい
1
2
using namespace clang;
using namespace CodeGen;

上の場合は clang::CodeGen

EmitAnyExprで止まったのでback traceを確認してみる

CodeGenはAbstractFactoryパターンで書かれているので、CodeGeneratorImpl::HandleTopLevelDeclを経由して呼び出されている

  • これはclangレベルなのでIRの出力のみしている
  • Nativeは多分あまりなにもしてない

この関数はclang::ParseASTから呼び出される

# ParseAST.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//===----------------------------------------------------------------------===//
// Public interface to the file
//===----------------------------------------------------------------------===//

/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as
/// the file is parsed.  This inserts the parsed decls into the translation unit
/// held by Ctx.
///
void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
                     ASTContext &Ctx, bool PrintStats,
                     TranslationUnitKind TUKind,
                     CodeCompleteConsumer *CompletionConsumer,
                     bool SkipFunctionBodies) {

  std::unique_ptr<Sema> S(
      new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));

  // Recover resources if we crash before exiting this method.
  llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());

  ParseAST(*S.get(), PrintStats, SkipFunctionBodies);
}

void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
  // Collect global stats on Decls/Stmts (until we have a module streamer).
  if (PrintStats) {
    Decl::EnableStatistics();
    Stmt::EnableStatistics();
  }

  // Also turn on collection of stats inside of the Sema object.

Interfaceに対応するpublic APIのじっそう 

  • 上のvoid clang::Parse((Preprocessor &PP, ASTConsumer *Consumer,)はコンスタクタでなくてただのメソッドっぽい
  • 実際に呼び出されているのは下のParseASTみたい

# Consumerで呼び出されているGen

Genとかいうオブジェクトがあった。定義はこれ

  • std::unique_ptr<CodeGenerator> Gen;
    • スマートポインタみたい
    • Get.get()で中身が取れる
      • clang::CodeGeneratorだった
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  ASTConsumer *Consumer = &S.getASTConsumer();

  std::unique_ptr<Parser> ParseOP(
      new Parser(S.getPreprocessor(), S, SkipFunctionBodies));
  Parser &P = *ParseOP.get();

  llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup>
      CleanupPrettyStack(llvm::SavePrettyStackState());
  PrettyStackTraceParserEntry CrashInfo(P);

  // Recover resources if we crash before exiting this method.
  llvm::CrashRecoveryContextCleanupRegistrar<Parser>
    CleanupParser(ParseOP.get());

  S.getPreprocessor().EnterMainSourceFile();
  ExternalASTSource *External = S.getASTContext().getExternalSource();
  if (External)
    External->StartTranslationUnit(Consumer);

  // If a PCH through header is specified that does not have an include in
  // the source, or a PCH is being created with #pragma hdrstop with nothing
  // after the pragma, there won't be any tokens or a Lexer.
  bool HaveLexer = S.getPreprocessor().getCurrentLexer();

  if (HaveLexer) {
    llvm::TimeTraceScope TimeScope("Frontend");
    P.Initialize();
    Parser::DeclGroupPtrTy ADecl;
    for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
         AtEOF = P.ParseTopLevelDecl(ADecl)) {
      // If we got a null return and something *was* parsed, ignore it.  This
      // is due to a top-level semicolon, an action override, or a parse error
      // skipping something.
      if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
        return;
    }
  }

Sema経由でConsumerとかを取ってきてそう

for分の中に出てきているAdeclは参照になっていて、順次updateされていくらしい

# Semaを見に行く

lib/Sema/Sema.cppを見る

1
2
// This file implements the actions class which performs semantic analysis and
// builds an AST out of a parse stream.

よくわからんのでヘッダファイルを見に行く include/clang/Sema/Sema.h

Parseは構文解析をしてパースするだけ

  • ASTを作りたい
  • このASTにセマンティクスをつける必要がある
  • ASTのFactoryが必要になる
  • これがSemaっぽい

なのでAST Factoryっぽい

336行目に書かれてる

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/// Sema - This implements semantic analysis and AST building for C.
class Sema final {
  Sema(const Sema &) = delete;
  void operator=(const Sema &) = delete;

  /// A key method to reduce duplicate debug info from Sema.
  virtual void anchor();

  ///Source of additional semantic information.
  ExternalSemaSource *ExternalSource;

  ///Whether Sema has generated a multiplexer and has to delete it.
  bool isMultiplexExternalSource;

  static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD);
  • finalは virtual function のoverrideの防止らしい
  • (const Sema &) = deleteとは一体?

# 試しにソートしてみた

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
      14      43     527 include/clang/Frontend/PCHContainerOperations.h
      14      43     545 include/clang/Serialization/SerializationDiagnostic.h
      14      43     610 include/clang/Tooling/Refactoring/RefactoringDiagnostic.h
      14      44     496 include/clang/Lex/LexDiagnostic.h
      14      44     501 include/clang/Sema/SemaDiagnostic.h
      14      44     506 include/clang/Parse/ParseDiagnostic.h
      14      44     511 include/clang/Driver/DriverDiagnostic.h
      14      44     521 include/clang/Analysis/AnalysisDiagnostic.h
      14      44     521 include/clang/Frontend/FrontendDiagnostic.h
      14      47     558 include/clang/CrossTU/CrossTUDiagnostic.h
      15      46     509 include/clang/AST/CommentDiagnostic.h
      23      62     770 include/clang/Tooling/ToolExecutorPluginRegistry.h
      24      66     662 include/clang/Basic/CapturedStmt.h
      24      69     749 include/clang/Basic/BitmaskEnum.h
      25      66     717 include/clang/Basic/ExpressionTraits.h
      25      73     757 include/clang/Basic/DiagnosticCategories.h
      26      68     877 include/clang/Frontend/FrontendPluginRegistry.h
      26     103     963 include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
      27      82     907 include/clang/AST/AST.h
      27      87     875 include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
      28      82     951 include/clang/Basic/DiagnosticRefactoring.h
      28      84     962 include/clang/Basic/DiagnosticSerialization.h
      28      85     903 include/clang/Basic/DiagnosticLex.h
      28      85     909 include/clang/Basic/DiagnosticSema.h
      28      85     915 include/clang/Basic/DiagnosticParse.h
      28      85     921 include/clang/Basic/DiagnosticDriver.h
      28      85     933 include/clang/Basic/DiagnosticAnalysis.h
      28      85     933 include/clang/Basic/DiagnosticFrontend.h
      28      86     927 include/clang/Basic/DiagnosticCrossTU.h
      28      87     903 include/clang/Basic/DiagnosticAST.h
      28      87     927 include/clang/Basic/DiagnosticComment.h
      30      86     877 include/clang/Frontend/MigratorOptions.h
      30      90     868 include/clang/Basic/PragmaKinds.h
      31      91     922 include/clang/AST/AbstractTypeReader.h
      31      93     957 include/clang/Basic/AttrSubjectMatchRules.h
      31     100     896 include/clang/Driver/Util.h
      31     100     924 include/clang/Basic/FileSystemOptions.h
      31     117    1268 include/clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h
      32      93     944 include/clang/AST/AbstractTypeWriter.h
      32     111    1266 include/clang-c/FatalErrorHandler.h
      33     102     929 include/clang/Basic/AttrKinds.h
      33     104     980 include/clang/Edit/EditsReceiver.h
      33     110    1270 include/clang/Tooling/Syntax/BuildTree.h
      34     108    1208 include/clang/Rewrite/Frontend/Rewriters.h
      35     143    1379 include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
      36      97    1031 include/clang/AST/ASTFwd.h
      36     105    1226 include/clang/Analysis/SelectorExtras.h
      36     142    1369 include/clang/AST/ASTDiagnostic.h
      37     108     895 include/clang/Driver/Phases.h
      37     137    1293 include/clang/Basic/PrettyStackTrace.h
      37     151    1367 include/clang/AST/ASTContextAllocate.h
      37     162    1506 include/clang/Tooling/Syntax/Mutations.h
      38      91    1103 include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
      38     113    1124 include/clang/Basic/CommentOptions.h
      38     124    1653 include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h
      38     139    1290 include/clang/FrontendTool/Utils.h
      39     100    1166 include/clang/Edit/Rewriters.h
      39     112    2007 include/clang-c/ExternC.h
      39     139    1315 include/clang/Sema/SemaLambda.h
      ...
    2456    6337   72088 include/clang/AST/TypeLoc.h
    2518    9954   84357 include/clang/Format/Format.h
    2562   11342   93946 include/clang/AST/DeclBase.h
    2702   10276  100082 include/clang/Sema/DeclSpec.h
    2922   10503  104051 include/clang/AST/DeclObjC.h
    3103   13260  122386 include/clang/AST/ASTContext.h
    3175   11308  130885 include/clang/Parse/Parser.h
    3283   12371  124927 include/clang/AST/DeclTemplate.h
    3495    9816  126411 include/clang/AST/RecursiveASTVisitor.h
    3594   12701  114449 include/clang/AST/Stmt.h
    3981   16688  151945 include/clang/AST/DeclCXX.h
    4525   19376  170110 include/clang/AST/Decl.h
    4599   18407  181669 include/clang/AST/StmtOpenMP.h
    4840   18045  175567 include/clang/AST/ExprCXX.h
    6009   25804  230882 include/clang/AST/Expr.h
    6663   25974  244789 include/clang/AST/OpenMPClause.h
    6782   28711  220435 include/clang-c/Index.h
    7107   28644  251058 include/clang/AST/Type.h
    7108   25250  212553 include/clang/ASTMatchers/ASTMatchers.h
   12190   48469  560994 include/clang/Sema/Sema.h
  217079  840657 7819915 total
  • Semaだけ1万2千行!!!!!

# lib/CodeGen/CGExprScalar.cpp

1
2
3
4
5
6
7
8
9
/// Emit the computation of the specified expression of scalar type, ignoring
/// the result.
Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
  assert(E && hasScalarEvaluationKind(E->getType()) &&
         "Invalid scalar expression to emit");

  return ScalarExprEmitter(*this, IgnoreResultAssign)
      .Visit(const_cast<Expr *>(E));
}
  • Expressionを受け取って、これからLLVM IRを生成する
    • Eはなんかが入ってそう
1
2
p E->getType()
(gdb) { Value = { Value = 2415319184 }}
  • なんかのポインタ?

ScalarExprEmitter

  • Exprを付けとって、それをたどっていく
  • .Visitはvisitor patternっぽい

# C++ の( …)

…はthree dot operatorとかいうらしい

https://stackoverflow.com/questions/23485643/understanding-the-dots-in-variadic-template-function

# 午後

直前のvisitor パターンがなんであるかを見に行きます

# clang::CodeGen::CodeGenFunction::EmitScalarExpr

b clang::CodeGen::CodeGenFunction::EmitScalarExpr してbreak pointをかけておく

lib/CodeGen/CGExprScalar.cppの中っぽい

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

  //===--------------------------------------------------------------------===//
  //                            Visitor Methods
  //===--------------------------------------------------------------------===//

  Value *Visit(Expr *E) {
    ApplyDebugLocation DL(CGF, E);
    return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E);
  }

  Value *VisitStmt(Stmt *S) {
  • nする

# include/clang/AST/StmtVisitor.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
namespace clang {
/// StmtVisitorBase - This class implements a simple visitor for Stmt
/// subclasses. Since Expr derives from Stmt, this also includes support for
/// visiting Exprs.
template<template <typename> class Ptr, typename ImplClass, typename RetTy=void,
         class... ParamTys>
class StmtVisitorBase {
public:
#define PTR(CLASS) typename Ptr<CLASS>::type
#define DISPATCH(NAME, CLASS) \
  return static_cast<ImplClass*>(this)->Visit ## NAME( \
    static_cast<PTR(CLASS)>(S), std::forward<ParamTys>(P)...)

 

  RetTy Visit(PTR(Stmt) S, ParamTys... P) {
    // If we have a binary expr, dispatch to the subcode of the binop.  A smart
    // optimizer (e.g. LLVM) will fold this comparison into the switch stmt
    // below.
    if (PTR(BinaryOperator) BinOp = dyn_cast<BinaryOperator>(S)) {
      switch (BinOp->getOpcode()) {
      case BO_PtrMemD:   DISPATCH(BinPtrMemD,   BinaryOperator);
      case BO_PtrMemI:   DISPATCH(BinPtrMemI,   BinaryOperator);
      case BO_Mul:       DISPATCH(BinMul,       BinaryOperator);
      case BO_Div:       DISPATCH(BinDiv,       BinaryOperator);
      case BO_Rem:       DISPATCH(BinRem,       BinaryOperator);
      case BO_Add:       DISPATCH(BinAdd,       BinaryOperator);
      case BO_Sub:       DISPATCH(BinSub,       BinaryOperator);
  • DISPATCHみたいなマクロ…
    • 型によって呼ばれるVisitorが異なりそう

実際に飛ばされたのはこれ(105行目)

1
2
3
4
5
6
7
8
    // Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
    switch (S->getStmtClass()) {
    default: llvm_unreachable("Unknown stmt kind!");
#define ABSTRACT_STMT(STMT)
#define STMT(CLASS, PARENT)                              \
    case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS);
#include "clang/AST/StmtNodes.inc"
    }
  • StmtNodes.incはclang/include/clang/Basic/StmtNodes.tdを元にビルド時に生成される
    • build側のディレクトリをfindして見つける

# 実際に呼ばれた箇所

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    return VisitCastExpr(E);
 }
 Value *VisitCastExpr(CastExpr *E);

 Value *VisitCallExpr(const CallExpr *E) {
   if (E->getCallReturnType(CGF.getContext())->isReferenceType())
     return EmitLoadOfLValue(E);

   Value *V = CGF.EmitCallExpr(E).getScalarVal();

   EmitLValueAlignmentAssumption(E, V);
   return V;
 }
  • Visitorパターンなので、VisitCallExprを実装すれば、マクロで解決されてこれが呼び出される
  • ここでコード生成が行われている
  • コード生成している箇所を見るにはVisitCall*をみること!!!

# back trace

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#0  (anonymous namespace)::ScalarExprEmitter::VisitCallExpr (this=0x7fffffff76e0, E=0xe6bdc10)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGExprScalar.cpp:580
#1  0x00000000039f9b02 in clang::StmtVisitorBase<std::add_pointer, (anonymous namespace)::ScalarExprEmitter, llvm::Value*>::Visit (this=0x7fffffff76e0, S=0xe6bdc10) at tools/clang/include/clang/AST/StmtNodes.inc:801
#2  0x00000000039e1bf2 in (anonymous namespace)::ScalarExprEmitter::Visit (this=0x7fffffff76e0, E=0xe6bdc10)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGExprScalar.cpp:426
#3  0x00000000039f71c2 in clang::CodeGen::CodeGenFunction::EmitScalarExpr (this=0x7fffffff7bc0, E=0xe6bdc10,
    IgnoreResultAssign=true) at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGExprScalar.cpp:4572
#4  0x00000000039955ec in clang::CodeGen::CodeGenFunction::EmitAnyExpr (this=0x7fffffff7bc0, E=0xe6bdc10,
    aggSlot=..., ignoreResult=true) at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGExpr.cpp:199
#5  0x000000000399556b in clang::CodeGen::CodeGenFunction::EmitIgnoredExpr (this=0x7fffffff7bc0, E=0xe6bdc10)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGExpr.cpp:184
#6  0x00000000035f731d in clang::CodeGen::CodeGenFunction::EmitStmt (this=0x7fffffff7bc0, S=0xe6bdc10, Attrs=...)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGStmt.cpp:113
#7  0x00000000035f8398 in clang::CodeGen::CodeGenFunction::EmitCompoundStmtWithoutScope (this=0x7fffffff7bc0,
    S=..., GetLast=false, AggSlot=...)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGStmt.cpp:444
#8  0x000000000367eddc in clang::CodeGen::CodeGenFunction::EmitFunctionBody (this=0x7fffffff7bc0, Body=0xe6bdc38)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CodeGenFunction.cpp:1170
#9  0x000000000367f976 in clang::CodeGen::CodeGenFunction::GenerateCode (this=0x7fffffff7bc0, GD=...,
    Fn=0xe69af68, FnInfo=...)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CodeGenFunction.cpp:1335
#10 0x00000000036a5adc in clang::CodeGen::CodeGenModule::EmitGlobalFunctionDefinition (this=0xe65b7a0, GD=...,
    GV=0xe69af68) at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CodeGenModule.cpp:4484
#11 0x000000000369f182 in clang::CodeGen::CodeGenModule::EmitGlobalDefinition (this=0xe65b7a0, GD=..., GV=0x0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CodeGenModule.cpp:2874
#12 0x000000000369de1e in clang::CodeGen::CodeGenModule::EmitGlobal (this=0xe65b7a0, GD=...)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CodeGenModule.cpp:2577
#13 0x00000000036a96e6 in clang::CodeGen::CodeGenModule::EmitTopLevelDecl (this=0xe65b7a0, D=0xe6bda30)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CodeGenModule.cpp:5289
#14 0x000000000457a4f6 in (anonymous namespace)::CodeGeneratorImpl::HandleTopLevelDecl (this=0xe65ad70, DG=...)
---Type <return> to continue, or q <return> to quit---
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/ModuleBuilder.cpp:170
#15 0x0000000004574165 in clang::BackendConsumer::HandleTopLevelDecl (this=0xe65aba0, D=...)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CodeGenAction.cpp:214
#16 0x0000000005970f01 in clang::ParseAST (S=..., PrintStats=false, SkipFunctionBodies=false)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Parse/ParseAST.cpp:162
#17 0x0000000003ce5a91 in clang::ASTFrontendAction::ExecuteAction (this=0xe63c1a0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Frontend/FrontendAction.cpp:1047
#18 0x0000000004572303 in clang::CodeGenAction::ExecuteAction (this=0xe63c1a0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CodeGenAction.cpp:1176
#19 0x0000000003ce53fd in clang::FrontendAction::Execute (this=0xe63c1a0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Frontend/FrontendAction.cpp:940
#20 0x0000000003c7db31 in clang::CompilerInstance::ExecuteAction (this=0xe6381d0, Act=...)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/Frontend/CompilerInstance.cpp:969
#21 0x0000000003e40b1d in clang::ExecuteCompilerInvocation (Clang=0xe6381d0)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:292
#22 0x0000000000a586fb in cc1_main (Argv=...,
    Argv0=0x7fffffffde32 "/mnt/dalmore-home/one/build/build_llvm_origin/bin/clang-11",
    MainAddr=0xa4ce20 <GetExecutablePath[abi:cxx11](char const*, bool)>)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/tools/driver/cc1_main.cpp:240
#23 0x0000000000a4e4c9 in ExecuteCC1Tool (ArgV=...)
    at /mnt/dalmore-home/one/src/LLVM_original/clang/tools/driver/driver.cpp:328
#24 0x0000000000a4ebc3 in main (argc_=53, argv_=0x7fffffffd9c8)
at /mnt/dalmore-home/one/src/LLVM_original/clang/tools/driver/driver.cpp:402

# 中身の確認

1
    if (E->getCallReturnType(CGF.getContext())->isReferenceType())
  • だいたいこれはfalseになるはず

  • stepして中身をおっていく

    • smart pointer関連の処理がわりと続く
  • そのあと北場所

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//===--------------------------------------------------------------------===//
//                             Expression Emission
//===--------------------------------------------------------------------===//

RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
                                     ReturnValueSlot ReturnValue) {
  // Builtins never have block type.
  if (E->getCallee()->getType()->isBlockPointerType())
    return EmitBlockCallExpr(E, ReturnValue);

  if (const auto *CE = dyn_cast<CXXMemberCallExpr>(E))
    return EmitCXXMemberCallExpr(CE, ReturnValue);

  if (const auto *CE = dyn_cast<CUDAKernelCallExpr>(E))
    return EmitCUDAKernelCallExpr(CE, ReturnValue);

  if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(E))
    if (const CXXMethodDecl *MD =
          dyn_cast_or_null<CXXMethodDecl>(CE->getCalleeDecl()))
      return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);

  CGCallee callee = EmitCallee(E->getCallee());

  if (callee.isBuiltin()) {
    return EmitBuiltinExpr(callee.getBuiltinDecl(), callee.getBuiltinID(),
                           E, ReturnValue);
  }
  • 呼び出す関数を計算しないと行けない可能性があるのでEmitCalle
    • Calleは呼び出す方
1
  CGCallee callee = EmitCallee(E->getCallee());
  • callするfunctionはcalleeが戻ってくるっぽい
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee,
                                 const CallExpr *E, ReturnValueSlot ReturnValue,
                                 llvm::Value *Chain) {
  // Get the actual function type. The callee type will always be a pointer to
  // function type or a block pointer type.
  assert(CalleeType->isFunctionPointerType() &&
         "Call must have function pointer type!");

  const Decl *TargetDecl =
      OrigCallee.getAbstractInfo().getCalleeDecl().getDecl();

  CalleeType = getContext().getCanonicalType(CalleeType);

  auto PointeeType = cast<PointerType>(CalleeType)->getPointeeType();

  CGCallee Callee = OrigCallee;

  if (getLangOpts().CPlusPlus && SanOpts.has(SanitizerKind::Function) &&
      (!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
    if (llvm::Constant *PrefixSig =
            CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
      SanitizerScope SanScope(this);
      // Remove any (C++17) exception specifications, to allow calling e.g. a
      // noexcept function through a non-noexcept pointer.
      auto ProtoTy =

# back trace

1
2
3
4
5
6
7
#0  clang::CodeGen::CodeGenFunction::EmitCall (this=0x7fffffff7bc0, CalleeType=..., OrigCallee=..., E=0xe6bdc10,
   ReturnValue=..., Chain=0x0) at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGExpr.cpp:4881
#1  0x00000000039ae87e in clang::CodeGen::CodeGenFunction::EmitCallExpr (this=0x7fffffff7bc0, E=0xe6bdc10,
   ReturnValue=...) at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGExpr.cpp:4630
#2  0x00000000039e282e in (anonymous namespace)::ScalarExprEmitter::VisitCallExpr (this=0x7fffffff76e0,
   E=0xe6bdc10) at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGExprScalar.cpp:583
#3  0x00000000039f9b02 in clang::StmtVisitorBase<std::add_pointer, (anonymous namespace)::ScalarExprEmitter, llvm::Value*>::Visit (this=0x7fffffff76e0, S=0xe6bdc10) at tools/clang/include/clang/AST/StmtNodes.inc:801

# emi call

./clang/lib/CodeGen/CodeGenFunction.hっぽい

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
  //===--------------------------------------------------------------------===//
  //                         Scalar Expression Emission
  //===--------------------------------------------------------------------===//
  /// EmitCall - Generate a call of the given function, expecting the given
  /// result type, and using the given argument list which specifies both the
  /// LLVM arguments and the types they were derived from.
  RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
                  ReturnValueSlot ReturnValue, const CallArgList &Args,
                  llvm::CallBase **callOrInvoke, SourceLocation Loc);
  RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
                  ReturnValueSlot ReturnValue, const CallArgList &Args,
                  llvm::CallBase **callOrInvoke = nullptr) {
    return EmitCall(CallInfo, Callee, ReturnValue, Args, callOrInvoke,
                    SourceLocation());
  }
  RValue EmitCall(QualType FnType, const CGCallee &Callee, const CallExpr *E,
                  ReturnValueSlot ReturnValue, llvm::Value *Chain = nullptr);
  RValue EmitCallExpr(const CallExpr *E,

# EmitCall

  • ./clang/lib/CodeGen/CGCall.cppを見ていく
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/// Helper data structure to emit `AllocAlignAttr`.
class AllocAlignAttrEmitter final
    : public AbstractAssumeAlignedAttrEmitter<AllocAlignAttr> {
public:
  AllocAlignAttrEmitter(CodeGenFunction &CGF_, const Decl *FuncDecl,
                        const CallArgList &CallArgs)
      : AbstractAssumeAlignedAttrEmitter(CGF_, FuncDecl) {
    if (!AA)
      return;
    // Alignment may or may not be a constant, and that is okay.
    Alignment = CallArgs[AA->getParamIndex().getLLVMIndex()]
                    .getRValue(CGF)
                    .getScalarVal();
  }
};

} // namespace

RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
                                 const CGCallee &Callee,
                                 ReturnValueSlot ReturnValue,
                                 const CallArgList &CallArgs,
                                 llvm::CallBase **callOrInvoke,
                                 SourceLocation Loc) {
  // FIXME: We no longer need the types from CallArgs; lift up and simplify.

  assert(Callee.isOrdinary() || Callee.isVirtual());

  // Handle struct-return functions by passing a pointer to the
  // location that we would like to return into.
  QualType RetTy = CallInfo.getReturnType();
  const ABIArgInfo &RetAI = CallInfo.getReturnInfo();

  llvm::FunctionType *IRFuncTy = getTypes().GetFunctionType(CallInfo);

  const Decl *TargetDecl = Callee.getAbstractInfo().getCalleeDecl().getDecl();
  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl))
    // We can only guarantee that a function is called from the correct
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    unsigned FirstIRArg, NumIRArgs;
    std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);

    switch (ArgInfo.getKind()) {
    case ABIArgInfo::InAlloca: {
      assert(NumIRArgs == 0);
      assert(getTarget().getTriple().getArch() == llvm::Triple::x86);
      if (I->isAggregate()) {
        Address Addr = I->hasLValue()
                           ? I->getKnownLValue().getAddress(*this)
                           : I->getKnownRValue().getAggregateAddress();
        llvm::Instruction *Placeholder =
            cast<llvm::Instruction>(Addr.getPointer());

        if (!ArgInfo.getInAllocaIndirect()) {
          // Replace the placeholder with the appropriate argument slot GEP.
          CGBuilderTy::InsertPoint IP = Builder.saveIP();
          Builder.SetInsertPoint(Placeholder);
          Addr = Builder.CreateStructGEP(ArgMemory,
                                         ArgInfo.getInAllocaFieldIndex());
          Builder.restoreIP(IP);
        } else {
          // For indirect things such as overaligned structs, replace the
          // placeholder with a regular aggregate temporary alloca. Store the
          // address of this alloca into the struct.
          Addr = CreateMemTemp(info_it->type, "inalloca.indirect.tmp");
          Address ArgSlot = Builder.CreateStructGEP(
              ArgMemory, ArgInfo.getInAllocaFieldIndex());
          Builder.CreateStore(Addr.getPointer(), ArgSlot);
        }
        deferPlaceholderReplacement(Placeholder, Addr.getPointer());
      } else if (ArgInfo.getInAllocaIndirect()) {
        // Make a temporary alloca and store the address of it into the argument
        // struct.
        Address Addr = CreateMemTempWithoutCast(
            I->Ty, getContext().getTypeAlignInChars(I->Ty),
            "indirect-arg-temp");
        I->copyInto(*this, Addr);
        Address ArgSlot =

なんかLifeTimeSizeとか出てきた

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
        if (NeedCopy) {
          // Create an aligned temporary, and copy to it.
          Address AI = CreateMemTempWithoutCast(
              I->Ty, ArgInfo.getIndirectAlign(), "byval-temp");
          IRCallArgs[FirstIRArg] = AI.getPointer();

          // Emit lifetime markers for the temporary alloca.
          uint64_t ByvalTempElementSize =
              CGM.getDataLayout().getTypeAllocSize(AI.getElementType());
          llvm::Value *LifetimeSize =
              EmitLifetimeStart(ByvalTempElementSize, AI.getPointer());

          // Add cleanup code to emit the end lifetime marker after the call.
          if (LifetimeSize) // In case we disabled lifetime markers.
            CallLifetimeEndAfterCall.emplace_back(AI, LifetimeSize);

          // Generate the copy.
          I->copyInto(*this, AI);
        } else {
          // Skip the extra memcpy call.
          auto *T = V->getType()->getPointerElementType()->getPointerTo(
              CGM.getDataLayout().getAllocaAddrSpace());
          IRCallArgs[FirstIRArg] = getTargetHooks().performAddrSpaceCast(
              *this, V, LangAS::Default, CGM.getASTAllocaAddressSpace(), T,
              true);
        }
      }

このfunction call時のclean upなLifeTime操作

  • このルーチンが有効化されていると、TailCall最適化できない
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
4543   // If we made a temporary, be sure to clean up after ourselves. Note that we
4544   // can't depend on being inside of an ExprWithCleanups, so we need to manually
4545   // pop this cleanup later on. Being eager about this is OK, since this
4546   // temporary is 'invisible' outside of the callee.
4547   if (UnusedReturnSizePtr)
4548     pushFullExprCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker, SRetAlloca,
4549                                          UnusedReturnSizePtr);
4550
4551   llvm::BasicBlock *InvokeDest = CannotThrow ? nullptr : getInvokeDest();
4552
4553   SmallVector<llvm::OperandBundleDef, 1> BundleList =
4554       getBundlesForFunclet(CalleePtr);
4555
4556   if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
4557     if (FD->usesFPIntrin())
4558       // All calls within a strictfp function are marked strictfp
4559       Attrs =
4560         Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
4561                            llvm::Attribute::StrictFP);
4562
4563   AssumeAlignedAttrEmitter AssumeAlignedAttrEmitter(*this, TargetDecl);
4564   Attrs = AssumeAlignedAttrEmitter.TryEmitAsCallSiteAttribute(Attrs);
4565
4566   AllocAlignAttrEmitter AllocAlignAttrEmitter(*this, TargetDecl, CallArgs);
4567   Attrs = AllocAlignAttrEmitter.TryEmitAsCallSiteAttribute(Attrs);

このあたりも関係してそう

1
2
3
4
5
6
7
8
9
4789   }
4790
4791   // Explicitly call CallLifetimeEnd::Emit just to re-use the code even though
4792   // we can't use the full cleanup mechanism.
4793   for (CallLifetimeEnd &LifetimeEnd : CallLifetimeEndAfterCall)
4794     LifetimeEnd.Emit(*this, /*Flags=*/{});
4795
4796   return Ret;
4797 }

Tail Call関連

1
2
3
4
5
6
4619	  // Suppress tail calls if requested.
4620	  if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI)) {
4621	    if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
(gdb) l
4622	      Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
4623	  }

# 使ったbreak point

1
2
3
4
5
6
7
Num     Type           Disp Enb Address            What
3       breakpoint     keep y   0x00000000039b0d76 in clang::CodeGen::CodeGenFunction::EmitCall(clang::QualType, clang::CodeGen::CGCallee const&, clang::CallExpr const*, clang::CodeGen::ReturnValueSlot, llvm::Value*)
                                                   at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGExpr.cpp:5047
	breakpoint already hit 1 time
4       breakpoint     keep y   0x000000000393619f in clang::CodeGen::CodeGenFunction::EmitCall(clang::CodeGen::CGFunctionInfo const&, clang::CodeGen::CGCallee const&, clang::CodeGen::ReturnValueSlot, clang::CodeGen::CallArgList const&, llvm::CallBase**, clang::SourceLocation)
                                                   at /mnt/dalmore-home/one/src/LLVM_original/clang/lib/CodeGen/CGCall.cpp:4547
breakpoint already hit 1 time

# 作ってそう?

  • CreateCallとかcreateBasicBlockとかしている
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
4566   AllocAlignAttrEmitter AllocAlignAttrEmitter(*this, TargetDecl, CallArgs);
4567   Attrs = AllocAlignAttrEmitter.TryEmitAsCallSiteAttribute(Attrs);
4568
4569   // Emit the actual call/invoke instruction.
4570   llvm::CallBase *CI;
4571   if (!InvokeDest) {
4572     CI = Builder.CreateCall(IRFuncTy, CalleePtr, IRCallArgs, BundleList);
4573   } else {
4574     llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
4575     CI = Builder.CreateInvoke(IRFuncTy, CalleePtr, Cont, InvokeDest, IRCallArgs,
4576                               BundleList);
4577     EmitBlock(Cont);
4578   }
4579   if (callOrInvoke)
4580     *callOrInvoke = CI;
4

# コード生成文

  • return Insert(CI, Name)で呼び出しているのが生成してそう
  • 多分 llvm/include/llvm/IR/IRBuilder.hで呼ばれているもの
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
llvm::IRBuilder<llvm::ConstantFolder, clang::CodeGen::CGBuilderInserter>::Insert<llvm::CallInst> (
    this=0x7fffffff7ca8, I=0xe6c2ee0, Name=...)
    at /mnt/dalmore-home/one/src/LLVM_original/llvm/include/llvm/IR/IRBuilder.h:993
993	    this->InsertHelper(I, Name, BB, InsertPt);
(gdb) l
988	  const T &getFolder() { return Folder; }
989
990	  /// Insert and return the specified instruction.
991	  template<typename InstTy>
992	  InstTy *Insert(InstTy *I, const Twine &Name = "") const {
993	    this->InsertHelper(I, Name, BB, InsertPt);
994	    this->SetInstDebugLocation(I);
995	    return I;
996	  }

ここのllvm::IRBuilderでコード生成されていそう

  • このInsertHelperが何をしているかによりそう
  • これ自体はtemplateなので109個のInsertが存在している
    • instruction typeの数だけ
    • call/add/条件分岐, 代入とか…
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy