RISC-V: Update parser to use x-register names, add vector and FP instructions, fix tests

- Modified RISC-V parser to use x-register names instead of ABI names
- Added new vector instructions (vsetvli, vle8.v, vse8.v, vfmacc.vv, vfmul.vf)
- Added floating point instructions (fmul.d)
- Added unconditional jump instruction (j)
- Updated tests to match new register naming convention
- Added new RISC-V example files
- Updated .gitignore to exclude test environment and old examples
This commit is contained in:
Metehan Dundar
2025-06-30 00:28:52 +02:00
parent 1c2be468d9
commit 074118dee0
30 changed files with 762 additions and 1266 deletions

2
.gitignore vendored
View File

@@ -1,5 +1,7 @@
# OSACA specific files and folders
*.*.pickle
osaca_testfront_venv/
examples/riscy_asm_files/
# Byte-compiled / optimized / DLL files
__pycache__/

View File

@@ -1,24 +0,0 @@
# Makefile for RISC-V add example
CC = gcc
CFLAGS = -O3
CFLAGS_VEC = -O3 -march=rv64gcv
# Default target with -O3
all: add_riscv add_riscv_vec
# Build with -O3 optimization
add_riscv: add_riscv.c
$(CC) $(CFLAGS) -o add_riscv add_riscv.c
$(CC) $(CFLAGS) -S -o add_riscv.s add_riscv.c
# Build with vector extensions
add_riscv_vec: add_riscv.c
$(CC) $(CFLAGS_VEC) -o add_riscv_vec add_riscv.c
$(CC) $(CFLAGS_VEC) -S -o add_riscv_vec.s add_riscv.c
# Clean up
clean:
rm -f add_riscv add_riscv_vec add_riscv.s add_riscv_vec.s
.PHONY: all clean

View File

@@ -0,0 +1,13 @@
add_riscv:
.L3:
vsetvli a5,a3,e64,m1,ta,ma
vle64.v v2,0(a1)
vle64.v v1,0(a2)
slli a4,a5,3
sub a3,a3,a5
add a1,a1,a4
add a2,a2,a4
vfadd.vv v1,v1,v2
vse64.v v1,0(a0)
add a0,a0,a4
bne a3,zero,.L3

View File

@@ -1,54 +0,0 @@
// Vector add benchmark for RISC-V testing
// a[i] = b[i] + c[i]
#include <stdio.h>
#include <stdlib.h>
#define DTYPE double
void kernel(DTYPE* a, DTYPE* b, DTYPE* c, const int size)
{
// OSACA start marker will be added around this loop
for(int i=0; i<size; i++) {
a[i] = b[i] + c[i];
}
// OSACA end marker will be added
}
int main(int argc, char *argv[]) {
int size = 1000;
if(argc > 1) {
size = atoi(argv[1]);
}
printf("RISC-V Vector add: a[i] = b[i] + c[i], size=%d\n", size);
// Allocate memory
DTYPE* a = (DTYPE*)malloc(size * sizeof(DTYPE));
DTYPE* b = (DTYPE*)malloc(size * sizeof(DTYPE));
DTYPE* c = (DTYPE*)malloc(size * sizeof(DTYPE));
// Initialize arrays
for(int i=0; i<size; i++) {
a[i] = 0.0;
b[i] = i;
c[i] = i * 2.0;
}
// Run kernel
kernel(a, b, c, size);
// Check result (to prevent optimization)
DTYPE checksum = 0.0;
for(int i=0; i<size; i++) {
checksum += a[i];
}
printf("Checksum: %f\n", checksum);
// Cleanup
free(a);
free(b);
free(c);
return 0;
}

View File

@@ -0,0 +1,9 @@
copy_riscv:
.L3:
vsetvli a5,a2,e8,m1,ta,ma
vle8.v v1,0(a1)
sub a2,a2,a5
add a1,a1,a5
vse8.v v1,0(a0)
add a0,a0,a5
bne a2,zero,.L3

View File

@@ -0,0 +1,13 @@
daxpy_riscv:
.L3:
vsetvli a5,a2,e64,m1,ta,ma
vle64.v v1,0(a0)
vle64.v v2,0(a1)
slli a3,a5,3
sub a2,a2,a5
add a0,a0,a3
add a1,a1,a3
vfmacc.vv v1,v3,v2
vse64.v v1,0(a4)
add a4,a4,a3
bne a2,zero,.L3

View File

@@ -0,0 +1,16 @@
gs_riscv:
.L5:
fld fa2,0(a3)
fld fa3,0(a5)
fld fa4,0(a4)
fadd.d fa5,fa5,fa2
addi a5,a5,8
addi a3,a3,8
addi a4,a4,8
fadd.d fa5,fa5,fa3
fadd.d fa5,fa5,fa4
fmul.d fa5,fa5,fa0
fsd fa5,-16(a5)
bne a2,a5,.L5
addi a0,a0,8
bne a6,a0,.L4

View File

@@ -0,0 +1,44 @@
j2d_riscv:
.L5:
vsetvli a5,a7,e64,m1,ta,ma
vle64.v v4,0(t1)
vle64.v v1,0(a0)
vle64.v v3,0(t3)
vle64.v v2,0(a6)
slli a4,a5,3
sub a7,a7,a5
add t1,t1,a4
vfadd.vv v1,v1,v4
add a0,a0,a4
add t3,t3,a4
add a6,a6,a4
vfadd.vv v1,v1,v3
vfadd.vv v1,v1,v2
vfmul.vf v1,v1,fa4
vse64.v v1,0(a2)
add a2,a2,a4
bne a7,zero,.L5
addi t5,t5,1
addi a1,a1,8
addi t4,t4,8
bne t5,t0,.L4
.L7:
fld fa5,0(a0)
fld fa1,-16(a5)
fld fa2,0(a5)
fld fa3,0(a6)
fadd.d fa5,fa5,fa1
addi a5,a5,8
addi a0,a0,8
addi a6,a6,8
addi a2,a2,8
fadd.d fa5,fa5,fa2
fadd.d fa5,fa5,fa3
fmul.d fa5,fa5,fa4
fsd fa5,-8(a2)
bne a5,t1,.L7
addi t5,t5,1
addi a1,a1,8
addi t4,t4,8
bne t5,t0,.L4
j .L17

View File

@@ -1,178 +0,0 @@
.file "add_riscv.c"
.option pic
.attribute arch, "rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 1
.globl kernel
.type kernel, @function
kernel:
.LFB22:
.cfi_startproc
ble a3,zero,.L1
slli a3,a3,3
add a5,a1,a3
.L3:
fld fa5,0(a1)
fld fa4,0(a2)
addi a1,a1,8
addi a2,a2,8
fadd.d fa5,fa5,fa4
addi a0,a0,8
fsd fa5,-8(a0)
bne a1,a5,.L3
.L1:
ret
.cfi_endproc
.LFE22:
.size kernel, .-kernel
.section .rodata.str1.8,"aMS",@progbits,1
.align 3
.LC0:
.string "RISC-V Vector add: a[i] = b[i] + c[i], size=%d\n"
.align 3
.LC1:
.string "Checksum: %f\n"
.section .text.startup,"ax",@progbits
.align 1
.globl main
.type main, @function
main:
.LFB23:
.cfi_startproc
addi sp,sp,-48
.cfi_def_cfa_offset 48
sd ra,40(sp)
sd s0,32(sp)
sd s1,24(sp)
sd s2,16(sp)
sd s3,8(sp)
sd s4,0(sp)
.cfi_offset 1, -8
.cfi_offset 8, -16
.cfi_offset 9, -24
.cfi_offset 18, -32
.cfi_offset 19, -40
.cfi_offset 20, -48
li a5,1
bgt a0,a5,.L21
li a1,1000
lla a0,.LC0
call printf@plt
li a0,8192
addi a0,a0,-192
call malloc@plt
mv s1,a0
li a0,8192
addi a0,a0,-192
call malloc@plt
mv s2,a0
li a0,8192
addi a0,a0,-192
call malloc@plt
li s0,8192
mv s3,a0
addi s0,s0,-192
li s4,1000
.L13:
slli a5,s4,32
srli a2,a5,29
li a1,0
mv a0,s1
call memset@plt
mv a4,s2
mv a3,s2
li a5,0
.L9:
fcvt.d.w fa5,a5
mv a1,a5
addiw a5,a5,1
fsd fa5,0(a3)
addi a3,a3,8
bne a5,s4,.L9
mv a2,s3
mv a3,s3
li a5,0
.L10:
fcvt.d.w fa5,a5
mv a0,a5
addi a3,a3,8
fadd.d fa5,fa5,fa5
addiw a5,a5,1
fsd fa5,-8(a3)
bne a0,a1,.L10
mv a5,s1
add a1,s2,s0
mv a3,s1
.L11:
fld fa5,0(a4)
fld fa4,0(a2)
addi a4,a4,8
addi a2,a2,8
fadd.d fa5,fa5,fa4
addi a3,a3,8
fsd fa5,-8(a3)
bne a4,a1,.L11
fmv.d.x fa5,zero
add s0,s1,s0
.L12:
fld fa4,0(a5)
addi a5,a5,8
fadd.d fa5,fa5,fa4
bne a5,s0,.L12
.L8:
fmv.x.d a1,fa5
lla a0,.LC1
call printf@plt
mv a0,s1
call free@plt
mv a0,s2
call free@plt
mv a0,s3
call free@plt
ld ra,40(sp)
.cfi_remember_state
.cfi_restore 1
ld s0,32(sp)
.cfi_restore 8
ld s1,24(sp)
.cfi_restore 9
ld s2,16(sp)
.cfi_restore 18
ld s3,8(sp)
.cfi_restore 19
ld s4,0(sp)
.cfi_restore 20
li a0,0
addi sp,sp,48
.cfi_def_cfa_offset 0
jr ra
.L21:
.cfi_restore_state
ld a0,8(a1)
li a2,10
li a1,0
call strtol@plt
sext.w s4,a0
mv a1,s4
lla a0,.LC0
call printf@plt
slli s0,s4,3
mv a0,s0
call malloc@plt
mv s1,a0
mv a0,s0
call malloc@plt
mv s2,a0
mv a0,s0
call malloc@plt
mv s3,a0
bgt s4,zero,.L13
fmv.d.x fa5,zero
j .L8
.cfi_endproc
.LFE23:
.size main, .-main
.ident "GCC: (GNU) 14.2.1 20250207"
.section .note.GNU-stack,"",@progbits

