[llvm] 426cedc - [LoongArch] Add support for the ud macro instruction (#171583)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 10 21:31:07 PST 2025
Author: hev
Date: 2025-12-11T13:31:03+08:00
New Revision: 426cedccd38502babad106fb0a9183750fae3092
URL: https://github.com/llvm/llvm-project/commit/426cedccd38502babad106fb0a9183750fae3092
DIFF: https://github.com/llvm/llvm-project/commit/426cedccd38502babad106fb0a9183750fae3092.diff
LOG: [LoongArch] Add support for the ud macro instruction (#171583)
This patch adds support for the `ud ui5` macro instruction. The `ui5`
operand must be inthe range `0-31`. The macro expands to:
`amswap.w $rd, $r1, $rj`
where `ui5` specifies the register number used for `$rd` in the expanded
instruction, and `$rd` is the same as `$rj`.
Relevant binutils patch:
https://sourceware.org/pipermail/binutils/2025-December/146042.html
Added:
Modified:
llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp
llvm/lib/Target/LoongArch/LoongArchInstrFormats.td
llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
llvm/test/CodeGen/LoongArch/trap.ll
llvm/test/MC/LoongArch/Basic/Integer/misc.s
Removed:
################################################################################
diff --git a/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp b/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp
index d4058fac4304a..584b45b4111cd 100644
--- a/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp
+++ b/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp
@@ -157,6 +157,29 @@ static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm,
return MCDisassembler::Success;
}
+// Decode AMSWAP.W and UD, which share the same base encoding.
+// If rk == 1 and rd == rj, interpret the instruction as UD;
+// otherwise decode as AMSWAP.W.
+static DecodeStatus DecodeAMOrUDInstruction(MCInst &Inst, unsigned Insn,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ unsigned Rd = fieldFromInstruction(Insn, 0, 5);
+ unsigned Rj = fieldFromInstruction(Insn, 5, 5);
+ unsigned Rk = fieldFromInstruction(Insn, 10, 5);
+
+ if (Rk == 1 && Rd == Rj) {
+ Inst.setOpcode(LoongArch::UD);
+ Inst.addOperand(MCOperand::createImm(Rd));
+ } else {
+ Inst.setOpcode(LoongArch::AMSWAP_W);
+ Inst.addOperand(MCOperand::createReg(LoongArch::R0 + Rd));
+ Inst.addOperand(MCOperand::createReg(LoongArch::R0 + Rk));
+ Inst.addOperand(MCOperand::createReg(LoongArch::R0 + Rj));
+ }
+
+ return MCDisassembler::Success;
+}
+
#include "LoongArchGenDisassemblerTables.inc"
DecodeStatus LoongArchDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrFormats.td b/llvm/lib/Target/LoongArch/LoongArchInstrFormats.td
index 419e20431c59f..fa049fcbc2d21 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrFormats.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrFormats.td
@@ -401,3 +401,16 @@ class FmtLDPTE<dag outs, dag ins, string opnstr, list<dag> pattern = []>
let Inst{9-5} = rj;
let Inst{4-0} = 0b00000;
}
+
+// FmtUD
+// <0b0011100001100000000001 | I5 | I5>
+class FmtUD<dag outs, dag ins, string opnstr, list<dag> pattern = []>
+ : LAInst<outs, ins, deriveInsnMnemonic<NAME>.ret, opnstr, pattern> {
+ bits<5> imm5;
+
+ let Inst{31-10} = 0b0011100001100000000001;
+ let Inst{9-5} = imm5;
+ let Inst{4-0} = imm5;
+
+ let DecoderMethod = "DecodeAMOrUDInstruction";
+}
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index 2e6653e1a09ac..d971f8bc1986b 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -800,6 +800,10 @@ class AM_3R<bits<32> op>
let Constraints = "@earlyclobber $rd";
}
+class AU_3R<bits<32> op> : AM_3R<op> {
+ let DecoderMethod = "DecodeAMOrUDInstruction";
+}
+
class AMCAS_3R<bits<32> op>
: Fmt3R<op, (outs GPR:$dst), (ins GPR:$rd, GPR:$rk, GPRMemAtomic:$rj),
"$rd, $rk, $rj"> {
@@ -923,6 +927,9 @@ def BREAK : MISC_I15<0x002a0000>;
def RDTIMEL_W : RDTIME_2R<0x00006000>;
def RDTIMEH_W : RDTIME_2R<0x00006400>;
+let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in
+def UD : FmtUD<(outs), (ins uimm5:$imm5), "$imm5">;
+
// The CPUCFG instruction offers a reliable way to probing CPU features.
// Although support is not guaranteed on LA32R, having compiler support
// nevertheless enables applications to rely on its presence, potentially
@@ -1087,7 +1094,7 @@ def STLE_D : STORE_3R<0x387f8000>;
// Atomic Memory Access Instructions for 64-bits
def AMSWAP_B : AM_3R<0x385c0000>;
def AMSWAP_H : AM_3R<0x385c8000>;
-def AMSWAP_W : AM_3R<0x38600000>;
+def AMSWAP_W : AU_3R<0x38600000>;
def AMSWAP_D : AM_3R<0x38608000>;
def AMADD_B : AM_3R<0x385d0000>;
def AMADD_H : AM_3R<0x385d8000>;
@@ -1410,12 +1417,8 @@ def : Pat<(and GPR:$rj, BstrinsImm:$imm),
/// Traps
-// We lower `trap` to `amswap.w rd:$r0, rk:$r1, rj:$r0`, as this is guaranteed
-// to trap with an INE (non-existent on LA32, explicitly documented to INE on
-// LA64). And the resulting signal is
diff erent from `debugtrap` like on some
-// other existing ports so programs/porters might have an easier time.
-def PseudoUNIMP : Pseudo<(outs), (ins), [(trap)]>,
- PseudoInstExpansion<(AMSWAP_W R0, R1, R0)>;
+// We lower `trap` to `ud 0`, which is an alias for `amswap.w $r0, $r1, $r0`.
+def PseudoUNIMP : Pseudo<(outs), (ins), [(trap)]>, PseudoInstExpansion<(UD 0)>;
// We lower `debugtrap` to `break 0`, as this is guaranteed to exist and work,
// even for LA32 Primary. Also, because so far the ISA does not provide a
diff --git a/llvm/test/CodeGen/LoongArch/trap.ll b/llvm/test/CodeGen/LoongArch/trap.ll
index 15a7ad82bd7a8..d433266b47e47 100644
--- a/llvm/test/CodeGen/LoongArch/trap.ll
+++ b/llvm/test/CodeGen/LoongArch/trap.ll
@@ -10,7 +10,7 @@ declare void @llvm.debugtrap()
define void @test_trap() nounwind {
; CHECK-LABEL: test_trap:
; CHECK: # %bb.0:
-; CHECK-NEXT: amswap.w $zero, $ra, $zero
+; CHECK-NEXT: ud 0
; CHECK-NEXT: ret
tail call void @llvm.trap()
ret void
diff --git a/llvm/test/MC/LoongArch/Basic/Integer/misc.s b/llvm/test/MC/LoongArch/Basic/Integer/misc.s
index 182d1da9b237e..26a9205d8e17d 100644
--- a/llvm/test/MC/LoongArch/Basic/Integer/misc.s
+++ b/llvm/test/MC/LoongArch/Basic/Integer/misc.s
@@ -7,7 +7,7 @@
# RUN: llvm-mc %s --triple=loongarch32 --filetype=obj | llvm-objdump -d - \
# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
# RUN: llvm-mc %s --triple=loongarch64 --filetype=obj --defsym=LA64=1 | llvm-objdump -d - \
-# RUN: | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ,CHECK64-ASM-AND-OBJ %s
+# RUN: | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ,CHECK64-OBJ,CHECK64-ASM-AND-OBJ %s
#############################################################
## Instructions for both loongarch32 and loongarch64
@@ -33,6 +33,13 @@ rdtimeh.w $a7, $a1
# CHECK-ASM: encoding: [0x03,0x6d,0x00,0x00]
cpucfg $sp, $a4
+# CHECK-ASM-AND-OBJ: ud 0
+# CHECK-ASM: encoding: [0x00,0x04,0x60,0x38]
+ud 0
+
+# CHECK-ASM-AND-OBJ: ud 31
+# CHECK-ASM: encoding: [0xff,0x07,0x60,0x38]
+ud 31
#############################################################
## Instructions only for loongarch64
@@ -40,6 +47,11 @@ cpucfg $sp, $a4
.ifdef LA64
+# CHECK64-OBJ: ud 0
+# CHECK64-ASM: amswap.w $zero, $ra, $zero
+# CHECK64-ASM: encoding: [0x00,0x04,0x60,0x38]
+amswap.w $zero, $ra, $zero
+
# CHECK64-ASM-AND-OBJ: asrtle.d $t0, $t5
# CHECK64-ASM: encoding: [0x80,0x45,0x01,0x00]
asrtle.d $t0, $t5
More information about the llvm-commits
mailing list