bpf: add new insns for bswap_to_le and negation
authorYonghong Song <yhs@fb.com>
Thu, 28 Sep 2017 02:46:11 +0000 (02:46 +0000)
committerYonghong Song <yhs@fb.com>
Thu, 28 Sep 2017 02:46:11 +0000 (02:46 +0000)
This patch adds new insn, "reg = be16/be32/be64 reg",
for bswap to little endian for big-endian target (bpfeb).
It also adds new insn for negation "reg = -reg".

Currently, for source code, e.g.,
  b = -a
LLVM still prefers to generate:
  b = 0 - a
But "reg = -reg" format can be used in assembly code.

Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
llvm-svn: 314376

llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
llvm/lib/Target/BPF/BPFInstrFormats.td
llvm/lib/Target/BPF/BPFInstrInfo.td
llvm/test/CodeGen/BPF/intrinsics.ll
llvm/test/CodeGen/BPF/objdump_intrinsics.ll
llvm/test/MC/BPF/insn-unit-32.s
llvm/test/MC/BPF/insn-unit.s

index d00200c..9e251d2 100644 (file)
@@ -30,6 +30,8 @@ struct BPFOperand;
 class BPFAsmParser : public MCTargetAsmParser {
   SMLoc getLoc() const { return getParser().getTok().getLoc(); }
 
+  bool PreMatchCheck(OperandVector &Operands);
+
   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
                                OperandVector &Operands, MCStreamer &Out,
                                uint64_t &ErrorInfo,
@@ -225,9 +227,6 @@ public:
         .Case("*", true)
         .Case("exit", true)
         .Case("lock", true)
-        .Case("bswap64", true)
-        .Case("bswap32", true)
-        .Case("bswap16", true)
         .Case("ld_pseudo", true)
         .Default(false);
   }
@@ -239,6 +238,12 @@ public:
         .Case("u32", true)
         .Case("u16", true)
         .Case("u8", true)
+        .Case("be64", true)
+        .Case("be32", true)
+        .Case("be16", true)
+        .Case("le64", true)
+        .Case("le32", true)
+        .Case("le16", true)
         .Case("goto", true)
         .Case("ll", true)
         .Case("skb", true)
@@ -252,6 +257,28 @@ public:
 #define GET_MATCHER_IMPLEMENTATION
 #include "BPFGenAsmMatcher.inc"
 
+bool BPFAsmParser::PreMatchCheck(OperandVector &Operands) {
+
+  if (Operands.size() == 4) {
+    // check "reg1 = -reg2" and "reg1 = be16/be32/be64/le16/le32/le64 reg2",
+    // reg1 must be the same as reg2
+    BPFOperand &Op0 = (BPFOperand &)*Operands[0];
+    BPFOperand &Op1 = (BPFOperand &)*Operands[1];
+    BPFOperand &Op2 = (BPFOperand &)*Operands[2];
+    BPFOperand &Op3 = (BPFOperand &)*Operands[3];
+    if (Op0.isReg() && Op1.isToken() && Op2.isToken() && Op3.isReg()
+        && Op1.getToken() == "="
+        && (Op2.getToken() == "-" || Op2.getToken() == "be16"
+            || Op2.getToken() == "be32" || Op2.getToken() == "be64"
+            || Op2.getToken() == "le16" || Op2.getToken() == "le32"
+            || Op2.getToken() == "le64")
+        && Op0.getReg() != Op3.getReg())
+      return true;
+  }
+
+  return false;
+}
+
 bool BPFAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
                                            OperandVector &Operands,
                                            MCStreamer &Out, uint64_t &ErrorInfo,
@@ -259,6 +286,9 @@ bool BPFAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   MCInst Inst;
   SMLoc ErrorLoc;
 
+  if (PreMatchCheck(Operands))
+    return Error(IDLoc, "additional inst constraint not met");
+
   switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
   default:
     break;
