Commit 174531ec by Karl Schimpf

Add BL (immediate) and BLX (register) to ARM assembler.

Adds BL and BLX to ARM integrated assembler. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334 R=jpp@chromium.org Review URL: https://codereview.chromium.org/1452293003 .
parent 9a10df70
...@@ -1467,7 +1467,7 @@ void Assembler::vcgtqs(QRegister qd, QRegister qn, QRegister qm) { ...@@ -1467,7 +1467,7 @@ void Assembler::vcgtqs(QRegister qd, QRegister qn, QRegister qm) {
#if 0 #if 0
// Moved to: ARM32::AssemblerARM32::bkpt() // Moved to ARM32::AssemblerARM32::bkpt()
void Assembler::bkpt(uint16_t imm16) { void Assembler::bkpt(uint16_t imm16) {
Emit(BkptEncoding(imm16)); Emit(BkptEncoding(imm16));
} }
...@@ -1479,12 +1479,13 @@ void Assembler::b(Label* label, Condition cond) { ...@@ -1479,12 +1479,13 @@ void Assembler::b(Label* label, Condition cond) {
} }
#if 0
// Moved to ARM32::AssemblerARM32::bl()
void Assembler::bl(Label* label, Condition cond) { void Assembler::bl(Label* label, Condition cond) {
EmitBranch(cond, label, true); EmitBranch(cond, label, true);
} }
#if 0 // Moved to ARM32::AssemblerARM32::bx()
// Moved to: ARM32::AssemblerARM32::bx()
void Assembler::bx(Register rm, Condition cond) { void Assembler::bx(Register rm, Condition cond) {
ASSERT(rm != kNoRegister); ASSERT(rm != kNoRegister);
ASSERT(cond != kNoCondition); ASSERT(cond != kNoCondition);
...@@ -1493,9 +1494,8 @@ void Assembler::bx(Register rm, Condition cond) { ...@@ -1493,9 +1494,8 @@ void Assembler::bx(Register rm, Condition cond) {
(static_cast<int32_t>(rm) << kRmShift); (static_cast<int32_t>(rm) << kRmShift);
Emit(encoding); Emit(encoding);
} }
#endif
// Moved to ARM32::AssemblerARM32::blx()
void Assembler::blx(Register rm, Condition cond) { void Assembler::blx(Register rm, Condition cond) {
ASSERT(rm != kNoRegister); ASSERT(rm != kNoRegister);
ASSERT(cond != kNoCondition); ASSERT(cond != kNoCondition);
...@@ -1504,6 +1504,7 @@ void Assembler::blx(Register rm, Condition cond) { ...@@ -1504,6 +1504,7 @@ void Assembler::blx(Register rm, Condition cond) {
(static_cast<int32_t>(rm) << kRmShift); (static_cast<int32_t>(rm) << kRmShift);
Emit(encoding); Emit(encoding);
} }
#endif
void Assembler::MarkExceptionHandler(Label* label) { void Assembler::MarkExceptionHandler(Label* label) {
...@@ -2356,7 +2357,7 @@ void Assembler::BindARMv6(Label* label) { ...@@ -2356,7 +2357,7 @@ void Assembler::BindARMv6(Label* label) {
} }
#if 0 #if 0
// Moved to: ARM32::AssemblerARM32::bind(Label* Label) // Moved to ARM32::AssemblerARM32::bind(Label* Label)
// Note: Most of this code isn't needed because instruction selection has // Note: Most of this code isn't needed because instruction selection has
// already been handler // already been handler
void Assembler::BindARMv7(Label* label) { void Assembler::BindARMv7(Label* label) {
......
...@@ -28,7 +28,7 @@ class RuntimeEntry; ...@@ -28,7 +28,7 @@ class RuntimeEntry;
class StubEntry; class StubEntry;
#if 0 #if 0
// Moved to: ARM32::AssemblerARM32 as needed // Moved to ARM32::AssemblerARM32 as needed
// Instruction encoding bits. // Instruction encoding bits.
enum { enum {
H = 1 << 5, // halfword (or byte) H = 1 << 5, // halfword (or byte)
...@@ -596,7 +596,7 @@ class Assembler : public ValueObject { ...@@ -596,7 +596,7 @@ class Assembler : public ValueObject {
void nop(Condition cond = AL); void nop(Condition cond = AL);
#if 0 #if 0
// Moved to: ARM32::AssemblerARM32::bkpt() // Moved to ARM32::AssemblerARM32::bkpt()
// Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0. // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
void bkpt(uint16_t imm16); void bkpt(uint16_t imm16);
...@@ -724,13 +724,16 @@ class Assembler : public ValueObject { ...@@ -724,13 +724,16 @@ class Assembler : public ValueObject {
void vzipqw(QRegister qd, QRegister qm); void vzipqw(QRegister qd, QRegister qm);
// Branch instructions. // Branch instructions.
#if 0
// Moved to ARM32::AssemblerARM32::b();
void b(Label* label, Condition cond = AL); void b(Label* label, Condition cond = AL);
// Moved to ARM32::AssemblerARM32::bl()
void bl(Label* label, Condition cond = AL); void bl(Label* label, Condition cond = AL);
#if 0 // Moved to ARM32::AssemblerARM32::bx()
// Moved to: ARM32::AssemblerARM32::bx()
void bx(Register rm, Condition cond = AL); void bx(Register rm, Condition cond = AL);
#endif // Moved to ARM32::AssemblerARM32::blx()
void blx(Register rm, Condition cond = AL); void blx(Register rm, Condition cond = AL);
#endif
void Branch(const StubEntry& stub_entry, void Branch(const StubEntry& stub_entry,
Patchability patchable = kNotPatchable, Patchability patchable = kNotPatchable,
...@@ -1264,8 +1267,9 @@ class Assembler : public ValueObject { ...@@ -1264,8 +1267,9 @@ class Assembler : public ValueObject {
DRegister dd, DRegister dn, DRegister dm); DRegister dd, DRegister dn, DRegister dm);
void EmitFarBranch(Condition cond, int32_t offset, bool link); void EmitFarBranch(Condition cond, int32_t offset, bool link);
void EmitBranch(Condition cond, Label* label, bool link);
#if 0 #if 0
// Moved to ARM32::AssemblerARM32::emitBranch()
void EmitBranch(Condition cond, Label* label, bool link);
// Moved to ARM32::AssemblerARM32::encodeBranchoffset(). // Moved to ARM32::AssemblerARM32::encodeBranchoffset().
int32_t EncodeBranchOffset(int32_t offset, int32_t inst); int32_t EncodeBranchOffset(int32_t offset, int32_t inst);
// Moved to ARM32::AssemberARM32::decodeBranchOffset(). // Moved to ARM32::AssemberARM32::decodeBranchOffset().
......
...@@ -327,6 +327,27 @@ MoveRelocatableFixup *AssemblerARM32::createMoveFixup(bool IsMovW, ...@@ -327,6 +327,27 @@ MoveRelocatableFixup *AssemblerARM32::createMoveFixup(bool IsMovW,
return F; return F;
} }
size_t BlRelocatableFixup::emit(GlobalContext *Ctx,
const Assembler &Asm) const {
if (!BuildDefs::dump())
return InstARM32::InstSize;
Ostream &Str = Ctx->getStrEmit();
IValueT Inst = Asm.load<IValueT>(position());
Str << "\tbl\t" << symbol(Ctx) << "\t@ .word "
<< llvm::format_hex_no_prefix(Inst, 8) << "\n";
return InstARM32::InstSize;
}
BlRelocatableFixup *
AssemblerARM32::createBlFixup(const ConstantRelocatable *Target) {
BlRelocatableFixup *F =
new (allocate<BlRelocatableFixup>()) BlRelocatableFixup();
F->set_kind(llvm::ELF::R_ARM_CALL);
F->set_value(Target);
Buffer.installFixup(F);
return F;
}
void AssemblerARM32::bindCfgNodeLabel(const CfgNode *Node) { void AssemblerARM32::bindCfgNodeLabel(const CfgNode *Node) {
GlobalContext *Ctx = Node->getCfg()->getContext(); GlobalContext *Ctx = Node->getCfg()->getContext();
if (BuildDefs::dump() && !Ctx->getFlags().getDisableHybridAssembly()) { if (BuildDefs::dump() && !Ctx->getFlags().getDisableHybridAssembly()) {
...@@ -686,6 +707,38 @@ void AssemblerARM32::bic(const Operand *OpRd, const Operand *OpRn, ...@@ -686,6 +707,38 @@ void AssemblerARM32::bic(const Operand *OpRd, const Operand *OpRn,
emitType01(Opcode, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Opcode, OpRd, OpRn, OpSrc1, SetFlags, Cond);
} }
void AssemblerARM32::bl(const ConstantRelocatable *Target) {
// BL (immediate) - ARM section A8.8.25, encoding A1:
// bl<c> <label>
//
// cccc1011iiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond (not currently allowed)
// and iiiiiiiiiiiiiiiiiiiiiiii is the (encoded) Target to branch to.
emitFixup(createBlFixup(Target));
constexpr CondARM32::Cond Cond = CondARM32::AL;
constexpr IValueT Immed = 0;
constexpr bool Link = true;
emitType05(Cond, Immed, Link);
}
void AssemblerARM32::blx(const Operand *Target) {
IValueT Rm;
if (decodeOperand(Target, Rm) != DecodedAsRegister)
return setNeedsTextFixup();
// BLX (register) - ARM section A8.8.26, encoding A1:
// blx<c> <Rm>
//
// cccc000100101111111111110011mmmm where cccc=Cond (not currently allowed)
// and mmmm=Rm.
if (Rm == RegARM32::Encoded_Reg_pc)
// Unpredictable.
return setNeedsTextFixup();
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
constexpr CondARM32::Cond Cond = CondARM32::AL;
int32_t Encoding = (static_cast<int32_t>(Cond) << kConditionShift) | B24 |
B21 | (0xfff << 8) | B5 | B4 | (Rm << kRmShift);
emitInst(Encoding);
}
void AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) { void AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) {
// BX - ARM section A8.8.27, encoding A1: // BX - ARM section A8.8.27, encoding A1:
// bx<c> <Rm> // bx<c> <Rm>
......
...@@ -45,13 +45,23 @@ using IValueT = uint32_t; ...@@ -45,13 +45,23 @@ using IValueT = uint32_t;
using IOffsetT = int32_t; using IOffsetT = int32_t;
/// Handles encoding of bottom/top 16 bits of an address using movw/movt. /// Handles encoding of bottom/top 16 bits of an address using movw/movt.
class MoveRelocatableFixup : public AssemblerFixup { class MoveRelocatableFixup final : public AssemblerFixup {
MoveRelocatableFixup &operator=(const MoveRelocatableFixup &) = delete; MoveRelocatableFixup &operator=(const MoveRelocatableFixup &) = delete;
MoveRelocatableFixup(const MoveRelocatableFixup &) = default; MoveRelocatableFixup(const MoveRelocatableFixup &) = default;
public: public:
MoveRelocatableFixup() = default; MoveRelocatableFixup() = default;
size_t emit(GlobalContext *Ctx, const Assembler &Asm) const override; size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final;
};
/// Handles encoding of branch and link to global location.
class BlRelocatableFixup final : public AssemblerFixup {
BlRelocatableFixup(const BlRelocatableFixup &) = delete;
BlRelocatableFixup &operator=(const BlRelocatableFixup &) = delete;
public:
BlRelocatableFixup() = default;
size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final;
}; };
class AssemblerARM32 : public Assembler { class AssemblerARM32 : public Assembler {
...@@ -103,6 +113,8 @@ public: ...@@ -103,6 +113,8 @@ public:
MoveRelocatableFixup *createMoveFixup(bool IsMovW, const Constant *Value); MoveRelocatableFixup *createMoveFixup(bool IsMovW, const Constant *Value);
BlRelocatableFixup *createBlFixup(const ConstantRelocatable *Target);
void alignFunction() override { void alignFunction() override {
const SizeT Align = 1 << getBundleAlignLog2Bytes(); const SizeT Align = 1 << getBundleAlignLog2Bytes();
SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align); SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align);
...@@ -186,15 +198,19 @@ public: ...@@ -186,15 +198,19 @@ public:
void b(Label *L, CondARM32::Cond Cond); void b(Label *L, CondARM32::Cond Cond);
void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL);
void bkpt(uint16_t Imm16); void bkpt(uint16_t Imm16);
void cmp(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond);
void bic(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, void bic(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond); bool SetFlags, CondARM32::Cond Cond);
void bl(const ConstantRelocatable *Target);
void blx(const Operand *Target);
void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL);
void cmp(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond);
void eor(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, void eor(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond); bool SetFlags, CondARM32::Cond Cond);
......
...@@ -1005,6 +1005,26 @@ void InstARM32Call::emit(const Cfg *Func) const { ...@@ -1005,6 +1005,26 @@ void InstARM32Call::emit(const Cfg *Func) const {
Func->getTarget()->resetStackAdjustment(); Func->getTarget()->resetStackAdjustment();
} }
void InstARM32Call::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1);
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
if (llvm::isa<ConstantInteger32>(getCallTarget())) {
// This shouldn't happen (typically have to copy the full 32-bits to a
// register and do an indirect jump).
llvm::report_fatal_error("ARM32Call to ConstantInteger32");
} else if (const auto *CallTarget =
llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) {
// Calls only have 24-bits, but the linker should insert veneers to extend
// the range if needed.
Asm->bl(CallTarget);
} else {
Asm->blx(getCallTarget());
}
if (Asm->needsTextFixup())
return emitUsingTextFixup(Func);
Func->getTarget()->resetStackAdjustment();
}
void InstARM32Call::dump(const Cfg *Func) const { void InstARM32Call::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
......
...@@ -1023,6 +1023,7 @@ public: ...@@ -1023,6 +1023,7 @@ public:
} }
Operand *getCallTarget() const { return getSrc(0); } Operand *getCallTarget() const { return getSrc(0); }
void emit(const Cfg *Func) const override; void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override; void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, Call); } static bool classof(const Inst *Inst) { return isClassof(Inst, Call); }
......
; Show that we know how to translate add.
; NOTE: We use -O2 to get rid of memory stores.
; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=ASM
; Show bytes in assembled standalone code.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
define internal void @callIndirect(i32 %addr) {
; ASM-LABEL:callIndirect:
; DIS-LABEL:00000000 <callIndirect>:
; IASM-LABEL:callIndirect:
entry:
; ASM-NEXT:.LcallIndirect$entry:
; IASM-NEXT:.LcallIndirect$entry:
; ASM-NEXT: push {lr}
; DIS-NEXT: 0: e52de004
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x2d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: sub sp, sp, #12
; DIS-NEXT: 4: e24dd00c
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2
%calladdr = inttoptr i32 %addr to void (i32)*
; ASM-NEXT: mov r1, r0
; DIS-NEXT: 8: e1a01000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1
call void %calladdr(i32 %addr)
; ASM-NEXT: blx r1
; DIS-NEXT: c: e12fff31
; IASM-NEXT: .byte 0x31
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
ret void
}
...@@ -57,7 +57,7 @@ define internal void @SinglePushPop() { ...@@ -57,7 +57,7 @@ define internal void @SinglePushPop() {
; IASM-NEXT: .byte 0xd0 ; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d ; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
; IASM-NEXT: bl DoSomething ; IASM-NEXT: bl DoSomething @ .word ebfffffe
; IASM-NEXT: .byte 0xc ; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0xd0 ; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x8d ; IASM-NEXT: .byte 0x8d
...@@ -134,7 +134,7 @@ define internal i32 @MultPushPop(i32 %v1, i32 %v2) { ...@@ -134,7 +134,7 @@ define internal i32 @MultPushPop(i32 %v1, i32 %v2) {
; IASM-NEXT: .byte 0xa0 ; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1 ; IASM-NEXT: .byte 0xe1
; IASM-NEXT: bl DoSomething ; IASM-NEXT: bl DoSomething @ .word ebfffffe
; IASM-NEXT: .byte 0x5 ; IASM-NEXT: .byte 0x5
; IASM-NEXT: .byte 0x40 ; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0x84 ; IASM-NEXT: .byte 0x84
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment