Skip to content

Commit

Permalink
[SOL] Remove neg and change the semantics of sub (anza-xyz#73)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
LucasSte committed Jun 28, 2024
1 parent 8da2e6d commit 84575f1
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 10 deletions.
40 changes: 34 additions & 6 deletions llvm/lib/Target/SBF/SBFInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ def SBFIsBigEndian : Predicate<"!CurDAG->getDataLayout().isLittleEndian()">;
def SBFHasALU32 : Predicate<"Subtarget->getHasAlu32()">;
def SBFNoALU32 : Predicate<"!Subtarget->getHasAlu32()">;
def SBFSubtargetSolana : Predicate<"Subtarget->isSolana()">;
def SBFv2 : Predicate<"Subtarget->isSBFv2()">;
def NoSBFv2 : Predicate<"!Subtarget->isSBFv2()">;

def brtarget : Operand<OtherVT> {
let PrintMethod = "printBrTargetOperand";
Expand Down Expand Up @@ -263,7 +265,7 @@ class ALU_RR<SBFOpClass Class, SBFArithOp Opc,
let SBFClass = Class;
}

multiclass ALU<SBFArithOp Opc, string Mnemonic, SDNode OpNode> {
multiclass ALU<SBFArithOp Opc, string Mnemonic, SDNode OpNode, bit UseImmPat = 1> {
def _rr : ALU_RR<SBF_ALU64, Opc,
(outs GPR:$dst),
(ins GPR:$src2, GPR:$src),
Expand All @@ -273,7 +275,9 @@ multiclass ALU<SBFArithOp Opc, string Mnemonic, SDNode OpNode> {
(outs GPR:$dst),
(ins GPR:$src2, i64imm:$imm),
Mnemonic # "64 $dst, $imm",
[(set GPR:$dst, (OpNode GPR:$src2, i64immSExt32:$imm))]>;
!if(UseImmPat,
[(set GPR:$dst,
(OpNode GPR:$src2, i64immSExt32:$imm))], [])>;
def _rr_32 : ALU_RR<SBF_ALU, Opc,
(outs GPR32:$dst),
(ins GPR32:$src2, GPR32:$src),
Expand All @@ -283,13 +287,15 @@ multiclass ALU<SBFArithOp Opc, string Mnemonic, SDNode OpNode> {
(outs GPR32:$dst),
(ins GPR32:$src2, i32imm:$imm),
Mnemonic # "32 $dst, $imm",
[(set GPR32:$dst, (OpNode GPR32:$src2, i32immSExt32:$imm))]>;
!if(UseImmPat,
[(set GPR32:$dst,
(OpNode GPR32:$src2, i32immSExt32:$imm))], [])>;
}

let Constraints = "$dst = $src2" in {
let isAsCheapAsAMove = 1 in {
defm ADD : ALU<SBF_ADD, "add", add>;
defm SUB : ALU<SBF_SUB, "sub", sub>;
defm SUB : ALU<SBF_SUB, "sub", sub, 0>;
defm OR : ALU<SBF_OR, "or", or>;
defm AND : ALU<SBF_AND, "and", and>;
defm SLL : ALU<SBF_LSH, "lsh", shl>;
Expand All @@ -306,6 +312,19 @@ let Constraints = "$dst = $src2" in {
}
}

// Special case for SBFv2
// In SBFv1, `sub reg, imm` is interpreted as reg = reg - imm,
// but in SBFv2 it means reg = imm - reg
def : Pat<(sub GPR:$src, i64immSExt32:$imm),
(SUB_ri GPR:$src, i64immSExt32:$imm)>, Requires<[NoSBFv2]>;
def : Pat<(sub GPR32:$src, i32immSExt32:$imm),
(SUB_ri_32 GPR32:$src, i32immSExt32:$imm)>, Requires<[NoSBFv2]>;

def : Pat<(sub i64immSExt32:$imm, GPR:$src),
(SUB_ri GPR:$src, i64immSExt32:$imm)>, Requires<[SBFv2]>;
def : Pat<(sub i32immSExt32:$imm, GPR32:$src),
(SUB_ri_32 GPR32:$src, i32immSExt32:$imm)>, Requires<[SBFv2]>;

class NEG_RR<SBFOpClass Class, SBFArithOp Opc,
dag outs, dag ins, string asmstr, list<dag> pattern>
: TYPE_ALU_JMP<Opc.Value, 0, outs, ins, asmstr, pattern> {
Expand All @@ -318,12 +337,21 @@ class NEG_RR<SBFOpClass Class, SBFArithOp Opc,
let Constraints = "$dst = $src", isAsCheapAsAMove = 1 in {
def NEG_64: NEG_RR<SBF_ALU64, SBF_NEG, (outs GPR:$dst), (ins GPR:$src),
"neg64 $dst",
[(set GPR:$dst, (ineg i64:$src))]>;
[]>;
def NEG_32: NEG_RR<SBF_ALU, SBF_NEG, (outs GPR32:$dst), (ins GPR32:$src),
"neg32 $dst",
[(set GPR32:$dst, (ineg i32:$src))]>;
[]>;
}

// Instruction `neg` exists on SBFv1, but not on SBFv2
// In SBFv2, the negate operation is done with a subtraction
def : Pat<(ineg i64:$src), (NEG_64 GPR:$src)>, Requires<[NoSBFv2]>;
def : Pat<(ineg i32:$src), (NEG_32 GPR32:$src)>, Requires<[NoSBFv2]>;

def : Pat<(ineg i64:$src), (SUB_ri GPR:$src, 0)>, Requires<[SBFv2]>;
def : Pat<(ineg i32:$src), (SUB_ri_32 GPR32:$src, 0)>, Requires<[SBFv2]>;


class LD_IMM64<bits<4> Pseudo, string Mnemonic>
: TYPE_LD_ST<SBF_IMM.Value, SBF_DW.Value,
(outs GPR:$dst),
Expand Down
7 changes: 5 additions & 2 deletions llvm/lib/Target/SBF/SBFSubtarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ void SBFSubtarget::initializeEnvironment(const Triple &TT) {
HasDynamicFrames = false;
HasSdiv = false;
UseDwarfRIS = false;
IsSBFv2 = false;
}

void SBFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
Expand All @@ -64,8 +65,10 @@ void SBFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
HasAlu32 = true;
}

if (CPU == "sbfv2" && !HasDynamicFrames) {
report_fatal_error("sbfv2 requires dynamic-frames\n", false);
if (CPU == "sbfv2") {
IsSBFv2 = true;
if (!HasDynamicFrames)
report_fatal_error("sbfv2 requires dynamic-frames\n", false);
}
}

Expand Down
9 changes: 7 additions & 2 deletions llvm/lib/Target/SBF/SBFSubtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,17 @@ class SBFSubtarget : public SBFGenSubtargetInfo {
// whether we should enable MCAsmInfo DwarfUsesRelocationsAcrossSections
bool UseDwarfRIS;

// whether we are targeting SBFv2
bool IsSBFv2;

public:
// This constructor initializes the data members to match that
// of the specified triple.
SBFSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS,
const TargetMachine &TM);

SBFSubtarget &initializeSubtargetDependencies(const Triple &TT, StringRef CPU, StringRef FS);
SBFSubtarget &initializeSubtargetDependencies(const Triple &TT, StringRef CPU,
StringRef FS);

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

const SBFInstrInfo *getInstrInfo() const override { return &InstrInfo; }
const SBFFrameLowering *getFrameLowering() const override {
Expand All @@ -105,6 +110,6 @@ class SBFSubtarget : public SBFGenSubtargetInfo {
return &InstrInfo.getRegisterInfo();
}
};
} // End llvm namespace
} // namespace llvm

#endif
79 changes: 79 additions & 0 deletions llvm/test/CodeGen/SBF/sub_reversed_immediate.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
; RUN: llc < %s -march=sbf -mattr=+alu32 | FileCheck --check-prefix=CHECK-v1 %s
; RUN: llc < %s -march=sbf -mattr=+alu32 -mcpu=sbfv2 | FileCheck --check-prefix=CHECK-v2 %s


; Function Attrs: norecurse nounwind readnone
define dso_local i64 @sub_imm_minus_reg_64(i64 %a) #0 {
entry:
; CHECK-LABEL: sub_imm_minus_reg_64:
%sub = sub nsw i64 50, %a

; CHECK-v1: mov64 r{{[0-9]+}}, 50
; CHECK-v1: sub64 r{{[0-9]+}}, r{{[0-9]+}}

; CHECK-v2: sub64 r{{[0-9]+}}, 50
ret i64 %sub
}

; Function Attrs: norecurse nounwind readnone
define dso_local i64 @sub_reg_minus_imm_64(i64 %a) #0 {
entry:
; CHECK-LABEL: sub_reg_minus_imm_64:
%t = sub nsw i64 %a, 50
; CHECK-v1: add64 r{{[0-9]+}}, -50

; CHECK-v2: add64 r{{[0-9]+}}, -50
ret i64 %t
}


; Function Attrs: norecurse nounwind readnone
define dso_local i32 @sub_imm_minus_reg_32(i32 %a) #0 {
entry:
; CHECK-LABEL: sub_imm_minus_reg_32:
%sub = sub nsw i32 50, %a

; CHECK-v1: mov32 w{{[0-9]+}}, 50
; CHECK-v1: sub32 w{{[0-9]+}}, w{{[0-9]+}}

; CHECK-v2: sub32 w{{[0-9]+}}, 50

ret i32 %sub
}

; Function Attrs: norecurse nounwind readnone
define dso_local i32 @sub_reg_minus_imm_32(i32 %a) #0 {
entry:
; CHECK-LABEL: sub_reg_minus_imm_32:
%t = sub nsw i32 %a, 50

; CHECK-v1: add32 w{{[0-9]+}}, -50

; CHECK-v2: add32 w{{[0-9]+}}, -50
ret i32 %t
}


; Function Attrs: norecurse nounwind readnone
define dso_local i64 @neg_64(i64 %a) #0 {
entry:
; CHECK-LABEL: neg_64:
%sub = sub nsw i64 0, %a

; CHECK-v1: neg64 r{{[0-9]+}}
; CHECK-v2: sub64 r{{[0-9]+}}, 0

ret i64 %sub
}

; Function Attrs: norecurse nounwind readnone
define dso_local i32 @neg_32(i32 %a) #0 {
entry:
; CHECK-LABEL: neg_32:
%sub = sub nsw i32 0, %a

; CHECK-v1: neg32 w{{[0-9]+}}
; CHECK-v2: sub32 w{{[0-9]+}}, 0

ret i32 %sub
}

0 comments on commit 84575f1

Please sign in to comment.