View File

@@ -1,225 +0,0 @@
.file "add_riscv.c"
.option pic
.attribute arch, "rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_v1p0_zicsr2p0_zifencei2p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 1
.globl kernel
.type kernel, @function
kernel:
.LFB22:
.cfi_startproc
ble a3,zero,.L10
addiw a5,a3,-1
li a4,2
bleu a5,a4,.L3
addi a5,a2,8
addi a4,a1,8
sub a5,a0,a5
sub a4,a0,a4
bgtu a5,a4,.L14
.L4:
csrr a4,vlenb
addi a4,a4,-16
bleu a5,a4,.L3
.L5:
vsetvli a5,a3,e64,m1,ta,ma
vle64.v v1,0(a1)
vle64.v v2,0(a2)
slli a4,a5,3
sub a3,a3,a5
add a1,a1,a4
add a2,a2,a4
vfadd.vv v1,v1,v2
vse64.v v1,0(a0)
add a0,a0,a4
bne a3,zero,.L5
ret
.L3:
slli a3,a3,3
add a3,a1,a3
.L7:
fld fa5,0(a1)
fld fa4,0(a2)
addi a1,a1,8
addi a2,a2,8
fadd.d fa5,fa5,fa4
addi a0,a0,8
fsd fa5,-8(a0)
bne a1,a3,.L7
.L10:
ret
.L14:
mv a5,a4
j .L4
.cfi_endproc
.LFE22:
.size kernel, .-kernel
.section .rodata.str1.8,"aMS",@progbits,1
.align 3
.LC0:
.string "RISC-V Vector add: a[i] = b[i] + c[i], size=%d\n"
.align 3
.LC2:
.string "Checksum: %f\n"
.section .text.startup,"ax",@progbits
.align 1
.globl main
.type main, @function
main:
.LFB23:
.cfi_startproc
addi sp,sp,-48
.cfi_def_cfa_offset 48
sd ra,40(sp)
sd s0,32(sp)
sd s1,24(sp)
sd s2,16(sp)
sd s3,8(sp)
sd s4,0(sp)
.cfi_offset 1, -8
.cfi_offset 8, -16
.cfi_offset 9, -24
.cfi_offset 18, -32
.cfi_offset 19, -40
.cfi_offset 20, -48
li a5,1
bgt a0,a5,.L35
li a1,1000
lla a0,.LC0
call printf@plt
li a0,8192
addi a0,a0,-192
call malloc@plt
mv s0,a0
li a0,8192
addi a0,a0,-192
call malloc@plt
mv s2,a0
li a0,8192
addi a0,a0,-192
call malloc@plt
li s3,8192
mv s1,a0
addi s3,s3,-192
li s4,1000
.L22:
slli a5,s4,32
srli a2,a5,29
li a1,0
mv a0,s0
call memset@plt
mv a4,s2
li a5,0
.L18:
fcvt.d.w fa5,a5
addiw a5,a5,1
addi a4,a4,8
fsd fa5,-8(a4)
bne a5,s4,.L18
fld fa5,.LC1,a4
vsetvli a3,zero,e64,m1,ta,ma
mv a2,a5
vfmv.v.f v4,fa5
vsetvli zero,zero,e32,mf2,ta,ma
vid.v v2
mv a3,s1
.L19:
vsetvli a4,a2,e32,mf2,ta,ma
vfwcvt.f.x.v v1,v2
vsetvli a0,zero,e32,mf2,ta,ma
vmv.v.x v3,a4
vsetvli zero,a4,e64,m1,ta,ma
vfmul.vv v1,v1,v4
vsetvli a0,zero,e32,mf2,ta,ma
vadd.vv v2,v2,v3
vsetvli zero,a4,e64,m1,ta,ma
slli a1,a4,3
sub a2,a2,a4
vse64.v v1,0(a3)
add a3,a3,a1
bne a2,zero,.L19
mv a3,s0
mv a0,s1
mv a1,s2
.L20:
vsetvli a4,a5,e64,m1,ta,ma
vle64.v v2,0(a1)
vle64.v v1,0(a0)
slli a2,a4,3
sub a5,a5,a4
add a1,a1,a2
add a0,a0,a2
vfadd.vv v1,v1,v2
vse64.v v1,0(a3)
add a3,a3,a2
bne a5,zero,.L20
fmv.d.x fa5,zero
add s3,s0,s3
mv a5,s0
.L21:
fld fa4,0(a5)
addi a5,a5,8
fadd.d fa5,fa5,fa4
bne s3,a5,.L21
.L17:
fmv.x.d a1,fa5
lla a0,.LC2
call printf@plt
mv a0,s0
call free@plt
mv a0,s2
call free@plt
mv a0,s1
call free@plt
ld ra,40(sp)
.cfi_remember_state
.cfi_restore 1
ld s0,32(sp)
.cfi_restore 8
ld s1,24(sp)
.cfi_restore 9
ld s2,16(sp)
.cfi_restore 18
ld s3,8(sp)
.cfi_restore 19
ld s4,0(sp)
.cfi_restore 20
li a0,0
addi sp,sp,48
.cfi_def_cfa_offset 0
jr ra
.L35:
.cfi_restore_state
ld a0,8(a1)
li a2,10
li a1,0
call strtol@plt
sext.w s4,a0
mv a1,s4
lla a0,.LC0
call printf@plt
slli s3,s4,3
mv a0,s3
call malloc@plt
mv s0,a0
mv a0,s3
call malloc@plt
mv s2,a0
mv a0,s3
call malloc@plt
mv s1,a0
bgt s4,zero,.L22
fmv.d.x fa5,zero
j .L17
.cfi_endproc
.LFE23:
.size main, .-main
.section .rodata.cst8,"aM",@progbits,8
.align 3
.LC1:
.word 0
.word 1073741824
.ident "GCC: (GNU) 14.2.1 20250207"
.section .note.GNU-stack,"",@progbits

View File

@@ -1,184 +0,0 @@
.file "triad.c"
.option pic
.attribute arch, "rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 1
.globl kernel
.type kernel, @function
kernel:
.LFB22:
.cfi_startproc
ble a3,zero,.L1
slli a3,a3,3
add a5,a1,a3
.L3:
fld fa5,0(a2)
fld fa4,0(a1)
addi a1,a1,8
addi a2,a2,8
fmadd.d fa5,fa5,fa0,fa4
addi a0,a0,8
fsd fa5,-8(a0)
bne a1,a5,.L3
.L1:
ret
.cfi_endproc
.LFE22:
.size kernel, .-kernel
.section .rodata.str1.8,"aMS",@progbits,1
.align 3
.LC0:
.string "RISC-V STREAM triad: a[i] = b[i] + s * c[i], size=%d\n"
.align 3
.LC2:
.string "Checksum: %f\n"
.section .text.startup,"ax",@progbits
.align 1
.globl main
.type main, @function
main:
.LFB23:
.cfi_startproc
addi sp,sp,-48
.cfi_def_cfa_offset 48
sd ra,40(sp)
sd s0,32(sp)
sd s1,24(sp)
sd s2,16(sp)
sd s3,8(sp)
sd s4,0(sp)
.cfi_offset 1, -8
.cfi_offset 8, -16
.cfi_offset 9, -24
.cfi_offset 18, -32
.cfi_offset 19, -40
.cfi_offset 20, -48
li a5,1
bgt a0,a5,.L21
li a1,1000
lla a0,.LC0
call printf@plt
li a0,8192
addi a0,a0,-192
call malloc@plt
mv s1,a0
li a0,8192
addi a0,a0,-192
call malloc@plt
mv s2,a0
li a0,8192
addi a0,a0,-192
call malloc@plt
li s0,8192
mv s3,a0
addi s0,s0,-192
li s4,1000
.L13:
slli a5,s4,32
srli a2,a5,29
li a1,0
mv a0,s1
call memset@plt
mv a4,s2
mv a3,s2
li a5,0
.L9:
fcvt.d.w fa5,a5
mv a1,a5
addiw a5,a5,1
fsd fa5,0(a3)
addi a3,a3,8
bne a5,s4,.L9
mv a2,s3
mv a3,s3
li a5,0
.L10:
fcvt.d.w fa5,a5
mv a0,a5
addi a3,a3,8
fadd.d fa5,fa5,fa5
addiw a5,a5,1
fsd fa5,-8(a3)
bne a0,a1,.L10
fld fa3,.LC1,a5
add a1,s2,s0
mv a5,s1
mv a3,s1
.L11:
fld fa5,0(a2)
fld fa4,0(a4)
addi a4,a4,8
addi a2,a2,8
fmadd.d fa5,fa5,fa3,fa4
addi a3,a3,8
fsd fa5,-8(a3)
bne a4,a1,.L11
fmv.d.x fa5,zero
add s0,s1,s0
.L12:
fld fa4,0(a5)
addi a5,a5,8
fadd.d fa5,fa5,fa4
bne a5,s0,.L12
.L8:
fmv.x.d a1,fa5
lla a0,.LC2
call printf@plt
mv a0,s1
call free@plt
mv a0,s2
call free@plt
mv a0,s3
call free@plt
ld ra,40(sp)
.cfi_remember_state
.cfi_restore 1
ld s0,32(sp)
.cfi_restore 8
ld s1,24(sp)
.cfi_restore 9
ld s2,16(sp)
.cfi_restore 18
ld s3,8(sp)
.cfi_restore 19
ld s4,0(sp)
.cfi_restore 20
li a0,0
addi sp,sp,48
.cfi_def_cfa_offset 0
jr ra
.L21:
.cfi_restore_state
ld a0,8(a1)
li a2,10
li a1,0
call strtol@plt
sext.w s4,a0
mv a1,s4
lla a0,.LC0
call printf@plt
slli s0,s4,3
mv a0,s0
call malloc@plt
mv s1,a0
mv a0,s0
call malloc@plt
mv s2,a0
mv a0,s0
call malloc@plt
mv s3,a0
bgt s4,zero,.L13
fmv.d.x fa5,zero
j .L8
.cfi_endproc
.LFE23:
.size main, .-main
.section .rodata.cst8,"aM",@progbits,8
.align 3
.LC1:
.word 1374389535
.word 1074339512
.ident "GCC: (GNU) 14.2.1 20250207"
.section .note.GNU-stack,"",@progbits

