Skip to content

Commit 1f65ea3

Browse files
committed
[SOL] Remove neg and change the semantics of sub (llvm#73)
Following the alterations made in solana-labs/rbpf#489, this PR removes the neg instructions and changes the semantics of sub when one of the operands is an immediate. sub r1, 2 now means r1 = 2 - r1, instead of r1 = r1 - 2. neg r1 is represented as r1 = 0 - r1. This is the second task in solana-labs/solana#34250.
1 parent db72612 commit 1f65ea3

File tree

4 files changed

+125
-10
lines changed

4 files changed

+125
-10
lines changed

llvm/lib/Target/SBF/SBFInstrInfo.td

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ def SBFIsBigEndian : Predicate<"!CurDAG->getDataLayout().isLittleEndian()">;
5454
def SBFHasALU32 : Predicate<"Subtarget->getHasAlu32()">;
5555
def SBFNoALU32 : Predicate<"!Subtarget->getHasAlu32()">;
5656
def SBFSubtargetSolana : Predicate<"Subtarget->isSolana()">;
57+
def SBFv2 : Predicate<"Subtarget->isSBFv2()">;
58+
def NoSBFv2 : Predicate<"!Subtarget->isSBFv2()">;
5759

5860
def brtarget : Operand<OtherVT> {
5961
let PrintMethod = "printBrTargetOperand";
@@ -263,7 +265,7 @@ class ALU_RR<SBFOpClass Class, SBFArithOp Opc,
263265
let SBFClass = Class;
264266
}
265267

266-
multiclass ALU<SBFArithOp Opc, string Mnemonic, SDNode OpNode> {
268+
multiclass ALU<SBFArithOp Opc, string Mnemonic, SDNode OpNode, bit UseImmPat = 1> {
267269
def _rr : ALU_RR<SBF_ALU64, Opc,
268270
(outs GPR:$dst),
269271
(ins GPR:$src2, GPR:$src),
@@ -273,7 +275,9 @@ multiclass ALU<SBFArithOp Opc, string Mnemonic, SDNode OpNode> {
273275
(outs GPR:$dst),
274276
(ins GPR:$src2, i64imm:$imm),
275277
Mnemonic # "64 $dst, $imm",
276-
[(set GPR:$dst, (OpNode GPR:$src2, i64immSExt32:$imm))]>;
278+
!if(UseImmPat,
279+
[(set GPR:$dst,
280+
(OpNode GPR:$src2, i64immSExt32:$imm))], [])>;
277281
def _rr_32 : ALU_RR<SBF_ALU, Opc,
278282
(outs GPR32:$dst),
279283
(ins GPR32:$src2, GPR32:$src),
@@ -283,13 +287,15 @@ multiclass ALU<SBFArithOp Opc, string Mnemonic, SDNode OpNode> {
283287
(outs GPR32:$dst),
284288
(ins GPR32:$src2, i32imm:$imm),
285289
Mnemonic # "32 $dst, $imm",
286-
[(set GPR32:$dst, (OpNode GPR32:$src2, i32immSExt32:$imm))]>;
290+
!if(UseImmPat,
291+
[(set GPR32:$dst,
292+
(OpNode GPR32:$src2, i32immSExt32:$imm))], [])>;
287293
}
288294

289295
let Constraints = "$dst = $src2" in {
290296
let isAsCheapAsAMove = 1 in {
291297
defm ADD : ALU<SBF_ADD, "add", add>;
292-
defm SUB : ALU<SBF_SUB, "sub", sub>;
298+
defm SUB : ALU<SBF_SUB, "sub", sub, 0>;
293299
defm OR : ALU<SBF_OR, "or", or>;
294300
defm AND : ALU<SBF_AND, "and", and>;
295301
defm SLL : ALU<SBF_LSH, "lsh", shl>;
@@ -306,6 +312,19 @@ let Constraints = "$dst = $src2" in {
306312
}
307313
}
308314

315+
// Special case for SBFv2
316+
// In SBFv1, `sub reg, imm` is interpreted as reg = reg - imm,
317+
// but in SBFv2 it means reg = imm - reg
318+
def : Pat<(sub GPR:$src, i64immSExt32:$imm),
319+
(SUB_ri GPR:$src, i64immSExt32:$imm)>, Requires<[NoSBFv2]>;
320+
def : Pat<(sub GPR32:$src, i32immSExt32:$imm),
321+
(SUB_ri_32 GPR32:$src, i32immSExt32:$imm)>, Requires<[NoSBFv2]>;
322+
323+
def : Pat<(sub i64immSExt32:$imm, GPR:$src),
324+
(SUB_ri GPR:$src, i64immSExt32:$imm)>, Requires<[SBFv2]>;
325+
def : Pat<(sub i32immSExt32:$imm, GPR32:$src),
326+
(SUB_ri_32 GPR32:$src, i32immSExt32:$imm)>, Requires<[SBFv2]>;
327+
309328
class NEG_RR<SBFOpClass Class, SBFArithOp Opc,
310329
dag outs, dag ins, string asmstr, list<dag> pattern>
311330
: TYPE_ALU_JMP<Opc.Value, 0, outs, ins, asmstr, pattern> {
@@ -318,12 +337,21 @@ class NEG_RR<SBFOpClass Class, SBFArithOp Opc,
318337
let Constraints = "$dst = $src", isAsCheapAsAMove = 1 in {
319338
def NEG_64: NEG_RR<SBF_ALU64, SBF_NEG, (outs GPR:$dst), (ins GPR:$src),
320339
"neg64 $dst",
321-
[(set GPR:$dst, (ineg i64:$src))]>;
340+
[]>;
322341
def NEG_32: NEG_RR<SBF_ALU, SBF_NEG, (outs GPR32:$dst), (ins GPR32:$src),
323342
"neg32 $dst",
324-
[(set GPR32:$dst, (ineg i32:$src))]>;
343+
[]>;
325344
}
326345

346+
// Instruction `neg` exists on SBFv1, but not on SBFv2
347+
// In SBFv2, the negate operation is done with a subtraction
348+
def : Pat<(ineg i64:$src), (NEG_64 GPR:$src)>, Requires<[NoSBFv2]>;
349+
def : Pat<(ineg i32:$src), (NEG_32 GPR32:$src)>, Requires<[NoSBFv2]>;
350+
351+
def : Pat<(ineg i64:$src), (SUB_ri GPR:$src, 0)>, Requires<[SBFv2]>;
352+
def : Pat<(ineg i32:$src), (SUB_ri_32 GPR32:$src, 0)>, Requires<[SBFv2]>;
353+
354+
327355
class LD_IMM64<bits<4> Pseudo, string Mnemonic>
328356
: TYPE_LD_ST<SBF_IMM.Value, SBF_DW.Value,
329357
(outs GPR:$dst),

llvm/lib/Target/SBF/SBFSubtarget.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ void SBFSubtarget::initializeEnvironment(const Triple &TT) {
4242
HasDynamicFrames = false;
4343
HasSdiv = false;
4444
UseDwarfRIS = false;
45+
IsSBFv2 = false;
4546
}
4647

4748
void SBFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
@@ -64,8 +65,10 @@ void SBFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
6465
HasAlu32 = true;
6566
}
6667

67-
if (CPU == "sbfv2" && !HasDynamicFrames) {
68-
report_fatal_error("sbfv2 requires dynamic-frames\n", false);
68+
if (CPU == "sbfv2") {
69+
IsSBFv2 = true;
70+
if (!HasDynamicFrames)
71+
report_fatal_error("sbfv2 requires dynamic-frames\n", false);
6972
}
7073
}
7174

llvm/lib/Target/SBF/SBFSubtarget.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,17 @@ class SBFSubtarget : public SBFGenSubtargetInfo {
7272
// whether we should enable MCAsmInfo DwarfUsesRelocationsAcrossSections
7373
bool UseDwarfRIS;
7474

75+
// whether we are targeting SBFv2
76+
bool IsSBFv2;
77+
7578
public:
7679
// This constructor initializes the data members to match that
7780
// of the specified triple.
7881
SBFSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS,
7982
const TargetMachine &TM);
8083

81-
SBFSubtarget &initializeSubtargetDependencies(const Triple &TT, StringRef CPU, StringRef FS);
84+
SBFSubtarget &initializeSubtargetDependencies(const Triple &TT, StringRef CPU,
85+
StringRef FS);
8286

8387
// ParseSubtargetFeatures - Parses features string setting specified
8488
// subtarget options. Definition of function is auto generated by tblgen.
@@ -90,6 +94,7 @@ class SBFSubtarget : public SBFGenSubtargetInfo {
9094
bool getHasDynamicFrames() const { return HasDynamicFrames; }
9195
bool getHasSdiv() const { return HasSdiv; }
9296
bool getUseDwarfRIS() const { return UseDwarfRIS; }
97+
bool isSBFv2() const { return IsSBFv2; }
9398

9499
const SBFInstrInfo *getInstrInfo() const override { return &InstrInfo; }
95100
const SBFFrameLowering *getFrameLowering() const override {
@@ -105,6 +110,6 @@ class SBFSubtarget : public SBFGenSubtargetInfo {
105110
return &InstrInfo.getRegisterInfo();
106111
}
107112
};
108-
} // End llvm namespace
113+
} // namespace llvm
109114

110115
#endif
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
; RUN: llc < %s -march=sbf -mattr=+alu32 | FileCheck --check-prefix=CHECK-v1 %s
2+
; RUN: llc < %s -march=sbf -mattr=+alu32 -mcpu=sbfv2 | FileCheck --check-prefix=CHECK-v2 %s
3+
4+
5+
; Function Attrs: norecurse nounwind readnone
6+
define dso_local i64 @sub_imm_minus_reg_64(i64 %a) #0 {
7+
entry:
8+
; CHECK-LABEL: sub_imm_minus_reg_64:
9+
%sub = sub nsw i64 50, %a
10+
11+
; CHECK-v1: mov64 r{{[0-9]+}}, 50
12+
; CHECK-v1: sub64 r{{[0-9]+}}, r{{[0-9]+}}
13+
14+
; CHECK-v2: sub64 r{{[0-9]+}}, 50
15+
ret i64 %sub
16+
}
17+
18+
; Function Attrs: norecurse nounwind readnone
19+
define dso_local i64 @sub_reg_minus_imm_64(i64 %a) #0 {
20+
entry:
21+
; CHECK-LABEL: sub_reg_minus_imm_64:
22+
%t = sub nsw i64 %a, 50
23+
; CHECK-v1: add64 r{{[0-9]+}}, -50
24+
25+
; CHECK-v2: add64 r{{[0-9]+}}, -50
26+
ret i64 %t
27+
}
28+
29+
30+
; Function Attrs: norecurse nounwind readnone
31+
define dso_local i32 @sub_imm_minus_reg_32(i32 %a) #0 {
32+
entry:
33+
; CHECK-LABEL: sub_imm_minus_reg_32:
34+
%sub = sub nsw i32 50, %a
35+
36+
; CHECK-v1: mov32 w{{[0-9]+}}, 50
37+
; CHECK-v1: sub32 w{{[0-9]+}}, w{{[0-9]+}}
38+
39+
; CHECK-v2: sub32 w{{[0-9]+}}, 50
40+
41+
ret i32 %sub
42+
}
43+
44+
; Function Attrs: norecurse nounwind readnone
45+
define dso_local i32 @sub_reg_minus_imm_32(i32 %a) #0 {
46+
entry:
47+
; CHECK-LABEL: sub_reg_minus_imm_32:
48+
%t = sub nsw i32 %a, 50
49+
50+
; CHECK-v1: add32 w{{[0-9]+}}, -50
51+
52+
; CHECK-v2: add32 w{{[0-9]+}}, -50
53+
ret i32 %t
54+
}
55+
56+
57+
; Function Attrs: norecurse nounwind readnone
58+
define dso_local i64 @neg_64(i64 %a) #0 {
59+
entry:
60+
; CHECK-LABEL: neg_64:
61+
%sub = sub nsw i64 0, %a
62+
63+
; CHECK-v1: neg64 r{{[0-9]+}}
64+
; CHECK-v2: sub64 r{{[0-9]+}}, 0
65+
66+
ret i64 %sub
67+
}
68+
69+
; Function Attrs: norecurse nounwind readnone
70+
define dso_local i32 @neg_32(i32 %a) #0 {
71+
entry:
72+
; CHECK-LABEL: neg_32:
73+
%sub = sub nsw i32 0, %a
74+
75+
; CHECK-v1: neg32 w{{[0-9]+}}
76+
; CHECK-v2: sub32 w{{[0-9]+}}, 0
77+
78+
ret i32 %sub
79+
}

0 commit comments

Comments
 (0)