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) {
#if 0
// Moved to: ARM32::AssemblerARM32::bkpt()
// Moved to ARM32::AssemblerARM32::bkpt()
void Assembler::bkpt(uint16_t imm16) {
Emit(BkptEncoding(imm16));
}
......@@ -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) {
EmitBranch(cond, label, true);
}
#if 0
// Moved to: ARM32::AssemblerARM32::bx()
// Moved to ARM32::AssemblerARM32::bx()
void Assembler::bx(Register rm, Condition cond) {
ASSERT(rm != kNoRegister);
ASSERT(cond != kNoCondition);
......@@ -1493,9 +1494,8 @@ void Assembler::bx(Register rm, Condition cond) {
(static_cast<int32_t>(rm) << kRmShift);
Emit(encoding);
}
#endif
// Moved to ARM32::AssemblerARM32::blx()
void Assembler::blx(Register rm, Condition cond) {
ASSERT(rm != kNoRegister);
ASSERT(cond != kNoCondition);
......@@ -1504,6 +1504,7 @@ void Assembler::blx(Register rm, Condition cond) {
(static_cast<int32_t>(rm) << kRmShift);
Emit(encoding);
}
#endif
void Assembler::MarkExceptionHandler(Label* label) {
......@@ -2356,7 +2357,7 @@ void Assembler::BindARMv6(Label* label) {
}
#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
// already been handler
void Assembler::BindARMv7(Label* label) {
......
......@@ -28,7 +28,7 @@ class RuntimeEntry;
class StubEntry;
#if 0
// Moved to: ARM32::AssemblerARM32 as needed
// Moved to ARM32::AssemblerARM32 as needed
// Instruction encoding bits.
enum {
H = 1 << 5, // halfword (or byte)
......@@ -596,7 +596,7 @@ class Assembler : public ValueObject {
void nop(Condition cond = AL);
#if 0
// Moved to: ARM32::AssemblerARM32::bkpt()
// Moved to ARM32::AssemblerARM32::bkpt()
// Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
void bkpt(uint16_t imm16);
......@@ -724,13 +724,16 @@ class Assembler : public ValueObject {
void vzipqw(QRegister qd, QRegister qm);
// Branch instructions.
#if 0
// Moved to ARM32::AssemblerARM32::b();
void b(Label* label, Condition cond = AL);
// Moved to ARM32::AssemblerARM32::bl()
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);
#endif
// Moved to ARM32::AssemblerARM32::blx()
void blx(Register rm, Condition cond = AL);
#endif
void Branch(const StubEntry& stub_entry,
Patchability patchable = kNotPatchable,
......@@ -1264,8 +1267,9 @@ class Assembler : public ValueObject {
DRegister dd, DRegister dn, DRegister dm);
void EmitFarBranch(Condition cond, int32_t offset, bool link);
void EmitBranch(Condition cond, Label* label, bool link);
#if 0
// Moved to ARM32::AssemblerARM32::emitBranch()
void EmitBranch(Condition cond, Label* label, bool link);
// Moved to ARM32::AssemblerARM32::encodeBranchoffset().
int32_t EncodeBranchOffset(int32_t offset, int32_t inst);
// Moved to ARM32::AssemberARM32::decodeBranchOffset().
......
......@@ -327,6 +327,27 @@ MoveRelocatableFixup *AssemblerARM32::createMoveFixup(bool IsMovW,
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) {
GlobalContext *Ctx = Node->getCfg()->getContext();
if (BuildDefs::dump() && !Ctx->getFlags().getDisableHybridAssembly()) {
......@@ -686,6 +707,38 @@ void AssemblerARM32::bic(const Operand *OpRd, const Operand *OpRn,
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) {
// BX - ARM section A8.8.27, encoding A1:
// bx<c> <Rm>
......
......@@ -45,13 +45,23 @@ using IValueT = uint32_t;
using IOffsetT = int32_t;
/// 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(const MoveRelocatableFixup &) = default;
public:
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 {
......@@ -103,6 +113,8 @@ public:
MoveRelocatableFixup *createMoveFixup(bool IsMovW, const Constant *Value);
BlRelocatableFixup *createBlFixup(const ConstantRelocatable *Target);
void alignFunction() override {
const SizeT Align = 1 << getBundleAlignLog2Bytes();
SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align);
......@@ -186,15 +198,19 @@ public:
void b(Label *L, CondARM32::Cond Cond);
void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL);
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,
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,
bool SetFlags, CondARM32::Cond Cond);
......
......@@ -1005,6 +1005,26 @@ void InstARM32Call::emit(const Cfg *Func) const {
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 {
if (!BuildDefs::dump())
return;
......
......@@ -1023,6 +1023,7 @@ public:
}
Operand *getCallTarget() const { return getSrc(0); }
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
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() {
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2
; IASM-NEXT: bl DoSomething
; IASM-NEXT: bl DoSomething @ .word ebfffffe
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x8d
......@@ -134,7 +134,7 @@ define internal i32 @MultPushPop(i32 %v1, i32 %v2) {
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1
; IASM-NEXT: bl DoSomething
; IASM-NEXT: bl DoSomething @ .word ebfffffe
; IASM-NEXT: .byte 0x5
; IASM-NEXT: .byte 0x40
; 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