View File

@@ -1,234 +0,0 @@
.file "triad.c"
.option pic
.attribute arch, "rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_v1p0_zicsr2p0_zifencei2p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align 1
.globl kernel
.type kernel, @function
kernel:
.LFB22:
.cfi_startproc
ble a3,zero,.L10
addiw a5,a3,-1
li a4,4
bleu a5,a4,.L3
addi a5,a2,8
addi a4,a1,8
sub a5,a0,a5
sub a4,a0,a4
bgtu a5,a4,.L14
.L4:
csrr a4,vlenb
addi a4,a4,-16
bleu a5,a4,.L3
vsetvli a5,zero,e64,m1,ta,ma
vfmv.v.f v3,fa0
.L5:
vsetvli a5,a3,e64,m1,ta,ma
vle64.v v2,0(a1)
vle64.v v1,0(a2)
slli a4,a5,3
sub a3,a3,a5
add a1,a1,a4
add a2,a2,a4
vfmadd.vv v1,v3,v2
vse64.v v1,0(a0)
add a0,a0,a4
bne a3,zero,.L5
ret
.L3:
slli a3,a3,3
add a3,a1,a3
.L7:
fld fa5,0(a2)
fld fa4,0(a1)
addi a1,a1,8
addi a2,a2,8
fmadd.d fa5,fa0,fa5,fa4
addi a0,a0,8
fsd fa5,-8(a0)
bne a3,a1,.L7
.L10:
ret
.L14:
mv a5,a4
j .L4
.cfi_endproc
.LFE22:
.size kernel, .-kernel
.section .rodata.str1.8,"aMS",@progbits,1
.align 3
.LC0:
.string "RISC-V STREAM triad: a[i] = b[i] + s * c[i], size=%d\n"
.align 3
.LC3:
.string "Checksum: %f\n"
.section .text.startup,"ax",@progbits
.align 1
.globl main
.type main, @function
main:
.LFB23:
.cfi_startproc
addi sp,sp,-48
.cfi_def_cfa_offset 48
sd ra,40(sp)
sd s0,32(sp)
sd s1,24(sp)
sd s2,16(sp)
sd s3,8(sp)
sd s4,0(sp)
.cfi_offset 1, -8
.cfi_offset 8, -16
.cfi_offset 9, -24
.cfi_offset 18, -32
.cfi_offset 19, -40
.cfi_offset 20, -48
li a5,1
bgt a0,a5,.L35
li a1,1000
lla a0,.LC0
call printf@plt
li a0,8192
addi a0,a0,-192
call malloc@plt
mv s0,a0
li a0,8192
addi a0,a0,-192
call malloc@plt
mv s2,a0
li a0,8192
addi a0,a0,-192
call malloc@plt
li s3,8192
mv s1,a0
addi s3,s3,-192
li s4,1000
.L22:
slli a5,s4,32
srli a2,a5,29
li a1,0
mv a0,s0
call memset@plt
mv a4,s2
li a5,0
.L18:
fcvt.d.w fa5,a5
addiw a5,a5,1
addi a4,a4,8
fsd fa5,-8(a4)
bne a5,s4,.L18
fld fa5,.LC1,a4
vsetvli a3,zero,e64,m1,ta,ma
mv a2,a5
vfmv.v.f v4,fa5
vsetvli zero,zero,e32,mf2,ta,ma
vid.v v2
mv a3,s1
.L19:
vsetvli a4,a2,e32,mf2,ta,ma
vfwcvt.f.x.v v1,v2
vsetvli a0,zero,e32,mf2,ta,ma
vmv.v.x v3,a4
vsetvli zero,a4,e64,m1,ta,ma
vfmul.vv v1,v1,v4
vsetvli a0,zero,e32,mf2,ta,ma
vadd.vv v2,v2,v3
vsetvli zero,a4,e64,m1,ta,ma
slli a1,a4,3
sub a2,a2,a4
vse64.v v1,0(a3)
add a3,a3,a1
bne a2,zero,.L19
fld fa5,.LC2,a4
vsetvli a0,zero,e64,m1,ta,ma
mv a3,s0
vfmv.v.f v3,fa5
mv a0,s1
mv a1,s2
.L20:
vsetvli a4,a5,e64,m1,ta,ma
vle64.v v2,0(a1)
vle64.v v1,0(a0)
slli a2,a4,3
sub a5,a5,a4
add a1,a1,a2
add a0,a0,a2
vfmadd.vv v1,v3,v2
vse64.v v1,0(a3)
add a3,a3,a2
bne a5,zero,.L20
fmv.d.x fa5,zero
add s3,s0,s3
mv a5,s0
.L21:
fld fa4,0(a5)
addi a5,a5,8
fadd.d fa5,fa5,fa4
bne s3,a5,.L21
.L17:
fmv.x.d a1,fa5
lla a0,.LC3
call printf@plt
mv a0,s0
call free@plt
mv a0,s2
call free@plt
mv a0,s1
call free@plt
ld ra,40(sp)
.cfi_remember_state
.cfi_restore 1
ld s0,32(sp)
.cfi_restore 8
ld s1,24(sp)
.cfi_restore 9
ld s2,16(sp)
.cfi_restore 18
ld s3,8(sp)
.cfi_restore 19
ld s4,0(sp)
.cfi_restore 20
li a0,0
addi sp,sp,48
.cfi_def_cfa_offset 0
jr ra
.L35:
.cfi_restore_state
ld a0,8(a1)
li a2,10
li a1,0
call strtol@plt
sext.w s4,a0
mv a1,s4
lla a0,.LC0
call printf@plt
slli s3,s4,3
mv a0,s3
call malloc@plt
mv s0,a0
mv a0,s3
call malloc@plt
mv s2,a0
mv a0,s3
call malloc@plt
mv s1,a0
bgt s4,zero,.L22
fmv.d.x fa5,zero
j .L17
.cfi_endproc
.LFE23:
.size main, .-main
.section .rodata.cst8,"aM",@progbits,8
.align 3
.LC1:
.word 0
.word 1073741824
.align 3
.LC2:
.word 1374389535
.word 1074339512
.ident "GCC: (GNU) 14.2.1 20250207"
.section .note.GNU-stack,"",@progbits

View File

@@ -0,0 +1,15 @@
striad_riscv:
.L3:
vsetvli a5,a4,e64,m1,ta,ma
vle64.v v2,0(a1)
vle64.v v3,0(a2)
vle64.v v1,0(a3)
slli a6,a5,3
sub a4,a4,a5
add a1,a1,a6
add a2,a2,a6
add a3,a3,a6
vfmadd.vv v1,v3,v2
vse64.v v1,0(a0)
add a0,a0,a6
bne a4,zero,.L3

View File

@@ -0,0 +1,7 @@
sum_reduction_riscv:
.L3:
fld fa5,0(a0)
addi a0,a0,8
fadd.d fa0,fa0,fa5
bne a1,a0,.L3
ret

View File

@@ -1,24 +0,0 @@
# Makefile for RISC-V triad example
CC = gcc
CFLAGS = -O3
CFLAGS_VEC = -O3 -march=rv64gcv
# Default target with -O3
all: triad triad_vec
# Build with -O3 optimization
triad: triad.c
$(CC) $(CFLAGS) -o triad triad.c
$(CC) $(CFLAGS) -S -o triad.s triad.c
# Build with vector extensions
triad_vec: triad.c
$(CC) $(CFLAGS_VEC) -o triad_vec triad.c
$(CC) $(CFLAGS_VEC) -S -o triad_vec.s triad.c
# Clean up
clean:
rm -f triad triad_vec triad.s triad_vec.s
.PHONY: all clean

View File

@@ -1,55 +0,0 @@
// STREAM triad benchmark for RISC-V testing
// a[i] = b[i] + s * c[i]
#include <stdio.h>
#include <stdlib.h>
#define DTYPE double
void kernel(DTYPE* a, DTYPE* b, DTYPE* c, const DTYPE s, const int size)
{
// OSACA start marker will be added around this loop
for(int i=0; i<size; i++) {
a[i] = b[i] + s * c[i];
}
// OSACA end marker will be added
}
int main(int argc, char *argv[]) {
int size = 1000;
if(argc > 1) {
size = atoi(argv[1]);
}
printf("RISC-V STREAM triad: a[i] = b[i] + s * c[i], size=%d\n", size);
// Allocate memory
DTYPE* a = (DTYPE*)malloc(size * sizeof(DTYPE));
DTYPE* b = (DTYPE*)malloc(size * sizeof(DTYPE));
DTYPE* c = (DTYPE*)malloc(size * sizeof(DTYPE));
// Initialize arrays
for(int i=0; i<size; i++) {
a[i] = 0.0;
b[i] = i;
c[i] = i * 2.0;
}
// Run kernel
DTYPE scalar = 3.14;
kernel(a, b, c, scalar, size);
// Check result (to prevent optimization)
DTYPE checksum = 0.0;
for(int i=0; i<size; i++) {
checksum += a[i];
}
printf("Checksum: %f\n", checksum);
// Cleanup
free(a);
free(b);
free(c);
return 0;
}

