How to create MachineNode and replace the former one?

6

Environment :
llvm-project-llvmorg-10.0.0
ubuntu 20.04

Question :
I’m developing a new backend for LoongArch. For LLVM ISD SMUL_LOHI, which multiply two integers of type iN, producing a signed/unsigned value of type i[2*N], and return the full value as two results, each of type iN (Some thing like :
t42: i32,i32 = smul_lohi t38, t35
I need to replace it by LoongArch instruction MULH_W and MUL_W. The two instructions’ format as below:

That is, to use MUL_W to get the Lo result of mutiplicaiton and use MULH_W to get the High result of mutipication, and then replace the 2 results of UMUL_LOHI. I catched SMUL_LOHI by trySelect() in LoongArchSEISelDAGToDAG as below:

I’m sure the trySelect() run correctly and it does catched UMUL_LOHI Node, I use gdb to test this:

7

I can run llc command and generate .s file successfully, but its output is out of logic
I use the following code to test UMUL_LOHI :

long long test()
{
    long long a = 0x300000002;
    long long b = 0x100000001;
    long long d = a * b;  // d = 0x00000005,00000002
   
    return d;
}

the .ll file corresponding to the C program is :

define dso_local i64 @test() #0 {
  %1 = alloca i64, align 8
  %2 = alloca i64, align 8
  %3 = alloca i64, align 8
  store i64 12884901890, i64* %1, align 8
  store i64 4294967297, i64* %2, align 8
  %4 = load i64, i64* %1, align 8
  %5 = load i64, i64* %2, align 8
  %6 = mul nsw i64 %4, %5
  store i64 %6, i64* %3, align 8
  %7 = load i64, i64* %3, align 8
  ret i64 %7
}

the corresponding .s file is:


test:
# %bb.0:
	addi.w	$r3, $r3, -32
	addi.w	$r4, $r3, 24
	ori	$r4, $r4, 4
	addi.w	$r5, $r0, 3
	st.w	$r5, $r4, 0
	addi.w	$r5, $r0, 2
	st.w	$r5, $r3, 24
	addi.w	$r5, $r3, 16
	ori	$r5, $r5, 4
	addi.w	$r6, $r0, 1
	st.w	$r6, $r5, 0
	st.w	$r6, $r3, 16
	ld.w	$r4, $r4, 0
	ld.w	$r6, $r3, 24
	ld.w	$r5, $r5, 0
	ld.w	$r7, $r3, 16
	mul.w	$r5, $r6, $r5
	mulh.wu	$r8, $r6, $r7
	add.w	$r5, $r8, $r5
	mul.w	$r4, $r4, $r7
	add.w	$r4, $r5, $r4
	mul.w	$r5, $r6, $r7
	addi.w	$r6, $r3, 8
	ori	$r6, $r6, 4
	st.w	$r4, $r6, 0
	st.w	$r5, $r3, 8
	ld.w	$r5, $r6, 0
	ld.w	$r4, $r3, 8
	addi.w	$r3, $r3, 32
	jr	$r1

As you can see, there is a i64 mul instruction in IR, which will be translated to llvm UMUL_LOHI,
my backend catched, and translate it to mul.w and mulh.wu successfully. But my backend misuse the result of them. For the following Code fragment in .s file :

     mul.w	$r5, $r6, $r5
	mulh.wu	$r8, $r6, $r7
	add.w	$r5, $r8, $r5

It gets the Lo result in r5 and the hi result in r8, the next work it needs to do is to store them into stack, but it add them up :thinking: My register is 32-bit , so this add operation is definely incorrect. I guess this strange output is because I did something wrong when I replaced the node .

I am really a beginner of LLVM, Could any one help me with it? Thank you very much !

If you want to check out the whole project, please check :

You should explain what the problem is; so far you’ve just said what you’ve done, but it’s not clear what specifically you’re getting that’s not what you intend.

1 Like

Sorry, sir.
I will fill out my question in the description