例えば、以下のようなプログラムをコンパイルする。 このプログラムは命令を生成する段階でローテートを示すIRを生成する。
int test_rotate_left() { unsigned int a = 8; int result = ((a << 30) | (a >> 2)); return result; }
./bin/clang -target mips-unknown-linux-gnu -c ../lbdex/input/ch4_1_rotate.cpp -emit-llvm ./bin/llc -debug -march=myriscvx32 -mcpu=simple32 -mattr=+64bit -relocation-model=pic -filetype=asm ch4_1_rotate.bc -o -
... Combining: t12: i32 = FrameIndex<1> Combining: t11: i32 = or t8, t10 Creating new node: t18: i32 = rotl t6, Constant:i32<30> ... into: t18: i32 = rotl t6, Constant:i32<30> Combining: t13: ch = store<(store 4 into %ir.result)> t6:1, t18, FrameIndex:i32<1>, undef:i32 ...
最終的に、rotl
を命令に変換しようとするが、当然エラーとなる。
ISEL: Starting pattern match Initial Opcode index to 0 Match failed at index 0 LLVM ERROR: Cannot select: t18: i32 = rotl t6, Constant:i32<30> t6: i32,ch = load<(dereferenceable load 4 from %ir.a)> t5, FrameIndex:i32<0>, undef:i32 t2: i32 = FrameIndex<0> t4: i32 = undef t7: i32 = Constant<30> In function: _Z16test_rotate_leftv
このような場合どうすればよいのかというと、MYRISCVXTargetLowering
に以下を追加する。
llvm-myriscvx/lib/Target/MYRISCVX/MYRISCVXSEISelLowering.cpp
//@MYRISCVXSETargetLowering { MYRISCVXSETargetLowering::MYRISCVXSETargetLowering(const MYRISCVXTargetMachine &TM, const MYRISCVXSubtarget &STI) ... setOperationAction(ISD::ROTL, MVT::i32, Expand); setOperationAction(ISD::ROTR, MVT::i32, Expand); }
llvm::TargetLoweringBase::setOperationAction
は、特定の命令においてターゲットアーキテクチャでのネイティブ命令が生成できない場合に指定する。これにより、一般的な命令に分解を行い命令を生成する。
./bin/llc -debug -march=myriscvx32 -mcpu=simple32 -mattr=+64bit -relocation-model=pic -filetype=asm ch4_1_rotate.bc -o -
addi x2, x2, -8 addi x10, zero, 8 sw x10, 4(x2) lw x10, 4(x2) slli x11, x10, 30 srli x10, x10, 2 or x10, x11, x10 sw x10, 0(x2) lw x10, 0(x2) addi x2, x2, 8 ret x1