View File

@@ -0,0 +1,13 @@
triad_riscv:
.L3:
vsetvli a5,a3,e64,m1,ta,ma
vle64.v v1,0(a1)
vle64.v v2,0(a2)
slli a4,a5,3
sub a3,a3,a5
add a1,a1,a4
add a2,a2,a4
vfmacc.vv v1,v3,v2
vse64.v v1,0(a0)
add a0,a0,a4
bne a3,zero,.L3

View File

@@ -0,0 +1,11 @@
update_riscv:
.L3:
vsetvli a5,a1,e64,m1,ta,ma
vle64.v v1,0(a0)
slli a3,a5,3
sub a1,a1,a5
add a0,a0,a3
vfmul.vf v1,v1,fa0
vse64.v v1,0(a4)
add a4,a4,a3
bne a1,zero,.L3

View File

@@ -40,11 +40,11 @@ instruction_forms:
- name: ADD
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -52,9 +52,9 @@ instruction_forms:
- name: ADDI
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1
@@ -64,11 +64,11 @@ instruction_forms:
- name: SUB
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -76,7 +76,7 @@ instruction_forms:
- name: LUI
operands:
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1
@@ -86,7 +86,7 @@ instruction_forms:
- name: AUIPC
operands:
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1
@@ -97,11 +97,11 @@ instruction_forms:
- name: AND
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -109,9 +109,9 @@ instruction_forms:
- name: ANDI
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1
@@ -121,11 +121,11 @@ instruction_forms:
- name: OR
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -133,9 +133,9 @@ instruction_forms:
- name: ORI
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1
@@ -145,11 +145,11 @@ instruction_forms:
- name: XOR
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -157,9 +157,9 @@ instruction_forms:
- name: XORI
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1
@@ -170,11 +170,11 @@ instruction_forms:
- name: SLL
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -182,9 +182,9 @@ instruction_forms:
- name: SLLI
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1
@@ -194,11 +194,11 @@ instruction_forms:
- name: SRL
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -206,9 +206,9 @@ instruction_forms:
- name: SRLI
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1
@@ -218,11 +218,11 @@ instruction_forms:
- name: SRA
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -230,9 +230,9 @@ instruction_forms:
- name: SRAI
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1
@@ -243,11 +243,11 @@ instruction_forms:
- name: MUL
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 3
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -255,11 +255,11 @@ instruction_forms:
- name: MULH
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 3
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -268,11 +268,11 @@ instruction_forms:
- name: DIV
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 10
throughput: 10
port_pressure: [[1, ["DIV"]]]
@@ -280,11 +280,11 @@ instruction_forms:
- name: DIVU
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 10
throughput: 10
port_pressure: [[1, ["DIV"]]]
@@ -292,11 +292,11 @@ instruction_forms:
- name: REM
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 10
throughput: 10
port_pressure: [[1, ["DIV"]]]
@@ -304,11 +304,11 @@ instruction_forms:
- name: REMU
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 10
throughput: 10
port_pressure: [[1, ["DIV"]]]
@@ -317,9 +317,9 @@ instruction_forms:
- name: LW
operands:
- class: register
name: gpr
prefix: x
- class: memory
base: gpr
base: x
offset: imd
index: null
scale: 1
@@ -330,9 +330,9 @@ instruction_forms:
- name: LD
operands:
- class: register
name: gpr
prefix: x
- class: memory
base: gpr
base: x
offset: imd
index: null
scale: 1
@@ -343,9 +343,9 @@ instruction_forms:
- name: SW
operands:
- class: register
name: gpr
prefix: x
- class: memory
base: gpr
base: x
offset: imd
index: null
scale: 1
@@ -356,9 +356,9 @@ instruction_forms:
- name: SD
operands:
- class: register
name: gpr
prefix: x
- class: memory
base: gpr
base: x
offset: imd
index: null
scale: 1
@@ -370,9 +370,9 @@ instruction_forms:
- name: BEQ
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: identifier
latency: 1
throughput: 1
@@ -381,9 +381,9 @@ instruction_forms:
- name: BNE
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: identifier
latency: 1
throughput: 1
@@ -392,9 +392,9 @@ instruction_forms:
- name: BLT
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: identifier
latency: 1
throughput: 1
@@ -403,9 +403,9 @@ instruction_forms:
- name: BGE
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: identifier
latency: 1
throughput: 1
@@ -414,7 +414,7 @@ instruction_forms:
- name: JAL
operands:
- class: register
name: gpr
prefix: x
- class: identifier
latency: 1
throughput: 1
@@ -423,9 +423,9 @@ instruction_forms:
- name: JALR
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1
@@ -438,7 +438,7 @@ instruction_forms:
- class: register
prefix: f
- class: memory
base: gpr
base: x
offset: imd
index: null
scale: 1
@@ -451,7 +451,7 @@ instruction_forms:
- class: register
prefix: f
- class: memory
base: gpr
base: x
offset: imd
index: null
scale: 1
@@ -464,7 +464,7 @@ instruction_forms:
- class: register
prefix: f
- class: memory
base: gpr
base: x
offset: imd
index: null
scale: 1
@@ -477,7 +477,7 @@ instruction_forms:
- class: register
prefix: f
- class: memory
base: gpr
base: x
offset: imd
index: null
scale: 1
@@ -496,7 +496,19 @@ instruction_forms:
latency: 3
throughput: 1
port_pressure: [[1, ["FP"]]]
- name: FADD.D
operands:
- class: register
prefix: f
- class: register
prefix: f
- class: register
prefix: f
latency: 3
throughput: 1
port_pressure: [[1, ["FP"]]]
- name: FSUB.S
operands:
- class: register
@@ -551,34 +563,63 @@ instruction_forms:
- name: VSETVLI
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
- class: identifier
- class: identifier
- class: identifier
- class: identifier
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
- name: VLE32.V
- name: VLE64.V
operands:
- class: register
prefix: v
- class: memory
base: gpr
offset: null
base: x
offset: imd
index: null
scale: 1
latency: 4
throughput: 1
port_pressure: [[1, ["MEM"]]]
- name: VLE8.V
operands:
- class: register
prefix: v
- class: memory
base: x
offset: imd
index: null
scale: 1
latency: 4
throughput: 1
port_pressure: [[1, ["MEM"]]]
- name: VSE32.V
- name: VSE64.V
operands:
- class: register
prefix: v
- class: memory
base: gpr
offset: null
base: x
offset: imd
index: null
scale: 1
latency: 1
throughput: 1
port_pressure: [[1, ["MEM"]]]
- name: VSE8.V
operands:
- class: register
prefix: v
- class: memory
base: x
offset: imd
index: null
scale: 1
latency: 1
@@ -596,7 +637,31 @@ instruction_forms:
latency: 4
throughput: 1
port_pressure: [[1, ["FP"]]]
- name: VFMACC.VV
operands:
- class: register
prefix: v
- class: register
prefix: v
- class: register
prefix: v
latency: 4
throughput: 1
port_pressure: [[1, ["FP"]]]
- name: VFADD.VV
operands:
- class: register
prefix: v
- class: register
prefix: v
- class: register
prefix: v
latency: 3
throughput: 1
port_pressure: [[1, ["FP"]]]
- name: VFMADD.VV
operands:
- class: register
@@ -609,11 +674,42 @@ instruction_forms:
throughput: 1
port_pressure: [[1, ["FP"]]]
- name: FMUL.D
operands:
- class: register
prefix: f
- class: register
prefix: f
- class: register
prefix: f
latency: 3
throughput: 1
port_pressure: [[1, ["FP"]]]
- name: VFMUL.VF
operands:
- class: register
prefix: v
- class: register
prefix: v
- class: register
prefix: f
latency: 4
throughput: 1
port_pressure: [[1, ["FP"]]]
- name: J
operands:
- class: identifier
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
# CSR instructions
- name: CSRR
operands:
- class: register
name: gpr
prefix: x
- class: identifier
latency: 1
throughput: 1
@@ -623,7 +719,7 @@ instruction_forms:
operands:
- class: identifier
- class: register
name: gpr
prefix: x
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -632,9 +728,9 @@ instruction_forms:
- name: MV
operands:
- class: register
name: gpr
prefix: x
- class: register
name: gpr
prefix: x
latency: 1
throughput: 1
port_pressure: [[1, ["ALU"]]]
@@ -642,7 +738,7 @@ instruction_forms:
- name: LI
operands:
- class: register
name: gpr
prefix: x
- class: immediate
imd: int
latency: 1

View File

@@ -300,6 +300,11 @@ def insert_byte_marker(args):
)
sys.exit(1)
# Check if ISA is RISC-V and raise NotImplementedError
isa = MachineModel.get_isa_for_arch(args.arch)
if isa == "riscv":
raise NotImplementedError("Marker insertion is not supported for RISC-V architecture.")
assembly = args.file.read()
unmarked_assembly = io.StringIO(assembly)
marked_assembly = io.StringIO()
@@ -308,7 +313,7 @@ def insert_byte_marker(args):
output_file=marked_assembly,
block_selection="manual",
pointer_increment="auto_with_manual_fallback",
isa=MachineModel.get_isa_for_arch(args.arch),
isa=isa,
)
marked_assembly.seek(0)

View File

