1 //===-- BPFMCCodeEmitter.cpp - Convert BPF code to machine code -----------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements the BPFMCCodeEmitter class.
11 //===----------------------------------------------------------------------===//
13 #include "MCTargetDesc/BPFMCTargetDesc.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/MC/MCCodeEmitter.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCFixup.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCInstrInfo.h"
20 #include "llvm/MC/MCRegisterInfo.h"
21 #include "llvm/MC/MCSubtargetInfo.h"
22 #include "llvm/Support/Endian.h"
23 #include "llvm/Support/EndianStream.h"
29 #define DEBUG_TYPE "mccodeemitter"
33 class BPFMCCodeEmitter
: public MCCodeEmitter
{
34 const MCInstrInfo
&MCII
;
35 const MCRegisterInfo
&MRI
;
39 BPFMCCodeEmitter(const MCInstrInfo
&mcii
, const MCRegisterInfo
&mri
,
41 : MCII(mcii
), MRI(mri
), IsLittleEndian(IsLittleEndian
) {}
42 BPFMCCodeEmitter(const BPFMCCodeEmitter
&) = delete;
43 void operator=(const BPFMCCodeEmitter
&) = delete;
44 ~BPFMCCodeEmitter() override
= default;
46 // getBinaryCodeForInstr - TableGen'erated function for getting the
47 // binary encoding for an instruction.
48 uint64_t getBinaryCodeForInstr(const MCInst
&MI
,
49 SmallVectorImpl
<MCFixup
> &Fixups
,
50 const MCSubtargetInfo
&STI
) const;
52 // getMachineOpValue - Return binary encoding of operand. If the machin
53 // operand requires relocation, record the relocation and return zero.
54 unsigned getMachineOpValue(const MCInst
&MI
, const MCOperand
&MO
,
55 SmallVectorImpl
<MCFixup
> &Fixups
,
56 const MCSubtargetInfo
&STI
) const;
58 uint64_t getMemoryOpValue(const MCInst
&MI
, unsigned Op
,
59 SmallVectorImpl
<MCFixup
> &Fixups
,
60 const MCSubtargetInfo
&STI
) const;
62 void encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
63 SmallVectorImpl
<MCFixup
> &Fixups
,
64 const MCSubtargetInfo
&STI
) const override
;
67 FeatureBitset
computeAvailableFeatures(const FeatureBitset
&FB
) const;
69 verifyInstructionPredicates(const MCInst
&MI
,
70 const FeatureBitset
&AvailableFeatures
) const;
73 } // end anonymous namespace
75 MCCodeEmitter
*llvm::createBPFMCCodeEmitter(const MCInstrInfo
&MCII
,
76 const MCRegisterInfo
&MRI
,
78 return new BPFMCCodeEmitter(MCII
, MRI
, true);
81 MCCodeEmitter
*llvm::createBPFbeMCCodeEmitter(const MCInstrInfo
&MCII
,
82 const MCRegisterInfo
&MRI
,
84 return new BPFMCCodeEmitter(MCII
, MRI
, false);
87 unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst
&MI
,
89 SmallVectorImpl
<MCFixup
> &Fixups
,
90 const MCSubtargetInfo
&STI
) const {
92 return MRI
.getEncodingValue(MO
.getReg());
94 return static_cast<unsigned>(MO
.getImm());
98 const MCExpr
*Expr
= MO
.getExpr();
100 assert(Expr
->getKind() == MCExpr::SymbolRef
);
102 if (MI
.getOpcode() == BPF::JAL
)
104 Fixups
.push_back(MCFixup::create(0, Expr
, FK_PCRel_4
));
105 else if (MI
.getOpcode() == BPF::LD_imm64
)
106 Fixups
.push_back(MCFixup::create(0, Expr
, FK_SecRel_8
));
109 Fixups
.push_back(MCFixup::create(0, Expr
, FK_PCRel_2
));
114 static uint8_t SwapBits(uint8_t Val
)
116 return (Val
& 0x0F) << 4 | (Val
& 0xF0) >> 4;
119 void BPFMCCodeEmitter::encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
120 SmallVectorImpl
<MCFixup
> &Fixups
,
121 const MCSubtargetInfo
&STI
) const {
122 verifyInstructionPredicates(MI
,
123 computeAvailableFeatures(STI
.getFeatureBits()));
125 unsigned Opcode
= MI
.getOpcode();
126 support::endian::Writer
OSE(OS
,
127 IsLittleEndian
? support::little
: support::big
);
129 if (Opcode
== BPF::LD_imm64
|| Opcode
== BPF::LD_pseudo
) {
130 uint64_t Value
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
131 OS
<< char(Value
>> 56);
133 OS
<< char((Value
>> 48) & 0xff);
135 OS
<< char(SwapBits((Value
>> 48) & 0xff));
136 OSE
.write
<uint16_t>(0);
137 OSE
.write
<uint32_t>(Value
& 0xffffFFFF);
139 const MCOperand
&MO
= MI
.getOperand(1);
140 uint64_t Imm
= MO
.isImm() ? MO
.getImm() : 0;
141 OSE
.write
<uint8_t>(0);
142 OSE
.write
<uint8_t>(0);
143 OSE
.write
<uint16_t>(0);
144 OSE
.write
<uint32_t>(Imm
>> 32);
146 // Get instruction encoding and emit it
147 uint64_t Value
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
148 OS
<< char(Value
>> 56);
150 OS
<< char((Value
>> 48) & 0xff);
152 OS
<< char(SwapBits((Value
>> 48) & 0xff));
153 OSE
.write
<uint16_t>((Value
>> 32) & 0xffff);
154 OSE
.write
<uint32_t>(Value
& 0xffffFFFF);
158 // Encode BPF Memory Operand
159 uint64_t BPFMCCodeEmitter::getMemoryOpValue(const MCInst
&MI
, unsigned Op
,
160 SmallVectorImpl
<MCFixup
> &Fixups
,
161 const MCSubtargetInfo
&STI
) const {
162 // For CMPXCHG instructions, output is implicitly in R0/W0,
163 // so memory operand starts from operand 0.
164 int MemOpStartIndex
= 1, Opcode
= MI
.getOpcode();
165 if (Opcode
== BPF::CMPXCHGW32
|| Opcode
== BPF::CMPXCHGD
)
169 const MCOperand Op1
= MI
.getOperand(MemOpStartIndex
);
170 assert(Op1
.isReg() && "First operand is not register.");
171 Encoding
= MRI
.getEncodingValue(Op1
.getReg());
173 MCOperand Op2
= MI
.getOperand(MemOpStartIndex
+ 1);
174 assert(Op2
.isImm() && "Second operand is not immediate.");
175 Encoding
|= Op2
.getImm() & 0xffff;
179 #define ENABLE_INSTR_PREDICATE_VERIFIER
180 #include "BPFGenMCCodeEmitter.inc"