🐥

C言語でforループ内にifが入る場合の挙動をアセンブリレベルで確認する

に公開

サマリ

C言語で通常のfor文、ifを内部に入れたfor文、最適化オプションを入れたもののアセンブリレベルでの比較を行いました。

マシンスペック

MacBook Air M2 arm64

1. 通常のforループの挙動

まずは通常のforループの挙動です。
単純な加算を行います。

#include <stdio.h>

int main() {
    int sum = 0;
    for (int i = 0; i < 100; i++) {
        sum += i;
    }
    printf("%d\n", sum);
    return 0;
}

下記のコマンドで、コンパイルしてアセンブリの内容が確認できます。

gcc -S -o simple_loop.s simple_loop.c
cat simple_loop.s

下記が出力結果です。

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 14, 0    sdk_version 14, 4
    .globl    _main                           ; -- Begin function main
    .p2align    2
_main:                                  ; @main
    .cfi_startproc
; %bb.0:
    sub    sp, sp, #48
    .cfi_def_cfa_offset 48
    stp    x29, x30, [sp, #32]             ; 16-byte Folded Spill
    add    x29, sp, #32
    .cfi_def_cfa w29, 16
    .cfi_offset w30, -8
    .cfi_offset w29, -16
    stur    wzr, [x29, #-4]
    stur    wzr, [x29, #-8]
    stur    wzr, [x29, #-12]
    b    LBB0_1
LBB0_1:                                 ; =>This Inner Loop Header: Depth=1
    ldur    w8, [x29, #-12]
    subs    w8, w8, #100
    cset    w8, ge
    tbnz    w8, #0, LBB0_4
    b    LBB0_2
LBB0_2:                                 ;   in Loop: Header=BB0_1 Depth=1
    ldur    w9, [x29, #-12]
    ldur    w8, [x29, #-8]
    add    w8, w8, w9
    stur    w8, [x29, #-8]
    b    LBB0_3
LBB0_3:                                 ;   in Loop: Header=BB0_1 Depth=1
    ldur    w8, [x29, #-12]
    add    w8, w8, #1
    stur    w8, [x29, #-12]
    b    LBB0_1
LBB0_4:
    ldur    w9, [x29, #-8]
                                        ; implicit-def: $x8
    mov    x8, x9
    mov    x9, sp
    str    x8, [x9]
    adrp    x0, l_.str@PAGE
    add    x0, x0, l_.str@PAGEOFF
    bl    _printf
    mov    w0, #0
    ldp    x29, x30, [sp, #32]             ; 16-byte Folded Reload
    add    sp, sp, #48
    ret
    .cfi_endproc
                                        ; -- End function
    .section    __TEXT,__cstring,cstring_literals
l_.str:                                 ; @.str
    .asciz    "%d\n"

.subsections_via_symbols

2. forループの中にifを入れた場合

次に、forの中にif文を入れて条件分岐を追加した場合です。
偶数の時に加算するようにしてみました。

#include <stdio.h>

int main() {
    int sum = 0;
    for (int i = 0; i < 100; i++) {
        if (i % 2 == 0) {
            sum += i;
        }
    }
    printf("%d\n", sum);
    return 0;
}

アセンブリファイルを確認します。

gcc -S -o loop_if.s loop_if.c
cat loop_if.s
    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 14, 0    sdk_version 14, 4
    .globl    _main                           ; -- Begin function main
    .p2align    2
_main:                                  ; @main
    .cfi_startproc
; %bb.0:
    sub    sp, sp, #48
    .cfi_def_cfa_offset 48
    stp    x29, x30, [sp, #32]             ; 16-byte Folded Spill
    add    x29, sp, #32
    .cfi_def_cfa w29, 16
    .cfi_offset w30, -8
    .cfi_offset w29, -16
    stur    wzr, [x29, #-4]
    stur    wzr, [x29, #-8]
    stur    wzr, [x29, #-12]
    b    LBB0_1
LBB0_1:                                 ; =>This Inner Loop Header: Depth=1
    ldur    w8, [x29, #-12]
    subs    w8, w8, #100
    cset    w8, ge
    tbnz    w8, #0, LBB0_6
    b    LBB0_2
LBB0_2:                                 ;   in Loop: Header=BB0_1 Depth=1
    ldur    w8, [x29, #-12]
    mov    w10, #2
    sdiv    w9, w8, w10
    mul    w9, w9, w10
    subs    w8, w8, w9
    subs    w8, w8, #0
    cset    w8, ne
    tbnz    w8, #0, LBB0_4
    b    LBB0_3
LBB0_3:                                 ;   in Loop: Header=BB0_1 Depth=1
    ldur    w9, [x29, #-12]
    ldur    w8, [x29, #-8]
    add    w8, w8, w9
    stur    w8, [x29, #-8]
    b    LBB0_4
LBB0_4:                                 ;   in Loop: Header=BB0_1 Depth=1
    b    LBB0_5
LBB0_5:                                 ;   in Loop: Header=BB0_1 Depth=1
    ldur    w8, [x29, #-12]
    add    w8, w8, #1
    stur    w8, [x29, #-12]
    b    LBB0_1
LBB0_6:
    ldur    w9, [x29, #-8]
                                        ; implicit-def: $x8
    mov    x8, x9
    mov    x9, sp
    str    x8, [x9]
    adrp    x0, l_.str@PAGE
    add    x0, x0, l_.str@PAGEOFF
    bl    _printf
    mov    w0, #0
    ldp    x29, x30, [sp, #32]             ; 16-byte Folded Reload
    add    sp, sp, #48
    ret
    .cfi_endproc
                                        ; -- End function
    .section    __TEXT,__cstring,cstring_literals
l_.str:                                 ; @.str
    .asciz    "%d\n"

.subsections_via_symbols

3. 最適化オプションを付与してみる

最適化オプションを付与して、2の内容をコンパイルして同様に確認してみます。

gcc -O2 -S -o loop_if_optimized.s loop_if.c
cat loop_if_optimized.s

結果は以下の通りです。

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 14, 0    sdk_version 14, 4
    .globl    _main                           ; -- Begin function main
    .p2align    2
_main:                                  ; @main
    .cfi_startproc
; %bb.0:
    sub    sp, sp, #32
    .cfi_def_cfa_offset 32
    stp    x29, x30, [sp, #16]             ; 16-byte Folded Spill
    add    x29, sp, #16
    .cfi_def_cfa w29, 16
    .cfi_offset w30, -8
    .cfi_offset w29, -16
    mov    w8, #2450
    str    x8, [sp]
Lloh0:
    adrp    x0, l_.str@PAGE
Lloh1:
    add    x0, x0, l_.str@PAGEOFF
    bl    _printf
    mov    w0, #0
    ldp    x29, x30, [sp, #16]             ; 16-byte Folded Reload
    add    sp, sp, #32
    ret
    .loh AdrpAdd    Lloh0, Lloh1
    .cfi_endproc
                                        ; -- End function
    .section    __TEXT,__cstring,cstring_literals
l_.str:                                 ; @.str
    .asciz    "%d\n"

.subsections_via_symbols

Discussion