I tried to define two intrinsics to read and write an implicit registers. But clang does not seem to recognize them correctly, so that the function is removed with ‘-O2’ option.
- The definition of intrinsics is as follows:
// to prevent "IntrHasSideEffects" be overwritten, didn't use "IntrReadmem"
class ImplicitRegLoad: Intrinsic<[], [llvm_i32_ty, LLVMPointerType<llvm_i32_ty>],
[IntrHasSideEffects]>;
class ImplicitRegRead: Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrHasSideEffects]>;
def int_riscv_loadToReg: ImplicitRegLoad;
def int_riscv_readFromReg: ImplicitRegRead;
- The source code for test case is as follows:
#include <stdio.h>
#include <stdlib.h>
int data[4] = {0xffff5555, 0x12345678, 0x77777777, 0x00000001};
int main(int argc, char *argv[]) {
int test_value;
__builtin_riscv_loadToReg(28, &data[0]); /* load data to implicit reg */
test_value = __builtin_riscv_readFromReg(28);/* read data from implicit reg */
if (test_value != 0xffff5555) {/* check reg value */
printf("fail1\n");
exit(1);
}
__builtin_riscv_loadToReg(28, &data[2]);
test_value = __builtin_riscv_readFromReg(28);
if (test_value != 0x77777777) {
printf("fail2\n");
exit(2);
}
printf("pass\n");
return 0;
}
- The compilation command used is as follows:
clang --target=riscv32 -march=rv32imafcv -emit-llvm -S -O2 foo.cpp -o foo.ll
The main code in file “foo.ll” is as follows:
entry:(main)
// first branch, load data to implicit register
tail call void @llvm.riscv.loadToReg(i32 0, i32* getelementptr inbounds ([4 x i32], [4 x i32]* @data, i32 0, i32 0))
// first branch, read data from implicit register
%0 = tail call i32 @llvm.riscv.readFromReg(i32 0)
%cmp.not.i = icmp eq i32 %0, -43691
br i1 %cmp.not.i, label %if.then.i19, label %if.then.i
if.then.i: ; preds = %entry
%call.i = tail call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @.str.1, i32 0, i32 0), i32 noundef 1, i32 noundef %0, i32 noundef -43691)
tail call void @exit(i32 noundef 1) #4
unreachable
if.then.i19: ; preds = %entry
// second branch, load new data to implicit register
tail call void @llvm.riscv.loadToReg(i32 0, i32* getelementptr inbounds ([4 x i32], [4 x i32]* @data, i32 0, i32 1))
// llvm.riscv.readFromReg not exist!!! It was eliminated by optimization
%call.i18 = tail call i32 (i8*, ...) @printf(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([60 x i8], [60 x i8]* @.str.1, i32 0, i32 0), i32 noundef 2, i32 noundef -43691, i32 noundef 305419896)
tail call void @exit(i32 noundef 2) #4
unreachable
}
As we can see, clang treat the second call of ‘readFromReg’ as redundant call, the property ‘IntrHasSideEffects’ does not prevent this optimization.
I don’t know what to do so that clang with ‘-O2’ option doesn’t over-optimize my intrinsic, and the clang version is 14.0.6. Any suggestions would be helpful, thanks!