aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYonghong Song <yhs@fb.com>2017-09-18 23:29:36 +0000
committerYonghong Song <yhs@fb.com>2017-09-18 23:29:36 +0000
commit9ef85f06775dea8b5f11b118421e5ce997eb7c88 (patch)
tree2cdadafbcfcde59e72c70040c43c30d3204983e1
parentbb4b4eef61d3377863a2fa7688db0d0c67fe5285 (diff)
downloadllvm-9ef85f06775dea8b5f11b118421e5ce997eb7c88.zip
llvm-9ef85f06775dea8b5f11b118421e5ce997eb7c88.tar.gz
llvm-9ef85f06775dea8b5f11b118421e5ce997eb7c88.tar.bz2
bpf: add inline-asm support
Signed-off-by: Yonghong Song <yhs@fb.com> Acked-by: Alexei Starovoitov <ast@kernel.org> llvm-svn: 313593
-rw-r--r--llvm/lib/Target/BPF/BPFAsmPrinter.cpp77
-rw-r--r--llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp24
-rw-r--r--llvm/lib/Target/BPF/BPFISelLowering.cpp16
-rw-r--r--llvm/lib/Target/BPF/BPFISelLowering.h4
-rw-r--r--llvm/test/CodeGen/BPF/inline_asm.ll54
5 files changed, 175 insertions, 0 deletions
diff --git a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
index 9397c78..705211b 100644
--- a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
+++ b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
@@ -40,11 +40,88 @@ public:
: AsmPrinter(TM, std::move(Streamer)) {}
StringRef getPassName() const override { return "BPF Assembly Printer"; }
+ void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) override;
+ bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) override;
void EmitInstruction(const MachineInstr *MI) override;
};
} // namespace
+void BPFAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
+ raw_ostream &O) {
+ const MachineOperand &MO = MI->getOperand(OpNum);
+
+ switch (MO.getType()) {
+ case MachineOperand::MO_Register:
+ O << BPFInstPrinter::getRegisterName(MO.getReg());
+ break;
+
+ case MachineOperand::MO_Immediate:
+ O << MO.getImm();
+ break;
+
+ case MachineOperand::MO_MachineBasicBlock:
+ O << *MO.getMBB()->getSymbol();
+ break;
+
+ case MachineOperand::MO_GlobalAddress:
+ O << *getSymbol(MO.getGlobal());
+ break;
+
+ case MachineOperand::MO_BlockAddress: {
+ MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
+ O << BA->getName();
+ break;
+ }
+
+ case MachineOperand::MO_ExternalSymbol:
+ O << *GetExternalSymbolSymbol(MO.getSymbolName());
+ break;
+
+ case MachineOperand::MO_JumpTableIndex:
+ case MachineOperand::MO_ConstantPoolIndex:
+ default:
+ llvm_unreachable("<unknown operand type>");
+ }
+}
+
+bool BPFAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned /*AsmVariant*/,
+ const char *ExtraCode, raw_ostream &O) {
+ if (ExtraCode && ExtraCode[0])
+ return true; // BPF does not have special modifiers
+
+ printOperand(MI, OpNo, O);
+ return false;
+}
+
+bool BPFAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
+ unsigned OpNum, unsigned AsmVariant,
+ const char *ExtraCode,
+ raw_ostream &O) {
+ assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands");
+ const MachineOperand &BaseMO = MI->getOperand(OpNum);
+ const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1);
+ assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand.");
+ assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand.");
+ int Offset = OffsetMO.getImm();
+
+ if (ExtraCode)
+ return true; // Unknown modifier.
+
+ if (Offset < 0)
+ O << "(" << BPFInstPrinter::getRegisterName(BaseMO.getReg()) << " - " << -Offset << ")";
+ else
+ O << "(" << BPFInstPrinter::getRegisterName(BaseMO.getReg()) << " + " << Offset << ")";
+
+ return false;
+}
+
void BPFAsmPrinter::EmitInstruction(const MachineInstr *MI) {
BPFMCInstLower MCInstLowering(OutContext, *this);
diff --git a/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp b/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
index f48429e..1f382f3 100644
--- a/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
+++ b/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
@@ -48,6 +48,10 @@ public:
void PreprocessISelDAG() override;
+ bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
+ std::vector<SDValue> &OutOps) override;
+
+
private:
// Include the pieces autogenerated from the target description.
#include "BPFGenDAGISel.inc"
@@ -145,6 +149,26 @@ bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base,
return false;
}
+bool BPFDAGToDAGISel::SelectInlineAsmMemoryOperand(
+ const SDValue &Op, unsigned ConstraintCode, std::vector<SDValue> &OutOps) {
+ SDValue Op0, Op1;
+ switch (ConstraintCode) {
+ default:
+ return true;
+ case InlineAsm::Constraint_m: // memory
+ if (!SelectAddr(Op, Op0, Op1))
+ return true;
+ break;
+ }
+
+ SDLoc DL(Op);
+ SDValue AluOp = CurDAG->getTargetConstant(ISD::ADD, DL, MVT::i32);;
+ OutOps.push_back(Op0);
+ OutOps.push_back(Op1);
+ OutOps.push_back(AluOp);
+ return false;
+}
+
void BPFDAGToDAGISel::Select(SDNode *Node) {
unsigned Opcode = Node->getOpcode();
diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp
index 94b3c7a..d4e06ddc 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.cpp
+++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp
@@ -139,6 +139,22 @@ bool BPFTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) cons
return false;
}
+std::pair<unsigned, const TargetRegisterClass *>
+BPFTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
+ StringRef Constraint,
+ MVT VT) const {
+ if (Constraint.size() == 1)
+ // GCC Constraint Letters
+ switch (Constraint[0]) {
+ case 'r': // GENERAL_REGS
+ return std::make_pair(0U, &BPF::GPRRegClass);
+ default:
+ break;
+ }
+
+ return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
+}
+
SDValue BPFTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
case ISD::BR_CC:
diff --git a/llvm/lib/Target/BPF/BPFISelLowering.h b/llvm/lib/Target/BPF/BPFISelLowering.h
index 35065f2..984843a 100644
--- a/llvm/lib/Target/BPF/BPFISelLowering.h
+++ b/llvm/lib/Target/BPF/BPFISelLowering.h
@@ -46,6 +46,10 @@ public:
// with the given GlobalAddress is legal.
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
+ std::pair<unsigned, const TargetRegisterClass *>
+ getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
+ StringRef Constraint, MVT VT) const override;
+
MachineBasicBlock *
EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *BB) const override;
diff --git a/llvm/test/CodeGen/BPF/inline_asm.ll b/llvm/test/CodeGen/BPF/inline_asm.ll
new file mode 100644
index 0000000..7822ac4
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/inline_asm.ll
@@ -0,0 +1,54 @@
+; RUN: llc < %s -march=bpfel -verify-machineinstrs | FileCheck %s
+; RUN: llc < %s -march=bpfeb -verify-machineinstrs | FileCheck %s
+
+; Source code:
+; int g[2];
+;
+; int test(void *ctx) {
+; int a = 4, b;
+; unsigned long long c = 333333333333ULL;
+; asm volatile("r0 = *(u16 *)skb[%0]" : : "i"(2));
+; asm volatile("r0 = *(u16 *)skb[%0]" : : "r"(a));
+; asm volatile("%0 = %1" : "=r"(b) : "i"(4));
+; asm volatile("%0 = %1 ll" : "=r"(b) : "i"(c));
+; asm volatile("%0 = *(u16 *) %1" : "=r"(b) : "m"(a));
+; asm volatile("%0 = *(u32 *) %1" : "=r"(b) : "m"(g[1]));
+; return b;
+; }
+;
+
+@g = common global [2 x i32] zeroinitializer, align 4
+
+; Function Attrs: nounwind
+define i32 @test(i8* nocapture readnone %ctx) local_unnamed_addr #0 {
+entry:
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) #2
+ store i32 4, i32* %a, align 4
+ tail call void asm sideeffect "r0 = *(u16 *)skb[$0]", "i"(i32 2) #2
+; CHECK: r0 = *(u16 *)skb[2]
+ tail call void asm sideeffect "r0 = *(u16 *)skb[$0]", "r"(i32 4) #2
+; CHECK: r0 = *(u16 *)skb[r1]
+ %1 = tail call i32 asm sideeffect "$0 = $1", "=r,i"(i32 4) #2
+; CHECK: r1 = 4
+ %2 = tail call i32 asm sideeffect "$0 = $1 ll", "=r,i"(i64 333333333333) #2
+; CHECK: r1 = 333333333333 ll
+ %3 = call i32 asm sideeffect "$0 = *(u16 *) $1", "=r,*m"(i32* nonnull %a) #2
+; CHECK: r1 = *(u16 *) (r10 - 4)
+ %4 = call i32 asm sideeffect "$0 = *(u32 *) $1", "=r,*m"(i32* getelementptr inbounds ([2 x i32], [2 x i32]* @g, i64 0, i64 1)) #2
+; CHECK: r1 = g ll
+; CHECK: r0 = *(u32 *) (r1 + 4)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) #2
+ ret i32 %4
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
+
+attributes #0 = { nounwind }
+attributes #1 = { argmemonly nounwind }
+attributes #2 = { nounwind }