[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 <yhs@plumgrid.com> llvm-svn: 249371
This commit is contained in:
parent
79dd1bf094
commit
4e01a38da0
|
@ -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<ConstantSDNode>(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<ConstantSDNode>(Addr.getOperand(1));
|
||||
if (isInt<32>(CN->getSExtValue())) {
|
||||
|
||||
// If the first operand is a FI, get the TargetFI Node
|
||||
if (FrameIndexSDNode *FIN =
|
||||
dyn_cast<FrameIndexSDNode>(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();
|
||||
|
||||
|
|
|
@ -54,7 +54,8 @@ def i64immSExt32 : PatLeaf<(imm),
|
|||
[{return isInt<32>(N->getSExtValue()); }]>;
|
||||
|
||||
// Addressing modes.
|
||||
def ADDRri : ComplexPattern<i64, 2, "SelectAddr", [frameindex], []>;
|
||||
def ADDRri : ComplexPattern<i64, 2, "SelectAddr", [], []>;
|
||||
def FIri : ComplexPattern<i64, 2, "SelectFIAddr", [add, or], []>;
|
||||
|
||||
// Address operands
|
||||
def MEMri : Operand<i64> {
|
||||
|
@ -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",
|
||||
|
|
|
@ -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 <target_reg>, frame_reg
|
||||
// ADD_ri <target_reg>, 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 {
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue