i32型の変数を引数として渡した関数の場合は、レジスタもスタックもサイズはi32で考えているのでこの場合は問題ないのだが、ではi32よりも小さな型の引数を渡す場合にはどのような処理になっているのだろうか。
この場合は呼び出し規約のルールで型の拡張を行っている。この時には、AssertSext
もしくはAssertZext
ノードを挿入する必要がある。このノードは2つのオペランドを持っており、1つは拡張された値そのもの、そしてもう一つは拡張前の値のビットサイズだ。
AssertSext |
レジスタに保持できる値よりも小さな値を保持している場合に挿入される。オリジナルの値よりも符号拡張された値が格納されていることを示す。 | オペランド1: 値そののもの オペランド2. 符号拡張される前の型 |
AssertZext |
レジスタに保持できる値よりも小さな値を保持している場合に挿入される。オリジナルの値よりも符号なし拡張された値が格納されていることを示す。 | オペランド1: 値そののもの オペランド2. 無し拡張される前の型 |
TRUNCATE |
上位ビットを除去する。 |
ch9_1_extend.cpp
int sum_i(short x1, short x2) { int sum = x1 + x2; return sum; }
引数の型がshort(=i16)
なのでi32に拡張が行われれ、さらにTRUNCATE
が挿入されるはずだ。具体的にDAGを生成してみよう。
./bin/clang -O3 -target mips-unknown-linux-gnu -c ../lbdex/input/ch9_1_extend.cpp -emit-llvm ./bin/llc -view-dag-combine1-dags -march=myriscvx32 -mcpu=simple32 -relocation-model=pic -filetype=asm -target-abi=lp32 ch9_1_extend.bc -o -
DAGをプロットしてみると、以下のようになった。
2つの引数について、まずAssertSext
が挿入されている。AssertSext
の1つ目の分岐には値そのものが接続されており、もう一つの分岐には元の値を示すノードValueType:i16
が接続されている。次にtruncate
で、上位ビットを削って実際の引数の型を元に戻すノードが挿入されている。