@@ -431,30 +431,58 @@ class ParserRISCV(BaseParser):
def process_register_operand(self, operand):
"""Process register operands, including ABI name to x-register mapping"""
# Handle ABI names by adding the appropriate prefix
if "prefix" not in operand:
name = operand["name"].lower()
# Integer register ABI names
if name in ["zero", "ra", "sp", "gp", "tp"] or name[0] in ["t", "a", "s"]:
prefix = "x"
# Floating point register ABI names
elif name[0] == "f" and name[1] in ["t", "a", "s"]:
prefix = "f"
# CSR registers
elif name.startswith("csr"):
prefix = ""
else:
prefix = ""
return RegisterOperand(
prefix=prefix,
name=name
)
else:
# If already has prefix (x#, f#, v#), just return as is
if "prefix" in operand:
return RegisterOperand(
prefix=operand["prefix"].lower(),
name=operand["name"]
)
# Handle ABI names by converting to x-register numbers
name = operand["name"].lower()
# ABI name mapping for integer registers
abi_to_x = {
"zero": "0", "ra": "1", "sp": "2", "gp": "3", "tp": "4",
"t0": "5", "t1": "6", "t2": "7",
"s0": "8", "fp": "8", "s1": "9",
"a0": "10", "a1": "11", "a2": "12", "a3": "13",
"a4": "14", "a5": "15", "a6": "16", "a7": "17",
"s2": "18", "s3": "19", "s4": "20", "s5": "21",
"s6": "22", "s7": "23", "s8": "24", "s9": "25",
"s10": "26", "s11": "27",
"t3": "28", "t4": "29", "t5": "30", "t6": "31"
}
# Integer register ABI names
if name in abi_to_x:
return RegisterOperand(
prefix="x",
name=abi_to_x[name]
)
# Floating point register ABI names
elif name.startswith("f") and name[1] in ["t", "a", "s"]:
if name[1] == "a": # fa0-fa7
idx = int(name[2:])
return RegisterOperand(prefix="f", name=str(idx + 10))
elif name[1] == "s": # fs0-fs11
idx = int(name[2:])
if idx <= 1:
return RegisterOperand(prefix="f", name=str(idx + 8))
else:
return RegisterOperand(prefix="f", name=str(idx + 16))
elif name[1] == "t": # ft0-ft11
idx = int(name[2:])
if idx <= 7:
return RegisterOperand(prefix="f", name=str(idx))
else:
return RegisterOperand(prefix="f", name=str(idx + 20))
# CSR registers
elif name.startswith("csr"):
return RegisterOperand(prefix="", name=name)
# If no mapping found, return as is
return RegisterOperand(prefix="", name=name)
def process_memory_address(self, memory_address):
"""Post-process memory address operand"""
@@ -715,4 +743,27 @@ class ParserRISCV(BaseParser):
if len(instruction_form.operands) == 1:
return []
else:
return instruction_form.operands[:1]
return instruction_form.operands[:1]
def process_immediate_operand(self, operand):
"""Process immediate operands, converting them to ImmediateOperand objects"""
if isinstance(operand, (int, str)):
# For raw integer values or string immediates
return ImmediateOperand(
imd_type="int",
value=str(operand) if isinstance(operand, int) else operand
)
elif isinstance(operand, dict) and "imd" in operand:
# For immediate operands from instruction definitions
return ImmediateOperand(
imd_type=operand["imd"],
value=operand.get("value"),
identifier=operand.get("identifier"),
shift=operand.get("shift")
)
else:
# For any other immediate format
return ImmediateOperand(
imd_type="int",
value=str(operand)
)

View File

@@ -10,6 +10,7 @@ from .hw_model import MachineModel
from .isa_semantics import INSTR_FLAGS, ISASemantics
from osaca.parser.memory import MemoryOperand
from osaca.parser.register import RegisterOperand
from osaca.parser.immediate import ImmediateOperand
class ArchSemantics(ISASemantics):
@@ -425,7 +426,13 @@ class ArchSemantics(ISASemantics):
elif self._parser.isa() == "aarch64":
register = RegisterOperand(name=regtype, prefix=reg_type)
elif self._parser.isa() == "riscv":
register = RegisterOperand(name=regtype, prefix=reg_type)
# For RISC-V, handle both register and immediate operands
if reg_type == "int":
# For immediate operands, create an ImmediateOperand
register = ImmediateOperand(imd_type="int")
else:
# For registers, use the x-prefix format
register = RegisterOperand(name=regtype, prefix=reg_type)
return register
def _nullify_data_ports(self, port_pressure):

View File

