Commit 856734ca by Karl Schimpf

Fix ARM emit() methods to count instructions generated.

Previously, the code assumed that the emit() method of all ARM instructions emitted a single instruction. This is false. Instructions like PUSH and POP may generate multiple instructions. This is only a problem when the hybrid ARM assembler reverts back to using the stand-alone assembler to generate instructions the integrated assembler can't handle. The fix is to add infrastructure to allow ARM instructions to communicate to the assembler, the number of instructions they generate, so that the correct-sized filler is added to the assembly buffer. This fixes all cross-test failures for (pc-relative) branches, except one. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1426513004 .
parent 94844f12
...@@ -270,9 +270,8 @@ namespace ARM32 { ...@@ -270,9 +270,8 @@ namespace ARM32 {
size_t MoveRelocatableFixup::emit(GlobalContext *Ctx, size_t MoveRelocatableFixup::emit(GlobalContext *Ctx,
const Assembler &Asm) const { const Assembler &Asm) const {
static constexpr const size_t FixupSize = sizeof(IValueT);
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return FixupSize; return InstARM32::InstSize;
Ostream &Str = Ctx->getStrEmit(); Ostream &Str = Ctx->getStrEmit();
IValueT Inst = Asm.load<IValueT>(position()); IValueT Inst = Asm.load<IValueT>(position());
Str << "\tmov" << (kind() == llvm::ELF::R_ARM_MOVW_ABS_NC ? "w" : "t") << "\t" Str << "\tmov" << (kind() == llvm::ELF::R_ARM_MOVW_ABS_NC ? "w" : "t") << "\t"
...@@ -280,7 +279,7 @@ size_t MoveRelocatableFixup::emit(GlobalContext *Ctx, ...@@ -280,7 +279,7 @@ size_t MoveRelocatableFixup::emit(GlobalContext *Ctx,
<< ", #:" << (kind() == llvm::ELF::R_ARM_MOVW_ABS_NC ? "lower" : "upper") << ", #:" << (kind() == llvm::ELF::R_ARM_MOVW_ABS_NC ? "lower" : "upper")
<< "16:" << symbol(Ctx) << "\t@ .word " << "16:" << symbol(Ctx) << "\t@ .word "
<< llvm::format_hex_no_prefix(Inst, 8) << "\n"; << llvm::format_hex_no_prefix(Inst, 8) << "\n";
return FixupSize; return InstARM32::InstSize;
} }
MoveRelocatableFixup *AssemblerARM32::createMoveFixup(bool IsMovW, MoveRelocatableFixup *AssemblerARM32::createMoveFixup(bool IsMovW,
...@@ -360,11 +359,12 @@ void AssemblerARM32::bind(Label *L) { ...@@ -360,11 +359,12 @@ void AssemblerARM32::bind(Label *L) {
} }
void AssemblerARM32::emitTextInst(const std::string &Text, SizeT InstSize) { void AssemblerARM32::emitTextInst(const std::string &Text, SizeT InstSize) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
AssemblerFixup *F = createTextFixup(Text, InstSize); AssemblerFixup *F = createTextFixup(Text, InstSize);
emitFixup(F); emitFixup(F);
for (SizeT I = 0; I < InstSize; ++I) for (SizeT I = 0; I < InstSize; ++I) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
Buffer.emit<char>(0); Buffer.emit<char>(0);
}
} }
void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Type, void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Type,
...@@ -393,10 +393,9 @@ void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd, ...@@ -393,10 +393,9 @@ void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd,
emitType01(Opcode, Rd, Rn, OpSrc1, SetFlags, Cond, RuleChecks); emitType01(Opcode, Rd, Rn, OpSrc1, SetFlags, Cond, RuleChecks);
} }
void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn,
IValueT Rn, const Operand *OpSrc1, const Operand *OpSrc1, bool SetFlags,
bool SetFlags, CondARM32::Cond Cond, CondARM32::Cond Cond, Type01Checks RuleChecks) {
Type01Checks RuleChecks) {
switch (RuleChecks) { switch (RuleChecks) {
case NoChecks: case NoChecks:
break; break;
......
...@@ -82,7 +82,7 @@ public: ...@@ -82,7 +82,7 @@ public:
SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align); SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align);
constexpr IValueT UndefinedInst = 0xe7fedef0; // udf #60896 constexpr IValueT UndefinedInst = 0xe7fedef0; // udf #60896
constexpr SizeT InstSize = sizeof(IValueT); constexpr SizeT InstSize = sizeof(IValueT);
assert(BytesNeeded % InstSize == 0); assert(BytesNeeded % InstARM32::InstSize == 0);
while (BytesNeeded > 0) { while (BytesNeeded > 0) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
emitInst(UndefinedInst); emitInst(UndefinedInst);
...@@ -137,6 +137,14 @@ public: ...@@ -137,6 +137,14 @@ public:
return false; return false;
} }
/// Accessors to keep track of the number of bytes generated inside
/// InstARM32::emit() methods, when run inside of
/// InstARM32::emitUsingTextFixup().
void resetEmitTextSize() { EmitTextSize = 0; }
void incEmitTextSize(size_t Amount) { EmitTextSize += Amount; }
void decEmitTextSize(size_t Amount) { EmitTextSize -= Amount; }
size_t getEmitTextSize() const { return EmitTextSize; }
void bind(Label *label); void bind(Label *label);
// List of instructions implemented by integrated assembler. // List of instructions implemented by integrated assembler.
...@@ -198,7 +206,7 @@ public: ...@@ -198,7 +206,7 @@ public:
return Asm->getKind() == Asm_ARM32; return Asm->getKind() == Asm_ARM32;
} }
void emitTextInst(const std::string &Text, SizeT InstSize = sizeof(IValueT)); void emitTextInst(const std::string &Text, SizeT InstSize);
private: private:
// A vector of pool-allocated x86 labels for CFG nodes. // A vector of pool-allocated x86 labels for CFG nodes.
...@@ -206,6 +214,9 @@ private: ...@@ -206,6 +214,9 @@ private:
LabelVector CfgNodeLabels; LabelVector CfgNodeLabels;
// A vector of pool-allocated x86 labels for Local labels. // A vector of pool-allocated x86 labels for Local labels.
LabelVector LocalLabels; LabelVector LocalLabels;
// Number of bytes emitted by InstARM32::emit() methods, when run inside
// InstARM32::emitUsingTextFixup().
size_t EmitTextSize = 0;
Label *getOrCreateLabel(SizeT Number, LabelVector &Labels); Label *getOrCreateLabel(SizeT Number, LabelVector &Labels);
......
...@@ -84,6 +84,11 @@ CondARM32::Cond InstARM32::getOppositeCondition(CondARM32::Cond Cond) { ...@@ -84,6 +84,11 @@ CondARM32::Cond InstARM32::getOppositeCondition(CondARM32::Cond Cond) {
return InstARM32CondAttributes[Cond].Opposite; return InstARM32CondAttributes[Cond].Opposite;
} }
void InstARM32::startNextInst(const Cfg *Func) const {
if (auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>())
Asm->incEmitTextSize(InstSize);
}
void InstARM32::emitUsingTextFixup(const Cfg *Func) const { void InstARM32::emitUsingTextFixup(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -98,9 +103,13 @@ void InstARM32::emitUsingTextFixup(const Cfg *Func) const { ...@@ -98,9 +103,13 @@ void InstARM32::emitUsingTextFixup(const Cfg *Func) const {
OstreamLocker L(Ctx); OstreamLocker L(Ctx);
Ostream &OldStr = Ctx->getStrEmit(); Ostream &OldStr = Ctx->getStrEmit();
Ctx->setStrEmit(StrBuf); Ctx->setStrEmit(StrBuf);
// Start counting instructions here, so that emit() methods don't
// need to call this for the first instruction.
Asm->resetEmitTextSize();
Asm->incEmitTextSize(InstSize);
emit(Func); emit(Func);
Ctx->setStrEmit(OldStr); Ctx->setStrEmit(OldStr);
Asm->emitTextInst(StrBuf.str()); Asm->emitTextInst(StrBuf.str(), Asm->getEmitTextSize());
} }
void InstARM32::emitIAS(const Cfg *Func) const { emitUsingTextFixup(Func); } void InstARM32::emitIAS(const Cfg *Func) const { emitUsingTextFixup(Func); }
...@@ -810,6 +819,7 @@ void InstARM32Br::emit(const Cfg *Func) const { ...@@ -810,6 +819,7 @@ void InstARM32Br::emit(const Cfg *Func) const {
} else { } else {
Str << getTargetTrue()->getAsmName(); Str << getTargetTrue()->getAsmName();
if (getTargetFalse()) { if (getTargetFalse()) {
startNextInst(Func);
Str << "\n\t" Str << "\n\t"
<< "b" << "b"
<< "\t" << getTargetFalse()->getAsmName(); << "\t" << getTargetFalse()->getAsmName();
...@@ -1069,6 +1079,7 @@ void InstARM32Pop::emit(const Cfg *Func) const { ...@@ -1069,6 +1079,7 @@ void InstARM32Pop::emit(const Cfg *Func) const {
for (const Operand *Op : Dests) { for (const Operand *Op : Dests) {
if (isScalarIntegerType(Op->getType())) if (isScalarIntegerType(Op->getType()))
continue; continue;
startNextInst(Func);
Str << "\t" Str << "\t"
<< "vpop" << "vpop"
<< "\t{"; << "\t{";
...@@ -1139,6 +1150,7 @@ void InstARM32Push::emit(const Cfg *Func) const { ...@@ -1139,6 +1150,7 @@ void InstARM32Push::emit(const Cfg *Func) const {
Str << "}\n"; Str << "}\n";
} }
if (IntegerCount != 0) { if (IntegerCount != 0) {
startNextInst(Func);
Str << "\t" Str << "\t"
<< "push" << "push"
<< "\t{"; << "\t{";
......
...@@ -334,10 +334,18 @@ public: ...@@ -334,10 +334,18 @@ public:
Vsub Vsub
}; };
static constexpr size_t InstSize = sizeof(uint32_t);
static const char *getWidthString(Type Ty); static const char *getWidthString(Type Ty);
static const char *getVecWidthString(Type Ty); static const char *getVecWidthString(Type Ty);
static CondARM32::Cond getOppositeCondition(CondARM32::Cond Cond); static CondARM32::Cond getOppositeCondition(CondARM32::Cond Cond);
/// Called inside derived methods emit() to communicate that multiple
/// instructions are being generated. Used by emitIAS() methods to
/// generate textual fixups for instructions that are not yet
/// implemented.
void startNextInst(const Cfg *Func) const;
/// Shared emit routines for common forms of instructions. /// Shared emit routines for common forms of instructions.
static void emitThreeAddrFP(const char *Opcode, const InstARM32 *Inst, static void emitThreeAddrFP(const char *Opcode, const InstARM32 *Inst,
const Cfg *Func); const Cfg *Func);
......
...@@ -331,7 +331,8 @@ protected: ...@@ -331,7 +331,8 @@ protected:
// _mov_i1_to_flags is used for bool folding. If "Boolean" is folded, this // _mov_i1_to_flags is used for bool folding. If "Boolean" is folded, this
// method returns true, and sets "CondIfTrue0" and "CondIfTrue1" to the // method returns true, and sets "CondIfTrue0" and "CondIfTrue1" to the
// appropriate ARM condition codes. If "Boolean" is not to be folded, then this // appropriate ARM condition codes. If "Boolean" is not to be folded, then
// this
// method returns false. // method returns false.
bool _mov_i1_to_flags(Operand *Boolean, CondARM32::Cond *CondIfTrue0, bool _mov_i1_to_flags(Operand *Boolean, CondARM32::Cond *CondIfTrue0,
CondARM32::Cond *CondIfTrue1, CondARM32::Cond *CondIfTrue1,
......
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