From df6ca162269f9d756f8742bf4b658dcf690e3eb5 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 28 Sep 2017 02:46:11 +0000 Subject: [PATCH] bpf: add new insns for bswap_to_le and negation 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 Acked-by: Alexei Starovoitov git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@314376 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/BPF/AsmParser/BPFAsmParser.cpp | 41 ++++++++++++++++++++++++------ lib/Target/BPF/BPFInstrFormats.td | 1 + lib/Target/BPF/BPFInstrInfo.td | 42 ++++++++++++++++++++++++++----- test/CodeGen/BPF/intrinsics.ll | 39 ++++++++++++++++++---------- test/CodeGen/BPF/objdump_intrinsics.ll | 39 ++++++++++++++++++---------- test/MC/BPF/insn-unit-32.s | 2 ++ test/MC/BPF/insn-unit.s | 14 ++++++----- 7 files changed, 132 insertions(+), 46 deletions(-) diff --git a/lib/Target/BPF/AsmParser/BPFAsmParser.cpp b/lib/Target/BPF/AsmParser/BPFAsmParser.cpp index d00200c1850..9e251d211d2 100644 --- a/lib/Target/BPF/AsmParser/BPFAsmParser.cpp +++ b/lib/Target/BPF/AsmParser/BPFAsmParser.cpp @@ -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. diff --git a/lib/Target/BPF/BPFInstrFormats.td b/lib/Target/BPF/BPFInstrFormats.td index 1e3bc3b7a6d..92d4a62fd87 100644 --- a/lib/Target/BPF/BPFInstrFormats.td +++ b/lib/Target/BPF/BPFInstrFormats.td @@ -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>; diff --git a/lib/Target/BPF/BPFInstrInfo.td b/lib/Target/BPF/BPFInstrInfo.td index e1f233e4d45..7d4b03deebe 100644 --- a/lib/Target/BPF/BPFInstrInfo.td +++ b/lib/Target/BPF/BPFInstrInfo.td @@ -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; def calltarget : Operand; @@ -232,6 +234,26 @@ let isAsCheapAsAMove = 1 in { defm DIV : ALU; } +class NEG_RR pattern> + : TYPE_ALU_JMP { + 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; + def NEG_32: NEG_RR; +} + class LD_IMM64 Pseudo, string OpcodeStr> : TYPE_LD_ST; } // bswap16, bswap32, bswap64 -class BSWAP SizeOp, string OpcodeStr, list Pattern> - : TYPE_ALU_JMP SizeOp, string OpcodeStr, BPFSrcType SrcType, list Pattern> + : TYPE_ALU_JMP { bits<4> dst; @@ -497,10 +519,18 @@ class BSWAP SizeOp, string OpcodeStr, list 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, diff --git a/test/CodeGen/BPF/intrinsics.ll b/test/CodeGen/BPF/intrinsics.ll index 88aba805ada..28aba0097d3 100644 --- a/test/CodeGen/BPF/intrinsics.ll +++ b/test/CodeGen/BPF/intrinsics.ll @@ -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 diff --git a/test/CodeGen/BPF/objdump_intrinsics.ll b/test/CodeGen/BPF/objdump_intrinsics.ll index 1d33e57de78..6a32da9ec04 100644 --- a/test/CodeGen/BPF/objdump_intrinsics.ll +++ b/test/CodeGen/BPF/objdump_intrinsics.ll @@ -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 diff --git a/test/MC/BPF/insn-unit-32.s b/test/MC/BPF/insn-unit-32.s index 956f5bcb07b..e5911f04cd0 100644 --- a/test/MC/BPF/insn-unit-32.s +++ b/test/MC/BPF/insn-unit-32.s @@ -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 diff --git a/test/MC/BPF/insn-unit.s b/test/MC/BPF/insn-unit.s index e6b69cd8a83..68b646262ea 100644 --- a/test/MC/BPF/insn-unit.s +++ b/test/MC/BPF/insn-unit.s @@ -118,6 +118,7 @@ // 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 -- 2.11.0