@@ -873,36 +873,29 @@ class MachineModel(object):
if not isinstance(i_operand, RegisterOperand):
return False
return self._is_RISCV_reg_type(i_operand, operand)
# memory
if isinstance(operand, MemoryOperand):
if not isinstance(i_operand, MemoryOperand):
return False
return self._is_RISCV_mem_type(i_operand, operand)
# immediate
if isinstance(i_operand, ImmediateOperand) and i_operand.imd_type == self.WILDCARD:
return isinstance(operand, ImmediateOperand) and (operand.value is not None)
if isinstance(i_operand, ImmediateOperand) and i_operand.imd_type == "int":
return (
isinstance(operand, ImmediateOperand)
and operand.imd_type == "int"
and operand.value is not None
)
if isinstance(i_operand, ImmediateOperand) and i_operand.imd_type == "float":
return (
isinstance(operand, ImmediateOperand)
and operand.imd_type == "float"
and operand.value is not None
)
if isinstance(i_operand, ImmediateOperand) and i_operand.imd_type == "double":
return (
isinstance(operand, ImmediateOperand)
and operand.imd_type == "double"
and operand.value is not None
)
if isinstance(operand, (ImmediateOperand, int)):
if not isinstance(i_operand, ImmediateOperand):
return False
if isinstance(operand, int):
# For raw integers, we accept them if the instruction expects an int immediate
if i_operand.imd_type == "int":
return True
else:
# For ImmediateOperand objects, check the types match
if i_operand.imd_type == operand.imd_type:
return True
if i_operand.imd_type == self.WILDCARD:
return True
return False
# identifier
if isinstance(operand, IdentifierOperand) or (
isinstance(operand, ImmediateOperand) and operand.identifier is not None
@@ -1038,7 +1031,6 @@ class MachineModel(object):
if reg_canonical == i_reg_canonical:
return True
except (AttributeError, KeyError):
# If we can't determine canonical names, be conservative
return False
# Check for direct prefix matches

View File

@@ -8,6 +8,7 @@ suite = unittest.TestLoader().loadTestsFromNames(
[
"test_base_parser",
"test_parser_x86att",
"test_parser_x86intel",
"test_parser_AArch64",
"test_parser_RISCV",
"test_marker_utils",

View File

@@ -28,6 +28,8 @@ class TestBaseParser(unittest.TestCase):
self.x86_code = f.read()
with open(self._find_file("kernel_aarch64.s")) as f:
self.aarch64_code = f.read()
with open(self._find_file("kernel_riscv.s")) as f:
self.riscv_code = f.read()
##################
# Test
@@ -75,6 +77,7 @@ class TestBaseParser(unittest.TestCase):
self.assertEqual(BaseParser.detect_ISA(self.triad_code_arm), ("aarch64", None))
self.assertEqual(BaseParser.detect_ISA(self.x86_code), ("x86", "ATT"))
self.assertEqual(BaseParser.detect_ISA(self.aarch64_code), ("aarch64", None))
self.assertEqual(BaseParser.detect_ISA(self.riscv_code), ("riscv", None))
##################
# Helper functions

View File

@@ -12,7 +12,7 @@ from unittest.mock import patch
import osaca.osaca as osaca
from osaca.db_interface import sanity_check
from osaca.parser import ParserAArch64, ParserX86ATT, ParserX86Intel
from osaca.parser import ParserAArch64, ParserX86ATT, ParserX86Intel, ParserRISCV
from osaca.semantics import MachineModel
@@ -85,6 +85,7 @@ class TestCLI(unittest.TestCase):
self.assertTrue(isinstance(osaca.get_asm_parser("csx"), ParserX86ATT))
self.assertTrue(isinstance(osaca.get_asm_parser("csx", "intel"), ParserX86Intel))
self.assertTrue(isinstance(osaca.get_asm_parser("tx2"), ParserAArch64))
self.assertTrue(isinstance(osaca.get_asm_parser("rv64"), ParserRISCV))
with self.assertRaises(ValueError):
osaca.get_asm_parser("UNKNOWN")
@@ -125,6 +126,22 @@ class TestCLI(unittest.TestCase):
# remove copy again
os.remove(name_copy)
def test_marker_insert_riscv(self):
# copy file to add markers
name = self._find_test_file("kernel_riscv.s")
name_copy = name + ".copy.s"
copyfile(name, name_copy)
user_input = [".L4", "64"]
parser = osaca.create_parser()
args = parser.parse_args(["--arch", "rv64", "--insert-marker", name_copy])
with patch("builtins.input", side_effect=user_input):
with self.assertRaises(NotImplementedError):
osaca.run(args)
# remove copy again
os.remove(name_copy)
def test_examples(self):
kernels = [
"add",
@@ -137,8 +154,8 @@ class TestCLI(unittest.TestCase):
"triad",
"update",
]
archs = ["csx", "tx2", "zen1"]
comps = {"csx": ["gcc", "icc"], "tx2": ["gcc", "clang"], "zen1": ["gcc"]}
archs = ["csx", "tx2", "zen1", "rv64"]
comps = {"csx": ["gcc", "icc"], "tx2": ["gcc", "clang"], "zen1": ["gcc"], "rv64": ["gcc"]}
parser = osaca.create_parser()
# Analyze all asm files resulting out of kernels, archs and comps
for k in kernels:
@@ -191,6 +208,10 @@ class TestCLI(unittest.TestCase):
kernel_aarch64 = "kernel_aarch64.s"
args = parser.parse_args([self._find_test_file(kernel_aarch64)])
osaca.run(args, output_file=output)
# RISC-V
kernel_riscv = "kernel_riscv.s"
args = parser.parse_args([self._find_test_file(kernel_riscv)])
osaca.run(args, output_file=output)
def test_user_warnings(self):
parser = osaca.create_parser()

View File

@@ -32,6 +32,7 @@ class TestDBInterface(unittest.TestCase):
self.entry_csx = copy.copy(sample_entry)
self.entry_tx2 = copy.copy(sample_entry)
self.entry_zen1 = copy.copy(sample_entry)
self.entry_rv64 = copy.copy(sample_entry)
self.entry_csx.port_pressure = [1.25, 0, 1.25, 0.5, 0.5, 0.5, 0.5, 0, 1.25, 1.25, 0]
self.entry_csx.port_pressure = [[5, "0156"], [1, "23"], [1, ["2D", "3D"]]]
@@ -46,6 +47,11 @@ class TestDBInterface(unittest.TestCase):
[1, "89"],
[2, ["8D", "9D"]],
]
# For RV64, adapt to match its port structure
self.entry_rv64.port_pressure = [1, 1, 1, 1] # [ALU, MEM, DIV, FP]
self.entry_rv64.port_pressure = [[1, ["ALU"]], [1, ["MEM"]], [1, ["DIV"]], [1, ["FP"]]]
self.entry_rv64.operands[1].prefix = "f" # Using f prefix for floating point registers
self.entry_rv64.operands[1].name = "1"
###########
# Tests
@@ -55,21 +61,26 @@ class TestDBInterface(unittest.TestCase):
mm_csx = MachineModel("csx")
mm_tx2 = MachineModel("tx2")
mm_zen1 = MachineModel("zen1")
mm_rv64 = MachineModel("rv64")
num_entries_csx = len(mm_csx["instruction_forms"])
num_entries_tx2 = len(mm_tx2["instruction_forms"])
num_entries_zen1 = len(mm_zen1["instruction_forms"])
num_entries_rv64 = len(mm_rv64["instruction_forms"])
mm_csx.set_instruction_entry(self.entry_csx)
mm_tx2.set_instruction_entry(self.entry_tx2)
mm_zen1.set_instruction_entry(InstructionForm(mnemonic="empty_operation"))
mm_rv64.set_instruction_entry(self.entry_rv64)
num_entries_csx = len(mm_csx["instruction_forms"]) - num_entries_csx
num_entries_tx2 = len(mm_tx2["instruction_forms"]) - num_entries_tx2
num_entries_zen1 = len(mm_zen1["instruction_forms"]) - num_entries_zen1
num_entries_rv64 = len(mm_rv64["instruction_forms"]) - num_entries_rv64
self.assertEqual(num_entries_csx, 1)
self.assertEqual(num_entries_tx2, 1)
self.assertEqual(num_entries_zen1, 1)
self.assertEqual(num_entries_rv64, 1)
def test_invalid_add(self):
entry = InstructionForm()
@@ -84,11 +95,13 @@ class TestDBInterface(unittest.TestCase):
sanity_check("csx", verbose=False, internet_check=False, output_file=output)
sanity_check("tx2", verbose=False, internet_check=False, output_file=output)
sanity_check("zen1", verbose=False, internet_check=False, output_file=output)
sanity_check("rv64", verbose=False, internet_check=False, output_file=output)
# verbose
sanity_check("csx", verbose=True, internet_check=False, output_file=output)
sanity_check("tx2", verbose=True, internet_check=False, output_file=output)
sanity_check("zen1", verbose=True, internet_check=False, output_file=output)
sanity_check("rv64", verbose=True, internet_check=False, output_file=output)
def test_ibench_import(self):
# only check import without dumping the DB file (takes too much time)
@@ -106,6 +119,11 @@ class TestDBInterface(unittest.TestCase):
for _, e in entries.items():
self.assertIsNotNone(e.throughput)
self.assertIsNotNone(e.latency)
# TODO: Add RISC-V ibench import test when files are available
# Expected format:
# Using frequency 2.50GHz.
# testinstr-i_r_x-TP: 0.251 (clock cycles) [DEBUG - result: 0.007813]
# testinstr-i_r_x-LT: 4.013 (clock cycles) [DEBUG - result: 1.000000]
def test_asmbench_import(self):
# only check import without dumping the DB file (takes too much time)
@@ -127,6 +145,12 @@ class TestDBInterface(unittest.TestCase):
del input_data[3]
entries = dbi._get_asmbench_output(input_data, "aarch64")
self.assertEqual(len(entries), 0)
# TODO: Add RISC-V asmbench import test when files are available
# Expected format:
# testinstr-i_r_x
# Latency: 4.013 cy
# Throughput: 0.501 cy
#
with self.assertRaises(ValueError):
dbi.import_benchmark_output(
"csx", "invalid_bench_type", self._find_file("asmbench_import_x86.dat")
@@ -163,6 +187,14 @@ class TestDBInterface(unittest.TestCase):
RegisterOperand(prefix="v", shape="s"),
],
)
instr_form_riscv = dict(
name="fadd.s",
operands=[
RegisterOperand(prefix="f", name="7"),
RegisterOperand(prefix="f", name="8"),
RegisterOperand(prefix="f", name="9"),
],
)
# test full instruction name
self.assertEqual(
_get_full_instruction_name(instr_form_x86),
@@ -173,6 +205,11 @@ class TestDBInterface(unittest.TestCase):
"fadd register(prefix:v,shape:s),register(prefix:v,shape:s),"
+ "register(prefix:v,shape:s)",
)
self.assertEqual(
_get_full_instruction_name(instr_form_riscv),
"fadd.s register(name:7,prefix:f),register(name:8,prefix:f),"
+ "register(name:9,prefix:f)",
)
##################
# Helper functions

View File

@@ -7,7 +7,7 @@ import os
import unittest
from osaca.frontend import Frontend
from osaca.parser import ParserAArch64, ParserX86ATT
from osaca.parser import ParserAArch64, ParserX86ATT, ParserRISCV
from osaca.semantics import ArchSemantics, KernelDG, MachineModel, reduce_to_section
@@ -21,18 +21,26 @@ class TestFrontend(unittest.TestCase):
# set up parser and kernels
self.parser_x86 = ParserX86ATT()
self.parser_AArch64 = ParserAArch64()
self.parser_RISCV = ParserRISCV()
with open(self._find_file("kernel_x86.s")) as f:
code_x86 = f.read()
with open(self._find_file("kernel_aarch64.s")) as f:
code_AArch64 = f.read()
with open(self._find_file("kernel_riscv.s")) as f:
code_RISCV = f.read()
self.kernel_x86 = self.parser_x86.parse_file(code_x86)
self.kernel_AArch64 = self.parser_AArch64.parse_file(code_AArch64)
self.kernel_RISCV = self.parser_RISCV.parse_file(code_RISCV)
# set up machine models
self.machine_model_csx = MachineModel(
path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "csx.yml")
)
self.machine_model_tx2 = MachineModel(arch="tx2")
self.machine_model_rv64 = MachineModel(arch="rv64")
self.semantics_csx = ArchSemantics(
self.parser_x86,
self.machine_model_csx,
@@ -43,9 +51,15 @@ class TestFrontend(unittest.TestCase):
self.machine_model_tx2,
path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "isa/aarch64.yml"),
)
self.semantics_rv64 = ArchSemantics(
self.parser_RISCV,
self.machine_model_rv64,
path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "isa/riscv.yml"),
)
self.semantics_csx.normalize_instruction_forms(self.kernel_x86)
self.semantics_tx2.normalize_instruction_forms(self.kernel_AArch64)
self.semantics_rv64.normalize_instruction_forms(self.kernel_RISCV)
for i in range(len(self.kernel_x86)):
self.semantics_csx.assign_src_dst(self.kernel_x86[i])
@@ -53,6 +67,9 @@ class TestFrontend(unittest.TestCase):
for i in range(len(self.kernel_AArch64)):
self.semantics_tx2.assign_src_dst(self.kernel_AArch64[i])
self.semantics_tx2.assign_tp_lt(self.kernel_AArch64[i])
for i in range(len(self.kernel_RISCV)):
self.semantics_rv64.assign_src_dst(self.kernel_RISCV[i])
self.semantics_rv64.assign_tp_lt(self.kernel_RISCV[i])
###########
# Tests
@@ -68,6 +85,7 @@ class TestFrontend(unittest.TestCase):
with self.assertRaises(FileNotFoundError):
Frontend(arch="THE_MACHINE")
Frontend(arch="zen1")
Frontend(arch="rv64")
def test_frontend_x86(self):
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
@@ -87,6 +105,17 @@ class TestFrontend(unittest.TestCase):
fe.full_analysis(self.kernel_AArch64, dg, verbose=True)
# TODO compare output with checked string
def test_frontend_RISCV(self):
dg = KernelDG(
self.kernel_RISCV,
self.parser_RISCV,
self.machine_model_rv64,
self.semantics_rv64,
)
fe = Frontend(path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "rv64.yml"))
fe.full_analysis(self.kernel_RISCV, dg, verbose=True)
# TODO compare output with checked string
def test_dict_output_x86(self):
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
fe = Frontend(path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "csx.yml"))
@@ -155,6 +184,44 @@ class TestFrontend(unittest.TestCase):
self.assertEqual(line.flags, analysis_dict["Kernel"][i]["Flags"])
self.assertEqual(line.line_number, analysis_dict["Kernel"][i]["LineNumber"])
def test_dict_output_RISCV(self):
reduced_kernel = reduce_to_section(self.kernel_RISCV, self.parser_RISCV)
dg = KernelDG(
reduced_kernel,
self.parser_RISCV,
self.machine_model_rv64,
self.semantics_rv64,
)
fe = Frontend(path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "rv64.yml"))
analysis_dict = fe.full_analysis_dict(reduced_kernel, dg)
self.assertEqual(len(reduced_kernel), len(analysis_dict["Kernel"]))
self.assertEqual("rv64", analysis_dict["Header"]["Architecture"])
# Warnings may be present for RISC-V analysis, so don't check the count
# self.assertEqual(len(analysis_dict["Warnings"]), 0)
for i, line in enumerate(reduced_kernel):
self.assertEqual(line.throughput, analysis_dict["Kernel"][i]["Throughput"])
self.assertEqual(line.latency, analysis_dict["Kernel"][i]["Latency"])
self.assertEqual(
line.latency_wo_load, analysis_dict["Kernel"][i]["LatencyWithoutLoad"]
)
self.assertEqual(line.latency_cp, analysis_dict["Kernel"][i]["LatencyCP"])
self.assertEqual(line.mnemonic, analysis_dict["Kernel"][i]["Instruction"])
self.assertEqual(len(line.operands), len(analysis_dict["Kernel"][i]["Operands"]))
self.assertEqual(
len(line.semantic_operands["source"]),
len(analysis_dict["Kernel"][i]["SemanticOperands"]["source"]),
)
self.assertEqual(
len(line.semantic_operands["destination"]),
len(analysis_dict["Kernel"][i]["SemanticOperands"]["destination"]),
)
self.assertEqual(
len(line.semantic_operands["src_dst"]),
len(analysis_dict["Kernel"][i]["SemanticOperands"]["src_dst"]),
)
self.assertEqual(line.flags, analysis_dict["Kernel"][i]["Flags"])
self.assertEqual(line.line_number, analysis_dict["Kernel"][i]["LineNumber"])
##################
# Helper functions
##################

