Commit 2fee2a2f by Karl Schimpf

Add hybrid assembler concept to ARM assembler.

Adds a notion of a hybrid assembler. That is, if the integrated assembler can lower an instruction to bytes, it does. Otherwise, it uses the standalone assembler to generate text as the placeholder for the instruction. This is done using a textual fixup in the assembly buffer. The advantage of the hybrid assembler is that one can incrementally implement the integrated assembler and still test the generated assembly. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4334 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1418523002 .
parent ac8da5cf
...@@ -35,15 +35,28 @@ static uintptr_t NewContents(Assembler &Assemblr, intptr_t Capacity) { ...@@ -35,15 +35,28 @@ static uintptr_t NewContents(Assembler &Assemblr, intptr_t Capacity) {
return Result; return Result;
} }
void AssemblerBuffer::installFixup(AssemblerFixup *F) {
F->set_position(0);
if (!Assemblr.getPreliminary())
Fixups.push_back(F);
}
AssemblerFixup *AssemblerBuffer::createFixup(FixupKind Kind, AssemblerFixup *AssemblerBuffer::createFixup(FixupKind Kind,
const Constant *Value) { const Constant *Value) {
AssemblerFixup *F = AssemblerFixup *F =
new (Assemblr.allocate<AssemblerFixup>()) AssemblerFixup(); new (Assemblr.allocate<AssemblerFixup>()) AssemblerFixup();
F->set_position(0);
F->set_kind(Kind); F->set_kind(Kind);
F->set_value(Value); F->set_value(Value);
if (!Assemblr.getPreliminary()) installFixup(F);
Fixups.push_back(F); return F;
}
AssemblerTextFixup *AssemblerBuffer::createTextFixup(const std::string &Text,
size_t BytesUsed) {
AssemblerTextFixup *F = new (Assemblr.allocate<AssemblerTextFixup>())
AssemblerTextFixup(Text, BytesUsed);
installFixup(F);
TextFixupNeeded = false;
return F; return F;
} }
...@@ -72,12 +85,13 @@ AssemblerBuffer::EnsureCapacity::~EnsureCapacity() { ...@@ -72,12 +85,13 @@ AssemblerBuffer::EnsureCapacity::~EnsureCapacity() {
} }
AssemblerBuffer::AssemblerBuffer(Assembler &Asm) : Assemblr(Asm) { AssemblerBuffer::AssemblerBuffer(Assembler &Asm) : Assemblr(Asm) {
const intptr_t OneKB = 1024; constexpr intptr_t OneKB = 1024;
static const intptr_t kInitialBufferCapacity = 4 * OneKB; static constexpr intptr_t kInitialBufferCapacity = 4 * OneKB;
Contents = NewContents(Assemblr, kInitialBufferCapacity); Contents = NewContents(Assemblr, kInitialBufferCapacity);
Cursor = Contents; Cursor = Contents;
Limit = computeLimit(Contents, kInitialBufferCapacity); Limit = computeLimit(Contents, kInitialBufferCapacity);
HasEnsuredCapacity = false; HasEnsuredCapacity = false;
TextFixupNeeded = false;
// Verify internal state. // Verify internal state.
assert(capacity() == kInitialBufferCapacity); assert(capacity() == kInitialBufferCapacity);
...@@ -89,7 +103,7 @@ AssemblerBuffer::~AssemblerBuffer() = default; ...@@ -89,7 +103,7 @@ AssemblerBuffer::~AssemblerBuffer() = default;
void AssemblerBuffer::extendCapacity() { void AssemblerBuffer::extendCapacity() {
intptr_t old_size = size(); intptr_t old_size = size();
intptr_t old_capacity = capacity(); intptr_t old_capacity = capacity();
const intptr_t OneMB = 1 << 20; constexpr intptr_t OneMB = 1 << 20;
intptr_t new_capacity = std::min(old_capacity * 2, old_capacity + OneMB); intptr_t new_capacity = std::min(old_capacity * 2, old_capacity + OneMB);
if (new_capacity < old_capacity) { if (new_capacity < old_capacity) {
llvm::report_fatal_error( llvm::report_fatal_error(
...@@ -123,7 +137,6 @@ void Assembler::emitIASBytes() const { ...@@ -123,7 +137,6 @@ void Assembler::emitIASBytes() const {
Ostream &Str = Ctx->getStrEmit(); Ostream &Str = Ctx->getStrEmit();
intptr_t EndPosition = Buffer.size(); intptr_t EndPosition = Buffer.size();
intptr_t CurPosition = 0; intptr_t CurPosition = 0;
const intptr_t FixupSize = 4;
for (const AssemblerFixup *NextFixup : fixups()) { for (const AssemblerFixup *NextFixup : fixups()) {
intptr_t NextFixupLoc = NextFixup->position(); intptr_t NextFixupLoc = NextFixup->position();
for (intptr_t i = CurPosition; i < NextFixupLoc; ++i) { for (intptr_t i = CurPosition; i < NextFixupLoc; ++i) {
...@@ -131,16 +144,13 @@ void Assembler::emitIASBytes() const { ...@@ -131,16 +144,13 @@ void Assembler::emitIASBytes() const {
Str.write_hex(Buffer.load<uint8_t>(i)); Str.write_hex(Buffer.load<uint8_t>(i));
Str << "\n"; Str << "\n";
} }
Str << "\t.long ";
// For PCRel fixups, we write the pc-offset from a symbol into the Buffer // For PCRel fixups, we write the pc-offset from a symbol into the Buffer
// (e.g., -4), but we don't represent that in the fixup's offset. Otherwise // (e.g., -4), but we don't represent that in the fixup's offset. Otherwise
// the fixup holds the true offset, and so does the Buffer. Just load the // the fixup holds the true offset, and so does the Buffer. Just load the
// offset from the buffer. // offset from the buffer.
NextFixup->emit(Ctx, Buffer.load<RelocOffsetT>(NextFixupLoc)); CurPosition = NextFixupLoc +
if (fixupIsPCRel(NextFixup->kind())) NextFixup->emit(Ctx, Buffer.load<RelocOffsetT>(NextFixupLoc),
Str << " - ."; fixupIsPCRel(NextFixup->kind()));
Str << "\n";
CurPosition = NextFixupLoc + FixupSize;
assert(CurPosition <= EndPosition); assert(CurPosition <= EndPosition);
} }
// Handle any bytes that are not prefixed by a fixup. // Handle any bytes that are not prefixed by a fixup.
......
...@@ -174,6 +174,20 @@ public: ...@@ -174,6 +174,20 @@ public:
/// Create and track a fixup in the current function. /// Create and track a fixup in the current function.
AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value); AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value);
/// Create and track a textual fixup in the current function.
AssemblerTextFixup *createTextFixup(const std::string &Text,
size_t BytesUsed);
/// Mark that an attempt was made to emit, but failed. Hence, in order to
/// continue, one must emit a text fixup.
void setNeedsTextFixup() { TextFixupNeeded = true; }
/// Returns true if last emit failed and needs a text fixup.
bool needsTextFixup() const { return TextFixupNeeded; }
/// Installs a created fixup, after it has been allocated.
void installFixup(AssemblerFixup *F);
const FixupRefList &fixups() const { return Fixups; } const FixupRefList &fixups() const { return Fixups; }
void setSize(intptr_t NewSize) { void setSize(intptr_t NewSize) {
...@@ -194,6 +208,9 @@ private: ...@@ -194,6 +208,9 @@ private:
Assembler &Assemblr; Assembler &Assemblr;
/// List of pool-allocated fixups relative to the current function. /// List of pool-allocated fixups relative to the current function.
FixupRefList Fixups; FixupRefList Fixups;
// True if a textual fixup is needed, because the assembler was unable to
// emit the last request.
bool TextFixupNeeded;
uintptr_t cursor() const { return Cursor; } uintptr_t cursor() const { return Cursor; }
uintptr_t limit() const { return Limit; } uintptr_t limit() const { return Limit; }
...@@ -268,12 +285,24 @@ public: ...@@ -268,12 +285,24 @@ public:
// Return a view of all the bytes of code for the current function. // Return a view of all the bytes of code for the current function.
llvm::StringRef getBufferView() const; llvm::StringRef getBufferView() const;
/// Emit a fixup at the current location.
void emitFixup(AssemblerFixup *Fixup) { Buffer.emitFixup(Fixup); }
const FixupRefList &fixups() const { return Buffer.fixups(); } const FixupRefList &fixups() const { return Buffer.fixups(); }
AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value) { AssemblerFixup *createFixup(FixupKind Kind, const Constant *Value) {
return Buffer.createFixup(Kind, Value); return Buffer.createFixup(Kind, Value);
} }
AssemblerTextFixup *createTextFixup(const std::string &Text,
size_t BytesUsed) {
return Buffer.createTextFixup(Text, BytesUsed);
}
void setNeedsTextFixup() { Buffer.setNeedsTextFixup(); }
bool needsTextFixup() const { return Buffer.needsTextFixup(); }
void emitIASBytes() const; void emitIASBytes() const;
bool getInternal() const { return IsInternal; } bool getInternal() const { return IsInternal; }
void setInternal(bool Internal) { IsInternal = Internal; } void setInternal(bool Internal) { IsInternal = Internal; }
...@@ -306,6 +335,9 @@ private: ...@@ -306,6 +335,9 @@ private:
/// fully committed (Preliminary=false). /// fully committed (Preliminary=false).
bool Preliminary = false; bool Preliminary = false;
/// Installs a created fixup, after it has been allocated.
void installFixup(AssemblerFixup *F) { Buffer.installFixup(F); }
protected: protected:
GlobalContext *Ctx; GlobalContext *Ctx;
// Buffer's constructor uses the Allocator, so it needs to appear after it. // Buffer's constructor uses the Allocator, so it needs to appear after it.
......
...@@ -70,6 +70,11 @@ static constexpr uint32_t kShiftShift = 5; ...@@ -70,6 +70,11 @@ static constexpr uint32_t kShiftShift = 5;
static constexpr uint32_t kImmed12Bits = 12; static constexpr uint32_t kImmed12Bits = 12;
static constexpr uint32_t kImm12Shift = 0; static constexpr uint32_t kImm12Shift = 0;
// Type of instruction encoding (bits 25-27). See ARM section A5.1
static constexpr uint32_t kInstTypeDataRegister = 0; // i.e. 000
static constexpr uint32_t kInstTypeDataImmediate = 1; // i.e. 001
static constexpr uint32_t kInstTypeMemImmediate = 2; // i.e. 010
inline uint32_t encodeBool(bool b) { return b ? 1 : 0; } inline uint32_t encodeBool(bool b) { return b ? 1 : 0; }
inline uint32_t encodeGPRRegister(RegARM32::GPRRegister Rn) { inline uint32_t encodeGPRRegister(RegARM32::GPRRegister Rn) {
...@@ -231,6 +236,14 @@ void ARM32::AssemblerARM32::bind(Label *label) { ...@@ -231,6 +236,14 @@ void ARM32::AssemblerARM32::bind(Label *label) {
label->bindTo(bound); label->bindTo(bound);
} }
void ARM32::AssemblerARM32::emitTextInst(const std::string &Text) {
static constexpr uint32_t Placeholder = 0;
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
AssemblerFixup *F = createTextFixup(Text, sizeof(Placeholder));
emitFixup(F);
emitInst(Placeholder);
}
void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type, void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type,
uint32_t Opcode, bool SetCc, uint32_t Rn, uint32_t Opcode, bool SetCc, uint32_t Rn,
uint32_t Rd, uint32_t Imm12) { uint32_t Rd, uint32_t Imm12) {
...@@ -261,54 +274,48 @@ void ARM32::AssemblerARM32::emitMemOp(CondARM32::Cond Cond, uint32_t InstType, ...@@ -261,54 +274,48 @@ void ARM32::AssemblerARM32::emitMemOp(CondARM32::Cond Cond, uint32_t InstType,
void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
// Note: Loop is used so that we can short circuit using break; uint32_t Rd;
do { if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
uint32_t Rd; return setNeedsTextFixup();
if (decodeOperand(OpRd, Rd) != DecodedAsRegister) uint32_t Rn;
break; if (decodeOperand(OpRn, Rn) != DecodedAsRegister)
uint32_t Rn; return setNeedsTextFixup();
if (decodeOperand(OpRn, Rn) != DecodedAsRegister) constexpr uint32_t Add = B2; // 0100
break; uint32_t Src1Value;
constexpr uint32_t Add = B2; // 0100 // TODO(kschimpf) Other possible decodings of add.
uint32_t Src1Value; switch (decodeOperand(OpSrc1, Src1Value)) {
// TODO(kschimpf) Other possible decodings of add. default:
switch (decodeOperand(OpSrc1, Src1Value)) { return setNeedsTextFixup();
default: case DecodedAsRegister: {
break; // ADD (register) - ARM section A8.8.7, encoding A1:
case DecodedAsRegister: { // add{s}<c> <Rd>, <Rn>, <Rm>{, <shiff>}
// ADD (register) - ARM section A8.8.7, encoding A1: // ADD (Sp plus register) - ARM section A8.8.11, encoding A1:
// add{s}<c> <Rd>, <Rn>, <Rm>{, <shiff>} // add{s}<c> sp, <Rn>, <Rm>{, <shiff>}
// ADD (Sp plus register) - ARM section A8.8.11, encoding A1: //
// add{s}<c> sp, <Rn>, <Rm>{, <shiff>} // cccc0000100snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
// // mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags
// cccc0000100snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn, Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, 0);
// mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags if (((Rd == RegARM32::Encoded_Reg_pc) && SetFlags))
Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, 0); // Conditions of rule violated.
if (((Rd == RegARM32::Encoded_Reg_pc) && SetFlags)) return setNeedsTextFixup();
// Conditions of rule violated. emitType01(Cond, kInstTypeDataRegister, Add, SetFlags, Rn, Rd, Src1Value);
break; return;
constexpr uint32_t InstTypeRegister = 0; }
emitType01(Cond, InstTypeRegister, Add, SetFlags, Rn, Rd, Src1Value); case DecodedAsRotatedImm8: {
return; // ADD (Immediate) - ARM section A8.8.5, encoding A1:
} // add{s}<c> <Rd>, <Rn>, #<RotatedImm8>
case DecodedAsRotatedImm8: { // ADD (SP plus immediate) - ARM section A8.8.9, encoding A1.
// ADD (Immediate) - ARM section A8.8.5, encoding A1: // add{s}<c> <Rd>, sp, #<RotatedImm8>
// add{s}<c> <Rd>, <Rn>, #<RotatedImm8> //
// ADD (SP plus immediate) - ARM section A8.8.9, encoding A1. // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// add{s}<c> <Rd>, sp, #<RotatedImm8> // s=SetFlags and iiiiiiiiiiii=Src1Value=RotatedImm8.
// if ((Rd == RegARM32::Encoded_Reg_pc && SetFlags))
// cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // Conditions of rule violated.
// s=SetFlags and iiiiiiiiiiii=Src1Value=RotatedImm8. return setNeedsTextFixup();
if ((Rd == RegARM32::Encoded_Reg_pc && SetFlags)) emitType01(Cond, kInstTypeDataImmediate, Add, SetFlags, Rn, Rd, Src1Value);
// Conditions of rule violated. return;
break; }
constexpr uint32_t InstTypeImmediate = 1; };
emitType01(Cond, InstTypeImmediate, Add, SetFlags, Rn, Rd, Src1Value);
return;
}
}
} while (0);
UnimplementedError(Ctx->getFlags());
} }
void ARM32::AssemblerARM32::bkpt(uint16_t Imm16) { void ARM32::AssemblerARM32::bkpt(uint16_t Imm16) {
...@@ -327,11 +334,8 @@ void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) { ...@@ -327,11 +334,8 @@ void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) {
// bx<c> <Rm> // bx<c> <Rm>
// //
// cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond. // cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond.
assert(isGPRRegisterDefined(Rm)); if (!(isGPRRegisterDefined(Rm) && isConditionDefined(Cond)))
// TODO(kschimpf): Remove void cast when MINIMAL build allows. return setNeedsTextFixup();
(void)isGPRRegisterDefined(Rm);
assert(isConditionDefined(Cond));
(void)isConditionDefined(Cond);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 |
B21 | (0xfff << 8) | B4 | B21 | (0xfff << 8) | B4 |
...@@ -341,169 +345,145 @@ void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) { ...@@ -341,169 +345,145 @@ void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) {
void ARM32::AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, void ARM32::AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
// Note: Loop is used so that we can short ciruit using break; uint32_t Rt;
do { if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
uint32_t Rt; return setNeedsTextFixup();
if (decodeOperand(OpRt, Rt) != DecodedAsRegister) uint32_t Address;
break; if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset)
uint32_t Address; return setNeedsTextFixup();
if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset) // LDR (immediate) - ARM section A8.8.63, encoding A1:
break; // ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// LDR (immediate) - ARM section A8.8.63, encoding A1: // ldr<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 // ldr<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
// ldr<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 // LDRB (immediate) - ARM section A8.8.68, encoding A1:
// ldr<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 // ldrb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// LDRB (immediate) - ARM section A8.8.68, encoding A1: // ldrb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldrb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 // ldrb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
// ldrb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 //
// ldrb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 // cccc010pubw1nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// // iiiiiiiiiiii=imm12, b=1 if STRB, u=1 if +.
// cccc010pubw1nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn, constexpr bool IsLoad = true;
// iiiiiiiiiiii=imm12, b=1 if STRB, u=1 if +. const Type Ty = OpRt->getType();
constexpr uint32_t InstType = B1; // 010 if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand?
constexpr bool IsLoad = true; return setNeedsTextFixup();
const Type Ty = OpRt->getType(); const bool IsByte = typeWidthInBytes(Ty) == 1;
if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand? // Check conditions of rules violated.
break; if (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc)
const bool IsByte = typeWidthInBytes(Ty) == 1; return setNeedsTextFixup();
if ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc) || if (!isBitSet(P, Address) && isBitSet(W, Address))
(!isBitSet(P, Address) && isBitSet(W, Address)) || return setNeedsTextFixup();
(!IsByte && if (!IsByte && (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) &&
(getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) && !isBitSet(P, Address) && isBitSet(U, Address) & !isBitSet(W, Address) &&
!isBitSet(P, Address) && (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))
isBitSet(U, Address) & !isBitSet(W, Address) && return setNeedsTextFixup();
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))) emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
break;
emitMemOp(Cond, InstType, IsLoad, IsByte, Rt, Address);
return;
} while (0);
UnimplementedError(Ctx->getFlags());
} }
void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
// Note: Loop is used so that we can short ciruit using break; uint32_t Rd;
do { if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
uint32_t Rd; return setNeedsTextFixup();
if (decodeOperand(OpRd, Rd) != DecodedAsRegister) uint32_t Src;
break; // TODO(kschimpf) Handle other forms of mov.
uint32_t Src; if (decodeOperand(OpSrc, Src) != DecodedAsRotatedImm8)
// TODO(kschimpf) Handle other forms of mov. return setNeedsTextFixup();
if (decodeOperand(OpSrc, Src) == DecodedAsRotatedImm8) { // MOV (immediate) - ARM section A8.8.102, encoding A1:
// MOV (immediate) - ARM section A8.8.102, encoding A1: // mov{S}<c> <Rd>, #<RotatedImm8>
// mov{S}<c> <Rd>, #<RotatedImm8> //
// // cccc0011101s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags, dddd=Rd,
// cccc0011101s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags, dddd=Rd, // and iiiiiiiiiiii=RotatedImm8=Src. Note: We don't use movs in this
// and iiiiiiiiiiii=RotatedImm8=Src. Note: We don't use movs in this // assembler.
// assembler. constexpr bool SetFlags = false;
constexpr bool SetFlags = false; if ((Rd == RegARM32::Encoded_Reg_pc && SetFlags))
if ((Rd == RegARM32::Encoded_Reg_pc && SetFlags)) // Conditions of rule violated.
// Conditions of rule violated. return setNeedsTextFixup();
break; constexpr uint32_t Rn = 0;
constexpr uint32_t Rn = 0; constexpr uint32_t Mov = B3 | B2 | B0; // 1101.
constexpr uint32_t Mov = B3 | B2 | B0; // 1101. emitType01(Cond, kInstTypeDataImmediate, Mov, SetFlags, Rn, Rd, Src);
constexpr uint32_t InstType = 1;
emitType01(Cond, InstType, Mov, SetFlags, Rn, Rd, Src);
return;
}
} while (0);
UnimplementedError(Ctx->getFlags());
} }
void ARM32::AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, void ARM32::AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
// Note: Loop is used so that we can short ciruit using break; uint32_t Rt;
do { if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
uint32_t Rt; return setNeedsTextFixup();
if (decodeOperand(OpRt, Rt) != DecodedAsRegister) uint32_t Address;
break; if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset)
uint32_t Address; return setNeedsTextFixup();
if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset) // STR (immediate) - ARM section A8.8.204, encoding A1:
break; // str<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// STR (immediate) - ARM section A8.8.204, encoding A1: // str<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// str<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 // str<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
// str<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 // STRB (immediate) - ARM section A8.8.207, encoding A1:
// str<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 // strb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// STRB (immediate) - ARM section A8.8.207, encoding A1: // strb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// strb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 // strb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
// strb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 //
// strb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 // cccc010pubw0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// // iiiiiiiiiiii=imm12, b=1 if STRB, u=1 if +.
// cccc010pubw0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn, constexpr bool IsLoad = false;
// iiiiiiiiiiii=imm12, b=1 if STRB, u=1 if +. const Type Ty = OpRt->getType();
constexpr uint32_t InstType = B1; // 010 if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand?
constexpr bool IsLoad = false; return setNeedsTextFixup();
const Type Ty = OpRt->getType(); const bool IsByte = typeWidthInBytes(Ty) == 1;
if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand? // Check for rule violations.
break; if ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc))
const bool IsByte = typeWidthInBytes(Ty) == 1; return setNeedsTextFixup();
// Check for rule violations. if (!isBitSet(P, Address) && isBitSet(W, Address))
if ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc) || return setNeedsTextFixup();
(!isBitSet(P, Address) && isBitSet(W, Address)) || if (!IsByte && (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) &&
(!IsByte && isBitSet(P, Address) && !isBitSet(U, Address) && isBitSet(W, Address) &&
(getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) && (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))
isBitSet(P, Address) && !isBitSet(U, Address) && return setNeedsTextFixup();
isBitSet(W, Address) && emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)))
// Conditions of rule violated.
break;
emitMemOp(Cond, InstType, IsLoad, IsByte, Rt, Address);
return;
} while (0);
UnimplementedError(Ctx->getFlags());
} }
void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
// Note: Loop is used so that we can short circuit using break; uint32_t Rd;
do { if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
uint32_t Rd; return setNeedsTextFixup();
if (decodeOperand(OpRd, Rd) != DecodedAsRegister) uint32_t Rn;
break; if (decodeOperand(OpRn, Rn) != DecodedAsRegister)
uint32_t Rn; return setNeedsTextFixup();
if (decodeOperand(OpRn, Rn) != DecodedAsRegister) constexpr uint32_t Sub = B1; // 0010
break; uint32_t Src1Value;
constexpr uint32_t Sub = B1; // 0010 // TODO(kschimpf) Other possible decodings of sub.
uint32_t Src1Value; switch (decodeOperand(OpSrc1, Src1Value)) {
// TODO(kschimpf) Other possible decodings of sub. default:
switch (decodeOperand(OpSrc1, Src1Value)) { return setNeedsTextFixup();
default: case DecodedAsRegister: {
break; // SUB (register) - ARM section A8.8.223, encoding A1:
case DecodedAsRegister: { // sub{s}<c> <Rd>, <Rn>, <Rm>{, <shift>}
// SUB (register) - ARM section A8.8.223, encoding A1: // SUB (SP minus register): See ARM section 8.8.226, encoding A1:
// sub{s}<c> <Rd>, <Rn>, <Rm>{, <shift>} // sub{s}<c> <Rd>, sp, <Rm>{, <Shift>}
// SUB (SP minus register): See ARM section 8.8.226, encoding A1: //
// sub{s}<c> <Rd>, sp, <Rm>{, <Shift>} // cccc0000010snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
// // mmmm=Rm, iiiiii=shift, tt=ShiftKind, and s=SetFlags.
// cccc0000010snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn, Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, 0);
// mmmm=Rm, iiiiii=shift, tt=ShiftKind, and s=SetFlags. if (((Rd == RegARM32::Encoded_Reg_pc) && SetFlags))
Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, 0); // Conditions of rule violated.
constexpr uint32_t InstType = 0; // i.e. register return setNeedsTextFixup();
if (((Rd == RegARM32::Encoded_Reg_pc) && SetFlags)) emitType01(Cond, kInstTypeDataRegister, Sub, SetFlags, Rn, Rd, Src1Value);
// Conditions of rule violated. return;
break; }
emitType01(Cond, InstType, Sub, SetFlags, Rn, Rd, Src1Value); case DecodedAsRotatedImm8: {
return; // Sub (Immediate) - ARM section A8.8.222, encoding A1:
} // sub{s}<c> <Rd>, <Rn>, #<RotatedImm8>
case DecodedAsRotatedImm8: { // Sub (Sp minus immediate) - ARM section A8.*.225, encoding A1:
// Sub (Immediate) - ARM section A8.8.222, encoding A1: // sub{s}<c> sp, <Rn>, #<RotatedImm8>
// sub{s}<c> <Rd>, <Rn>, #<RotatedImm8> //
// Sub (Sp minus immediate) - ARM section A8.*.225, encoding A1: // cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// sub{s}<c> sp, <Rn>, #<RotatedImm8> // s=SetFlags and iiiiiiiiiiii=Src1Value=RotatedImm8
// if (Rd == RegARM32::Encoded_Reg_pc)
// cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // Conditions of rule violated.
// s=SetFlags and iiiiiiiiiiii=Src1Value=RotatedImm8 return setNeedsTextFixup();
if (Rd == RegARM32::Encoded_Reg_pc) emitType01(Cond, kInstTypeDataImmediate, Sub, SetFlags, Rn, Rd, Src1Value);
// Conditions of rule violated. return;
break; }
constexpr uint32_t InstType = 1; }
emitType01(Cond, InstType, Sub, SetFlags, Rn, Rd, Src1Value);
return;
}
}
} while (0);
UnimplementedError(Ctx->getFlags());
} }
} // end of namespace Ice } // end of namespace Ice
...@@ -53,11 +53,12 @@ public: ...@@ -53,11 +53,12 @@ public:
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);
constexpr uint32_t UndefinedInst = 0xe7fedef0; // udf #60896
constexpr SizeT InstSize = sizeof(int32_t); constexpr SizeT InstSize = sizeof(int32_t);
assert(BytesNeeded % InstSize == 0); assert(BytesNeeded % InstSize == 0);
while (BytesNeeded > 0) { while (BytesNeeded > 0) {
// TODO(kschimpf) Should this be NOP or some other instruction? AssemblerBuffer::EnsureCapacity ensured(&Buffer);
bkpt(0); emitInst(UndefinedInst);
BytesNeeded -= InstSize; BytesNeeded -= InstSize;
} }
} }
...@@ -91,7 +92,8 @@ public: ...@@ -91,7 +92,8 @@ public:
bool fixupIsPCRel(FixupKind Kind) const override { bool fixupIsPCRel(FixupKind Kind) const override {
(void)Kind; (void)Kind;
llvm_unreachable("Not yet implemented."); // TODO(kschimpf) Decide if we need this.
return false;
} }
void bind(Label *label); void bind(Label *label);
...@@ -118,6 +120,8 @@ public: ...@@ -118,6 +120,8 @@ public:
return Asm->getKind() == Asm_ARM32; return Asm->getKind() == Asm_ARM32;
} }
void emitTextInst(const std::string &Text);
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 *>;
......
...@@ -885,7 +885,6 @@ private: ...@@ -885,7 +885,6 @@ private:
inline void emitRegisterOperand(int rm, int reg); inline void emitRegisterOperand(int rm, int reg);
template <typename RegType, typename RmType> template <typename RegType, typename RmType>
inline void emitXmmRegisterOperand(RegType reg, RmType rm); inline void emitXmmRegisterOperand(RegType reg, RmType rm);
inline void emitFixup(AssemblerFixup *fixup);
inline void emitOperandSizeOverride(); inline void emitOperandSizeOverride();
void emitOperand(int rm, const typename Traits::Operand &operand); void emitOperand(int rm, const typename Traits::Operand &operand);
...@@ -1063,11 +1062,6 @@ inline void AssemblerX86Base<Machine>::emitXmmRegisterOperand(RegType reg, ...@@ -1063,11 +1062,6 @@ inline void AssemblerX86Base<Machine>::emitXmmRegisterOperand(RegType reg,
} }
template <class Machine> template <class Machine>
inline void AssemblerX86Base<Machine>::emitFixup(AssemblerFixup *fixup) {
Buffer.emitFixup(fixup);
}
template <class Machine>
inline void AssemblerX86Base<Machine>::emitOperandSizeOverride() { inline void AssemblerX86Base<Machine>::emitOperandSizeOverride() {
emitUint8(0x66); emitUint8(0x66);
} }
......
...@@ -74,6 +74,11 @@ cl::opt<std::string> ...@@ -74,6 +74,11 @@ cl::opt<std::string>
cl::desc("Define default global prefix for naming " cl::desc("Define default global prefix for naming "
"unnamed globals"), "unnamed globals"),
cl::init("Global")); cl::init("Global"));
cl::opt<bool> DisableHybridAssembly(
"no-hybrid-asm", cl::desc("Disable hybrid assembly when -filetype=iasm"),
cl::init(false));
cl::opt<bool> DisableInternal("externalize", cl::opt<bool> DisableInternal("externalize",
cl::desc("Externalize all symbols")); cl::desc("Externalize all symbols"));
// Note: Modifiable only if ALLOW_DISABLE_IR_GEN. // Note: Modifiable only if ALLOW_DISABLE_IR_GEN.
...@@ -380,6 +385,7 @@ void ClFlags::resetClFlags(ClFlags &OutFlags) { ...@@ -380,6 +385,7 @@ void ClFlags::resetClFlags(ClFlags &OutFlags) {
OutFlags.AllowUninitializedGlobals = false; OutFlags.AllowUninitializedGlobals = false;
OutFlags.DataSections = false; OutFlags.DataSections = false;
OutFlags.DecorateAsm = false; OutFlags.DecorateAsm = false;
OutFlags.DisableHybridAssembly = false;
OutFlags.DisableInternal = false; OutFlags.DisableInternal = false;
OutFlags.DisableIRGeneration = false; OutFlags.DisableIRGeneration = false;
OutFlags.DisableTranslation = false; OutFlags.DisableTranslation = false;
...@@ -445,6 +451,7 @@ void ClFlags::getParsedClFlags(ClFlags &OutFlags) { ...@@ -445,6 +451,7 @@ void ClFlags::getParsedClFlags(ClFlags &OutFlags) {
OutFlags.setDecorateAsm(::DecorateAsm); OutFlags.setDecorateAsm(::DecorateAsm);
OutFlags.setDefaultFunctionPrefix(::DefaultFunctionPrefix); OutFlags.setDefaultFunctionPrefix(::DefaultFunctionPrefix);
OutFlags.setDefaultGlobalPrefix(::DefaultGlobalPrefix); OutFlags.setDefaultGlobalPrefix(::DefaultGlobalPrefix);
OutFlags.setDisableHybridAssembly(::DisableHybridAssembly);
OutFlags.setDisableInternal(::DisableInternal); OutFlags.setDisableInternal(::DisableInternal);
OutFlags.setDisableIRGeneration(::DisableIRGeneration); OutFlags.setDisableIRGeneration(::DisableIRGeneration);
OutFlags.setDisableTranslation(::DisableTranslation); OutFlags.setDisableTranslation(::DisableTranslation);
......
...@@ -62,6 +62,11 @@ public: ...@@ -62,6 +62,11 @@ public:
bool getDecorateAsm() const { return DecorateAsm; } bool getDecorateAsm() const { return DecorateAsm; }
void setDecorateAsm(bool NewValue) { DecorateAsm = NewValue; } void setDecorateAsm(bool NewValue) { DecorateAsm = NewValue; }
bool getDisableHybridAssembly() const { return DisableHybridAssembly; }
void setDisableHybridAssembly(bool NewValue) {
DisableHybridAssembly = NewValue;
}
bool getDisableInternal() const { return DisableInternal; } bool getDisableInternal() const { return DisableInternal; }
void setDisableInternal(bool NewValue) { DisableInternal = NewValue; } void setDisableInternal(bool NewValue) { DisableInternal = NewValue; }
...@@ -253,6 +258,7 @@ private: ...@@ -253,6 +258,7 @@ private:
bool AllowUninitializedGlobals; bool AllowUninitializedGlobals;
bool DataSections; bool DataSections;
bool DecorateAsm; bool DecorateAsm;
bool DisableHybridAssembly;
bool DisableInternal; bool DisableInternal;
bool DisableIRGeneration; bool DisableIRGeneration;
bool DisableTranslation; bool DisableTranslation;
......
...@@ -48,11 +48,13 @@ IceString AssemblerFixup::symbol(const GlobalContext *Ctx) const { ...@@ -48,11 +48,13 @@ IceString AssemblerFixup::symbol(const GlobalContext *Ctx) const {
return Str.str(); return Str.str();
} }
void AssemblerFixup::emit(GlobalContext *Ctx, size_t AssemblerFixup::emit(GlobalContext *Ctx, RelocOffsetT OverrideOffset,
RelocOffsetT OverrideOffset) const { bool IsPCRel) const {
static constexpr const size_t FixupSize = 4;
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return FixupSize;
Ostream &Str = Ctx->getStrEmit(); Ostream &Str = Ctx->getStrEmit();
Str << "\t.long ";
if (isNullSymbol()) if (isNullSymbol())
Str << "__Sz_AbsoluteZero"; Str << "__Sz_AbsoluteZero";
else else
...@@ -60,6 +62,22 @@ void AssemblerFixup::emit(GlobalContext *Ctx, ...@@ -60,6 +62,22 @@ void AssemblerFixup::emit(GlobalContext *Ctx,
RelocOffsetT Offset = OverrideOffset; RelocOffsetT Offset = OverrideOffset;
if (Offset) if (Offset)
Str << " + " << Offset; Str << " + " << Offset;
// For PCRel fixups, we write the pc-offset from a symbol into the Buffer
// (e.g., -4), but we don't represent that in the fixup's offset. Otherwise
// the fixup holds the true offset, and so does the Buffer. Just load the
// offset from the buffer.
if (IsPCRel)
Str << " - .";
Str << "\n";
return FixupSize;
}
size_t AssemblerTextFixup::emit(GlobalContext *Ctx, RelocOffsetT OverrideOffset,
bool IsPCRel) const {
(void)OverrideOffset;
(void)IsPCRel;
Ctx->getStrEmit() << Message << "\n";
return NumBytes;
} }
} // end of namespace Ice } // end of namespace Ice
...@@ -45,7 +45,9 @@ public: ...@@ -45,7 +45,9 @@ public:
void set_value(const Constant *Value) { value_ = Value; } void set_value(const Constant *Value) { value_ = Value; }
void emit(GlobalContext *Ctx, RelocOffsetT OverrideOffset) const; /// Emits fixup, then returns the number of bytes to skip.
virtual size_t emit(GlobalContext *Ctx, RelocOffsetT OverrideOffset,
bool IsPCRel) const;
private: private:
intptr_t position_ = 0; intptr_t position_ = 0;
...@@ -53,6 +55,26 @@ private: ...@@ -53,6 +55,26 @@ private:
const Constant *value_ = nullptr; const Constant *value_ = nullptr;
}; };
/// Extends a fixup to be textual. That is, it emits text instead of a sequence
/// of bytes. This class is used as a fallback for unimplemented emitIAS
/// methods, allowing them to generate compilable assembly code.
class AssemblerTextFixup : public AssemblerFixup {
AssemblerTextFixup() = delete;
AssemblerTextFixup(const AssemblerTextFixup &) = delete;
AssemblerTextFixup &operator=(const AssemblerTextFixup &) = delete;
public:
AssemblerTextFixup(const std::string &Message, size_t NumBytes)
: AssemblerFixup(), Message(Message), NumBytes(NumBytes) {}
~AssemblerTextFixup() = default;
virtual size_t emit(GlobalContext *Ctx, RelocOffsetT OverrideOffset,
bool isPcRel) const;
private:
const std::string Message;
const size_t NumBytes;
};
using FixupList = std::vector<AssemblerFixup>; using FixupList = std::vector<AssemblerFixup>;
using FixupRefList = std::vector<AssemblerFixup *>; using FixupRefList = std::vector<AssemblerFixup *>;
......
...@@ -175,6 +175,7 @@ public: ...@@ -175,6 +175,7 @@ public:
Ostream &getStrDump() { return *StrDump; } Ostream &getStrDump() { return *StrDump; }
Ostream &getStrError() { return *StrError; } Ostream &getStrError() { return *StrError; }
Ostream &getStrEmit() { return *StrEmit; } Ostream &getStrEmit() { return *StrEmit; }
void setStrEmit(Ostream &NewStrEmit) { StrEmit = &NewStrEmit; }
LockedPtr<ErrorCode> getErrorStatus() { LockedPtr<ErrorCode> getErrorStatus() {
return LockedPtr<ErrorCode>(&ErrorStatus, &ErrorStatusLock); return LockedPtr<ErrorCode>(&ErrorStatus, &ErrorStatusLock);
......
...@@ -84,6 +84,27 @@ CondARM32::Cond InstARM32::getOppositeCondition(CondARM32::Cond Cond) { ...@@ -84,6 +84,27 @@ CondARM32::Cond InstARM32::getOppositeCondition(CondARM32::Cond Cond) {
return InstARM32CondAttributes[Cond].Opposite; return InstARM32CondAttributes[Cond].Opposite;
} }
void InstARM32::emitUsingTextFixup(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
GlobalContext *Ctx = Func->getContext();
if (Ctx->getFlags().getDisableHybridAssembly()) {
UnimplementedError(Ctx->getFlags());
return;
}
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
std::string Buffer;
llvm::raw_string_ostream StrBuf(Buffer);
OstreamLocker L(Ctx);
Ostream &OldStr = Ctx->getStrEmit();
Ctx->setStrEmit(StrBuf);
emit(Func);
Ctx->setStrEmit(OldStr);
Asm->emitTextInst(StrBuf.str());
}
void InstARM32::emitIAS(const Cfg *Func) const { emitUsingTextFixup(Func); }
void InstARM32Pred::emitUnaryopGPR(const char *Opcode, void InstARM32Pred::emitUnaryopGPR(const char *Opcode,
const InstARM32Pred *Inst, const Cfg *Func, const InstARM32Pred *Inst, const Cfg *Func,
bool NeedsWidthSuffix) { bool NeedsWidthSuffix) {
...@@ -320,20 +341,23 @@ bool InstARM32Br::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { ...@@ -320,20 +341,23 @@ bool InstARM32Br::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
template <InstARM32::InstKindARM32 K> template <InstARM32::InstKindARM32 K>
void InstARM32ThreeAddrGPR<K>::emitIAS(const Cfg *Func) const { void InstARM32ThreeAddrGPR<K>::emitIAS(const Cfg *Func) const {
(void)Func; emitUsingTextFixup(Func);
UnimplementedError(Func->getContext()->getFlags());
} }
template <> template <>
void InstARM32ThreeAddrGPR<InstARM32::Add>::emitIAS(const Cfg *Func) const { void InstARM32ThreeAddrGPR<InstARM32::Add>::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->add(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); Asm->add(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
} }
template <> template <>
void InstARM32ThreeAddrGPR<InstARM32::Sub>::emitIAS(const Cfg *Func) const { void InstARM32ThreeAddrGPR<InstARM32::Sub>::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->sub(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); Asm->sub(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
} }
InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget) InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget)
...@@ -614,35 +638,29 @@ void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const { ...@@ -614,35 +638,29 @@ void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Variable *Dest = getDest(); Variable *Dest = getDest();
Operand *Src0 = getSrc(0); Operand *Src0 = getSrc(0);
// Note: Loop is used so that we can short circuit using break. if (Dest->hasReg()) {
do { const Type DestTy = Dest->getType();
if (Dest->hasReg()) { const bool DestIsVector = isVectorType(DestTy);
const Type DestTy = Dest->getType(); const bool DestIsScalarFP = isScalarFloatingType(DestTy);
const bool DestIsVector = isVectorType(DestTy); const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
const bool DestIsScalarFP = isScalarFloatingType(DestTy); if (DestIsVector || DestIsScalarFP || CoreVFPMove)
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0); return Asm->setNeedsTextFixup();
if (DestIsVector || DestIsScalarFP || CoreVFPMove) if (isMemoryAccess(Src0)) {
break; // TODO(kschimpf) Figure out how to do ldr on CoreVPFMove? (see
if (isMemoryAccess(Src0)) { // emitSingleDestSingleSource, local variable LoadOpcode).
// TODO(kschimpf) Figure out how to do ldr on CoreVPFMove? (see return Asm->ldr(Dest, Src0, getPredicate());
// emitSingleDestSingleSource, local variable LoadOpcode).
Asm->ldr(Dest, Src0, getPredicate());
} else {
Asm->mov(Dest, Src0, getPredicate());
}
return;
} else {
const Type Src0Type = Src0->getType();
const bool Src0IsVector = isVectorType(Src0Type);
const bool Src0IsScalarFP = isScalarFloatingType(Src0Type);
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
if (Src0IsVector || Src0IsScalarFP || CoreVFPMove)
break;
Asm->str(Src0, Dest, getPredicate());
return;
} }
} while (0); return Asm->mov(Dest, Src0, getPredicate());
llvm_unreachable("not yet implemented"); } else {
const Type Src0Type = Src0->getType();
const bool Src0IsVector = isVectorType(Src0Type);
const bool Src0IsScalarFP = isScalarFloatingType(Src0Type);
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
if (Src0IsVector || Src0IsScalarFP || CoreVFPMove)
return Asm->setNeedsTextFixup();
return Asm->str(Src0, Dest, getPredicate());
}
Asm->setNeedsTextFixup();
} }
void InstARM32Mov::emit(const Cfg *Func) const { void InstARM32Mov::emit(const Cfg *Func) const {
...@@ -666,12 +684,13 @@ void InstARM32Mov::emitIAS(const Cfg *Func) const { ...@@ -666,12 +684,13 @@ void InstARM32Mov::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1); assert(getSrcSize() == 1);
(void)Func; (void)Func;
assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type."); assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type.");
if (isMultiDest()) ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
llvm_unreachable("Not yet implemented"); if (!(isMultiDest() || isMultiSource())) {
if (isMultiSource()) // Must be single source/dest.
llvm_unreachable("Not yet implemented"); emitIASSingleDestSingleSource(Func);
// Must be single source/dest. }
emitIASSingleDestSingleSource(Func); if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
} }
void InstARM32Mov::dump(const Cfg *Func) const { void InstARM32Mov::dump(const Cfg *Func) const {
...@@ -715,11 +734,6 @@ void InstARM32Br::emit(const Cfg *Func) const { ...@@ -715,11 +734,6 @@ void InstARM32Br::emit(const Cfg *Func) const {
} }
} }
void InstARM32Br::emitIAS(const Cfg *Func) const {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Br::dump(const Cfg *Func) const { void InstARM32Br::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -768,11 +782,6 @@ void InstARM32Call::emit(const Cfg *Func) const { ...@@ -768,11 +782,6 @@ void InstARM32Call::emit(const Cfg *Func) const {
Func->getTarget()->resetStackAdjustment(); Func->getTarget()->resetStackAdjustment();
} }
void InstARM32Call::emitIAS(const Cfg *Func) const {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Call::dump(const Cfg *Func) const { void InstARM32Call::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -792,11 +801,6 @@ void InstARM32Label::emit(const Cfg *Func) const { ...@@ -792,11 +801,6 @@ void InstARM32Label::emit(const Cfg *Func) const {
Str << getName(Func) << ":"; Str << getName(Func) << ":";
} }
void InstARM32Label::emitIAS(const Cfg *Func) const {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Label::dump(const Cfg *Func) const { void InstARM32Label::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -825,12 +829,6 @@ template <> void InstARM32Ldr::emit(const Cfg *Func) const { ...@@ -825,12 +829,6 @@ template <> void InstARM32Ldr::emit(const Cfg *Func) const {
getSrc(0)->emit(Func); getSrc(0)->emit(Func);
} }
template <> void InstARM32Ldr::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1);
(void)Func;
llvm_unreachable("Not yet implemented");
}
template <> void InstARM32Ldrex::emit(const Cfg *Func) const { template <> void InstARM32Ldrex::emit(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -847,10 +845,9 @@ template <> void InstARM32Ldrex::emit(const Cfg *Func) const { ...@@ -847,10 +845,9 @@ template <> void InstARM32Ldrex::emit(const Cfg *Func) const {
getSrc(0)->emit(Func); getSrc(0)->emit(Func);
} }
template <> void InstARM32Ldrex::emitIAS(const Cfg *Func) const { template <InstARM32::InstKindARM32 K>
assert(getSrcSize() == 1); void InstARM32TwoAddrGPR<K>::emitIAS(const Cfg *Func) const {
(void)Func; emitUsingTextFixup(Func);
llvm_unreachable("Not yet implemented");
} }
template <> void InstARM32Movw::emit(const Cfg *Func) const { template <> void InstARM32Movw::emit(const Cfg *Func) const {
...@@ -926,11 +923,6 @@ void InstARM32Pop::emit(const Cfg *Func) const { ...@@ -926,11 +923,6 @@ void InstARM32Pop::emit(const Cfg *Func) const {
} }
} }
void InstARM32Pop::emitIAS(const Cfg *Func) const {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Pop::dump(const Cfg *Func) const { void InstARM32Pop::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -960,12 +952,6 @@ void InstARM32AdjustStack::emit(const Cfg *Func) const { ...@@ -960,12 +952,6 @@ void InstARM32AdjustStack::emit(const Cfg *Func) const {
Func->getTarget()->updateStackAdjustment(Amount); Func->getTarget()->updateStackAdjustment(Amount);
} }
void InstARM32AdjustStack::emitIAS(const Cfg *Func) const {
(void)Func;
llvm_unreachable("Not yet implemented");
Func->getTarget()->updateStackAdjustment(Amount);
}
void InstARM32AdjustStack::dump(const Cfg *Func) const { void InstARM32AdjustStack::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1016,11 +1002,6 @@ void InstARM32Push::emit(const Cfg *Func) const { ...@@ -1016,11 +1002,6 @@ void InstARM32Push::emit(const Cfg *Func) const {
} }
} }
void InstARM32Push::emitIAS(const Cfg *Func) const {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Push::dump(const Cfg *Func) const { void InstARM32Push::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1047,6 +1028,8 @@ void InstARM32Ret::emit(const Cfg *Func) const { ...@@ -1047,6 +1028,8 @@ void InstARM32Ret::emit(const Cfg *Func) const {
void InstARM32Ret::emitIAS(const Cfg *Func) const { void InstARM32Ret::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->bx(RegARM32::Encoded_Reg_lr); Asm->bx(RegARM32::Encoded_Reg_lr);
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
} }
void InstARM32Ret::dump(const Cfg *Func) const { void InstARM32Ret::dump(const Cfg *Func) const {
...@@ -1075,12 +1058,6 @@ void InstARM32Str::emit(const Cfg *Func) const { ...@@ -1075,12 +1058,6 @@ void InstARM32Str::emit(const Cfg *Func) const {
getSrc(1)->emit(Func); getSrc(1)->emit(Func);
} }
void InstARM32Str::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 2);
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Str::dump(const Cfg *Func) const { void InstARM32Str::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1109,12 +1086,6 @@ void InstARM32Strex::emit(const Cfg *Func) const { ...@@ -1109,12 +1086,6 @@ void InstARM32Strex::emit(const Cfg *Func) const {
emitSources(Func); emitSources(Func);
} }
void InstARM32Strex::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 2);
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Strex::dump(const Cfg *Func) const { void InstARM32Strex::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1144,12 +1115,6 @@ void InstARM32Trap::emit(const Cfg *Func) const { ...@@ -1144,12 +1115,6 @@ void InstARM32Trap::emit(const Cfg *Func) const {
} }
} }
void InstARM32Trap::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 0);
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Trap::dump(const Cfg *Func) const { void InstARM32Trap::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1174,12 +1139,6 @@ void InstARM32Umull::emit(const Cfg *Func) const { ...@@ -1174,12 +1139,6 @@ void InstARM32Umull::emit(const Cfg *Func) const {
getSrc(1)->emit(Func); getSrc(1)->emit(Func);
} }
void InstARM32Umull::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 2);
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Umull::dump(const Cfg *Func) const { void InstARM32Umull::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1232,12 +1191,6 @@ void InstARM32Vcvt::emit(const Cfg *Func) const { ...@@ -1232,12 +1191,6 @@ void InstARM32Vcvt::emit(const Cfg *Func) const {
getSrc(0)->emit(Func); getSrc(0)->emit(Func);
} }
void InstARM32Vcvt::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1);
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Vcvt::dump(const Cfg *Func) const { void InstARM32Vcvt::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1261,12 +1214,6 @@ void InstARM32Vcmp::emit(const Cfg *Func) const { ...@@ -1261,12 +1214,6 @@ void InstARM32Vcmp::emit(const Cfg *Func) const {
getSrc(1)->emit(Func); getSrc(1)->emit(Func);
} }
void InstARM32Vcmp::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 2);
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Vcmp::dump(const Cfg *Func) const { void InstARM32Vcmp::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1287,12 +1234,6 @@ void InstARM32Vmrs::emit(const Cfg *Func) const { ...@@ -1287,12 +1234,6 @@ void InstARM32Vmrs::emit(const Cfg *Func) const {
"FPSCR"; "FPSCR";
} }
void InstARM32Vmrs::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 0);
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Vmrs::dump(const Cfg *Func) const { void InstARM32Vmrs::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1314,12 +1255,6 @@ void InstARM32Vabs::emit(const Cfg *Func) const { ...@@ -1314,12 +1255,6 @@ void InstARM32Vabs::emit(const Cfg *Func) const {
getSrc(0)->emit(Func); getSrc(0)->emit(Func);
} }
void InstARM32Vabs::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1);
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Vabs::dump(const Cfg *Func) const { void InstARM32Vabs::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1339,12 +1274,6 @@ void InstARM32Dmb::emit(const Cfg *Func) const { ...@@ -1339,12 +1274,6 @@ void InstARM32Dmb::emit(const Cfg *Func) const {
"sy"; "sy";
} }
void InstARM32Dmb::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1);
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Dmb::dump(const Cfg *Func) const { void InstARM32Dmb::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1486,9 +1415,12 @@ template class InstARM32ThreeAddrGPR<InstARM32::Sbc>; ...@@ -1486,9 +1415,12 @@ template class InstARM32ThreeAddrGPR<InstARM32::Sbc>;
template class InstARM32ThreeAddrGPR<InstARM32::Sdiv>; template class InstARM32ThreeAddrGPR<InstARM32::Sdiv>;
template class InstARM32ThreeAddrGPR<InstARM32::Sub>; template class InstARM32ThreeAddrGPR<InstARM32::Sub>;
template class InstARM32ThreeAddrGPR<InstARM32::Udiv>; template class InstARM32ThreeAddrGPR<InstARM32::Udiv>;
template class InstARM32ThreeAddrFP<InstARM32::Vadd>; template class InstARM32ThreeAddrFP<InstARM32::Vadd>;
template class InstARM32ThreeAddrFP<InstARM32::Vdiv>; template class InstARM32ThreeAddrFP<InstARM32::Vdiv>;
template class InstARM32ThreeAddrFP<InstARM32::Vmul>; template class InstARM32ThreeAddrFP<InstARM32::Vmul>;
template class InstARM32ThreeAddrFP<InstARM32::Vsub>; template class InstARM32ThreeAddrFP<InstARM32::Vsub>;
template class InstARM32TwoAddrGPR<InstARM32::Movt>;
} // end of namespace Ice } // end of namespace Ice
...@@ -344,6 +344,8 @@ public: ...@@ -344,6 +344,8 @@ public:
void dump(const Cfg *Func) const override; void dump(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
protected: protected:
InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest) InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest)
: InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {} : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {}
...@@ -351,6 +353,10 @@ protected: ...@@ -351,6 +353,10 @@ protected:
static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) { static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) {
return Inst->getKind() == static_cast<InstKind>(MyKind); return Inst->getKind() == static_cast<InstKind>(MyKind);
} }
// Generates text of assembly instruction using method emit(), and then adds
// to the assembly buffer as a Fixup.
void emitUsingTextFixup(const Cfg *Func) const;
}; };
/// A predicable ARM instruction. /// A predicable ARM instruction.
...@@ -412,10 +418,6 @@ public: ...@@ -412,10 +418,6 @@ public:
return; return;
emitUnaryopGPR(Opcode, this, Func, NeedsWidthSuffix); emitUnaryopGPR(Opcode, this, Func, NeedsWidthSuffix);
} }
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override { void dump(const Cfg *Func) const override {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -456,10 +458,6 @@ public: ...@@ -456,10 +458,6 @@ public:
return; return;
emitUnaryopFP(Opcode, this, Func); emitUnaryopFP(Opcode, this, Func);
} }
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm::report_fatal_error("Not yet implemented");
}
void dump(const Cfg *Func) const override { void dump(const Cfg *Func) const override {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -501,10 +499,7 @@ public: ...@@ -501,10 +499,7 @@ public:
return; return;
emitTwoAddr(Opcode, this, Func); emitTwoAddr(Opcode, this, Func);
} }
void emitIAS(const Cfg *Func) const override { void emitIAS(const Cfg *Func) const override;
(void)Func;
llvm::report_fatal_error("Not yet implemented");
}
void dump(const Cfg *Func) const override { void dump(const Cfg *Func) const override {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -542,7 +537,6 @@ public: ...@@ -542,7 +537,6 @@ public:
InstARM32LoadBase(Func, Dest, Source, Predicate); InstARM32LoadBase(Func, Dest, Source, Predicate);
} }
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 {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -636,10 +630,6 @@ public: ...@@ -636,10 +630,6 @@ public:
return; return;
emitThreeAddrFP(Opcode, this, Func); emitThreeAddrFP(Opcode, this, Func);
} }
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm::report_fatal_error("Not yet implemented");
}
void dump(const Cfg *Func) const override { void dump(const Cfg *Func) const override {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -682,10 +672,6 @@ public: ...@@ -682,10 +672,6 @@ public:
return; return;
emitFourAddr(Opcode, this, Func); emitFourAddr(Opcode, this, Func);
} }
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm::report_fatal_error("Not yet implemented");
}
void dump(const Cfg *Func) const override { void dump(const Cfg *Func) const override {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -729,10 +715,6 @@ public: ...@@ -729,10 +715,6 @@ public:
return; return;
emitCmpLike(Opcode, this, Func); emitCmpLike(Opcode, this, Func);
} }
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override { void dump(const Cfg *Func) const override {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -810,7 +792,6 @@ public: ...@@ -810,7 +792,6 @@ 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:
...@@ -879,7 +860,6 @@ public: ...@@ -879,7 +860,6 @@ public:
} }
bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override; bool repointEdges(CfgNode *OldNode, CfgNode *NewNode) override;
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, Br); } static bool classof(const Inst *Inst) { return isClassof(Inst, Br); }
...@@ -910,7 +890,6 @@ public: ...@@ -910,7 +890,6 @@ public:
InstARM32AdjustStack(Func, SP, Amount, SrcAmount); InstARM32AdjustStack(Func, SP, Amount, SrcAmount);
} }
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, Adjuststack); } static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); }
SizeT getAmount() const { return Amount; } SizeT getAmount() const { return Amount; }
...@@ -936,7 +915,6 @@ public: ...@@ -936,7 +915,6 @@ 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); }
...@@ -956,7 +934,6 @@ public: ...@@ -956,7 +934,6 @@ public:
return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests); return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests);
} }
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, Pop); } static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); }
...@@ -978,7 +955,6 @@ public: ...@@ -978,7 +955,6 @@ public:
return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs);
} }
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, Push); } static bool classof(const Inst *Inst) { return isClassof(Inst, Push); }
...@@ -1029,7 +1005,6 @@ public: ...@@ -1029,7 +1005,6 @@ public:
InstARM32Str(Func, Value, Mem, Predicate); InstARM32Str(Func, Value, Mem, Predicate);
} }
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, Str); } static bool classof(const Inst *Inst) { return isClassof(Inst, Str); }
...@@ -1055,7 +1030,6 @@ public: ...@@ -1055,7 +1030,6 @@ public:
InstARM32Strex(Func, Dest, Value, Mem, Predicate); InstARM32Strex(Func, Dest, Value, Mem, Predicate);
} }
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, Strex); } static bool classof(const Inst *Inst) { return isClassof(Inst, Strex); }
...@@ -1074,7 +1048,6 @@ public: ...@@ -1074,7 +1048,6 @@ public:
return new (Func->allocate<InstARM32Trap>()) InstARM32Trap(Func); return new (Func->allocate<InstARM32Trap>()) InstARM32Trap(Func);
} }
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, Trap); } static bool classof(const Inst *Inst) { return isClassof(Inst, Trap); }
...@@ -1097,7 +1070,6 @@ public: ...@@ -1097,7 +1070,6 @@ public:
InstARM32Umull(Func, DestLo, DestHi, Src0, Src1, Predicate); InstARM32Umull(Func, DestLo, DestHi, Src0, Src1, Predicate);
} }
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, Umull); } static bool classof(const Inst *Inst) { return isClassof(Inst, Umull); }
...@@ -1122,7 +1094,6 @@ public: ...@@ -1122,7 +1094,6 @@ public:
InstARM32Vcvt(Func, Dest, Src, Variant, Predicate); InstARM32Vcvt(Func, Dest, Src, Variant, Predicate);
} }
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, Vcvt); } static bool classof(const Inst *Inst) { return isClassof(Inst, Vcvt); }
...@@ -1189,7 +1160,6 @@ public: ...@@ -1189,7 +1160,6 @@ public:
InstARM32Vcmp(Func, Src0, Src1, Predicate); InstARM32Vcmp(Func, Src0, Src1, Predicate);
} }
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, Vcmp); } static bool classof(const Inst *Inst) { return isClassof(Inst, Vcmp); }
...@@ -1209,7 +1179,6 @@ public: ...@@ -1209,7 +1179,6 @@ public:
return new (Func->allocate<InstARM32Vmrs>()) InstARM32Vmrs(Func, Predicate); return new (Func->allocate<InstARM32Vmrs>()) InstARM32Vmrs(Func, Predicate);
} }
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, Vmrs); } static bool classof(const Inst *Inst) { return isClassof(Inst, Vmrs); }
...@@ -1229,7 +1198,6 @@ public: ...@@ -1229,7 +1198,6 @@ public:
InstARM32Vabs(Func, Dest, Src, Predicate); InstARM32Vabs(Func, Dest, Src, Predicate);
} }
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, Vabs); } static bool classof(const Inst *Inst) { return isClassof(Inst, Vabs); }
...@@ -1248,7 +1216,6 @@ public: ...@@ -1248,7 +1216,6 @@ public:
return new (Func->allocate<InstARM32Dmb>()) InstARM32Dmb(Func); return new (Func->allocate<InstARM32Dmb>()) InstARM32Dmb(Func);
} }
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, Dmb); } static bool classof(const Inst *Inst) { return isClassof(Inst, Dmb); }
......
...@@ -48,7 +48,6 @@ const char *InstMIPS32::getWidthString(Type Ty) { ...@@ -48,7 +48,6 @@ const char *InstMIPS32::getWidthString(Type Ty) {
return "TBD"; return "TBD";
} }
template <> const char *InstMIPS32Addiu::Opcode = "addiu"; template <> const char *InstMIPS32Addiu::Opcode = "addiu";
template <> const char *InstMIPS32Lui::Opcode = "lui"; template <> const char *InstMIPS32Lui::Opcode = "lui";
template <> const char *InstMIPS32La::Opcode = "la"; template <> const char *InstMIPS32La::Opcode = "la";
......
...@@ -44,6 +44,7 @@ public: ...@@ -44,6 +44,7 @@ public:
if (BuildDefs::dump()) if (BuildDefs::dump())
Str << "<OperandMIPS32>"; Str << "<OperandMIPS32>";
} }
protected: protected:
OperandMIPS32(OperandKindMIPS32 Kind, Type Ty) OperandMIPS32(OperandKindMIPS32 Kind, Type Ty)
: Operand(static_cast<OperandKind>(Kind), Ty) {} : Operand(static_cast<OperandKind>(Kind), Ty) {}
...@@ -272,13 +273,12 @@ public: ...@@ -272,13 +273,12 @@ public:
private: private:
InstMIPS32Imm16(Cfg *Func, Variable *Dest, Operand *Source, uint32_t Imm) InstMIPS32Imm16(Cfg *Func, Variable *Dest, Operand *Source, uint32_t Imm)
: InstMIPS32(Func, K, 1, Dest), Imm(Imm){ : InstMIPS32(Func, K, 1, Dest), Imm(Imm) {
addSource(Source); addSource(Source);
} }
InstMIPS32Imm16(Cfg *Func, Variable *Dest, uint32_t Imm) InstMIPS32Imm16(Cfg *Func, Variable *Dest, uint32_t Imm)
: InstMIPS32(Func, K, 0, Dest), Imm(Imm) { : InstMIPS32(Func, K, 0, Dest), Imm(Imm) {}
}
static const char *Opcode; static const char *Opcode;
...@@ -304,7 +304,7 @@ public: ...@@ -304,7 +304,7 @@ public:
return !isMultiDest() && !isMultiSource() && return !isMultiDest() && !isMultiSource() &&
checkForRedundantAssign(getDest(), getSrc(0)); checkForRedundantAssign(getDest(), getSrc(0));
} }
//bool isSimpleAssign() const override { return true; } // bool isSimpleAssign() const override { return true; }
void emit(const Cfg *Func) const override; void emit(const Cfg *Func) const override;
void emitIAS(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;
......
...@@ -4,11 +4,22 @@ ...@@ -4,11 +4,22 @@
; REQUIRES: allow_dump ; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \ ; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=ASM ; 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: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=IASM ; 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 i32 @add1ToR0(i32 %p) { define internal i32 @add1ToR0(i32 %p) {
%v = add i32 %p, 1 %v = add i32 %p, 1
ret i32 %v ret i32 %v
...@@ -18,11 +29,21 @@ define internal i32 @add1ToR0(i32 %p) { ...@@ -18,11 +29,21 @@ define internal i32 @add1ToR0(i32 %p) {
; ASM: add r0, r0, #1 ; ASM: add r0, r0, #1
; ASM-NEXT: bx lr ; ASM-NEXT: bx lr
; DIS-LABEL:00000000 <add1ToR0>:
; DIS-NEXT: 0: e2800001
; DIS-NEXT: 4: e12fff1e
; IASM-LABEL: add1ToR0: ; IASM-LABEL: add1ToR0:
; IASM: .byte 0x1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x80 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0xe2
; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
define internal i32 @Add2Regs(i32 %p1, i32 %p2) { define internal i32 @Add2Regs(i32 %p1, i32 %p2) {
%v = add i32 %p1, %p2 %v = add i32 %p1, %p2
...@@ -33,9 +54,18 @@ define internal i32 @Add2Regs(i32 %p1, i32 %p2) { ...@@ -33,9 +54,18 @@ define internal i32 @Add2Regs(i32 %p1, i32 %p2) {
; ASM: add r0, r0, r1 ; ASM: add r0, r0, r1
; ASM-NEXT: bx lr ; ASM-NEXT: bx lr
; DIS-LABEL:00000010 <Add2Regs>:
; DIS-NEXT: 10: e0800001
; DIS-NEXT: 14: e12fff1e
; IASM-LABEL: Add2Regs: ; IASM-LABEL: Add2Regs:
; IASM: .byte 0x1 ; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x80 ; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0xe0 ; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
; TODO(kschimpf): Show that we can handle global variable loads/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
@global1 = internal global [4 x i8] zeroinitializer, align 4
; ASM-LABEL: global1:
; ASM-NEXT: .zero 4
; ASM-NEXT: .size global1, 4
; ASM-NEXT: .text
; ASM-NEXT: .p2alignl 4,0xe7fedef0
; IASM-LABEL:global1:
; IASM-NEXT: .zero 4
; IASM-NEXT: .size global1, 4
; IASM-NEXT: .text
; IASM-NEXT: .p2alignl 4,0xe7fedef0
define internal i32 @load() {
%addr = bitcast [4 x i8]* @global1 to i32*
%v = load i32, i32* %addr, align 1
ret i32 %v
}
; ASM-LABEL: load:
; ASM-NEXT: .Lload$__0:
; ASM-NEXT: movw r0, #:lower16:global1
; ASM-NEXT: movt r0, #:upper16:global1
; ASM-NEXT: ldr r0, [r0]
; ASM-NEXT: bx lr
; DIS-LABEL:00000000 <load>:
; DIS-NEXT: 0: e3000000
; DIS-NEXT: 4: e3400000
; DIS-NEXT: 8: e5900000
; DIS-NEXT: c: e12fff1e
; IASM-LABEL:load:
; IASM-NEXT: movw r0, #:lower16:global1
; IASM-NEXT: movt r0, #:upper16:global1
; IASM-NEXT: ldr r0, [r0]
; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
define internal void @store(i32 %v) {
%addr = bitcast [4 x i8]* @global1 to i32*
store i32 %v, i32* %addr, align 1
ret void
}
; ASM-LABEL:store:
; ASM-NEXT: .Lstore$__0:
; ASM-NEXT: movw r1, #:lower16:global1
; ASM-NEXT: movt r1, #:upper16:global1
; ASM-NEXT: str r0, [r1]
; ASM-NEXT: bx lr
; DIS-LABEL:00000010 <store>:
; DIS-NEXT: 10: e3001000
; DIS-NEXT: 14: e3401000
; DIS-NEXT: 18: e5810000
; DIS-NEXT: 1c: e12fff1e
; IASM-LABEL:store:
; IASM-NEXT: movw r1, #:lower16:global1
; IASM-NEXT: movt r1, #:upper16:global1
; IASM-NEXT: str r0, [r1]
; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
...@@ -2,11 +2,22 @@ ...@@ -2,11 +2,22 @@
; REQUIRES: allow_dump ; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \ ; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
; RUN: | FileCheck %s --check-prefix=ASM ; 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: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
; RUN: | FileCheck %s --check-prefix=IASM ; 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
define internal i32 @add1ToR0(i32 %p) { define internal i32 @add1ToR0(i32 %p) {
%v = add i32 %p, 1 %v = add i32 %p, 1
ret i32 %v ret i32 %v
...@@ -14,52 +25,61 @@ define internal i32 @add1ToR0(i32 %p) { ...@@ -14,52 +25,61 @@ define internal i32 @add1ToR0(i32 %p) {
; ASM-LABEL: add1ToR0: ; ASM-LABEL: add1ToR0:
; IASM-LABEL: add1ToR0: ; IASM-LABEL: add1ToR0:
; DIS-LABEL:00000000 <add1ToR0>:
; ASM: sub sp, sp, #8 ; ASM: sub sp, sp, #8
; DIS-NEXT: 0: e24dd008
; IASM: .byte 0x8 ; IASM: .byte 0x8
; IASM-NEXT: .byte 0xd0 ; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d ; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
; ASM-NEXT: str r0, [sp, #4] ; ASM-NEXT: str r0, [sp, #4]
; DIS-NEXT: 4: e58d0004
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d ; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
; ASM-NEXT: ldr r0, [sp, #4] ; ASM-NEXT: ldr r0, [sp, #4]
; DIS-NEXT: 8: e59d0004
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d ; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
; ASM-NEXT: add r0, r0, #1 ; ASM-NEXT: add r0, r0, #1
; DIS-NEXT: c: e2800001
; IASM-NEXT: .byte 0x1 ; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x80 ; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
; ASM-NEXT: str r0, [sp] ; ASM-NEXT: str r0, [sp]
; DIS-NEXT: 10: e58d0000
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d ; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
; ASM-NEXT: ldr r0, [sp] ; ASM-NEXT: ldr r0, [sp]
; DIS-NEXT: 14: e59d0000
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d ; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
; ASM-NEXT: add sp, sp, #8 ; ASM-NEXT: add sp, sp, #8
; DIS-NEXT: 18: e28dd008
; IASM-NEXT: .byte 0x8 ; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0xd0 ; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x8d ; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
; ASM-NEXT: bx lr ; ASM-NEXT: bx lr
; IASM-NEXT: .byte 0x1e ; DIS-NEXT: 1c: e12fff1e
; IASM-NEXT: .byte 0xff ; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0x2f ; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xe1 ; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
...@@ -2,22 +2,37 @@ ...@@ -2,22 +2,37 @@
; REQUIRES: allow_dump ; REQUIRES: allow_dump
; RUN: %p2i --filetype=asm -i %s --target=arm32 \ ; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=ASM ; RUN: | FileCheck %s --check-prefix=ASM
; RUN: %p2i --filetype=iasm -i %s --target=arm32 \
; 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 ; 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 i32 @Imm1() { define internal i32 @Imm1() {
ret i32 1 ret i32 1
} }
; ASM-LABEL: Imm1: ; ASM-LABEL: Imm1:
; ASM: mov r0, #1 ; ASM: mov r0, #1
; DIS-LABEL:00000000 <Imm1>:
; DIS-NEXT: 0: e3a00001
; IASM-LABEL: Imm1: ; IASM-LABEL: Imm1:
; IASM: .byte 0x1 ; IASM: .byte 0x1
; IASM: .byte 0x0 ; IASM: .byte 0x0
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotateFImmAA() { define internal i32 @rotateFImmAA() {
...@@ -26,13 +41,16 @@ define internal i32 @rotateFImmAA() { ...@@ -26,13 +41,16 @@ define internal i32 @rotateFImmAA() {
} }
; ASM-LABEL: rotateFImmAA: ; ASM-LABEL: rotateFImmAA:
; ASM: mov r0, #680 ; ASM: mov r0, #680
; DIS-LABEL:00000010 <rotateFImmAA>:
; DIS-NEXT: 10: e3a00faa
; IASM-LABEL: rotateFImmAA: ; IASM-LABEL: rotateFImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0xf ; IASM: .byte 0xf
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotateEImmAA() { define internal i32 @rotateEImmAA() {
; immediate = 0x00000aa0 = b 0000 0000 0000 0000 0000 1010 1010 0000 ; immediate = 0x00000aa0 = b 0000 0000 0000 0000 0000 1010 1010 0000
...@@ -40,13 +58,16 @@ define internal i32 @rotateEImmAA() { ...@@ -40,13 +58,16 @@ define internal i32 @rotateEImmAA() {
} }
; ASM-LABEL: rotateEImmAA: ; ASM-LABEL: rotateEImmAA:
; ASM: mov r0, #2720 ; ASM: mov r0, #2720
; DIS-LABEL:00000020 <rotateEImmAA>:
; DIS-NEXT: 20: e3a00eaa
; IASM-LABEL: rotateEImmAA: ; IASM-LABEL: rotateEImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0xe ; IASM: .byte 0xe
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotateDImmAA() { define internal i32 @rotateDImmAA() {
; immediate = 0x00002a80 = b 0000 0000 0000 0000 0010 1010 1000 0000 ; immediate = 0x00002a80 = b 0000 0000 0000 0000 0010 1010 1000 0000
...@@ -54,13 +75,16 @@ define internal i32 @rotateDImmAA() { ...@@ -54,13 +75,16 @@ define internal i32 @rotateDImmAA() {
} }
; ASM-LABEL: rotateDImmAA: ; ASM-LABEL: rotateDImmAA:
; ASM: mov r0, #10880 ; ASM: mov r0, #10880
; DIS-LABEL:00000030 <rotateDImmAA>:
; DIS-NEXT: 30: e3a00daa
; IASM-LABEL: rotateDImmAA: ; IASM-LABEL: rotateDImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0xd ; IASM: .byte 0xd
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotateCImmAA() { define internal i32 @rotateCImmAA() {
; immediate = 0x0000aa00 = b 0000 0000 0000 0000 1010 1010 0000 0000 ; immediate = 0x0000aa00 = b 0000 0000 0000 0000 1010 1010 0000 0000
...@@ -68,13 +92,16 @@ define internal i32 @rotateCImmAA() { ...@@ -68,13 +92,16 @@ define internal i32 @rotateCImmAA() {
} }
; ASM-LABEL: rotateCImmAA: ; ASM-LABEL: rotateCImmAA:
; ASM: mov r0, #43520 ; ASM: mov r0, #43520
; DIS-LABEL:00000040 <rotateCImmAA>:
; DIS-NEXT: 40: e3a00caa
; IASM-LABEL: rotateCImmAA: ; IASM-LABEL: rotateCImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0xc ; IASM: .byte 0xc
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotateBImmAA() { define internal i32 @rotateBImmAA() {
; immediate = 0x0002a800 = b 0000 0000 0000 0010 1010 1000 0000 0000 ; immediate = 0x0002a800 = b 0000 0000 0000 0010 1010 1000 0000 0000
...@@ -82,13 +109,16 @@ define internal i32 @rotateBImmAA() { ...@@ -82,13 +109,16 @@ define internal i32 @rotateBImmAA() {
} }
; ASM-LABEL: rotateBImmAA: ; ASM-LABEL: rotateBImmAA:
; ASM: mov r0, #174080 ; ASM: mov r0, #174080
; DIS-LABEL:00000050 <rotateBImmAA>:
; DIS-NEXT: 50: e3a00baa
; IASM-LABEL: rotateBImmAA: ; IASM-LABEL: rotateBImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0xb ; IASM: .byte 0xb
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotateAImmAA() { define internal i32 @rotateAImmAA() {
; immediate = 0x000aa000 = b 0000 0000 0000 1010 1010 0000 0000 0000 ; immediate = 0x000aa000 = b 0000 0000 0000 1010 1010 0000 0000 0000
...@@ -96,13 +126,16 @@ define internal i32 @rotateAImmAA() { ...@@ -96,13 +126,16 @@ define internal i32 @rotateAImmAA() {
} }
; ASM-LABEL: rotateAImmAA: ; ASM-LABEL: rotateAImmAA:
; ASM: mov r0, #696320 ; ASM: mov r0, #696320
; DIS-LABEL:00000060 <rotateAImmAA>:
; DIS-NEXT: 60: e3a00aaa
; IASM-LABEL: rotateAImmAA: ; IASM-LABEL: rotateAImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0xa ; IASM: .byte 0xa
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotate9ImmAA() { define internal i32 @rotate9ImmAA() {
; immediate = 0x002a8000 = b 0000 0000 0010 1010 1000 0000 0000 0000 ; immediate = 0x002a8000 = b 0000 0000 0010 1010 1000 0000 0000 0000
...@@ -110,13 +143,16 @@ define internal i32 @rotate9ImmAA() { ...@@ -110,13 +143,16 @@ define internal i32 @rotate9ImmAA() {
} }
; ASM-LABEL: rotate9ImmAA: ; ASM-LABEL: rotate9ImmAA:
; ASM: mov r0, #2785280 ; ASM: mov r0, #2785280
; DIS-LABEL:00000070 <rotate9ImmAA>:
; DIS-NEXT: 70: e3a009aa
; IASM-LABEL: rotate9ImmAA: ; IASM-LABEL: rotate9ImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0x9 ; IASM: .byte 0x9
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotate8ImmAA() { define internal i32 @rotate8ImmAA() {
; immediate = 0x00aa0000 = b 0000 0000 1010 1010 0000 0000 0000 0000 ; immediate = 0x00aa0000 = b 0000 0000 1010 1010 0000 0000 0000 0000
...@@ -124,13 +160,16 @@ define internal i32 @rotate8ImmAA() { ...@@ -124,13 +160,16 @@ define internal i32 @rotate8ImmAA() {
} }
; ASM-LABEL: rotate8ImmAA: ; ASM-LABEL: rotate8ImmAA:
; ASM: mov r0, #11141120 ; ASM: mov r0, #11141120
; DIS-LABEL:00000080 <rotate8ImmAA>:
; DIS-NEXT: 80: e3a008aa
; IASM-LABEL: rotate8ImmAA: ; IASM-LABEL: rotate8ImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0x8 ; IASM: .byte 0x8
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotate7ImmAA() { define internal i32 @rotate7ImmAA() {
; immediate = 0x02a80000 = b 0000 0010 1010 1000 0000 0000 0000 0000 ; immediate = 0x02a80000 = b 0000 0010 1010 1000 0000 0000 0000 0000
...@@ -138,13 +177,16 @@ define internal i32 @rotate7ImmAA() { ...@@ -138,13 +177,16 @@ define internal i32 @rotate7ImmAA() {
} }
; ASM-LABEL: rotate7ImmAA: ; ASM-LABEL: rotate7ImmAA:
; ASM: mov r0, #44564480 ; ASM: mov r0, #44564480
; DIS-LABEL:00000090 <rotate7ImmAA>:
; DIS-NEXT: 90: e3a007aa
; IASM-LABEL: rotate7ImmAA: ; IASM-LABEL: rotate7ImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0x7 ; IASM: .byte 0x7
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotate6ImmAA() { define internal i32 @rotate6ImmAA() {
; immediate = 0x0aa00000 = b 0000 1010 1010 0000 0000 0000 0000 0000 ; immediate = 0x0aa00000 = b 0000 1010 1010 0000 0000 0000 0000 0000
...@@ -152,13 +194,16 @@ define internal i32 @rotate6ImmAA() { ...@@ -152,13 +194,16 @@ define internal i32 @rotate6ImmAA() {
} }
; ASM-LABEL: rotate6ImmAA: ; ASM-LABEL: rotate6ImmAA:
; ASM: mov r0, #178257920 ; ASM: mov r0, #178257920
; DIS-LABEL:000000a0 <rotate6ImmAA>:
; DIS-NEXT: a0: e3a006aa
; IASM-LABEL: rotate6ImmAA: ; IASM-LABEL: rotate6ImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0x6 ; IASM: .byte 0x6
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotate5ImmAA() { define internal i32 @rotate5ImmAA() {
; immediate = 0x2a800000 = b 0010 1010 1000 0000 0000 0000 0000 0000 ; immediate = 0x2a800000 = b 0010 1010 1000 0000 0000 0000 0000 0000
...@@ -166,13 +211,16 @@ define internal i32 @rotate5ImmAA() { ...@@ -166,13 +211,16 @@ define internal i32 @rotate5ImmAA() {
} }
; ASM-LABEL: rotate5ImmAA: ; ASM-LABEL: rotate5ImmAA:
; ASM: mov r0, #713031680 ; ASM: mov r0, #713031680
; DIS-LABEL:000000b0 <rotate5ImmAA>:
; DIS-NEXT: b0: e3a005aa
; IASM-LABEL: rotate5ImmAA: ; IASM-LABEL: rotate5ImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0x5 ; IASM: .byte 0x5
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotate4ImmAA() { define internal i32 @rotate4ImmAA() {
; immediate = 0xaa000000 = b 1010 1010 0000 0000 0000 0000 0000 0000 ; immediate = 0xaa000000 = b 1010 1010 0000 0000 0000 0000 0000 0000
...@@ -180,13 +228,16 @@ define internal i32 @rotate4ImmAA() { ...@@ -180,13 +228,16 @@ define internal i32 @rotate4ImmAA() {
} }
; ASM-LABEL: rotate4ImmAA: ; ASM-LABEL: rotate4ImmAA:
; ASM: mov r0, #2852126720 ; ASM: mov r0, #2852126720
; DIS-LABEL:000000c0 <rotate4ImmAA>:
; DIS-NEXT: c0: e3a004aa
; IASM-LABEL: rotate4ImmAA: ; IASM-LABEL: rotate4ImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0x4 ; IASM: .byte 0x4
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotate3ImmAA() { define internal i32 @rotate3ImmAA() {
; immediate = 0xa8000002 = b 1010 1000 0000 0000 0000 0000 0000 0010 ; immediate = 0xa8000002 = b 1010 1000 0000 0000 0000 0000 0000 0010
...@@ -194,13 +245,16 @@ define internal i32 @rotate3ImmAA() { ...@@ -194,13 +245,16 @@ define internal i32 @rotate3ImmAA() {
} }
; ASM-LABEL: rotate3ImmAA: ; ASM-LABEL: rotate3ImmAA:
; ASM: mov r0, #2818572290 ; ASM: mov r0, #2818572290
; DIS-LABEL:000000d0 <rotate3ImmAA>:
; DIS-NEXT: d0: e3a003aa
; IASM-LABEL: rotate3ImmAA: ; IASM-LABEL: rotate3ImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0x3 ; IASM: .byte 0x3
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotate2ImmAA() { define internal i32 @rotate2ImmAA() {
; immediate = 0xa000000a = b 1010 0000 0000 0000 0000 0000 0000 1010 ; immediate = 0xa000000a = b 1010 0000 0000 0000 0000 0000 0000 1010
...@@ -208,13 +262,16 @@ define internal i32 @rotate2ImmAA() { ...@@ -208,13 +262,16 @@ define internal i32 @rotate2ImmAA() {
} }
; ASM-LABEL: rotate2ImmAA: ; ASM-LABEL: rotate2ImmAA:
; ASM: mov r0, #2684354570 ; ASM: mov r0, #2684354570
; DIS-LABEL:000000e0 <rotate2ImmAA>:
; DIS-NEXT: e0: e3a002aa
; IASM-LABEL: rotate2ImmAA: ; IASM-LABEL: rotate2ImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0x2 ; IASM: .byte 0x2
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotate1ImmAA() { define internal i32 @rotate1ImmAA() {
; immediate = 0x8000002a = b 1000 1000 0000 0000 0000 0000 0010 1010 ; immediate = 0x8000002a = b 1000 1000 0000 0000 0000 0000 0010 1010
...@@ -222,13 +279,16 @@ define internal i32 @rotate1ImmAA() { ...@@ -222,13 +279,16 @@ define internal i32 @rotate1ImmAA() {
} }
; ASM-LABEL: rotate1ImmAA: ; ASM-LABEL: rotate1ImmAA:
; ASM: mov r0, #2147483690 ; ASM: mov r0, #2147483690
; DIS-LABEL:000000f0 <rotate1ImmAA>:
; DIS-NEXT: f0: e3a001aa
; IASM-LABEL: rotate1ImmAA: ; IASM-LABEL: rotate1ImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0x1 ; IASM: .byte 0x1
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
define internal i32 @rotate0ImmAA() { define internal i32 @rotate0ImmAA() {
; immediate = 0x000000aa = b 0000 0000 0000 0000 0000 0000 1010 1010 ; immediate = 0x000000aa = b 0000 0000 0000 0000 0000 0000 1010 1010
...@@ -236,10 +296,13 @@ define internal i32 @rotate0ImmAA() { ...@@ -236,10 +296,13 @@ define internal i32 @rotate0ImmAA() {
} }
; ASM-LABEL: rotate0ImmAA: ; ASM-LABEL: rotate0ImmAA:
; ASM: mov r0, #170 ; ASM: mov r0, #170
; DIS-LABEL:00000100 <rotate0ImmAA>:
; DIS-NEXT: 100: e3a000aa
; IASM-LABEL: rotate0ImmAA: ; IASM-LABEL: rotate0ImmAA:
; IASM: .byte 0xaa ; IASM: .byte 0xaa
; IASM: .byte 0x0 ; IASM: .byte 0x0
; IASM: .byte 0xa0 ; IASM: .byte 0xa0
; IASM: .byte 0xe3 ; IASM: .byte 0xe3
...@@ -3,36 +3,63 @@ ...@@ -3,36 +3,63 @@
; REQUIRES: allow_dump ; REQUIRES: allow_dump
; RUN: %p2i --filetype=asm -i %s --target=arm32 \ ; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
; RUN: | FileCheck %s --check-prefix=ASM ; RUN: | FileCheck %s --check-prefix=ASM
; RUN: %p2i --filetype=iasm -i %s --target=arm32 \
; 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 ; 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
define internal void @f() { define internal void @f() {
ret void ret void
} }
; ASM-LABEL:f: ; ASM-LABEL:f:
; ASM-NEXT: .Lf$__0: ; ASM-NEXT: .Lf$__0:
; ASM-NEXT: bx lr ; ASM-NEXT: bx lr
; DIS-LABEL:00000000 <f>:
; IASM-LABEL:f: ; IASM-LABEL:f:
; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff ; DIS-NEXT: 0: e12fff1e
; IASM-NEXT: .byte 0x2f ; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xe1 ; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0x70 ; IASM-NEXT: .byte 0xe1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x20 ; DIS-NEXT: 4: e7fedef0
; IASM-NEXT: .byte 0xe1 ; IASM-NEXT: .byte 0xf0
; IASM-NEXT: .byte 0xde
; IASM-NEXT: .byte 0x70 ; IASM-NEXT: .byte 0xfe
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0xe7
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0xe1 ; DIS-NEXT: 8: e7fedef0
; IASM-NEXT: .byte 0xf0
; IASM-NEXT: .byte 0x70 ; IASM-NEXT: .byte 0xde
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0xfe
; IASM-NEXT: .byte 0x20 ; IASM-NEXT: .byte 0xe7
; IASM-NEXT: .byte 0xe1
; DIS-NEXT: c: e7fedef0
; IASM-NEXT: .byte 0xf0
; IASM-NEXT: .byte 0xde
; IASM-NEXT: .byte 0xfe
; IASM-NEXT: .byte 0xe7
define internal void @ignore() {
ret void
}
; ASM-LABEL:ignore:
; DIS-LABEL:00000010 <ignore>:
; IASM-LABEL:ignore:
; Show that we know how to translate instruction sub. ; Show that we know how to translate instruction sub.
; NOTE: We use -O2 to get rid of memory stores.
; REQUIRES: allow_dump ; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \ ; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=ASM ; 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: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=IASM ; 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 i32 @sub1FromR0(i32 %p) { define internal i32 @sub1FromR0(i32 %p) {
%v = sub i32 %p, 1 %v = sub i32 %p, 1
ret i32 %v ret i32 %v
...@@ -18,6 +27,9 @@ define internal i32 @sub1FromR0(i32 %p) { ...@@ -18,6 +27,9 @@ define internal i32 @sub1FromR0(i32 %p) {
; ASM: sub r0, r0, #1 ; ASM: sub r0, r0, #1
; ASM: bx lr ; ASM: bx lr
; DIS-LABEL:00000000 <sub1FromR0>:
; DIS-NEXT: 0: e2400001
; IASM-LABEL: sub1FromR0: ; IASM-LABEL: sub1FromR0:
; IASM: .byte 0x1 ; IASM: .byte 0x1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
...@@ -34,9 +46,11 @@ define internal i32 @Sub2Regs(i32 %p1, i32 %p2) { ...@@ -34,9 +46,11 @@ define internal i32 @Sub2Regs(i32 %p1, i32 %p2) {
; ASM: sub r0, r0, r1 ; ASM: sub r0, r0, r1
; ASM-NEXT: bx lr ; ASM-NEXT: bx lr
; IASM-LABEL: Sub2Regs: ; DIS-LABEL:00000010 <Sub2Regs>:
; DIS-NEXT: 10: e0400001
; IASM: .byte 0x1 ; IASM-LABEL: Sub2Regs:
; IASM-NEXT: .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