5.18 純関数と非純関数の比較

__pure キーワードの使用法を、以下の表の 2 つのサンプルルーチンに示します。

いずれのルーチンも、関数 fact() を呼び出して、n!n! の合計を計算します。.fact() は、n! の計算に入力引数 n しか使用しません。そのため、fact() は純関数であると言えます。
最初のルーチンは、関数 fact() のネイティブ実装を示しています。ここで、fact()__pure として宣言されていません。2 番目のルーチンでは、fact() が純関数であることをコンパイラに通知するために、__pure として修飾されています。

表 5-7 純関数および非純関数を表す 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);
}
以下の表は、コンパイラによって生成されたマシンコードが、上述の各実装例でどのように逆アセンブルされるかを示したものです。いずれの実装の C コードも、オプション -O2 を使用してコンパイルされ、インライン展開が抑止されています。

表 5-8 純関数および非純関数を表す逆アセンブリコード

__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
fact()__pure として修飾されていない逆アセンブリでは、この関数が共通部分式の削除(CSE)の対象であることを認識しないので、fact() は 2 回呼び出されます。一方、fact()__pure として修飾されている逆アセンブリではコンパイラは fact(n) + fact(n) の追加時に CSE を実行することに成功しているので、fact() は 1 回しか呼び出されません。
関連する概念
5.17 同じ引数を使用して呼び出されたときに同じ結果を返す関数
関連する参考文書
10.13 __pure
非機密扱いPDF file icon PDF 版ARM DUI0472LJ
Copyright © 2010-2015 ARM.All rights reserved.