純関数と非純関数の比較

__pure キーワードの使用法を、Table 14 の 2 つのサンプルルーチンに示します。いずれのルーチンも、関数 fact() を呼び出して、n!n! の合計を計算します。fact() は、n! の計算に入力引数しか使用しません。そのため、fact() は純関数であると言えます。

最初のルーチンは、関数 fact() のネイティブ実装を示しています。ここで、fact()__pure として宣言されていません。2 番目のルーチンでは、fact() が純関数であることをコンパイラに通知するために、__pure として修飾されています。

Table 14. 純関数および非純関数を表す C コード

__pure として宣言されていない純関数__pure として宣言されている純関数
int fact(int n)
{
    int f = 1;
    while (n > 0)
        f *= n--;
    return f;
} 
int foo(int n)
{
    return fact(n)+fact(n);
}
int fact(int n) __pure
{
    int f = 1;
    while (n > 0)
        f *= n--;
    return f;
}
int foo(int n)
{
    return fact(n)+fact(n);
}

Table 15 は、コンパイラによって生成されたマシンコードがTable 14 の各実装例でどのように逆アセンブルされるかを示したものです。いずれの実装の C コードも、オプション -O2 を使用してコンパイルされ、インライン展開が抑止されています。

Table 15. 純関数および非純関数を表す逆アセンブリコード

__pure として宣言されていない純関数__pure として宣言されている純関数
fact PROC
    ...
foo PROC
    MOV      r3, r0
    PUSH     {lr}
    BL       fact
    MOV      r2, r0
    MOV      r0, r3
    BL       fact
    ADD      r0, r0, r2
    POP      {pc}
    ENDP
fact PROC
    ...
foo PROC
    PUSH     {lr}
    BL       fact
    LSL      r0,r0,#1
    POP      {pc}
    ENDP

Table 15 に示す関数 foo() の逆アセンブリでは、fact()__pure として修飾されていません。コンパイラは関数 fact()共通部分式の削除(CSE)の対象であることを認識しないので、この関数は 2 回呼び出されます。一方、Table 15 に示す foo() の逆アセンブリでは、fact()__pure として修飾されています。コンパイラは fact(n) + fact(n) の追加時に CSE を実行することに成功しているので、fact() は 1 度しか呼び出されません。

Show/hide関連項目

Copyright © 2010 ARM. All rights reserved.ARM DUI 0472BJ
Non-ConfidentialID011811