@@ -324,13 +354,8 @@ BPFAsmParser::parseOperandAsOperator(OperandVector &Operands) {
   switch (getLexer().getKind()) {
   case AsmToken::Minus:
   case AsmToken::Plus: {
-    StringRef Name = getLexer().getTok().getString();
-
     if (getLexer().peekTok().is(AsmToken::Integer))
       return MatchOperand_NoMatch;
-
-    getLexer().Lex();
-    Operands.push_back(BPFOperand::createToken(Name, S));
   }
   // Fall through.
 
index 1e3bc3b..92d4a62 100644 (file)
@@ -38,6 +38,7 @@ def BPF_OR   : BPFArithOp<0x4>;
 def BPF_AND  : BPFArithOp<0x5>;
 def BPF_LSH  : BPFArithOp<0x6>;
 def BPF_RSH  : BPFArithOp<0x7>;
+def BPF_NEG  : BPFArithOp<0x8>;
 def BPF_XOR  : BPFArithOp<0xa>;
 def BPF_MOV  : BPFArithOp<0xb>;
 def BPF_ARSH : BPFArithOp<0xc>;
index e1f233e..7d4b03d 100644 (file)
@@ -43,6 +43,8 @@ def BPFbrcc         : SDNode<"BPFISD::BR_CC", SDT_BPFBrCC,
 
 def BPFselectcc     : SDNode<"BPFISD::SELECT_CC", SDT_BPFSelectCC, [SDNPInGlue]>;
 def BPFWrapper      : SDNode<"BPFISD::Wrapper", SDT_BPFWrapper>;
+def BPFIsLittleEndian : Predicate<"CurDAG->getDataLayout().isLittleEndian()">;
+def BPFIsBigEndian    : Predicate<"!CurDAG->getDataLayout().isLittleEndian()">;
 
 def brtarget : Operand<OtherVT>;
 def calltarget : Operand<i64>;
@@ -232,6 +234,26 @@ let isAsCheapAsAMove = 1 in {
   defm DIV : ALU<BPF_DIV, "/=", udiv>;
 }
 
+class NEG_RR<BPFOpClass Class, BPFArithOp Opc,
+             dag outs, dag ins, string asmstr, list<dag> pattern>
+    : TYPE_ALU_JMP<Opc.Value, 0, outs, ins, asmstr, pattern> {
+  bits<4> dst;
+  bits<4> src;
+
+  let Inst{55-52} = src;
+  let Inst{51-48} = dst;
+  let BPFClass = Class;
+}
+
+let Constraints = "$dst = $src", isAsCheapAsAMove = 1 in {
+  def NEG_64: NEG_RR<BPF_ALU64, BPF_NEG, (outs GPR:$dst), (ins GPR:$src),
+                     "$dst = -$src",
+                     [(set GPR:$dst, (ineg i64:$src))]>;
+  def NEG_32: NEG_RR<BPF_ALU, BPF_NEG, (outs GPR32:$dst), (ins GPR32:$src),
+                     "$dst = -$src",
+                     [(set GPR32:$dst, (ineg i32:$src))]>;
+}
+
 class LD_IMM64<bits<4> Pseudo, string OpcodeStr>
     : TYPE_LD_ST<BPF_IMM.Value, BPF_DW.Value,
                  (outs GPR:$dst),
@@ -484,11 +506,11 @@ def XADD64 : XADD<BPF_DW, "u64", atomic_load_add_64>;
 }
 
 // bswap16, bswap32, bswap64
-class BSWAP<bits<32> SizeOp, string OpcodeStr, list<dag> Pattern>
-    : TYPE_ALU_JMP<BPF_END.Value, BPF_TO_BE.Value,
+class BSWAP<bits<32> SizeOp, string OpcodeStr, BPFSrcType SrcType, list<dag> Pattern>
+    : TYPE_ALU_JMP<BPF_END.Value, SrcType.Value,
                    (outs GPR:$dst),
                    (ins GPR:$src),
-                   !strconcat(OpcodeStr, "\t$dst"),
+                   "$dst = "#OpcodeStr#" $src",
                    Pattern> {
   bits<4> dst;
 
@@ -497,10 +519,18 @@ class BSWAP<bits<32> SizeOp, string OpcodeStr, list<dag> Pattern>
   let BPFClass = BPF_ALU;
 }
 
+
 let Constraints = "$dst = $src" in {
-def BSWAP16 : BSWAP<16, "bswap16", [(set GPR:$dst, (srl (bswap GPR:$src), (i64 48)))]>;
-def BSWAP32 : BSWAP<32, "bswap32", [(set GPR:$dst, (srl (bswap GPR:$src), (i64 32)))]>;
-def BSWAP64 : BSWAP<64, "bswap64", [(set GPR:$dst, (bswap GPR:$src))]>;
+    let Predicates = [BPFIsLittleEndian] in {
+        def BE16 : BSWAP<16, "be16", BPF_TO_BE, [(set GPR:$dst, (srl (bswap GPR:$src), (i64 48)))]>;
+        def BE32 : BSWAP<32, "be32", BPF_TO_BE, [(set GPR:$dst, (srl (bswap GPR:$src), (i64 32)))]>;
+        def BE64 : BSWAP<64, "be64", BPF_TO_BE, [(set GPR:$dst, (bswap GPR:$src))]>;
+    }
+    let Predicates = [BPFIsBigEndian] in {
+        def LE16 : BSWAP<16, "le16", BPF_TO_LE, [(set GPR:$dst, (srl (bswap GPR:$src), (i64 48)))]>;
+        def LE32 : BSWAP<32, "le32", BPF_TO_LE, [(set GPR:$dst, (srl (bswap GPR:$src), (i64 32)))]>;
+        def LE64 : BSWAP<64, "le64", BPF_TO_LE, [(set GPR:$dst, (bswap GPR:$src))]>;
+    }
 }
 
 let Defs = [R0, R1, R2, R3, R4, R5], Uses = [R6], hasSideEffects = 1,
index 88aba80..28aba00 100644 (file)
@@ -1,4 +1,5 @@
-; RUN: llc < %s -march=bpfel -show-mc-encoding | FileCheck %s
+; RUN: llc < %s -march=bpfel -show-mc-encoding | FileCheck --check-prefix=CHECK-EL %s
+; RUN: llc < %s -march=bpfeb -show-mc-encoding | FileCheck --check-prefix=CHECK-EB %s
 
 ; Function Attrs: nounwind uwtable
 define i32 @ld_b(i64 %foo, i64* nocapture %bar, i8* %ctx, i8* %ctx2) #0 {
@@ -13,8 +14,10 @@ define i32 @ld_b(i64 %foo, i64* nocapture %bar, i8* %ctx, i8* %ctx2) #0 {
   %9 = trunc i64 %8 to i32
   ret i32 %9
 ; CHECK-LABEL: ld_b:
-; CHECK: r0 = *(u8 *)skb[123]
-; CHECK: r0 = *(u8 *)skb[r
+; CHECK-EL: r0 = *(u8 *)skb[123]
+; CHECK-EL: r0 = *(u8 *)skb[r
+; CHECK-EB: r0 = *(u8 *)skb[123]
+; CHECK-EB: r0 = *(u8 *)skb[r
 }
 
 declare i64 @llvm.bpf.load.byte(i8*, i64) #1
@@ -28,8 +31,10 @@ define i32 @ld_h(i8* %ctx, i8* %ctx2, i32 %foo) #0 {
   %5 = trunc i64 %4 to i32
   ret i32 %5
 ; CHECK-LABEL: ld_h:
-; CHECK: r0 = *(u16 *)skb[r
-; CHECK: r0 = *(u16 *)skb[123]
+; CHECK-EL: r0 = *(u16 *)skb[r
+; CHECK-EL: r0 = *(u16 *)skb[123]
+; CHECK-EB: r0 = *(u16 *)skb[r
+; CHECK-EB: r0 = *(u16 *)skb[123]
 }
 
 declare i64 @llvm.bpf.load.half(i8*, i64) #1
@@ -43,8 +48,10 @@ define i32 @ld_w(i8* %ctx, i8* %ctx2, i32 %foo) #0 {
   %5 = trunc i64 %4 to i32
   ret i32 %5
 ; CHECK-LABEL: ld_w:
-; CHECK: r0 = *(u32 *)skb[r
-; CHECK: r0 = *(u32 *)skb[123]
+; CHECK-EL: r0 = *(u32 *)skb[r
+; CHECK-EL: r0 = *(u32 *)skb[123]
+; CHECK-EB: r0 = *(u32 *)skb[r
+; CHECK-EB: r0 = *(u32 *)skb[123]
 }
 
 declare i64 @llvm.bpf.load.word(i8*, i64) #1
@@ -55,7 +62,8 @@ entry:
   tail call void inttoptr (i64 4 to void (i64, i32)*)(i64 %call, i32 4) #2
   ret i32 0
 ; CHECK-LABEL: ld_pseudo:
-; CHECK: ld_pseudo r1, 2, 3 # encoding: [0x18,0x21,0x00,0x00,0x03,0x00
+; CHECK-EL: ld_pseudo r1, 2, 3 # encoding: [0x18,0x21,0x00,0x00,0x03,0x00,0x00,0x00
+; CHECK-EB: ld_pseudo r1, 2, 3 # encoding: [0x18,0x12,0x00,0x00,0x00,0x00,0x00,0x03
 }
 
 declare i64 @llvm.bpf.pseudo(i64, i64) #2
@@ -74,11 +82,16 @@ entry:
   %conv5 = trunc i64 %add4 to i32
   ret i32 %conv5
 ; CHECK-LABEL: bswap:
-; CHECK: bswap64 r1     # encoding: [0xdc,0x01,0x00,0x00,0x40,0x00,0x00,0x00]
-; CHECK: bswap32 r2     # encoding: [0xdc,0x02,0x00,0x00,0x20,0x00,0x00,0x00]
-; CHECK: r2 += r1 # encoding: [0x0f,0x12,0x00,0x00,0x00,0x00,0x00,0x00]
-; CHECK: bswap16 r3     # encoding: [0xdc,0x03,0x00,0x00,0x10,0x00,0x00,0x00]
-; CHECK: r2 += r3 # encoding: [0x0f,0x32,0x00,0x00,0x00,0x00,0x00,0x00]
+; CHECK-EL: r1 = be64 r1     # encoding: [0xdc,0x01,0x00,0x00,0x40,0x00,0x00,0x00]
+; CHECK-EL: r2 = be32 r2     # encoding: [0xdc,0x02,0x00,0x00,0x20,0x00,0x00,0x00]
+; CHECK-EL: r2 += r1 # encoding: [0x0f,0x12,0x00,0x00,0x00,0x00,0x00,0x00]
+; CHECK-EL: r3 = be16 r3     # encoding: [0xdc,0x03,0x00,0x00,0x10,0x00,0x00,0x00]
+; CHECK-EL: r2 += r3 # encoding: [0x0f,0x32,0x00,0x00,0x00,0x00,0x00,0x00]
+; CHECK-EB: r1 = le64 r1     # encoding: [0xd4,0x10,0x00,0x00,0x00,0x00,0x00,0x40]
+; CHECK-EB: r2 = le32 r2     # encoding: [0xd4,0x20,0x00,0x00,0x00,0x00,0x00,0x20]
+; CHECK-EB: r2 += r1 # encoding: [0x0f,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
+; CHECK-EB: r3 = le16 r3     # encoding: [0xd4,0x30,0x00,0x00,0x00,0x00,0x00,0x10]
+; CHECK-EB: r2 += r3 # encoding: [0x0f,0x23,0x00,0x00,0x00,0x00,0x00,0x00]
 }
 
 declare i64 @llvm.bswap.i64(i64) #1
index 1d33e57..6a32da9 100644 (file)
@@ -1,4 +1,5 @@
-; RUN: llc -march=bpfel -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s
+; RUN: llc -march=bpfel -filetype=obj -o - %s | llvm-objdump -d - | FileCheck --check-prefix=CHECK-EL %s
+; RUN: llc -march=bpfeb -filetype=obj -o - %s | llvm-objdump -d - | FileCheck --check-prefix=CHECK-EB %s
 
 ; Function Attrs: nounwind uwtable
 define i32 @ld_b(i64 %foo, i64* nocapture %bar, i8* %ctx, i8* %ctx2) #0 {
@@ -13,8 +14,10 @@ define i32 @ld_b(i64 %foo, i64* nocapture %bar, i8* %ctx, i8* %ctx2) #0 {
   %9 = trunc i64 %8 to i32
   ret i32 %9
 ; CHECK-LABEL: ld_b:
-; CHECK: r0 = *(u8 *)skb[123]
-; CHECK: r0 = *(u8 *)skb[r
+; CHECK-EL: r0 = *(u8 *)skb[123]
+; CHECK-EL: r0 = *(u8 *)skb[r
+; CHECK-EB: r0 = *(u8 *)skb[123]
+; CHECK-EB: r0 = *(u8 *)skb[r
 }
 
 declare i64 @llvm.bpf.load.byte(i8*, i64) #1
@@ -28,8 +31,10 @@ define i32 @ld_h(i8* %ctx, i8* %ctx2, i32 %foo) #0 {
   %5 = trunc i64 %4 to i32
   ret i32 %5
 ; CHECK-LABEL: ld_h:
-; CHECK: r0 = *(u16 *)skb[r
-; CHECK: r0 = *(u16 *)skb[123]
+; CHECK-EL: r0 = *(u16 *)skb[r
+; CHECK-EL: r0 = *(u16 *)skb[123]
+; CHECK-EB: r0 = *(u16 *)skb[r
+; CHECK-EB: r0 = *(u16 *)skb[123]
 }
 
 declare i64 @llvm.bpf.load.half(i8*, i64) #1
@@ -43,8 +48,10 @@ define i32 @ld_w(i8* %ctx, i8* %ctx2, i32 %foo) #0 {
   %5 = trunc i64 %4 to i32
   ret i32 %5
 ; CHECK-LABEL: ld_w:
-; CHECK: r0 = *(u32 *)skb[r
-; CHECK: r0 = *(u32 *)skb[123]
+; CHECK-EL: r0 = *(u32 *)skb[r
+; CHECK-EL: r0 = *(u32 *)skb[123]
+; CHECK-EB: r0 = *(u32 *)skb[r
+; CHECK-EB: r0 = *(u32 *)skb[123]
 }
 
 declare i64 @llvm.bpf.load.word(i8*, i64) #1
@@ -55,7 +62,8 @@ entry:
   tail call void inttoptr (i64 4 to void (i64, i32)*)(i64 %call, i32 4) #2
   ret i32 0
 ; CHECK-LABEL: ld_pseudo:
-; CHECK: ld_pseudo r1, 2, 3
+; CHECK-EL: ld_pseudo r1, 2, 3
+; CHECK-EB: ld_pseudo r1, 2, 3
 }
 
 declare i64 @llvm.bpf.pseudo(i64, i64) #2
@@ -74,11 +82,16 @@ entry:
   %conv5 = trunc i64 %add4 to i32
   ret i32 %conv5
 ; CHECK-LABEL: bswap:
-; CHECK: bswap64 r1
-; CHECK: bswap32 r2
-; CHECK: r2 += r1
-; CHECK: bswap16 r3
-; CHECK: r2 += r3
+; CHECK-EL: r1 = be64 r1
+; CHECK-EL: r2 = be32 r2
+; CHECK-EL: r2 += r1
+; CHECK-EL: r3 = be16 r3
+; CHECK-EL: r2 += r3
+; CHECK-EB: r1 = le64 r1
+; CHECK-EB: r2 = le32 r2
+; CHECK-EB: r2 += r1
+; CHECK-EB: r3 = le16 r3
+; CHECK-EB: r2 += r3
 }
 
 declare i64 @llvm.bswap.i64(i64) #1
index 956f5bc..e5911f0 100644 (file)
@@ -2,10 +2,12 @@
 # RUN: llvm-objdump -d -r %t | FileCheck %s
 
 // ======== BPF_ALU Class ========
+  w1 = -w1    // BPF_NEG
   w0 += w1    // BPF_ADD  | BPF_X
   w1 -= w2    // BPF_SUB  | BPF_X
   w2 *= w3    // BPF_MUL  | BPF_X
   w3 /= w4    // BPF_DIV  | BPF_X
+// CHECK: 84 11 00 00 00 00 00 00      w1 = -w1
 // CHECK: 0c 10 00 00 00 00 00 00      w0 += w1
 // CHECK: 1c 21 00 00 00 00 00 00      w1 -= w2
 // CHECK: 2c 32 00 00 00 00 00 00      w2 *= w3
index e6b69cd..68b6462 100644 (file)
 // CHECK: 3f 43 00 00 00 00 00 00      r3 /= r4
 
 Llabel0 :
+  r0 = -r0    // BPF_NEG
   r4 |= r5    // BPF_OR   | BPF_X
   r5 &= r6    // BPF_AND  | BPF_X
   r6 <<= r7   // BPF_LSH  | BPF_X
@@ -126,6 +127,7 @@ Llabel0 :
   r9 = r10    // BPF_MOV  | BPF_X
   r10 s>>= r0 // BPF_ARSH | BPF_X
 // CHECK:Llabel0:
+// CHECK: 87 00 00 00 00 00 00 00      r0 = -r0
 // CHECK: 4f 54 00 00 00 00 00 00      r4 |= r5
 // CHECK: 5f 65 00 00 00 00 00 00      r5 &= r6
 // CHECK: 6f 76 00 00 00 00 00 00      r6 <<= r7
@@ -134,12 +136,12 @@ Llabel0 :
 // CHECK: bf a9 00 00 00 00 00 00      r9 = r10
 // CHECK: cf 0a 00 00 00 00 00 00      r10 s>>= r0
 
-  bswap16 r1  // BPF_END  | BPF_TO_BE
-  bswap32 r2  // BPF_END  | BPF_TO_BE
-  bswap64 r3  // BPF_END  | BPF_TO_BE
-// CHECK: dc 01 00 00 10 00 00 00      bswap16 r1
-// CHECK: dc 02 00 00 20 00 00 00      bswap32 r2
-// CHECK: dc 03 00 00 40 00 00 00      bswap64 r3
+  r1 = be16 r1  // BPF_END  | BPF_TO_BE
+  r2 = be32 r2  // BPF_END  | BPF_TO_BE
+  r3 = be64 r3  // BPF_END  | BPF_TO_BE
+// CHECK: dc 01 00 00 10 00 00 00      r1 = be16 r1
+// CHECK: dc 02 00 00 20 00 00 00      r2 = be32 r2
+// CHECK: dc 03 00 00 40 00 00 00      r3 = be64 r3
 
   r0 += 1           // BPF_ADD  | BPF_K
   r1 -= 0x1         // BPF_SUB  | BPF_K