Skip to content

Commit b96945e

Browse files
committed
[LoongArch] Record the special AMO operand constraint with TableGen
The LoongArch Reference Manual says that the 3-register atomic memory operations cannot have their rd equal to either rj or rk [^1], and both GNU as and LLVM IAS enforce the constraint. However, currently LoongArch AsmParser is checking for the opcode with a direct numerical comparison on the opcode, which is enum-typed: the fact that all AMO insns have adjacent numerical values is a coincidence, and it is better to not rely on the current TableGen file layout and the particular TableGen implementation behavior. Instead, start to leverage the target-specific flags field of MCInstrDesc, and record the constraint with TableGen, so we can stop treating the opcode enum as number. While documenting the new flag, it was found that v1.10 of the Manual did not specify the similar constraint for the AMCAS instructions. Experiments were done on a Loongson 3A6000 (LA664 uarch) and it turned out that at least AMCAS will still signal INE with `rd == rj`. The `rd == rk` case should be a no-op according to the semantics, but as it is meaningless to perform CAS with the "old value" same as the "new value", it is not worth special-casing. So the current behavior of also enforcing the constraint for AMCAS is kept. [^1]: if `rd == rj` an INE would be signaled; if `rd == rk` it is UB.
1 parent b396921 commit b96945e

File tree

5 files changed

+45
-2
lines changed

5 files changed

+45
-2
lines changed

llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "MCTargetDesc/LoongArchBaseInfo.h"
910
#include "MCTargetDesc/LoongArchInstPrinter.h"
1011
#include "MCTargetDesc/LoongArchMCExpr.h"
1112
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
@@ -1560,9 +1561,10 @@ bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
15601561

15611562
unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
15621563
unsigned Opc = Inst.getOpcode();
1564+
const MCInstrDesc &MCID = MII.get(Opc);
15631565
switch (Opc) {
15641566
default:
1565-
if (Opc >= LoongArch::AMADD_D && Opc <= LoongArch::AMXOR_W) {
1567+
if (LoongArchII::isSubjectToAMORdConstraint(MCID.TSFlags)) {
15661568
MCRegister Rd = Inst.getOperand(0).getReg();
15671569
MCRegister Rk = Inst.getOperand(1).getReg();
15681570
MCRegister Rj = Inst.getOperand(2).getReg();

llvm/lib/Target/LoongArch/LoongArchInstrFormats.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ class LAInst<dag outs, dag ins, string opcstr, string opnstr,
3232
let InOperandList = ins;
3333
let AsmString = opcstr # "\t" # opnstr;
3434
let Pattern = pattern;
35+
36+
// Target-specific instruction info and defaults
37+
38+
bit IsSubjectToAMORdConstraint = 0;
39+
let TSFlags{0} = IsSubjectToAMORdConstraint;
3540
}
3641

3742
// Pseudo instructions

llvm/lib/Target/LoongArch/LoongArchInstrInfo.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,9 @@ class STORE_2RI14<bits<32> op>
713713
let hasSideEffects = 0, mayLoad = 1, mayStore = 1, Constraints = "@earlyclobber $rd" in
714714
class AM_3R<bits<32> op>
715715
: Fmt3R<op, (outs GPR:$rd), (ins GPR:$rk, GPRMemAtomic:$rj),
716-
"$rd, $rk, $rj">;
716+
"$rd, $rk, $rj"> {
717+
let IsSubjectToAMORdConstraint = 1;
718+
}
717719

718720
let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
719721
class LLBase<bits<32> op>

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,29 @@ enum {
5656
MO_DESC_CALL,
5757
// TODO: Add more flags.
5858
};
59+
60+
// Target-specific flags of LAInst.
61+
// All definitions must match LoongArchInstrFormats.td.
62+
enum {
63+
// Whether the instruction's rd is normally required to differ from rj and
64+
// rk, in the way the 3-register atomic memory operations behave
65+
// (Section 2.2.7.1 and 2.2.7.2, LoongArch Reference Manual Volume 1 v1.10;
66+
// while Section 2.2.7.3 lacked similar description for the AMCAS
67+
// instructions, at least the INE exception is still signaled on Loongson
68+
// 3A6000 when its rd == rj).
69+
//
70+
// Used for generating diagnostics for assembler input that violate the
71+
// constraint. As described on the manual, the covered instructions require
72+
// rd != rj && rd != rk to work as intended.
73+
IsSubjectToAMORdConstraintShift = 0,
74+
IsSubjectToAMORdConstraintMask = 1 << IsSubjectToAMORdConstraintShift,
75+
};
76+
77+
/// \returns true if this instruction's rd is normally required to differ
78+
/// from rj and rk, in the way 3-register atomic memory operations behave.
79+
static inline bool isSubjectToAMORdConstraint(uint64_t TSFlags) {
80+
return TSFlags & IsSubjectToAMORdConstraintMask;
81+
}
5982
} // end namespace LoongArchII
6083

6184
namespace LoongArchABI {

llvm/test/MC/LoongArch/Basic/Integer/invalid64.s

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,14 @@ amxor.w $a0, $a1, $a0
9191
amadd.d $a0, $a1, $a2, $a3
9292
# CHECK: :[[#@LINE+1]]:24: error: optional integer offset must be 0
9393
amadd.d $a0, $a1, $a2, 1
94+
95+
## According to experiment results on real LA664 HW, the AMCAS instructions
96+
## are subject to the same constraint as the other 3-register atomic insns.
97+
## This is undocumented in v1.10 of the LoongArch Reference Manual.
98+
99+
# CHECK: :[[#@LINE+1]]:10: error: $rd must be different from both $rk and $rj
100+
amcas.b $a0, $a0, $a0
101+
# CHECK: :[[#@LINE+1]]:10: error: $rd must be different from both $rk and $rj
102+
amcas.h $a0, $a0, $a1
103+
# CHECK: :[[#@LINE+1]]:13: error: $rd must be different from both $rk and $rj
104+
amcas_db.w $a0, $a1, $a0

0 commit comments

Comments
 (0)