LLVM Backend Code compilation

I build a simple (just to try and to learn roughly) LLVM Backend for custom RISC-V.
I simply convert sequential add and multiply to one instruction as in many examples to explain selectionDAG. After I built, I couldn’t compile the code below.

C code:

int a,b,c;

void maddFunc() {
	a = 3;
	b = 103;
	
	c = 127;
	a = a * b +c;
}

ll Code:

	.text
	.attribute	4, 16
	.attribute	5, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0_v1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0"
	.file	"madd.c"
	.globl	maddFunc
	.p2align	1
	.type	maddFunc,@function
maddFunc:
	addi	sp, sp, -16
	sd	ra, 8(sp)
	sd	s0, 0(sp)
	addi	s0, sp, 16
	lui	a1, %hi(a)
	li	a0, 3
	sw	a0, %lo(a)(a1)
	lui	a3, %hi(b)
	li	a0, 103
	sw	a0, %lo(b)(a3)
	lui	a2, %hi(c)
	li	a0, 127
	sw	a0, %lo(c)(a2)
	lw	a0, %lo(a)(a1)
	lw	a3, %lo(b)(a3)
	mulw	a0, a0, a3
	lw	a2, %lo(c)(a2)
	addw	a0, a0, a2
	sw	a0, %lo(a)(a1)
	ld	ra, 8(sp)
	ld	s0, 0(sp)
	addi	sp, sp, 16
	ret
.Lfunc_end0:
	.size	maddFunc, .Lfunc_end0-maddFunc

	.type	a,@object
	.section	.sbss,"aw",@nobits
	.globl	a
	.p2align	2
a:
	.word	0
	.size	a, 4

	.type	b,@object
	.globl	b
	.p2align	2
b:
	.word	0
	.size	b, 4

	.type	c,@object
	.globl	c
	.p2align	2
c:
	.word	0
	.size	c, 4

	.ident	"clang version 14.0.0"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym a
	.addrsig_sym b
	.addrsig_sym c

The command that I used to compile from C to ll file is /home/llvm/Downloads/clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04/bin/clang-14 -S -emit-llvm -g madd.c. The command that I used to convert ll to s file is /home/llvm/llvm-project/FirstTrial/bin/llc -mtriple=riscv32 madd.ll.
However, I am getting an error like that:

'x86-64' is not a recognized processor for this target (ignoring processor)
'generic' is not a recognized processor for this target (ignoring processor)
'+cx8' is not a recognized feature for this target (ignoring feature)
'+fxsr' is not a recognized feature for this target (ignoring feature)
'+mmx' is not a recognized feature for this target (ignoring feature)
'+sse' is not a recognized feature for this target (ignoring feature)
'+sse2' is not a recognized feature for this target (ignoring feature)
'+x87' is not a recognized feature for this target (ignoring feature)
'generic' is not a recognized processor for this target (ignoring processor)
'x86-64' is not a recognized processor for this target (ignoring processor)
'generic' is not a recognized processor for this target (ignoring processor)
'+cx8' is not a recognized feature for this target (ignoring feature)
'+fxsr' is not a recognized feature for this target (ignoring feature)
'+mmx' is not a recognized feature for this target (ignoring feature)
'+sse' is not a recognized feature for this target (ignoring feature)
'+sse2' is not a recognized feature for this target (ignoring feature)
'+x87' is not a recognized feature for this target (ignoring feature)
'generic' is not a recognized processor for this target (ignoring processor)

Is this mean that I can compile my code successfully ? or there is an error? because it creates s file which seems correct. The problematic part is I cannot see that my new instruction in the final assembly file. It should be about either use of llc or the code that I wrote for selection dag.

Clang generates different IR depending on what it’s targeting. For simple functions like yours, the differences are minimal, really just these feature attributes that tell the backend what instructions it’s allowed to use.

So when the IR is read by the RISC-V backend instead of X86 it has no idea what SSE2 is so warns about that (it is just a warning, as you noticed it still managed to produce code).

The best fix is probably to add -target riscv32-linux-gnu to the Clang command-line; then it really will be RISC-V IR that’s produced; as well as silencing these warnings it’ll head off lots of compatibility headaches if you ever try compiling bigger programs or running code.

I think you’ve accidentally broken your Pat. When I use this one from the other thread:

def : Pat<  (add (mul GPR:$src1, GPR:$src2), GPR:$src3),
            (MLA GPR:$src1, GPR:$src2, GPR:$src3)>;

I see an mla instruction.

Though I’m not quite sure how you’re getting a mul instruction like that. I have to specify a CPU or -mattr=+m or I get a libcall. The -target fix for Clang should cover any discrepancy there though.

1 Like

Adding -target riscv32-linux-gnu solved my problem. Also, I was able to see the mla instruction in the final assembly code.
However, I didn’t understand your last words:

Though I’m not quite sure how you’re getting a mul instruction like that. I have to specify a CPU or -mattr=+m or I get a libcall.

Could you explain again, please?

Never mind, I think I’ve worked out what’s different between us. You’re on Linux and I’m on MacOS so it’s inferring the rest of the triple differently for us.

It meant that instead of the mulw a0, a0, a3 you saw, I was getting call __mulsi3@plt (because it thought my CPU didn’t have a native multiply instruction).

1 Like

Ok, I got it.
Thank you so much. I achieved my first working LLVM Backend. You contributed a lot thank you so much.