From c8f25f796edd14cdb72ca4badc52623a80c76883 Mon Sep 17 00:00:00 2001 From: Sam Elliott Date: Mon, 30 Jun 2025 19:34:30 -0700 Subject: [PATCH 1/4] [RISCV][NFC] Add Coverage For Symbol Operands This adds assembly test coverage for the following operand types: - simm12 - uimm20_lui - uimm20_auipc - simm6 - simm6nonzero - simm5 - simm5_plus1 - simm20_li --- llvm/test/MC/RISCV/rv32c-invalid.s | 17 +++++++++++++++-- llvm/test/MC/RISCV/rv64c-invalid.s | 13 ++++++++++++- llvm/test/MC/RISCV/rv64c-valid.s | 7 +++++++ llvm/test/MC/RISCV/rvc-invalid.s | 23 +++++++++++++++++++++++ llvm/test/MC/RISCV/rvc-valid.s | 17 +++++++++++++++++ llvm/test/MC/RISCV/rvi-invalid.s | 25 +++++++++++++++++++++++++ llvm/test/MC/RISCV/rvv/symbol-invalid.s | 20 ++++++++++++++++++++ llvm/test/MC/RISCV/rvv/symbol-valid.s | 18 ++++++++++++++++++ llvm/test/MC/RISCV/xqcibi-relocations.s | 15 ++++++++++++++- llvm/test/MC/RISCV/xqcilb-relocations.s | 17 ++++++++++++++++- llvm/test/MC/RISCV/xqcili-invalid.s | 14 ++++++++++++++ llvm/test/MC/RISCV/xqcili-relocations.s | 13 ++++++++++++- 12 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 llvm/test/MC/RISCV/rvc-invalid.s create mode 100644 llvm/test/MC/RISCV/rvi-invalid.s create mode 100644 llvm/test/MC/RISCV/rvv/symbol-invalid.s create mode 100644 llvm/test/MC/RISCV/rvv/symbol-valid.s diff --git a/llvm/test/MC/RISCV/rv32c-invalid.s b/llvm/test/MC/RISCV/rv32c-invalid.s index 413573af1c5e6..b3aee6b38ae3c 100644 --- a/llvm/test/MC/RISCV/rv32c-invalid.s +++ b/llvm/test/MC/RISCV/rv32c-invalid.s @@ -35,6 +35,10 @@ c.addi16sp t0, 16 # CHECK: :[[@LINE]]:13: error: register must be sp (x2) # Out of range immediates +reldef: + +.global undef + ## uimmlog2xlennonzero c.slli t0, 64 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 31] c.srli a0, 32 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 31] @@ -53,16 +57,23 @@ c.andi a0, %hi(foo) # CHECK: :[[@LINE]]:12: error: immediate must be an integer ## simm6nonzero c.addi t0, -33 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] c.addi t0, 32 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] -c.addi t0, foo # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] c.addi t0, %lo(foo) # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] c.addi t0, %hi(foo) # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] +c.addi t0, reldef # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] +c.addi t0, reldef-. # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] +c.addi t0, undef # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] +c.addi t0, latedef # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] + ## c_lui_imm c.lui t0, 0 # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31] c.lui t0, 32 # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31] c.lui t0, 0xffffdf # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31] c.lui t0, 0x1000000 # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31] -c.lui t0, foo # CHECK: [[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31] +c.lui t0, reldef # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31] +c.lui t0, reldef-. # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31] +c.lui t0, undef # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31] +c.lui t0, latedef # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31] ## uimm8_lsb00 c.lwsp ra, 256(sp) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 4 bytes in the range [0, 252] @@ -87,3 +98,5 @@ c.addi4spn a0, sp, 1024 # CHECK: :[[@LINE]]:21: error: immediate must be a mult c.addi16sp sp, -528 # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 16 bytes and non-zero in the range [-512, 496] c.addi16sp sp, 512 # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 16 bytes and non-zero in the range [-512, 496] c.addi16sp sp, 0 # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 16 bytes and non-zero in the range [-512, 496] + +.set latedef, 1 diff --git a/llvm/test/MC/RISCV/rv64c-invalid.s b/llvm/test/MC/RISCV/rv64c-invalid.s index 9b0a3244f3aac..1be93746d31d3 100644 --- a/llvm/test/MC/RISCV/rv64c-invalid.s +++ b/llvm/test/MC/RISCV/rv64c-invalid.s @@ -13,17 +13,26 @@ c.ldsp zero, 4(sp) # CHECK: :[[@LINE]]:9: error: register must be a GPR excludi # Out of range immediates +reldef: +.global undef + ## uimmlog2xlennonzero c.slli t0, 64 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 63] c.srli a0, -1 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 63] c.srai a0, 0 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 63] +c.slli t0, reldef # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 63] +c.srli a0, reldef-. # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 63] +c.srai a0, undef # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 63] ## simm6 c.addiw t0, -33 # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-32, 31] c.addiw t0, 32 # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-32, 31] -c.addiw t0, foo # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-32, 31] c.addiw t0, %lo(foo) # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-32, 31] c.addiw t0, %hi(foo) # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-32, 31] +c.addiw t0, reldef # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-32, 31] +c.addiw t0, reldef-. # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-32, 31] +c.addiw t0, undef # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-32, 31] +c.addiw t0, latedef # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-32, 31] ## uimm9_lsb000 c.ldsp ra, 512(sp) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 8 bytes in the range [0, 504] @@ -31,3 +40,5 @@ c.sdsp ra, -8(sp) # CHECK: :[[@LINE]]:13: error: immediate must be a multiple o ## uimm8_lsb000 c.ld s0, -8(sp) # CHECK: :[[@LINE]]:11: error: immediate must be a multiple of 8 bytes in the range [0, 248] c.sd s0, 256(sp) # CHECK: :[[@LINE]]:11: error: immediate must be a multiple of 8 bytes in the range [0, 248] + +.set latedef, 1 diff --git a/llvm/test/MC/RISCV/rv64c-valid.s b/llvm/test/MC/RISCV/rv64c-valid.s index 9f53c6a3b4b0a..d856ace7a029f 100644 --- a/llvm/test/MC/RISCV/rv64c-valid.s +++ b/llvm/test/MC/RISCV/rv64c-valid.s @@ -72,3 +72,10 @@ c.srli a3, 63 # CHECK-ASM: encoding: [0x7d,0x96] # CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores){{$}} c.srai a2, 63 + +.set absdef, 1 + +# CHECK-ASM-AND-OBJ: c.addiw a0, 1 +# CHECK-ASM: encoding: [0x05,0x25] +# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores){{$}} +c.addiw a0, absdef diff --git a/llvm/test/MC/RISCV/rvc-invalid.s b/llvm/test/MC/RISCV/rvc-invalid.s new file mode 100644 index 0000000000000..153f3d4a75778 --- /dev/null +++ b/llvm/test/MC/RISCV/rvc-invalid.s @@ -0,0 +1,23 @@ +# RUN: not llvm-mc %s -triple=riscv32 2>&1 | FileCheck %s +# RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck %s + +reldef: + +.global undef + +c.addi a0, reldef # CHECK: :[[@LINE]]:12: error: invalid operand for instruction +c.addi a0, reldef-. # CHECK: :[[@LINE]]:12: error: invalid operand for instruction +c.addi a0, undef # CHECK: :[[@LINE]]:12: error: invalid operand for instruction +c.addi a0, latedef # CHECK: :[[@LINE]]:12: error: invalid operand for instruction + +c.li a0, reldef # CHECK: :[[@LINE]]:10: error: invalid operand for instruction +c.li a0, reldef-. # CHECK: :[[@LINE]]:10: error: invalid operand for instruction +c.li a0, undef # CHECK: :[[@LINE]]:10: error: invalid operand for instruction +c.li a0, latedef # CHECK: :[[@LINE]]:10: error: invalid operand for instruction + +c.andi a0, reldef # CHECK: :[[@LINE]]:12: error: invalid operand for instruction +c.andi a0, reldef-. # CHECK: :[[@LINE]]:12: error: invalid operand for instruction +c.andi a0, undef # CHECK: :[[@LINE]]:12: error: invalid operand for instruction +c.andi a0, latedef # CHECK: :[[@LINE]]:12: error: invalid operand for instruction + +.set latedef, 1 diff --git a/llvm/test/MC/RISCV/rvc-valid.s b/llvm/test/MC/RISCV/rvc-valid.s index 798bff8630cc4..bedbdc9ec1094 100644 --- a/llvm/test/MC/RISCV/rvc-valid.s +++ b/llvm/test/MC/RISCV/rvc-valid.s @@ -175,3 +175,20 @@ c.lui s0, 0xfffff # CHECK-ASM: encoding: [0x00,0x00] # CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores){{$}} c.unimp + +.set absdef, 1 + +c.addi a0, absdef +# CHECK-ASM-AND-OBJ: c.addi a0, 1 +# CHECK-ASM: encoding: [0x05,0x05] +# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores){{$}} + +c.li a0, absdef +# CHECK-ASM-AND-OBJ: c.li a0, 1 +# CHECK-ASM: encoding: [0x05,0x45] +# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores){{$}} + +c.andi a0, absdef +# CHECK-ASM-AND-OBJ: c.andi a0, 1 +# CHECK-ASM: encoding: [0x05,0x89] +# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores){{$}} diff --git a/llvm/test/MC/RISCV/rvi-invalid.s b/llvm/test/MC/RISCV/rvi-invalid.s new file mode 100644 index 0000000000000..3f97349d35754 --- /dev/null +++ b/llvm/test/MC/RISCV/rvi-invalid.s @@ -0,0 +1,25 @@ +# RUN: not llvm-mc -triple=riscv32 < %s 2>&1 | FileCheck %s +# RUN: not llvm-mc -triple=riscv64 < %s 2>&1 | FileCheck %s + +reldef: + +.global undef + +## simm12 +addi a0, a1, reldef # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo specifier or an integer in the range [-2048, 2047] +addi a0, a1, reldef-. # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo specifier or an integer in the range [-2048, 2047] +addi a0, a1, undef # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo specifier or an integer in the range [-2048, 2047] +addi a0, a1, latedef # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo specifier or an integer in the range [-2048, 2047] + + +lui a0, reldef # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi/%tprel_hi specifier or an integer in the range [0, 1048575] +lui a0, reldef-. # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi/%tprel_hi specifier or an integer in the range [0, 1048575] +lui a0, undef # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi/%tprel_hi specifier or an integer in the range [0, 1048575] +lui a0, latedef # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi/%tprel_hi specifier or an integer in the range [0, 1048575] + +auipc a0, reldef # CHECK: :[[@LINE]]:11: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi specifier or an integer in the range [0, 1048575] +auipc a0, reldef-. # CHECK: :[[@LINE]]:11: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi specifier or an integer in the range [0, 1048575] +auipc a0, undef # CHECK: :[[@LINE]]:11: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi specifier or an integer in the range [0, 1048575] +auipc a0, latedef # CHECK: :[[@LINE]]:11: error: operand must be a symbol with a %pcrel_hi/%got_pcrel_hi/%tls_ie_pcrel_hi/%tls_gd_pcrel_hi specifier or an integer in the range [0, 1048575] + +.set latedef, 1 diff --git a/llvm/test/MC/RISCV/rvv/symbol-invalid.s b/llvm/test/MC/RISCV/rvv/symbol-invalid.s new file mode 100644 index 0000000000000..c31b455bd6b4a --- /dev/null +++ b/llvm/test/MC/RISCV/rvv/symbol-invalid.s @@ -0,0 +1,20 @@ +# RUN: not llvm-mc --triple=riscv64 -mattr=+v < %s 2>&1 | FileCheck %s + +reldef: + +.global undef + +## simm5_plus1 +vmsgeu.vi v3, v4, reldef, v0.t # CHECK: :[[@LINE]]:19: error: immediate must be in the range [-15, 16] +vmsgeu.vi v3, v4, reldef-., v0.t # CHECK: :[[@LINE]]:19: error: immediate must be in the range [-15, 16] +vmsgeu.vi v3, v4, undef, v0.t # CHECK: :[[@LINE]]:19: error: immediate must be in the range [-15, 16] +vmsgeu.vi v3, v4, latedef, v0.t # CHECK: :[[@LINE]]:19: error: immediate must be in the range [-15, 16] + + +## simm5 +vadd.vi v4, v5, reldef, v0.t # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [-16, 15] +vadd.vi v4, v5, reldef-., v0.t # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [-16, 15] +vadd.vi v4, v5, undef, v0.t # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [-16, 15] +vadd.vi v4, v5, latedef, v0.t # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [-16, 15] + +.set latedef, 1 diff --git a/llvm/test/MC/RISCV/rvv/symbol-valid.s b/llvm/test/MC/RISCV/rvv/symbol-valid.s new file mode 100644 index 0000000000000..ab9bb19b66a55 --- /dev/null +++ b/llvm/test/MC/RISCV/rvv/symbol-valid.s @@ -0,0 +1,18 @@ +# RUN: llvm-mc --triple=riscv64 -mattr=+v < %s | FileCheck %s --check-prefix=ASM +# RUN: llvm-mc --triple=riscv64 -mattr=+v < %s -filetype=obj -o - \ +# RUN: | llvm-objdump -d --mattr=+v - \ +# RUN: | FileCheck %s --check-prefix=OBJ + + +.set absdef, 1 + +## simm5_plus1 +# ASM: vmsgtu.vi v3, v4, 0, v0.t +# OBJ: vmsgtu.vi v3, v4, 0x0, v0.t +vmsgeu.vi v3, v4, absdef, v0.t + +## simm5 +# ASM: vadd.vi v4, v5, 1, v0.t +# OBJ: vadd.vi v4, v5, 0x1, v0.t +vadd.vi v4, v5, absdef, v0.t + diff --git a/llvm/test/MC/RISCV/xqcibi-relocations.s b/llvm/test/MC/RISCV/xqcibi-relocations.s index 0f7cc8c5787a1..931cd7c9314bb 100644 --- a/llvm/test/MC/RISCV/xqcibi-relocations.s +++ b/llvm/test/MC/RISCV/xqcibi-relocations.s @@ -84,7 +84,20 @@ qc.bnei t3, 14, same_section # OBJ-NEXT: qc.e.bgeui s2, 0x18, 0x28 qc.e.bgeui s2, 24, same_section -.option norelax +## Enable compression/relaxation to check how symbols are handled. +.option noexact + +# ASM: qc.bnei t1, 10, undef +# OBJ: qc.beqi t1, 0xa, 0x42 +# OBJ-NEXT: j 0x3e +# OBJ-NEXT: R_RISCV_JAL undef{{$}} +qc.bnei t1, 10, undef + +# ASM: qc.e.bgeui s0, 40, undef +# OBJ-NEXT: qc.e.bltui s0, 0x28, 0x4c +# OBJ-NEXT: j 0x48 +# OBJ-NEXT: R_RISCV_JAL undef{{$}} +qc.e.bgeui s0, 40, undef .section .text.second, "ax", @progbits diff --git a/llvm/test/MC/RISCV/xqcilb-relocations.s b/llvm/test/MC/RISCV/xqcilb-relocations.s index ab08beed9be94..48c8c6931c8af 100644 --- a/llvm/test/MC/RISCV/xqcilb-relocations.s +++ b/llvm/test/MC/RISCV/xqcilb-relocations.s @@ -92,7 +92,22 @@ qc.e.j same_section # OBJ-NEXT: R_RISCV_RELAX qc.e.jal same_section -.option norelax +## Enable compression/relaxation to check how symbols are handled. +.option noexact + +qc.e.j undef +# ASM: j undef +# OBJ: qc.e.j 0x44 +# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} +# OBJ-NEXT: R_RISCV_CUSTOM195 undef{{$}} +# OBJ-NEXT: R_RISCV_RELAX + +qc.e.jal undef +# ASM: jal undef +# OBJ: qc.e.jal 0x4a +# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} +# OBJ-NEXT: R_RISCV_CUSTOM195 undef{{$}} +# OBJ-NEXT: R_RISCV_RELAX .section .text.other, "ax", @progbits diff --git a/llvm/test/MC/RISCV/xqcili-invalid.s b/llvm/test/MC/RISCV/xqcili-invalid.s index 567ed8ba89736..f7a9b80e91f92 100644 --- a/llvm/test/MC/RISCV/xqcili-invalid.s +++ b/llvm/test/MC/RISCV/xqcili-invalid.s @@ -30,3 +30,17 @@ qc.li x10, 33554432 # CHECK-EXT: :[[@LINE+1]]:1: error: instruction requires the following: 'Xqcili' (Qualcomm uC Load Large Immediate Extension) qc.li x10, 114514 + +reldef: +.global undef + +# CHECK-IMM: :[[@LINE+1]]:12: error: operand must be a symbol with a %qc.abs20 specifier or an integer in the range [-524288, 524287] +qc.li x10, reldef +# CHECK-IMM: :[[@LINE+1]]:12: error: operand must be a symbol with a %qc.abs20 specifier or an integer in the range [-524288, 524287] +qc.li x10, reldef-. +# CHECK-IMM: :[[@LINE+1]]:12: error: operand must be a symbol with a %qc.abs20 specifier or an integer in the range [-524288, 524287] +qc.li x10, undef +# CHECK-IMM: :[[@LINE+1]]:12: error: operand must be a symbol with a %qc.abs20 specifier or an integer in the range [-524288, 524287] +qc.li x10, latedef + +.set latedef, 1 diff --git a/llvm/test/MC/RISCV/xqcili-relocations.s b/llvm/test/MC/RISCV/xqcili-relocations.s index 866586236fa46..5184125cc9a81 100644 --- a/llvm/test/MC/RISCV/xqcili-relocations.s +++ b/llvm/test/MC/RISCV/xqcili-relocations.s @@ -97,7 +97,18 @@ qc.li a1, %qc.abs20(undef) # OBJ-NEXT: R_RISCV_RELAX qc.e.li s1, undef -.option norelax +## Enable compression/relaxation to check how symbols are handled. +.option noexact + +# ASM: qc.li a1, %qc.abs20(undef) +# OBJ-NEXT: qc.li a1, 0x0 +# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} +# OBJ-NEXT: R_RISCV_CUSTOM192 undef{{$}} +# OBJ-NEXT: R_RISCV_RELAX +qc.li a1, %qc.abs20(undef) + +## FIXME: Broken +## qc.e.li a2, undef .section .text.other, "ax", @progbits From 002af0c1438d66edfd9e72db95e4af73f7e9e029 Mon Sep 17 00:00:00 2001 From: Sam Elliott Date: Mon, 30 Jun 2025 21:22:39 -0700 Subject: [PATCH 2/4] [RISCV] Align MCOperandPredicates with AsmParser Before this change, many MCOperandPredicates accepted bare symbols but there was no cohesive logic as to which did and which didn't, and it did not correspond to where the parser did and did not accept bare symbols. MCOperandPredicates are used by the assembly printer when choosing to whether to use an alias, and by the assembler compression and decompression mechanism. RISC-V uses both of these extensively. Xqci had a bug with a compress pattern for `qc.e.li` (to `c.li`) which was causing crashes because `RISCVMCCodeEmitter::getImmOpValue` could not handle a bare symbol ref when encoding the `c.li` instruction. This patch aligns the MCOperandPredicates with the predicates in the RISC-V assembly parser, denying bare symbol references in places they were accepted for aliases/compression in the past. This is not NFC, as some assembly printing has changed with the `li` alias for `addi`, but this seems very minor. The crash when assembling `qc.e.li a0, undef` is now fixed. --- llvm/include/llvm/MC/MCExpr.h | 4 +- llvm/include/llvm/MC/MCInst.h | 3 +- llvm/lib/MC/MCInst.cpp | 25 +++++++++-- .../RISCV/MCTargetDesc/RISCVBaseInfo.cpp | 4 ++ .../RISCV/MCTargetDesc/RISCVInstPrinter.cpp | 3 ++ llvm/lib/Target/RISCV/RISCVInstrInfo.td | 41 +++++++++++++++---- llvm/lib/Target/RISCV/RISCVInstrInfoC.td | 12 +++--- llvm/lib/Target/RISCV/RISCVInstrInfoV.td | 12 +++--- llvm/lib/Target/RISCV/RISCVInstrInfoXSf.td | 6 +-- llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td | 7 +++- llvm/test/MC/RISCV/rv32i-aliases-valid.s | 4 +- llvm/test/MC/RISCV/rv64i-aliases-valid.s | 5 ++- llvm/test/MC/RISCV/xqcili-relocations.s | 8 +++- 13 files changed, 98 insertions(+), 36 deletions(-) diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h index b3585693afa02..7928552cc305f 100644 --- a/llvm/include/llvm/MC/MCExpr.h +++ b/llvm/include/llvm/MC/MCExpr.h @@ -46,6 +46,9 @@ class MCExpr { Target ///< Target specific expression. }; + /// The type of a Specifier (used in MCSymbolRefExpr and MCSpecifierExpr). + using Spec = uint16_t; + private: static const unsigned NumSubclassDataBits = 24; static_assert( @@ -63,7 +66,6 @@ class MCExpr { bool InSet) const; protected: - using Spec = uint16_t; explicit MCExpr(ExprKind Kind, SMLoc Loc, unsigned SubclassData = 0) : Kind(Kind), SubclassData(SubclassData), Loc(Loc) { assert(SubclassData < (1 << NumSubclassDataBits) && diff --git a/llvm/include/llvm/MC/MCInst.h b/llvm/include/llvm/MC/MCInst.h index f26af88d92140..5a9a194937c60 100644 --- a/llvm/include/llvm/MC/MCInst.h +++ b/llvm/include/llvm/MC/MCInst.h @@ -18,6 +18,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/bit.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCRegister.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/SMLoc.h" @@ -28,7 +29,6 @@ namespace llvm { class MCContext; -class MCExpr; class MCInst; class MCInstPrinter; class MCRegisterInfo; @@ -179,6 +179,7 @@ class MCOperand { LLVM_ABI void print(raw_ostream &OS, const MCContext *Ctx = nullptr) const; LLVM_ABI void dump() const; LLVM_ABI bool isBareSymbolRef() const; + LLVM_ABI bool isSimpleSymbolRef(MCExpr::Spec &Specifier) const; LLVM_ABI bool evaluateAsConstantImm(int64_t &Imm) const; }; diff --git a/llvm/lib/MC/MCInst.cpp b/llvm/lib/MC/MCInst.cpp index 46a6a18e15963..b455cbfcb4f43 100644 --- a/llvm/lib/MC/MCInst.cpp +++ b/llvm/lib/MC/MCInst.cpp @@ -63,12 +63,29 @@ bool MCOperand::evaluateAsConstantImm(int64_t &Imm) const { } bool MCOperand::isBareSymbolRef() const { - assert(isExpr() && - "isBareSymbolRef expects only expressions"); + MCExpr::Spec Specifier; + return isSimpleSymbolRef(Specifier) && Specifier == 0; +} + +bool MCOperand::isSimpleSymbolRef(MCExpr::Spec &Specifier) const { + assert(isExpr() && "isBareSymbolRef expects only expressions"); const MCExpr *Expr = getExpr(); MCExpr::ExprKind Kind = getExpr()->getKind(); - return Kind == MCExpr::SymbolRef && - cast(Expr)->getSpecifier() == 0; + + switch (Kind) { + case MCExpr::Binary: + case MCExpr::Unary: + case MCExpr::Constant: + case MCExpr::Target: + break; + case MCExpr::SymbolRef: + Specifier = cast(Expr)->getSpecifier(); + return true; + case MCExpr::Specifier: + Specifier = cast(Expr)->getSpecifier(); + return true; + } + return false; } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp index d407beffcd7d1..25c0076565c5f 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp @@ -12,9 +12,13 @@ //===----------------------------------------------------------------------===// #include "RISCVBaseInfo.h" +#include "MCTargetDesc/RISCVMCAsmInfo.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/TargetParser.h" #include "llvm/TargetParser/Triple.h" diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp index 8c9ab8effa71b..7163486e763c7 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp @@ -11,13 +11,16 @@ //===----------------------------------------------------------------------===// #include "RISCVInstPrinter.h" +#include "MCTargetDesc/RISCVMCAsmInfo.h" #include "RISCVBaseInfo.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index e0321443ba2d4..0adbc53a854db 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -327,12 +327,20 @@ def uimm16 : RISCVUImmOp<16>; def uimm32 : RISCVUImmOp<32>; def uimm48 : RISCVUImmOp<48>; def uimm64 : RISCVUImmOp<64>; + def simm12 : RISCVSImmLeafOp<12> { let MCOperandPredicate = [{ int64_t Imm; if (MCOp.evaluateAsConstantImm(Imm)) return isInt<12>(Imm); - return MCOp.isBareSymbolRef(); + + MCExpr::Spec S; + if (!MCOp.isExpr() || !MCOp.isSimpleSymbolRef(S)) + return false; + + return (S == RISCV::S_LO) || (S == RISCV::S_PCREL_LO) || + (S == RISCV::S_TPREL_LO) || (S == ELF::R_RISCV_TLSDESC_LOAD_LO12) || + (S == ELF::R_RISCV_TLSDESC_ADD_LO12); }]; } @@ -368,20 +376,37 @@ def bare_simm13_lsb0 : BareSImm13Lsb0MaybeSym, // is used to match with a basic block (eg. BccPat<>). def bare_simm13_lsb0_bb : BareSImm13Lsb0MaybeSym; -class UImm20OperandMaybeSym : RISCVUImmOp<20> { +def uimm20_lui : RISCVUImmOp<20> { + let ParserMatchClass = UImmAsmOperand<20, "LUI">; let MCOperandPredicate = [{ int64_t Imm; if (MCOp.evaluateAsConstantImm(Imm)) return isUInt<20>(Imm); - return MCOp.isBareSymbolRef(); - }]; -} -def uimm20_lui : UImm20OperandMaybeSym { - let ParserMatchClass = UImmAsmOperand<20, "LUI">; + MCExpr::Spec S; + if (!MCOp.isExpr() || !MCOp.isSimpleSymbolRef(S)) + return false; + + return (S == ELF::R_RISCV_HI20) || + (S == ELF::R_RISCV_TPREL_HI20); + }]; } -def uimm20_auipc : UImm20OperandMaybeSym { +def uimm20_auipc : RISCVUImmOp<20> { let ParserMatchClass = UImmAsmOperand<20, "AUIPC">; + let MCOperandPredicate = [{ + int64_t Imm; + if (MCOp.evaluateAsConstantImm(Imm)) + return isUInt<20>(Imm); + + MCExpr::Spec S; + if (!MCOp.isExpr() || !MCOp.isSimpleSymbolRef(S)) + return false; + + return (S == ELF::R_RISCV_PCREL_HI20) || (S == ELF::R_RISCV_GOT_HI20) || + (S == ELF::R_RISCV_TLS_GOT_HI20) || + (S == ELF::R_RISCV_TLS_GD_HI20) || + (S == ELF::R_RISCV_TLSDESC_HI20); + }]; } def uimm20 : RISCVUImmOp<20>; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td index 8252a9b170eb3..de235b3d8dde8 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td @@ -37,9 +37,9 @@ def uimmlog2xlennonzero : RISCVOp, ImmLeaf { let MCOperandPredicate = [{ int64_t Imm; - if (MCOp.evaluateAsConstantImm(Imm)) - return isInt<6>(Imm); - return MCOp.isBareSymbolRef(); + if (!MCOp.evaluateAsConstantImm(Imm)) + return false; + return isInt<6>(Imm); }]; } @@ -51,9 +51,9 @@ def simm6nonzero : RISCVOp, let OperandType = "OPERAND_SIMM6_NONZERO"; let MCOperandPredicate = [{ int64_t Imm; - if (MCOp.evaluateAsConstantImm(Imm)) - return (Imm != 0) && isInt<6>(Imm); - return MCOp.isBareSymbolRef(); + if (!MCOp.evaluateAsConstantImm(Imm)) + return false; + return (Imm != 0) && isInt<6>(Imm); }]; } diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoV.td index 5d13a877c90a2..c61bfdecfe33c 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoV.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoV.td @@ -72,9 +72,9 @@ def VMaskCarryInOp : RegisterOperand { def simm5 : RISCVSImmLeafOp<5> { let MCOperandPredicate = [{ int64_t Imm; - if (MCOp.evaluateAsConstantImm(Imm)) - return isInt<5>(Imm); - return MCOp.isBareSymbolRef(); + if (!MCOp.evaluateAsConstantImm(Imm)) + return false; + return isInt<5>(Imm); }]; } @@ -84,9 +84,9 @@ def simm5_plus1 : RISCVOp, ImmLeaf(Imm) && Imm != -16) || Imm == 16; - return MCOp.isBareSymbolRef(); + if (!MCOp.evaluateAsConstantImm(Imm)) + return false; + return (isInt<5>(Imm) && Imm != -16) || Imm == 16; }]; } diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXSf.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXSf.td index affe3a8476753..d678cab7de8b0 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoXSf.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXSf.td @@ -43,9 +43,9 @@ def tsimm5 : Operand, TImmLeaf(Imm);}]> { let DecoderMethod = "decodeSImmOperand<5>"; let MCOperandPredicate = [{ int64_t Imm; - if (MCOp.evaluateAsConstantImm(Imm)) - return isInt<5>(Imm); - return MCOp.isBareSymbolRef(); + if (!MCOp.evaluateAsConstantImm(Imm)) + return false; + return isInt<5>(Imm); }]; } diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td index e8dd164714875..090fd6eb22ba6 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXqci.td @@ -146,7 +146,12 @@ def simm20_li : RISCVOp, int64_t Imm; if (MCOp.evaluateAsConstantImm(Imm)) return isInt<20>(Imm); - return MCOp.isBareSymbolRef(); + + MCExpr::Spec S; + if (!MCOp.isExpr() || !MCOp.isSimpleSymbolRef(S)) + return false; + + return S == RISCV::S_QC_ABS20; }]; } diff --git a/llvm/test/MC/RISCV/rv32i-aliases-valid.s b/llvm/test/MC/RISCV/rv32i-aliases-valid.s index d35fdccedf7f0..b4f22ad06556d 100644 --- a/llvm/test/MC/RISCV/rv32i-aliases-valid.s +++ b/llvm/test/MC/RISCV/rv32i-aliases-valid.s @@ -85,7 +85,7 @@ li x12, 0xFFFFFFFF # CHECK-ASM-NOALIAS: addi a0, zero, %lo(1193046) # CHECK-OBJ-NOALIAS: addi a0, zero, 1110 -# CHECK-ASM: addi a0, zero, %lo(1193046) +# CHECK-ASM: li a0, %lo(1193046) li a0, %lo(0x123456) # CHECK-OBJ-NOALIAS: addi a0, zero, 0 @@ -109,7 +109,7 @@ li a0, CONST+1 li a0, CONST .equ CONST, .Lbuf_end - .Lbuf -# CHECK-ASM: li a0, CONST +# CHECK-ASM: addi a0, zero, CONST # CHECK-ASM-NOALIAS: addi a0, zero, CONST # CHECK-OBJ-NOALIAS: addi a0, zero, 8 li a0, CONST diff --git a/llvm/test/MC/RISCV/rv64i-aliases-valid.s b/llvm/test/MC/RISCV/rv64i-aliases-valid.s index 2a37caa0c5c2a..94dc87e6ebc6b 100644 --- a/llvm/test/MC/RISCV/rv64i-aliases-valid.s +++ b/llvm/test/MC/RISCV/rv64i-aliases-valid.s @@ -192,7 +192,8 @@ li x13, 0xffffffff55555556 # CHECK-S-OBJ-NEXT: addi t0, t0, -1365 li x5, -2147485013 -# CHECK-ASM: addi a0, zero, %lo(1193046) +# CHECK-ASM: li a0, %lo(1193046) +# CHECK-ASM-NOALIAS: addi a0, zero, %lo(1193046) # CHECK-OBJ: addi a0, zero, %lo(1193046) li a0, %lo(0x123456) @@ -214,7 +215,7 @@ li a0, CONST li a0, CONST .equ CONST, .Lbuf_end - .Lbuf -# CHECK-ASM: li a0, CONST +# CHECK-ASM: addi a0, zero, CONST # CHECK-ASM-NOALIAS: addi a0, zero, CONST # CHECK-OBJ-NOALIAS: addi a0, zero, 8 li a0, CONST diff --git a/llvm/test/MC/RISCV/xqcili-relocations.s b/llvm/test/MC/RISCV/xqcili-relocations.s index 5184125cc9a81..7eff61fc782d8 100644 --- a/llvm/test/MC/RISCV/xqcili-relocations.s +++ b/llvm/test/MC/RISCV/xqcili-relocations.s @@ -107,8 +107,12 @@ qc.e.li s1, undef # OBJ-NEXT: R_RISCV_RELAX qc.li a1, %qc.abs20(undef) -## FIXME: Broken -## qc.e.li a2, undef +# ASM: qc.e.li a2, undef +# OBJ-NEXT: qc.e.li a2, 0x0 +# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}} +# OBJ-NEXT: R_RISCV_CUSTOM194 undef{{$}} +# OBJ-NEXT: R_RISCV_RELAX +qc.e.li a2, undef .section .text.other, "ax", @progbits From 6314d5a34432af8ceea92dc73327ab5c01c1abd6 Mon Sep 17 00:00:00 2001 From: Sam Elliott Date: Mon, 30 Jun 2025 22:51:06 -0700 Subject: [PATCH 3/4] Address feedback, comment on target kind --- llvm/lib/MC/MCInst.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/llvm/lib/MC/MCInst.cpp b/llvm/lib/MC/MCInst.cpp index b455cbfcb4f43..ad6715cf7f610 100644 --- a/llvm/lib/MC/MCInst.cpp +++ b/llvm/lib/MC/MCInst.cpp @@ -68,7 +68,7 @@ bool MCOperand::isBareSymbolRef() const { } bool MCOperand::isSimpleSymbolRef(MCExpr::Spec &Specifier) const { - assert(isExpr() && "isBareSymbolRef expects only expressions"); + assert(isExpr() && "isSimpleSymbolRef expects only expressions"); const MCExpr *Expr = getExpr(); MCExpr::ExprKind Kind = getExpr()->getKind(); @@ -76,7 +76,9 @@ bool MCOperand::isSimpleSymbolRef(MCExpr::Spec &Specifier) const { case MCExpr::Binary: case MCExpr::Unary: case MCExpr::Constant: + break; case MCExpr::Target: + // It's not clear this is right, does MCTargetExpr need another virtual method? break; case MCExpr::SymbolRef: Specifier = cast(Expr)->getSpecifier(); From 427a2c4037342a495d3fb8180a7c60f806ce61d6 Mon Sep 17 00:00:00 2001 From: Sam Elliott Date: Mon, 30 Jun 2025 23:06:11 -0700 Subject: [PATCH 4/4] clang-format --- llvm/lib/MC/MCInst.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/MC/MCInst.cpp b/llvm/lib/MC/MCInst.cpp index ad6715cf7f610..e2fb8eb82d616 100644 --- a/llvm/lib/MC/MCInst.cpp +++ b/llvm/lib/MC/MCInst.cpp @@ -78,7 +78,8 @@ bool MCOperand::isSimpleSymbolRef(MCExpr::Spec &Specifier) const { case MCExpr::Constant: break; case MCExpr::Target: - // It's not clear this is right, does MCTargetExpr need another virtual method? + // It's not clear this is right, does MCTargetExpr need another virtual + // method? break; case MCExpr::SymbolRef: Specifier = cast(Expr)->getSpecifier();