Commit 50a3331c by Karl Schimpf

Generate block labels in the ARM hybrid assembler.

Fixes an issue where branches don't compile in the hybrid integrated assembler because some jump instructions have not yet been integrated. It does this by adding an instruction label for each corresponding label generated by the standalone ARM assembler. Note that in order to fix this, I had to change the signature of virtual method Assembler::bindCfgNodeLabel to get the Cfg node (rather than the index value). This allows the ARM hybrid assembler to generate a label for each CfgNode (using the getAsmName() method). BUG= https://code.google.com/p/nativeclient/issues/detail?id=4334 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1407273006 .
parent 2fee2a2f
...@@ -276,9 +276,8 @@ public: ...@@ -276,9 +276,8 @@ public:
/// Get the label for a CfgNode. /// Get the label for a CfgNode.
virtual Label *getCfgNodeLabel(SizeT NodeNumber) = 0; virtual Label *getCfgNodeLabel(SizeT NodeNumber) = 0;
/// Mark the current text location as the start of a CFG node (represented by /// Mark the current text location as the start of a CFG node.
/// NodeNumber). virtual void bindCfgNodeLabel(const CfgNode *Node) = 0;
virtual void bindCfgNodeLabel(SizeT NodeNumber) = 0;
virtual bool fixupIsPCRel(FixupKind Kind) const = 0; virtual bool fixupIsPCRel(FixupKind Kind) const = 0;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "IceAssemblerARM32.h" #include "IceAssemblerARM32.h"
#include "IceCfgNode.h"
#include "IceUtils.h" #include "IceUtils.h"
namespace { namespace {
...@@ -204,6 +205,18 @@ DecodedResult decodeAddress(const Operand *Opnd, uint32_t &Value) { ...@@ -204,6 +205,18 @@ DecodedResult decodeAddress(const Operand *Opnd, uint32_t &Value) {
namespace Ice { namespace Ice {
void ARM32::AssemblerARM32::bindCfgNodeLabel(const CfgNode *Node) {
if (BuildDefs::dump() && !Ctx->getFlags().getDisableHybridAssembly()) {
// Generate label name so that branches can find it.
constexpr SizeT InstSize = 0;
emitTextInst(Node->getAsmName() + ":", InstSize);
}
SizeT NodeNumber = Node->getIndex();
assert(!getPreliminary());
Label *L = getOrCreateCfgNodeLabel(NodeNumber);
this->bind(L);
}
Label *ARM32::AssemblerARM32::getOrCreateLabel(SizeT Number, Label *ARM32::AssemblerARM32::getOrCreateLabel(SizeT Number,
LabelVector &Labels) { LabelVector &Labels) {
Label *L = nullptr; Label *L = nullptr;
...@@ -236,12 +249,13 @@ void ARM32::AssemblerARM32::bind(Label *label) { ...@@ -236,12 +249,13 @@ void ARM32::AssemblerARM32::bind(Label *label) {
label->bindTo(bound); label->bindTo(bound);
} }
void ARM32::AssemblerARM32::emitTextInst(const std::string &Text) { void ARM32::AssemblerARM32::emitTextInst(const std::string &Text,
static constexpr uint32_t Placeholder = 0; SizeT InstSize) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
AssemblerFixup *F = createTextFixup(Text, sizeof(Placeholder)); AssemblerFixup *F = createTextFixup(Text, InstSize);
emitFixup(F); emitFixup(F);
emitInst(Placeholder); for (SizeT I = 0; I < InstSize; ++I)
Buffer.emit<char>(0);
} }
void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type, void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type,
......
...@@ -39,6 +39,7 @@ namespace Ice { ...@@ -39,6 +39,7 @@ namespace Ice {
namespace ARM32 { namespace ARM32 {
class AssemblerARM32 : public Assembler { class AssemblerARM32 : public Assembler {
AssemblerARM32() = delete;
AssemblerARM32(const AssemblerARM32 &) = delete; AssemblerARM32(const AssemblerARM32 &) = delete;
AssemblerARM32 &operator=(const AssemblerARM32 &) = delete; AssemblerARM32 &operator=(const AssemblerARM32 &) = delete;
...@@ -48,7 +49,16 @@ public: ...@@ -48,7 +49,16 @@ public:
// TODO(kschimpf): Add mode if needed when branches are handled. // TODO(kschimpf): Add mode if needed when branches are handled.
(void)use_far_branches; (void)use_far_branches;
} }
~AssemblerARM32() override = default; ~AssemblerARM32() override {
if (BuildDefs::asserts()) {
for (const Label *Label : CfgNodeLabels) {
Label->finalCheck();
}
for (const Label *Label : LocalLabels) {
Label->finalCheck();
}
}
}
void alignFunction() override { void alignFunction() override {
const SizeT Align = 1 << getBundleAlignLog2Bytes(); const SizeT Align = 1 << getBundleAlignLog2Bytes();
...@@ -84,10 +94,12 @@ public: ...@@ -84,10 +94,12 @@ public:
return CfgNodeLabels[NodeNumber]; return CfgNodeLabels[NodeNumber];
} }
void bindCfgNodeLabel(SizeT NodeNumber) override { void bindCfgNodeLabel(const CfgNode *Node) override;
assert(!getPreliminary());
Label *L = getOrCreateCfgNodeLabel(NodeNumber); void bindLocalLabel(SizeT Number) {
this->bind(L); Label *L = getOrCreateLocalLabel(Number);
if (!getPreliminary())
this->bind(L);
} }
bool fixupIsPCRel(FixupKind Kind) const override { bool fixupIsPCRel(FixupKind Kind) const override {
...@@ -120,17 +132,22 @@ public: ...@@ -120,17 +132,22 @@ public:
return Asm->getKind() == Asm_ARM32; return Asm->getKind() == Asm_ARM32;
} }
void emitTextInst(const std::string &Text); void emitTextInst(const std::string &Text, SizeT InstSize = sizeof(uint32_t));
private: private:
// A vector of pool-allocated x86 labels for CFG nodes. // A vector of pool-allocated x86 labels for CFG nodes.
using LabelVector = std::vector<Label *>; using LabelVector = std::vector<Label *>;
LabelVector CfgNodeLabels; LabelVector CfgNodeLabels;
// A vector of pool-allocated x86 labels for Local labels.
LabelVector LocalLabels;
Label *getOrCreateLabel(SizeT Number, LabelVector &Labels); Label *getOrCreateLabel(SizeT Number, LabelVector &Labels);
Label *getOrCreateCfgNodeLabel(SizeT NodeNumber) { Label *getOrCreateCfgNodeLabel(SizeT NodeNumber) {
return getOrCreateLabel(NodeNumber, CfgNodeLabels); return getOrCreateLabel(NodeNumber, CfgNodeLabels);
} }
Label *getOrCreateLocalLabel(SizeT Number) {
return getOrCreateLabel(Number, LocalLabels);
}
void emitInst(uint32_t Value) { Buffer.emit<uint32_t>(Value); } void emitInst(uint32_t Value) { Buffer.emit<uint32_t>(Value); }
......
...@@ -67,8 +67,7 @@ public: ...@@ -67,8 +67,7 @@ public:
llvm_unreachable("Not yet implemented."); llvm_unreachable("Not yet implemented.");
} }
void bindCfgNodeLabel(SizeT NodeNumber) override { void bindCfgNodeLabel(const CfgNode *) override {
(void)NodeNumber;
llvm::report_fatal_error("Not yet implemented."); llvm::report_fatal_error("Not yet implemented.");
} }
......
...@@ -152,7 +152,7 @@ public: ...@@ -152,7 +152,7 @@ public:
} }
Ice::Label *getCfgNodeLabel(SizeT NodeNumber) override; Ice::Label *getCfgNodeLabel(SizeT NodeNumber) override;
void bindCfgNodeLabel(SizeT NodeNumber) override; void bindCfgNodeLabel(const CfgNode *Node) override;
Label *getOrCreateCfgNodeLabel(SizeT Number); Label *getOrCreateCfgNodeLabel(SizeT Number);
Label *getOrCreateLocalLabel(SizeT Number); Label *getOrCreateLocalLabel(SizeT Number);
void bindLocalLabel(SizeT Number); void bindLocalLabel(SizeT Number);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "IceAssemblerX86Base.h" #include "IceAssemblerX86Base.h"
#include "IceCfg.h" #include "IceCfg.h"
#include "IceCfgNode.h"
#include "IceOperand.h" #include "IceOperand.h"
namespace Ice { namespace Ice {
...@@ -86,9 +87,9 @@ Label *AssemblerX86Base<Machine>::getOrCreateLocalLabel(SizeT Number) { ...@@ -86,9 +87,9 @@ Label *AssemblerX86Base<Machine>::getOrCreateLocalLabel(SizeT Number) {
} }
template <class Machine> template <class Machine>
void AssemblerX86Base<Machine>::bindCfgNodeLabel(SizeT NodeNumber) { void AssemblerX86Base<Machine>::bindCfgNodeLabel(const CfgNode *Node) {
assert(!getPreliminary()); assert(!getPreliminary());
Label *L = getOrCreateCfgNodeLabel(NodeNumber); Label *L = getOrCreateCfgNodeLabel(Node->getIndex());
this->bind(L); this->bind(L);
} }
......
...@@ -1184,7 +1184,7 @@ void CfgNode::emitIAS(Cfg *Func) const { ...@@ -1184,7 +1184,7 @@ void CfgNode::emitIAS(Cfg *Func) const {
// TODO(stichnot): When sandboxing, defer binding the node label until just // TODO(stichnot): When sandboxing, defer binding the node label until just
// before the first instruction is emitted, to reduce the chance that a // before the first instruction is emitted, to reduce the chance that a
// padding nop is a branch target. // padding nop is a branch target.
Asm->bindCfgNodeLabel(getIndex()); Asm->bindCfgNodeLabel(this);
for (const Inst &I : Phis) { for (const Inst &I : Phis) {
if (I.isDeleted()) if (I.isDeleted())
continue; continue;
......
...@@ -801,6 +801,13 @@ void InstARM32Label::emit(const Cfg *Func) const { ...@@ -801,6 +801,13 @@ void InstARM32Label::emit(const Cfg *Func) const {
Str << getName(Func) << ":"; Str << getName(Func) << ":";
} }
void InstARM32Label::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->bindLocalLabel(Number);
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
void InstARM32Label::dump(const Cfg *Func) const { void InstARM32Label::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
......
...@@ -792,6 +792,7 @@ public: ...@@ -792,6 +792,7 @@ public:
IceString getName(const Cfg *Func) const; IceString getName(const Cfg *Func) const;
SizeT getNumber() const { return Number; } SizeT getNumber() const { return Number; }
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;
private: private:
......
...@@ -26,15 +26,16 @@ define internal i32 @add1ToR0(i32 %p) { ...@@ -26,15 +26,16 @@ define internal i32 @add1ToR0(i32 %p) {
} }
; ASM-LABEL: add1ToR0: ; ASM-LABEL: add1ToR0:
; ASM: add r0, r0, #1 ; ASM-NEXT: .Ladd1ToR0$__0:
; ASM-NEXT: bx lr ; ASM-NEXT: add r0, r0, #1
; ASM-NEXT: bx lr
; DIS-LABEL:00000000 <add1ToR0>: ; DIS-LABEL:00000000 <add1ToR0>:
; DIS-NEXT: 0: e2800001 ; DIS-NEXT: 0: e2800001
; DIS-NEXT: 4: e12fff1e ; DIS-NEXT: 4: e12fff1e
; IASM-LABEL: add1ToR0: ; IASM-LABEL: add1ToR0:
; IASM-LABEL: .Ladd1ToR0$__0:
; IASM-NEXT: .byte 0x1 ; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x80 ; IASM-NEXT: .byte 0x80
...@@ -51,15 +52,16 @@ define internal i32 @Add2Regs(i32 %p1, i32 %p2) { ...@@ -51,15 +52,16 @@ define internal i32 @Add2Regs(i32 %p1, i32 %p2) {
} }
; ASM-LABEL: Add2Regs: ; ASM-LABEL: Add2Regs:
; ASM: add r0, r0, r1 ; ASM-NEXT: .LAdd2Regs$__0:
; ASM-NEXT: bx lr ; ASM-NEXT: add r0, r0, r1
; ASM-NEXT: bx lr
; DIS-LABEL:00000010 <Add2Regs>: ; DIS-LABEL:00000010 <Add2Regs>:
; DIS-NEXT: 10: e0800001 ; DIS-NEXT: 10: e0800001
; DIS-NEXT: 14: e12fff1e ; DIS-NEXT: 14: e12fff1e
; IASM-LABEL: Add2Regs: ; IASM-LABEL: Add2Regs:
; IASM-NEXT: .LAdd2Regs$__0:
; IASM-NEXT: .byte 0x1 ; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x80 ; IASM-NEXT: .byte 0x80
......
; Test branching instructions.
; TODO(kschimpf): Get this working.
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
; RUN: | FileCheck %s --check-prefix=ASM
; Show bytes in assembled standalone code.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -Om1 | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
; RUN: | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -Om1 | FileCheck %s --check-prefix=DIS
; REQUIRES: allow_dump
define internal void @simple_uncond_branch() {
; DIS-LABEL: 00000000 <simple_uncond_branch>:
; ASM-LABEL: simple_uncond_branch:
; IASM-LABEL:simple_uncond_branch:
; ASM-NEXT: .Lsimple_uncond_branch$__0:
; IASM-NEXT: .Lsimple_uncond_branch$__0:
br label %l2
; ASM-NEXT: b .Lsimple_uncond_branch$l2
; IASM-NEXT: b .Lsimple_uncond_branch$l2
; DIS-NEXT: 0: ea000000
l1:
; ASM-NEXT: .Lsimple_uncond_branch$l1:
; IASM-NEXT: .Lsimple_uncond_branch$l1:
br label %l3
; ASM-NEXT: b .Lsimple_uncond_branch$l3
; IASM-NEXT: b .Lsimple_uncond_branch$l3
; DIS-NEXT: 4: ea000000
l2:
; ASM-NEXT: .Lsimple_uncond_branch$l2:
; IASM-NEXT: .Lsimple_uncond_branch$l2:
br label %l1
; ASM-NEXT: b .Lsimple_uncond_branch$l1
; IASM-NEXT: b .Lsimple_uncond_branch$l1
; DIS-NEXT: 8: eafffffd
l3:
; ASM-NEXT: .Lsimple_uncond_branch$l3:
; IASM-NEXT: .Lsimple_uncond_branch$l3:
ret void
; ASM-NEXT: bx lr
; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
}
...@@ -52,6 +52,7 @@ define internal i32 @load() { ...@@ -52,6 +52,7 @@ define internal i32 @load() {
; DIS-NEXT: c: e12fff1e ; DIS-NEXT: c: e12fff1e
; IASM-LABEL:load: ; IASM-LABEL:load:
; IASM-NEXT: .Lload$__0:
; IASM-NEXT: movw r0, #:lower16:global1 ; IASM-NEXT: movw r0, #:lower16:global1
; IASM-NEXT: movt r0, #:upper16:global1 ; IASM-NEXT: movt r0, #:upper16:global1
; IASM-NEXT: ldr r0, [r0] ; IASM-NEXT: ldr r0, [r0]
...@@ -80,6 +81,7 @@ define internal void @store(i32 %v) { ...@@ -80,6 +81,7 @@ define internal void @store(i32 %v) {
; DIS-NEXT: 1c: e12fff1e ; DIS-NEXT: 1c: e12fff1e
; IASM-LABEL:store: ; IASM-LABEL:store:
; IASM-NEXT: .Lstore$__0:
; IASM-NEXT: movw r1, #:lower16:global1 ; IASM-NEXT: movw r1, #:lower16:global1
; IASM-NEXT: movt r1, #:upper16:global1 ; IASM-NEXT: movt r1, #:upper16:global1
; IASM-NEXT: str r0, [r1] ; IASM-NEXT: str r0, [r1]
......
...@@ -27,10 +27,9 @@ define internal void @f() { ...@@ -27,10 +27,9 @@ define internal void @f() {
; ASM-NEXT: .Lf$__0: ; ASM-NEXT: .Lf$__0:
; ASM-NEXT: bx lr ; ASM-NEXT: bx lr
; DIS-LABEL:00000000 <f>: ; DIS-LABEL:00000000 <f>:
; IASM-LABEL:f: ; IASM-LABEL:f:
; IASM-NEXT:.Lf$__0:
; DIS-NEXT: 0: e12fff1e ; DIS-NEXT: 0: e12fff1e
; IASM-NEXT: .byte 0x1e ; IASM-NEXT: .byte 0x1e
......
...@@ -50,7 +50,7 @@ define internal i32 @Sub2Regs(i32 %p1, i32 %p2) { ...@@ -50,7 +50,7 @@ define internal i32 @Sub2Regs(i32 %p1, i32 %p2) {
; DIS-NEXT: 10: e0400001 ; DIS-NEXT: 10: e0400001
; IASM-LABEL: Sub2Regs: ; IASM-LABEL: Sub2Regs:
; IASM-NEXT: .byte 0x1 ; IASM: .byte 0x1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x40 ; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0xe0 ; IASM-NEXT: .byte 0xe0
......
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