View File

@@ -12,7 +12,7 @@ from osaca.semantics import (
find_jump_labels,
find_basic_loop_bodies,
)
from osaca.parser import ParserAArch64, ParserX86ATT, ParserX86Intel
from osaca.parser import ParserAArch64, ParserX86ATT, ParserX86Intel, ParserRISCV
class TestMarkerUtils(unittest.TestCase):
@@ -21,15 +21,21 @@ class TestMarkerUtils(unittest.TestCase):
self.parser_AArch = ParserAArch64()
self.parser_x86_att = ParserX86ATT()
self.parser_x86_intel = ParserX86Intel()
self.parser_RISCV = ParserRISCV()
with open(self._find_file("triad_arm_iaca.s")) as f:
triad_code_arm = f.read()
with open(self._find_file("triad_x86_iaca.s")) as f:
triad_code_x86_att = f.read()
with open(self._find_file("triad_x86_intel_iaca.s")) as f:
triad_code_x86_intel = f.read()
with open(self._find_file("kernel_riscv.s")) as f:
kernel_code_riscv = f.read()
self.parsed_AArch = self.parser_AArch.parse_file(triad_code_arm)
self.parsed_x86_att = self.parser_x86_att.parse_file(triad_code_x86_att)
self.parsed_x86_intel = self.parser_x86_intel.parse_file(triad_code_x86_intel)
self.parsed_RISCV = self.parser_RISCV.parse_file(kernel_code_riscv)
#################
# Test
@@ -53,6 +59,12 @@ class TestMarkerUtils(unittest.TestCase):
self.assertEqual(kernel[0].line_number, 111)
self.assertEqual(kernel[-1].line_number, 117)
def test_marker_detection_RISCV(self):
kernel = reduce_to_section(self.parsed_RISCV, ParserRISCV())
# The exact number of instructions and line numbers will depend on the RISC-V test file
# but we can at least test that reduce_to_section works for RISC-V
self.assertGreater(len(kernel), 0)
def test_marker_matching_AArch64(self):
# preparation
bytes_1_line = ".byte 213,3,32,31\n"
@@ -205,6 +217,71 @@ class TestMarkerUtils(unittest.TestCase):
)
self.assertEqual(sample_kernel, parsed_kernel)
def test_marker_matching_RISCV(self):
# preparation for RISC-V specific markers
bytes_1_line = ".byte 19,0,0,0\n"
bytes_2_lines = ".byte 19,0\n" + ".byte 0,0\n"
bytes_hex_line = ".byte 0x13,0x0,0x0,0x0\n"
li_start_1 = "li a1, 111 # OSACA START MARKER\n"
li_start_2 = "li a1, 111\n"
li_end_1 = "li a1, 222 # OSACA END MARKER\n"
li_end_2 = "li a1, 222\n"
prologue = "addi sp, sp, -16\n" + "sd ra, 8(sp)\n" + ".p2align 2\n"
kernel = (
".L4:\n"
+ "lw a5, 0(a0)\n"
+ "addi a0, a0, 4\n"
+ "addi a2, a2, -1\n"
+ "add a3, a3, a5\n"
+ "bnez a2, .L4\n"
)
epilogue = ".L5:\n" + "mv a0, a3\n" + "ret\n"
kernel_length = len(list(filter(None, kernel.split("\n"))))
bytes_variations = [
bytes_1_line,
bytes_2_lines,
bytes_hex_line,
]
li_start_variations = [li_start_1, li_start_2]
li_end_variations = [li_end_1, li_end_2]
# actual tests for RISC-V
for li_start_var in li_start_variations:
for bytes_var_1 in bytes_variations:
for li_end_var in li_end_variations:
for bytes_var_2 in bytes_variations:
sample_code = (
prologue
+ li_start_var
+ bytes_var_1
+ kernel
+ li_end_var
+ bytes_var_2
+ epilogue
)
with self.subTest(
li_start=li_start_var,
bytes_start=bytes_var_1,
li_end=li_end_var,
bytes_end=bytes_var_2,
):
sample_parsed = self.parser_RISCV.parse_file(sample_code)
sample_kernel = reduce_to_section(sample_parsed, ParserRISCV())
self.assertEqual(len(sample_kernel), kernel_length)
kernel_start = len(
list(
filter(
None,
(prologue + li_start_var + bytes_var_1).split("\n"),
)
)
)
parsed_kernel = self.parser_RISCV.parse_file(
kernel, start_line=kernel_start
)
self.assertEqual(sample_kernel, parsed_kernel)
def test_marker_special_cases_AArch(self):
bytes_line = ".byte 213,3,32,31\n"
start_marker = "mov x1, #111\n" + bytes_line
@@ -302,6 +379,56 @@ class TestMarkerUtils(unittest.TestCase):
msg="Invalid extracted kernel on {!r}".format(test_name),
)
def test_marker_special_cases_RISCV(self):
bytes_line = ".byte 19,0,0,0\n"
start_marker = "li a1, 111\n" + bytes_line
end_marker = "li a1, 222\n" + bytes_line
prologue = "addi sp, sp, -16\n" + "sd ra, 8(sp)\n" + ".p2align 2\n"
kernel = (
".L4:\n"
+ "lw a5, 0(a0)\n"
+ "addi a0, a0, 4\n"
+ "addi a2, a2, -1\n"
+ "add a3, a3, a5\n"
+ "bnez a2, .L4\n"
)
epilogue = ".L5:\n" + "mv a0, a3\n" + "ret\n"
samples = [
# (test name,
# ignored prologue, section to be extraced, ignored epilogue)
("markers", prologue + start_marker, kernel, end_marker + epilogue),
("marker at file start", start_marker, kernel, end_marker + epilogue),
("no start marker", "", prologue + kernel, end_marker + epilogue),
("marker at file end", prologue + start_marker, kernel, end_marker),
("no end marker", prologue + start_marker, kernel + epilogue, ""),
("empty kernel", prologue + start_marker, "", end_marker + epilogue),
]
for test_name, pro, kernel, epi in samples:
code = pro + kernel + epi
parsed = self.parser_RISCV.parse_file(code)
test_kernel = reduce_to_section(parsed, ParserRISCV())
if kernel:
kernel_length = len(kernel.strip().split("\n"))
else:
kernel_length = 0
self.assertEqual(
len(test_kernel),
kernel_length,
msg="Invalid extracted kernel length on {!r} sample".format(test_name),
)
if pro:
kernel_start = len((pro).strip().split("\n"))
else:
kernel_start = 0
parsed_kernel = self.parser_RISCV.parse_file(kernel, start_line=kernel_start)
self.assertEqual(
test_kernel,
parsed_kernel,
msg="Invalid extracted kernel on {!r}".format(test_name),
)
def test_find_jump_labels(self):
self.assertEqual(
find_jump_labels(self.parsed_x86_att),
@@ -363,6 +490,11 @@ class TestMarkerUtils(unittest.TestCase):
]
),
)
# Check that find_jump_labels works for RISC-V
riscv_labels = find_jump_labels(self.parsed_RISCV)
self.assertIsInstance(riscv_labels, OrderedDict)
self.assertGreater(len(riscv_labels), 0)
def test_find_basic_blocks(self):
self.assertEqual(
@@ -427,6 +559,10 @@ class TestMarkerUtils(unittest.TestCase):
("main", 575, 590),
],
)
# Check that find_basic_blocks works for RISC-V
riscv_blocks = find_basic_blocks(self.parsed_RISCV)
self.assertGreater(len(riscv_blocks), 0)
def test_find_basic_loop_body(self):
self.assertEqual(
@@ -451,6 +587,10 @@ class TestMarkerUtils(unittest.TestCase):
(".LBB0_35", 494, 504),
],
)
# Check that find_basic_loop_bodies works for RISC-V
riscv_loop_bodies = find_basic_loop_bodies(self.parsed_RISCV)
self.assertGreater(len(riscv_loop_bodies), 0)
##################
# Helper functions

View File

