Skip to content

Commit

Permalink
bpf: generate better lowering code for certain select/setcc instructions
Browse files Browse the repository at this point in the history
Currently, for code like below,
===
  inner_map = bpf_map_lookup_elem(outer_map, &port_key);
  if (!inner_map) {
    inner_map = &fallback_map;
  }
===
the compiler generates (pseudo) code like the below:
===
  I1: r1 = bpf_map_lookup_elem(outer_map, &port_key);
  I2: r2 = 0
  I3: if (r1 == r2)
  I4:   r6 = &fallback_map
  I5: ...
===

During kernel verification process, After I1, r1 holds a state
map_ptr_or_null. If I3 condition is not taken
(path [I1, I2, I3, I5]), supposedly r1 should become map_ptr.
Unfortunately, kernel does not recognize this pattern
and r1 remains map_ptr_or_null at insn I5. This will cause
verificaiton failure later on.

Kernel, however, is able to recognize pattern "if (r1 == 0)"
properly and give a map_ptr state to r1 in the above case.

LLVM here generates suboptimal code which causes kernel verification
failure. This patch fixes the issue by changing BPF insn pattern
matching and lowering to generate proper codes if the righthand
parameter of the above condition is a constant. A test case
is also added.

Signed-off-by: Yonghong Song <[email protected]>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@308080 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
yonghong-song committed Jul 15, 2017
1 parent cf17bf0 commit 7c423e0
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 28 deletions.
46 changes: 20 additions & 26 deletions lib/Target/BPF/BPFISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,8 +515,10 @@ BPFTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *BB) const {
const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo();
DebugLoc DL = MI.getDebugLoc();
bool isSelectOp = MI.getOpcode() == BPF::Select;
bool isSelectRiOp = MI.getOpcode() == BPF::Select_Ri;

assert(MI.getOpcode() == BPF::Select && "Unexpected instr type to insert");
assert((isSelectOp || isSelectRiOp) && "Unexpected instr type to insert");

// To "insert" a SELECT instruction, we actually have to insert the diamond
// control-flow pattern. The incoming instruction knows the destination vreg
Expand Down Expand Up @@ -548,48 +550,40 @@ BPFTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,

// Insert Branch if Flag
unsigned LHS = MI.getOperand(1).getReg();
unsigned RHS = MI.getOperand(2).getReg();
int CC = MI.getOperand(3).getImm();
int NewCC;
switch (CC) {
case ISD::SETGT:
BuildMI(BB, DL, TII.get(BPF::JSGT_rr))
.addReg(LHS)
.addReg(RHS)
.addMBB(Copy1MBB);
NewCC = isSelectOp ? BPF::JSGT_rr : BPF::JSGT_ri;
break;
case ISD::SETUGT:
BuildMI(BB, DL, TII.get(BPF::JUGT_rr))
.addReg(LHS)
.addReg(RHS)
.addMBB(Copy1MBB);
NewCC = isSelectOp ? BPF::JUGT_rr : BPF::JUGT_ri;
break;
case ISD::SETGE:
BuildMI(BB, DL, TII.get(BPF::JSGE_rr))
.addReg(LHS)
.addReg(RHS)
.addMBB(Copy1MBB);
NewCC = isSelectOp ? BPF::JSGE_rr : BPF::JSGE_ri;
break;
case ISD::SETUGE:
BuildMI(BB, DL, TII.get(BPF::JUGE_rr))
.addReg(LHS)
.addReg(RHS)
.addMBB(Copy1MBB);
NewCC = isSelectOp ? BPF::JUGE_rr : BPF::JUGE_ri;
break;
case ISD::SETEQ:
BuildMI(BB, DL, TII.get(BPF::JEQ_rr))
.addReg(LHS)
.addReg(RHS)
.addMBB(Copy1MBB);
NewCC = isSelectOp ? BPF::JEQ_rr : BPF::JEQ_ri;
break;
case ISD::SETNE:
BuildMI(BB, DL, TII.get(BPF::JNE_rr))
.addReg(LHS)
.addReg(RHS)
.addMBB(Copy1MBB);
NewCC = isSelectOp ? BPF::JNE_rr : BPF::JNE_ri;
break;
default:
report_fatal_error("unimplemented select CondCode " + Twine(CC));
}
if (isSelectOp)
BuildMI(BB, DL, TII.get(NewCC))
.addReg(LHS)
.addReg(MI.getOperand(2).getReg())
.addMBB(Copy1MBB);
else
BuildMI(BB, DL, TII.get(NewCC))
.addReg(LHS)
.addImm(MI.getOperand(2).getImm())
.addMBB(Copy1MBB);

// Copy0MBB:
// %FalseValue = ...
Expand Down
5 changes: 5 additions & 0 deletions lib/Target/BPF/BPFInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,11 @@ let usesCustomInserter = 1 in {
"# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2",
[(set i64:$dst,
(BPFselectcc i64:$lhs, i64:$rhs, (i64 imm:$imm), i64:$src, i64:$src2))]>;
def Select_Ri : Pseudo<(outs GPR:$dst),
(ins GPR:$lhs, i64imm:$rhs, i64imm:$imm, GPR:$src, GPR:$src2),
"# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2",
[(set i64:$dst,
(BPFselectcc i64:$lhs, (i64 imm:$rhs), (i64 imm:$imm), i64:$src, i64:$src2))]>;
}

// load 64-bit global addr into register
Expand Down
27 changes: 27 additions & 0 deletions test/CodeGen/BPF/select_ri.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
; RUN: llc < %s -march=bpf -verify-machineinstrs | FileCheck %s
;
; Source file:
; int b, c;
; int test() {
; int a = b;
; if (a)
; a = c;
; return a;
; }
@b = common local_unnamed_addr global i32 0, align 4
@c = common local_unnamed_addr global i32 0, align 4

; Function Attrs: norecurse nounwind readonly
define i32 @test() local_unnamed_addr #0 {
entry:
%0 = load i32, i32* @b, align 4
%tobool = icmp eq i32 %0, 0
%1 = load i32, i32* @c, align 4
%. = select i1 %tobool, i32 0, i32 %1
; CHECK: r1 = <MCOperand Expr:(b)>ll
; CHECK: r1 = *(u32 *)(r1 + 0)
; CHECK: if r1 == 0 goto
ret i32 %.
}

attributes #0 = { norecurse nounwind readonly }
4 changes: 2 additions & 2 deletions test/CodeGen/BPF/setcc.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ define i16 @sccweqand(i16 %a, i16 %b) nounwind {
ret i16 %t3
}
; CHECK-LABEL: sccweqand:
; CHECK: if r1 == r2
; CHECK: if r1 == 0

define i16 @sccwneand(i16 %a, i16 %b) nounwind {
%t1 = and i16 %a, %b
Expand All @@ -16,7 +16,7 @@ define i16 @sccwneand(i16 %a, i16 %b) nounwind {
ret i16 %t3
}
; CHECK-LABEL: sccwneand:
; CHECK: if r1 != r2
; CHECK: if r1 != 0

define i16 @sccwne(i16 %a, i16 %b) nounwind {
%t1 = icmp ne i16 %a, %b
Expand Down

0 comments on commit 7c423e0

Please sign in to comment.