From 49cdd6c3d109b734fea339568b147e4c06feed52 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 6 Oct 2015 04:00:53 +0000 Subject: [PATCH] [bpf] Avoid extra pointer arithmetic for stack access For the program like below struct key_t { int pid; char name[16]; }; extern void test1(char *); int test() { struct key_t key = {}; test1(key.name); return 0; } For key.name, the llc/bpf may generate the below code: R1 = R10 // R10 is the frame pointer R1 += -24 // framepointer adjustment R1 |= 4 // R1 is then used as the first parameter of test1 OR operation is not recognized by in-kernel verifier. This patch introduces an intermediate FI_ri instruction and generates the following code that can be properly verified: R1 = R10 R1 += -20 Patch by Yonghong Song git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249371 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/BPF/BPFISelDAGToDAG.cpp | 28 +++++++++++++++++++++++++++- lib/Target/BPF/BPFInstrInfo.td | 12 +++++++++++- lib/Target/BPF/BPFRegisterInfo.cpp | 25 ++++++++++++++++++++----- test/CodeGen/BPF/fi_ri.ll | 25 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 test/CodeGen/BPF/fi_ri.ll diff --git a/lib/Target/BPF/BPFISelDAGToDAG.cpp b/lib/Target/BPF/BPFISelDAGToDAG.cpp index d9e654c7642..44ecb181a1c 100644 --- a/lib/Target/BPF/BPFISelDAGToDAG.cpp +++ b/lib/Target/BPF/BPFISelDAGToDAG.cpp @@ -50,6 +50,7 @@ private: // Complex Pattern for address selection. bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset); + bool SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset); }; } @@ -67,7 +68,7 @@ bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { Addr.getOpcode() == ISD::TargetGlobalAddress) return false; - // Addresses of the form FI+const or FI|const + // Addresses of the form Addr+const or Addr|const if (CurDAG->isBaseWithConstantOffset(Addr)) { ConstantSDNode *CN = dyn_cast(Addr.getOperand(1)); if (isInt<32>(CN->getSExtValue())) { @@ -89,6 +90,31 @@ bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { return true; } +// ComplexPattern used on BPF FI instruction +bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { + SDLoc DL(Addr); + + if (!CurDAG->isBaseWithConstantOffset(Addr)) + return false; + + // Addresses of the form Addr+const or Addr|const + ConstantSDNode *CN = dyn_cast(Addr.getOperand(1)); + if (isInt<32>(CN->getSExtValue())) { + + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = + dyn_cast(Addr.getOperand(0))) + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); + else + return false; + + Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64); + return true; + } + + return false; +} + SDNode *BPFDAGToDAGISel::Select(SDNode *Node) { unsigned Opcode = Node->getOpcode(); diff --git a/lib/Target/BPF/BPFInstrInfo.td b/lib/Target/BPF/BPFInstrInfo.td index 26b2cfebdc8..6b73db87fa2 100644 --- a/lib/Target/BPF/BPFInstrInfo.td +++ b/lib/Target/BPF/BPFInstrInfo.td @@ -54,7 +54,8 @@ def i64immSExt32 : PatLeaf<(imm), [{return isInt<32>(N->getSExtValue()); }]>; // Addressing modes. -def ADDRri : ComplexPattern; +def ADDRri : ComplexPattern; +def FIri : ComplexPattern; // Address operands def MEMri : Operand { @@ -260,6 +261,15 @@ def MOV_rr : MOV_RR<"mov">; def MOV_ri : MOV_RI<"mov">; } +def FI_ri + : InstBPF<(outs GPR:$dst), (ins MEMri:$addr), + "lea\t$dst, $addr", + [(set i64:$dst, FIri:$addr)]> { + // This is a tentative instruction, and will be replaced + // with MOV_rr and ADD_ri in PEI phase +} + + def LD_pseudo : InstBPF<(outs GPR:$dst), (ins i64imm:$pseudo, u64imm:$imm), "ld_pseudo\t$dst, $pseudo, $imm", diff --git a/lib/Target/BPF/BPFRegisterInfo.cpp b/lib/Target/BPF/BPFRegisterInfo.cpp index 8f885c3ea61..952615bd1c2 100644 --- a/lib/Target/BPF/BPFRegisterInfo.cpp +++ b/lib/Target/BPF/BPFRegisterInfo.cpp @@ -58,14 +58,13 @@ void BPFRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, unsigned FrameReg = getFrameRegister(MF); int FrameIndex = MI.getOperand(i).getIndex(); + const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); + MachineBasicBlock &MBB = *MI.getParent(); if (MI.getOpcode() == BPF::MOV_rr) { - const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex); MI.getOperand(i).ChangeToRegister(FrameReg, false); - - MachineBasicBlock &MBB = *MI.getParent(); unsigned reg = MI.getOperand(i - 1).getReg(); BuildMI(MBB, ++II, DL, TII.get(BPF::ADD_ri), reg) .addReg(reg) @@ -79,8 +78,24 @@ void BPFRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, if (!isInt<32>(Offset)) llvm_unreachable("bug in frame offset"); - MI.getOperand(i).ChangeToRegister(FrameReg, false); - MI.getOperand(i + 1).ChangeToImmediate(Offset); + if (MI.getOpcode() == BPF::FI_ri) { + // architecture does not really support FI_ri, replace it with + // MOV_rr , frame_reg + // ADD_ri , imm + unsigned reg = MI.getOperand(i - 1).getReg(); + + BuildMI(MBB, ++II, DL, TII.get(BPF::MOV_rr), reg) + .addReg(FrameReg); + BuildMI(MBB, II, DL, TII.get(BPF::ADD_ri), reg) + .addReg(reg) + .addImm(Offset); + + // Remove FI_ri instruction + MI.eraseFromParent(); + } else { + MI.getOperand(i).ChangeToRegister(FrameReg, false); + MI.getOperand(i + 1).ChangeToImmediate(Offset); + } } unsigned BPFRegisterInfo::getFrameRegister(const MachineFunction &MF) const { diff --git a/test/CodeGen/BPF/fi_ri.ll b/test/CodeGen/BPF/fi_ri.ll new file mode 100644 index 00000000000..64773b429fb --- /dev/null +++ b/test/CodeGen/BPF/fi_ri.ll @@ -0,0 +1,25 @@ +; RUN: llc < %s -march=bpf | FileCheck %s + +%struct.key_t = type { i32, [16 x i8] } + +; Function Attrs: nounwind uwtable +define i32 @test() #0 { + %key = alloca %struct.key_t, align 4 + %1 = bitcast %struct.key_t* %key to i8* +; CHECK: mov r1, 0 +; CHECK: stw -8(r10), r1 +; CHECK: std -16(r10), r1 +; CHECK: std -24(r10), r1 + call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 20, i32 4, i1 false) +; CHECK: mov r1, r10 +; CHECK: addi r1, -20 + %2 = getelementptr inbounds %struct.key_t, %struct.key_t* %key, i64 0, i32 1, i64 0 +; CHECK: call test1 + call void @test1(i8* %2) #3 + ret i32 0 +} + +; Function Attrs: nounwind argmemonly +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) #1 + +declare void @test1(i8*) #2 -- 2.11.0