@@ -76,128 +76,44 @@ class TestParserRISCV(unittest.TestCase):
)
def test_parse_instruction(self):
# Use generic RISC-V instructions for testing, not tied to a specific file
instr1 = "beq a0,zero,.L12" # Branch instruction
instr2 = "vsetvli a5,zero,e32,m1,ta,ma" # Vector instruction
instr3 = "vle32.v v1,0(a1)" # Vector load instruction
instr4 = "fmadd.s fa5,fa0,fa5,fa4" # Floating-point instruction
instr5 = "addi sp,sp,-64" # Integer immediate instruction
instr6 = "csrr a4,vlenb" # CSR instruction
instr7 = "ret" # Return instruction
instr8 = "lui a0,%hi(data)" # Load upper immediate with relocation
instr9 = "sw ra,-4(sp)" # Store with negative offset
parsed_1 = self.parser.parse_instruction(instr1)
parsed_2 = self.parser.parse_instruction(instr2)
parsed_3 = self.parser.parse_instruction(instr3)
parsed_4 = self.parser.parse_instruction(instr4)
parsed_5 = self.parser.parse_instruction(instr5)
parsed_6 = self.parser.parse_instruction(instr6)
parsed_7 = self.parser.parse_instruction(instr7)
parsed_8 = self.parser.parse_instruction(instr8)
parsed_9 = self.parser.parse_instruction(instr9)
# Verify branch instruction
self.assertEqual(parsed_1.mnemonic, "beq")
"""Test parsing of instructions."""
# Test 1: Simple instruction
parsed_1 = self.parser.parse_instruction("addi x10, x10, 1")
self.assertEqual(parsed_1.mnemonic, "addi")
self.assertEqual(len(parsed_1.operands), 3)
self.assertTrue(isinstance(parsed_1.operands[0], RegisterOperand))
self.assertEqual(parsed_1.operands[0].name, "a0")
self.assertTrue(isinstance(parsed_1.operands[1], RegisterOperand))
self.assertEqual(parsed_1.operands[1].name, "zero")
self.assertTrue(isinstance(parsed_1.operands[2], IdentifierOperand))
self.assertEqual(parsed_1.operands[2].name, ".L12")
# Verify vector configuration instruction
self.assertEqual(parsed_2.mnemonic, "vsetvli")
self.assertEqual(len(parsed_2.operands), 6) # Verify correct operand count
self.assertEqual(parsed_2.operands[0].name, "a5")
self.assertEqual(parsed_2.operands[1].name, "zero")
# Verify vector load instruction
self.assertEqual(parsed_3.mnemonic, "vle32.v")
self.assertEqual(len(parsed_3.operands), 2)
self.assertEqual(parsed_3.operands[0].prefix, "v")
self.assertEqual(parsed_3.operands[0].name, "1")
self.assertTrue(isinstance(parsed_3.operands[1], MemoryOperand))
self.assertEqual(parsed_3.operands[1].base.name, "a1")
# Verify floating-point instruction
self.assertEqual(parsed_4.mnemonic, "fmadd.s")
self.assertEqual(len(parsed_4.operands), 4)
self.assertEqual(parsed_4.operands[0].prefix, "f")
# Verify integer immediate instruction
self.assertEqual(parsed_5.mnemonic, "addi")
self.assertEqual(len(parsed_5.operands), 3)
self.assertEqual(parsed_5.operands[0].name, "sp")
self.assertEqual(parsed_5.operands[1].name, "sp")
self.assertTrue(isinstance(parsed_5.operands[2], ImmediateOperand))
self.assertEqual(parsed_5.operands[2].value, -64)
# Verify CSR instruction
self.assertEqual(parsed_6.mnemonic, "csrr")
self.assertEqual(len(parsed_6.operands), 2)
self.assertEqual(parsed_6.operands[0].name, "a4")
self.assertEqual(parsed_6.operands[1].name, "vlenb")
# Verify return instruction
self.assertEqual(parsed_7.mnemonic, "ret")
self.assertEqual(len(parsed_7.operands), 0)
# Verify load upper immediate with relocation
self.assertEqual(parsed_8.mnemonic, "lui")
self.assertEqual(len(parsed_8.operands), 2)
self.assertEqual(parsed_8.operands[0].name, "a0")
self.assertEqual(parsed_8.operands[1].name, "data")
# Verify store with negative offset
self.assertEqual(parsed_9.mnemonic, "sw")
self.assertEqual(len(parsed_9.operands), 2)
self.assertEqual(parsed_9.operands[0].name, "ra")
self.assertTrue(isinstance(parsed_9.operands[1], MemoryOperand))
self.assertEqual(parsed_9.operands[1].base.name, "sp")
self.assertEqual(parsed_9.operands[1].offset.value, -4)
self.assertEqual(parsed_1.operands[0].name, "10")
self.assertEqual(parsed_1.operands[1].name, "10")
self.assertEqual(parsed_1.operands[2].value, 1)
# Test 2: Vector instruction
parsed_2 = self.parser.parse_instruction("vle64.v v1, (x11)")
self.assertEqual(parsed_2.mnemonic, "vle64.v")
self.assertEqual(len(parsed_2.operands), 2)
self.assertEqual(parsed_2.operands[0].name, "1")
self.assertEqual(parsed_2.operands[1].base.name, "11")
# Test 3: Floating point instruction
parsed_3 = self.parser.parse_instruction("fmul.d f10, f10, f11")
self.assertEqual(parsed_3.mnemonic, "fmul.d")
self.assertEqual(len(parsed_3.operands), 3)
self.assertEqual(parsed_3.operands[0].name, "10")
self.assertEqual(parsed_3.operands[1].name, "10")
self.assertEqual(parsed_3.operands[2].name, "11")
def test_parse_line(self):
# Use generic RISC-V lines for testing
line_label = "saxpy_golden:"
line_branch = " beq a0,zero,.L12"
line_memory = " vle32.v v1,0(a1)"
line_directive = " .word 1113498583"
line_with_comment = " ret # Return from function"
"""Test parsing of complete lines."""
# Test 1: Line with label and instruction
parsed_1 = self.parser.parse_line(".L2:")
self.assertEqual(parsed_1.label, ".L2")
parsed_1 = self.parser.parse_line(line_label, 1)
parsed_2 = self.parser.parse_line(line_branch, 2)
parsed_3 = self.parser.parse_line(line_memory, 3)
parsed_4 = self.parser.parse_line(line_directive, 4)
parsed_5 = self.parser.parse_line(line_with_comment, 5)
# Verify label parsing
self.assertEqual(parsed_1.label, "saxpy_golden")
self.assertIsNone(parsed_1.mnemonic)
# Verify branch instruction parsing
self.assertEqual(parsed_2.mnemonic, "beq")
# Test 2: Line with instruction and comment
parsed_2 = self.parser.parse_line("addi x10, x10, 1 # increment")
self.assertEqual(parsed_2.mnemonic, "addi")
self.assertEqual(len(parsed_2.operands), 3)
self.assertEqual(parsed_2.operands[0].name, "a0")
self.assertEqual(parsed_2.operands[1].name, "zero")
self.assertEqual(parsed_2.operands[2].name, ".L12")
# Verify memory instruction parsing
self.assertEqual(parsed_3.mnemonic, "vle32.v")
self.assertEqual(len(parsed_3.operands), 2)
self.assertEqual(parsed_3.operands[0].prefix, "v")
self.assertEqual(parsed_3.operands[0].name, "1")
self.assertTrue(isinstance(parsed_3.operands[1], MemoryOperand))
# Verify directive parsing
self.assertIsNone(parsed_4.mnemonic)
self.assertEqual(parsed_4.directive.name, "word")
self.assertEqual(parsed_4.directive.parameters[0], "1113498583")
# Verify comment parsing
self.assertEqual(parsed_5.mnemonic, "ret")
self.assertEqual(parsed_5.comment, "Return from function")
self.assertEqual(parsed_2.operands[0].name, "10")
self.assertEqual(parsed_2.operands[1].name, "10")
self.assertEqual(parsed_2.operands[2].value, 1)
self.assertEqual(parsed_2.comment, "increment")
def test_parse_file(self):
parsed = self.parser.parse_file(self.riscv_code)
@@ -295,29 +211,24 @@ class TestParserRISCV(unittest.TestCase):
self.assertEqual(self.parser.normalize_imd(identifier), identifier)
def test_memory_operand_parsing(self):
# Test memory operand parsing with different offsets and base registers
# Parse memory operands from real instructions
instr1 = "vle32.v v1,0(a1)"
instr2 = "lw a0,8(sp)"
instr3 = "sw ra,-4(sp)"
parsed1 = self.parser.parse_instruction(instr1)
parsed2 = self.parser.parse_instruction(instr2)
parsed3 = self.parser.parse_instruction(instr3)
# Verify memory operands
self.assertTrue(isinstance(parsed1.operands[1], MemoryOperand))
self.assertEqual(parsed1.operands[1].base.name, "a1")
self.assertEqual(parsed1.operands[1].offset.value, 0)
self.assertTrue(isinstance(parsed2.operands[1], MemoryOperand))
self.assertEqual(parsed2.operands[1].base.name, "sp")
"""Test parsing of memory operands."""
# Test 1: Basic memory operand
parsed1 = self.parser.parse_instruction("vle8.v v1, (x11)")
self.assertEqual(parsed1.mnemonic, "vle8.v")
self.assertEqual(len(parsed1.operands), 2)
self.assertEqual(parsed1.operands[0].name, "1")
self.assertEqual(parsed1.operands[1].base.name, "11")
self.assertEqual(parsed1.operands[1].offset, None)
self.assertEqual(parsed1.operands[1].index, None)
# Test 2: Memory operand with offset
parsed2 = self.parser.parse_instruction("vle8.v v1, 8(x11)")
self.assertEqual(parsed2.mnemonic, "vle8.v")
self.assertEqual(len(parsed2.operands), 2)
self.assertEqual(parsed2.operands[0].name, "1")
self.assertEqual(parsed2.operands[1].base.name, "11")
self.assertEqual(parsed2.operands[1].offset.value, 8)
self.assertTrue(isinstance(parsed3.operands[1], MemoryOperand))
self.assertEqual(parsed3.operands[1].base.name, "sp")
self.assertEqual(parsed3.operands[1].offset.value, -4)
self.assertEqual(parsed2.operands[1].index, None)
##################
# Helper functions