Commit 1956788f by Karl Schimpf

More coverage of load/stores in ARM integrated assembler.

Adds many more cases of ldr{b,h}/str{b,h} instructions to the ARM integerated assembler. Also refactored decodeAddress() to deal with the fact that immediate/register arguments for LDR/LDRB/STR/STRB differ for LDRH/LDRD/STRH/STRD, by passing in the layout wanted. Note: LDRD/STRD instructions are currently not used by Subzero. BUG=https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1486263002 .
parent c39ec10e
...@@ -28,6 +28,8 @@ DECLARE_FLAG(bool, allow_absolute_addresses); ...@@ -28,6 +28,8 @@ DECLARE_FLAG(bool, allow_absolute_addresses);
DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
DECLARE_FLAG(bool, inline_alloc); DECLARE_FLAG(bool, inline_alloc);
#if 0
// Moved to encodeImmRegOffsetEnc3 in IceAssemblerARM32.cpp
uint32_t Address::encoding3() const { uint32_t Address::encoding3() const {
if (kind_ == Immediate) { if (kind_ == Immediate) {
uint32_t offset = encoding_ & kOffset12Mask; uint32_t offset = encoding_ & kOffset12Mask;
...@@ -38,7 +40,7 @@ uint32_t Address::encoding3() const { ...@@ -38,7 +40,7 @@ uint32_t Address::encoding3() const {
ASSERT(kind_ == IndexRegister); ASSERT(kind_ == IndexRegister);
return encoding_; return encoding_;
} }
#endif
uint32_t Address::vencoding() const { uint32_t Address::vencoding() const {
ASSERT(kind_ == Immediate); ASSERT(kind_ == Immediate);
...@@ -117,8 +119,8 @@ void Assembler::EmitMemOp(Condition cond, ...@@ -117,8 +119,8 @@ void Assembler::EmitMemOp(Condition cond,
ad.encoding(); ad.encoding();
Emit(encoding); Emit(encoding);
} }
#endif
// Moved to AssemblerARM32::emitMemOpEnc3();
void Assembler::EmitMemOpAddressMode3(Condition cond, void Assembler::EmitMemOpAddressMode3(Condition cond,
int32_t mode, int32_t mode,
Register rd, Register rd,
...@@ -132,7 +134,6 @@ void Assembler::EmitMemOpAddressMode3(Condition cond, ...@@ -132,7 +134,6 @@ void Assembler::EmitMemOpAddressMode3(Condition cond,
Emit(encoding); Emit(encoding);
} }
#if 0
// Moved to ARM32::AssemblerARM32::emitMuliMemOp() // Moved to ARM32::AssemblerARM32::emitMuliMemOp()
void Assembler::EmitMultiMemOp(Condition cond, void Assembler::EmitMultiMemOp(Condition cond,
BlockAddressMode am, BlockAddressMode am,
...@@ -191,9 +192,7 @@ void Assembler::EmitShiftRegister(Condition cond, ...@@ -191,9 +192,7 @@ void Assembler::EmitShiftRegister(Condition cond,
void Assembler::and_(Register rd, Register rn, Operand o, Condition cond) { void Assembler::and_(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), AND, 0, rn, rd, o); EmitType01(cond, o.type(), AND, 0, rn, rd, o);
} }
#endif
#if 0
// Moved to ARM32::AssemberARM32::eor() // Moved to ARM32::AssemberARM32::eor()
void Assembler::eor(Register rd, Register rn, Operand o, Condition cond) { void Assembler::eor(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), EOR, 0, rn, rd, o); EmitType01(cond, o.type(), EOR, 0, rn, rd, o);
...@@ -213,7 +212,6 @@ void Assembler::rsbs(Register rd, Register rn, Operand o, Condition cond) { ...@@ -213,7 +212,6 @@ void Assembler::rsbs(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), RSB, 1, rn, rd, o); EmitType01(cond, o.type(), RSB, 1, rn, rd, o);
} }
#if 0 #if 0
// Moved to ARM32::AssemberARM32::add() // Moved to ARM32::AssemberARM32::add()
void Assembler::add(Register rd, Register rn, Operand o, Condition cond) { void Assembler::add(Register rd, Register rn, Operand o, Condition cond) {
...@@ -241,7 +239,6 @@ void Assembler::adcs(Register rd, Register rn, Operand o, Condition cond) { ...@@ -241,7 +239,6 @@ void Assembler::adcs(Register rd, Register rn, Operand o, Condition cond) {
} }
#endif #endif
void Assembler::sbc(Register rd, Register rn, Operand o, Condition cond) { void Assembler::sbc(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), SBC, 0, rn, rd, o); EmitType01(cond, o.type(), SBC, 0, rn, rd, o);
} }
...@@ -267,7 +264,6 @@ void Assembler::teq(Register rn, Operand o, Condition cond) { ...@@ -267,7 +264,6 @@ void Assembler::teq(Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), TEQ, 1, rn, R0, o); EmitType01(cond, o.type(), TEQ, 1, rn, R0, o);
} }
#if 0 #if 0
// Moved to ARM32::AssemblerARM32::cmp() // Moved to ARM32::AssemblerARM32::cmp()
void Assembler::cmp(Register rn, Operand o, Condition cond) { void Assembler::cmp(Register rn, Operand o, Condition cond) {
...@@ -339,7 +335,7 @@ void Assembler::clz(Register rd, Register rm, Condition cond) { ...@@ -339,7 +335,7 @@ void Assembler::clz(Register rd, Register rm, Condition cond) {
} }
#if #if 0
// Moved to ARM32::AssemblerARM32::movw() // Moved to ARM32::AssemblerARM32::movw()
void Assembler::movw(Register rd, uint16_t imm16, Condition cond) { void Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
ASSERT(cond != kNoCondition); ASSERT(cond != kNoCondition);
...@@ -358,9 +354,7 @@ void Assembler::movt(Register rd, uint16_t imm16, Condition cond) { ...@@ -358,9 +354,7 @@ void Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff); static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff);
Emit(encoding); Emit(encoding);
} }
#endif
#if 0
// Moved to ARM32::AssemblerARM32::emitMulOp() // Moved to ARM32::AssemblerARM32::emitMulOp()
void Assembler::EmitMulOp(Condition cond, int32_t opcode, void Assembler::EmitMulOp(Condition cond, int32_t opcode,
Register rd, Register rn, Register rd, Register rn,
...@@ -2611,7 +2605,6 @@ void Assembler::Lsl(Register rd, Register rm, Register rs, Condition cond) { ...@@ -2611,7 +2605,6 @@ void Assembler::Lsl(Register rd, Register rm, Register rs, Condition cond) {
} }
#endif #endif
void Assembler::Lsr(Register rd, Register rm, const Operand& shift_imm, void Assembler::Lsr(Register rd, Register rm, const Operand& shift_imm,
Condition cond) { Condition cond) {
ASSERT(shift_imm.type() == 1); ASSERT(shift_imm.type() == 1);
......
...@@ -342,8 +342,11 @@ class Address : public ValueObject { ...@@ -342,8 +342,11 @@ class Address : public ValueObject {
uint32_t encoding() const { return encoding_; } uint32_t encoding() const { return encoding_; }
#if 0
// Moved to encodeImmRegOffsetEnc3 in IceAssemblerARM32.cpp
// Encoding for addressing mode 3. // Encoding for addressing mode 3.
uint32_t encoding3() const; uint32_t encoding3() const;
#endif
// Encoding for vfp load/store addressing. // Encoding for vfp load/store addressing.
uint32_t vencoding() const; uint32_t vencoding() const;
...@@ -1183,14 +1186,13 @@ class Assembler : public ValueObject { ...@@ -1183,14 +1186,13 @@ class Assembler : public ValueObject {
bool byte, bool byte,
Register rd, Register rd,
Address ad); Address ad);
#endif
// Moved to AssemblerARM32::emitMemOpEnc3();
void EmitMemOpAddressMode3(Condition cond, void EmitMemOpAddressMode3(Condition cond,
int32_t mode, int32_t mode,
Register rd, Register rd,
Address ad); Address ad);
#if 0
// Moved to ARM32::AssemblerARM32::emitMultiMemOp() // Moved to ARM32::AssemblerARM32::emitMultiMemOp()
void EmitMultiMemOp(Condition cond, void EmitMultiMemOp(Condition cond,
BlockAddressMode am, BlockAddressMode am,
......
...@@ -191,13 +191,17 @@ enum DecodedResult { ...@@ -191,13 +191,17 @@ enum DecodedResult {
// p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to // p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to
// Rn should be used, and iiiiiiiiiiii defines the rotated Imm8 value. // Rn should be used, and iiiiiiiiiiii defines the rotated Imm8 value.
DecodedAsImmRegOffset, DecodedAsImmRegOffset,
// Value=00000000pu0w0nnnn0000iiii0000jjjj where nnnn=Rn, iiiijjjj=Imm8, p=1
// if pre-indexed addressing, u=1 if offset positive, and w=1 if writeback to
// Rn.
DecodedAsImmRegOffsetEnc3,
// Value=0000000pu0w00nnnnttttiiiiiss0mmmm where nnnn is the base register Rn, // Value=0000000pu0w00nnnnttttiiiiiss0mmmm where nnnn is the base register Rn,
// mmmm is the index register Rm, iiiii is the shift amount, ss is the shift // mmmm is the index register Rm, iiiii is the shift amount, ss is the shift
// kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if // kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if
// writeback to Rn. // writeback to Rn.
DecodedAsShiftRotateImm5, DecodedAsShiftRotateImm5,
// Value=000000000000000000000iiiii0000000 iiii defines the Imm5 value to // Value=000000000000000000000iiiii0000000 where iiii defines the Imm5 value
// shift. // to shift.
DecodedAsShiftImm5, DecodedAsShiftImm5,
// i.e. iiiiiss0mmmm where mmmm is the register to rotate, ss is the shift // i.e. iiiiiss0mmmm where mmmm is the register to rotate, ss is the shift
// kind, and iiiii is the shift amount. // kind, and iiiii is the shift amount.
...@@ -272,9 +276,9 @@ DecodedResult decodeOperand(const Operand *Opnd, IValueT &Value) { ...@@ -272,9 +276,9 @@ DecodedResult decodeOperand(const Operand *Opnd, IValueT &Value) {
return CantDecode; return CantDecode;
} }
IValueT decodeImmRegOffset(RegARM32::GPRRegister Reg, IOffsetT Offset, IValueT encodeImmRegOffset(IValueT Reg, IOffsetT Offset,
OperandARM32Mem::AddrMode Mode) { OperandARM32Mem::AddrMode Mode) {
IValueT Value = Mode | (encodeGPRRegister(Reg) << kRnShift); IValueT Value = Mode | (Reg << kRnShift);
if (Offset < 0) { if (Offset < 0) {
Value = (Value ^ U) | -Offset; // Flip U to adjust sign. Value = (Value ^ U) | -Offset; // Flip U to adjust sign.
} else { } else {
...@@ -283,10 +287,33 @@ IValueT decodeImmRegOffset(RegARM32::GPRRegister Reg, IOffsetT Offset, ...@@ -283,10 +287,33 @@ IValueT decodeImmRegOffset(RegARM32::GPRRegister Reg, IOffsetT Offset,
return Value; return Value;
} }
// Encodes immediate register offset using encoding 3.
IValueT encodeImmRegOffsetEnc3(IValueT Rn, IOffsetT Imm8,
OperandARM32Mem::AddrMode Mode) {
IValueT Value = Mode | (Rn << kRnShift);
if (Imm8 < 0) {
Imm8 = -Imm8;
Value = (Value ^ U);
}
assert(Imm8 < (1 << 8));
Value = Value | B22 | ((Imm8 & 0xf0) << 4) | (Imm8 & 0x0f);
return Value;
}
// Defines alternate layouts of instruction operands, should the (common)
// default pattern not be used.
enum OpEncoding {
// No alternate layout specified.
DefaultOpEncoding,
// Alternate encoding 3.
OpEncoding3
};
// Decodes memory address Opnd, and encodes that information into Value, // Decodes memory address Opnd, and encodes that information into Value,
// based on how ARM represents the address. Returns how the value was encoded. // based on how ARM represents the address. Returns how the value was encoded.
DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value, DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value,
const AssemblerARM32::TargetInfo &TInfo) { const AssemblerARM32::TargetInfo &TInfo,
OpEncoding AddressEncoding = DefaultOpEncoding) {
Value = 0; // Make sure initialized. Value = 0; // Make sure initialized.
if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
// Should be a stack variable, with an offset. // Should be a stack variable, with an offset.
...@@ -298,8 +325,7 @@ DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value, ...@@ -298,8 +325,7 @@ DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value,
int32_t BaseRegNum = Var->getBaseRegNum(); int32_t BaseRegNum = Var->getBaseRegNum();
if (BaseRegNum == Variable::NoRegister) if (BaseRegNum == Variable::NoRegister)
BaseRegNum = TInfo.FrameOrStackReg; BaseRegNum = TInfo.FrameOrStackReg;
Value = decodeImmRegOffset(decodeGPRRegister(BaseRegNum), Offset, Value = encodeImmRegOffset(BaseRegNum, Offset, OperandARM32Mem::Offset);
OperandARM32Mem::Offset);
return DecodedAsImmRegOffset; return DecodedAsImmRegOffset;
} }
if (const auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Opnd)) { if (const auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Opnd)) {
...@@ -318,9 +344,15 @@ DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value, ...@@ -318,9 +344,15 @@ DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value,
} }
// Decoded as immediate register offset. // Decoded as immediate register offset.
ConstantInteger32 *Offset = Mem->getOffset(); ConstantInteger32 *Offset = Mem->getOffset();
Value = decodeImmRegOffset(decodeGPRRegister(Rn), Offset->getValue(), switch (AddressEncoding) {
Mem->getAddrMode()); case DefaultOpEncoding:
return DecodedAsImmRegOffset; Value = encodeImmRegOffset(Rn, Offset->getValue(), Mem->getAddrMode());
return DecodedAsImmRegOffset;
case OpEncoding3:
Value =
encodeImmRegOffsetEnc3(Rn, Offset->getValue(), Mem->getAddrMode());
return DecodedAsImmRegOffsetEnc3;
}
} }
return CantDecode; return CantDecode;
} }
...@@ -607,6 +639,128 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType, ...@@ -607,6 +639,128 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType,
emitInst(Encoding); emitInst(Encoding);
} }
void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte,
IValueT Rt, const Operand *OpAddress,
const TargetInfo &TInfo) {
IValueT Address;
switch (decodeAddress(OpAddress, Address, TInfo)) {
default:
return setNeedsTextFixup();
case DecodedAsImmRegOffset: {
// XXX{B} (immediate):
// xxx{b}<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// xxx{b}<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// xxx{b}<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
//
// cccc010pubwlnnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, b=IsByte, pu0w<<21 is a BlockAddr, l=IsLoad, and
// pu0w0nnnn0000iiiiiiiiiiii=Address.
RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
// Check if conditions of rules violated.
if (Rn == RegARM32::Encoded_Reg_pc)
return setNeedsTextFixup();
if (!isBitSet(P, Address) && isBitSet(W, Address))
return setNeedsTextFixup();
if (!IsByte && (Rn == RegARM32::Encoded_Reg_sp) && !isBitSet(P, Address) &&
isBitSet(U, Address) & !isBitSet(W, Address) &&
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))
return setNeedsTextFixup();
return emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
}
case DecodedAsShiftRotateImm5: {
// XXX{B} (register)
// xxx{b}<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
// xxx{b}<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
//
// cccc011pubwlnnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt,
// b=IsByte, U=1 if +, pu0b is a BlockAddr, l=IsLoad, and
// pu0w0nnnn0000iiiiiss0mmmm=Address.
RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
RegARM32::GPRRegister Rm = getGPRReg(kRmShift, Address);
// Check if conditions of rules violated.
if (isBitSet(P, Address) && isBitSet(W, Address))
// Instruction XXXBT!
return setNeedsTextFixup();
if (IsByte &&
((Rt == RegARM32::Encoded_Reg_pc) || (Rm == RegARM32::Encoded_Reg_pc)))
// Unpredictable.
return setNeedsTextFixup();
if (!IsByte && Rm == RegARM32::Encoded_Reg_pc)
// Unpredictable.
return setNeedsTextFixup();
if (isBitSet(W, Address) &&
((Rn == RegARM32::Encoded_Reg_pc) || encodeGPRRegister(Rn) == Rt))
// Unpredictable
return setNeedsTextFixup();
return emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address);
}
}
}
void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode,
IValueT Rt, const Operand *OpAddress,
const TargetInfo &TInfo) {
IValueT Address;
switch (decodeAddress(OpAddress, Address, TInfo, OpEncoding3)) {
default:
return setNeedsTextFixup();
case DecodedAsImmRegOffsetEnc3: {
// XXXH (immediate)
// xxxh<c> <Rt>, [<Rn>{, #+-<Imm8>}]
// xxxh<c> <Rt>, [<Rn>, #+/-<Imm8>]
// xxxh<c> <Rt>, [<Rn>, #+/-<Imm8>]!
//
// cccc000pu0wxnnnnttttiiiiyyyyjjjj where cccc=Cond, nnnn=Rn, tttt=Rt,
// iiiijjjj=Imm8, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode,
// and pu0w0nnnn0000iiii0000jjjj=Address.
if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond))
return setNeedsTextFixup();
if (!isBitSet(P, Address) && isBitSet(W, Address))
return setNeedsTextFixup();
if ((Rt == RegARM32::Encoded_Reg_pc) ||
(isBitSet(W, Address) &&
(getGPRReg(kRnShift, Address) == decodeGPRRegister(Rt))))
return setNeedsTextFixup();
const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
Opcode | (Rt << kRdShift) | Address;
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
return emitInst(Encoding);
}
case DecodedAsShiftRotateImm5: {
// XXXH (register)
// xxxh<c> <Rt>, [<Rn>, +/-<Rm>]{!}
// xxxh<c> <Rt>, [<Rn>], +/-<Rm>
//
// cccc000pu0wxnnnntttt00001011mmmm where cccc=Cond, tttt=Rt, nnnn=Rn,
// mmmm=Rm, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode, and
// pu0w0nnnn000000000000mmmm=Address.
if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond))
return setNeedsTextFixup();
if (!isBitSet(P, Address) && isBitSet(W, Address))
return setNeedsTextFixup();
if (Rt == RegARM32::Encoded_Reg_pc)
return setNeedsTextFixup();
if (getGPRReg(kRmShift, Address) == RegARM32::Encoded_Reg_pc)
return setNeedsTextFixup();
const RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
if (isBitSet(W, Address) &&
((Rn == RegARM32::Encoded_Reg_pc) || (encodeGPRRegister(Rn) == Rt)))
return setNeedsTextFixup();
if (mask(Address, kShiftImmShift, 5) != 0)
// For encoding 3, no shift is allowed.
return setNeedsTextFixup();
const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
Opcode | (Rt << kRdShift) | Address;
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
return emitInst(Encoding);
}
}
}
void AssemblerARM32::emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, void AssemblerARM32::emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
IValueT Rn, IValueT Rm) { IValueT Rn, IValueT Rm) {
if (!isGPRRegisterDefined(Rd) || !isGPRRegisterDefined(Rn) || if (!isGPRRegisterDefined(Rd) || !isGPRRegisterDefined(Rn) ||
...@@ -840,75 +994,68 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, ...@@ -840,75 +994,68 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
if (decodeOperand(OpRt, Rt) != DecodedAsRegister) if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
return setNeedsTextFixup(); return setNeedsTextFixup();
const Type Ty = OpRt->getType(); const Type Ty = OpRt->getType();
if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand? switch (typeWidthInBytesLog2(Ty)) {
return setNeedsTextFixup(); case 3:
const bool IsByte = isByteSizedType(Ty); // LDRD is not implemented because target lowering handles i64 and double by
IValueT Address; // using two (32-bit) load instructions. Note: Intenionally drop to default
switch (decodeAddress(OpAddress, Address, TInfo)) { // case.
default: default:
return setNeedsTextFixup(); llvm::report_fatal_error(std::string("Type ") + typeString(Ty) +
case DecodedAsImmRegOffset: { " not implementable using ldr\n");
// LDR (immediate) - ARM section A8.8.63, encoding A1: case 0: {
// ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 // Handles i1 and i8 loads.
// ldr<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldr<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
// //
// LDRB (immediate) - ARM section A8.8.68, encoding A1: // LDRB (immediate) - ARM section A8.8.68, encoding A1:
// ldrb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 // ldrb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// ldrb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1 // ldrb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldrb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1 // ldrb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
// //
// cccc010pubw1nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn, // cccc010pu1w1nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, b=1 if LDRB, u=1 if +, pu0w is a BlockAddr, and // iiiiiiiiiiii=imm12, u=1 if +, pu0w is a BlockAddr, and
// pu0w0nnnn0000iiiiiiiiiiii=Address. // pu0w0nnnn0000iiiiiiiiiiii=Address.
//
RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address); // LDRB (register) - ARM section A8.8.66, encoding A1:
// ldrb<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
// Check if conditions of rules violated. // ldrb<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
if (Rn == RegARM32::Encoded_Reg_pc) //
return setNeedsTextFixup(); // cccc011pu1w1nnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, U=1 if +, pu0b
if (!isBitSet(P, Address) && isBitSet(W, Address)) // is a BlockAddr, and pu0w0nnnn0000iiiiiss0mmmm=Address.
return setNeedsTextFixup(); constexpr bool IsByte = true;
if (!IsByte && (Rn == RegARM32::Encoded_Reg_sp) && !isBitSet(P, Address) && return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo);
isBitSet(U, Address) & !isBitSet(W, Address) &&
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))
return setNeedsTextFixup();
return emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
} }
case DecodedAsShiftRotateImm5: { case 1: {
// LDR (register) - ARM section A8.8.66, encoding A1: // Handles i16 loads.
// ldr<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!} //
// ldr<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>} // LDRH (immediate) - ARM section A8.8.80, encoding A1:
// ldrh<c> <Rt>, [<Rn>{, #+/-<Imm8>}]
// ldrh<c> <Rt>, [<Rn>], #+/-<Imm8>
// ldrh<c> <Rt>, [<Rn>, #+/-<Imm8>]!
//
// cccc000pu1w1nnnnttttiiii1011iiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiii=Imm8, u=1 if +, pu0w is a BlockAddr, and
// pu0w0nnnn0000iiiiiiiiiiii=Address.
return emitMemOpEnc3(Cond, L | B7 | B5 | B4, Rt, OpAddress, TInfo);
}
case 2: {
// Note: Handles i32 and float loads. Target lowering handles i64 and
// double by using two (32 bit) load instructions.
//
// LDR (immediate) - ARM section A8.8.63, encoding A1:
// ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// ldr<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldr<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
//
// cccc010pu0w1nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, u=1 if +, pu0w is a BlockAddr, and
// //
// LDRB (register) - ARM section A8.8.70, encoding A1: // LDR (register) - ARM section A8.8.70, encoding A1:
// ldrb<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!} // ldrb<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
// ldrb<c> <Rt>, [<Rn>], +-<Rm>{, <shift>} // ldrb<c> <Rt>, [<Rn>], +-<Rm>{, <shift>}
// //
// cccc011pubw1nnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, // cccc011pu0w1nnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, U=1 if +, pu0b
// b=1 if LDRB, U=1 if +, pu0b is a BlockAddr, and // is a BlockAddr, and pu0w0nnnn0000iiiiiss0mmmm=Address.
// pu0w0nnnn0000iiiiiss0mmmm=Address. constexpr bool IsByte = false;
return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo);
RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
RegARM32::GPRRegister Rm = getGPRReg(kRmShift, Address);
// Check if conditions of rules violated.
if (isBitSet(P, Address) && isBitSet(W, Address))
// Instruction LDRBT!
return setNeedsTextFixup();
if (IsByte &&
((Rt == RegARM32::Encoded_Reg_pc) || (Rm == RegARM32::Encoded_Reg_pc)))
// Unpredictable.
return setNeedsTextFixup();
if (!IsByte && Rm == RegARM32::Encoded_Reg_pc)
// Unpredictable.
return setNeedsTextFixup();
if (isBitSet(W, Address) &&
((Rn == RegARM32::Encoded_Reg_pc) || encodeGPRRegister(Rn) == Rt))
// Unpredictable
return setNeedsTextFixup();
return emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address);
} }
} }
} }
...@@ -1127,38 +1274,61 @@ void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn, ...@@ -1127,38 +1274,61 @@ void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn,
void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
CondARM32::Cond Cond, const TargetInfo &TInfo) { CondARM32::Cond Cond, const TargetInfo &TInfo) {
constexpr bool IsLoad = false;
IValueT Rt; IValueT Rt;
if (decodeOperand(OpRt, Rt) != DecodedAsRegister) if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
return setNeedsTextFixup(); return setNeedsTextFixup();
IValueT Address;
if (decodeAddress(OpAddress, Address, TInfo) != DecodedAsImmRegOffset)
return setNeedsTextFixup();
// STR (immediate) - ARM section A8.8.204, encoding A1:
// str<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// str<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// str<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
// STRB (immediate) - ARM section A8.8.207, encoding A1:
// strb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// 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 +.
constexpr bool IsLoad = false;
const Type Ty = OpRt->getType(); const Type Ty = OpRt->getType();
if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand? switch (typeWidthInBytesLog2(Ty)) {
return setNeedsTextFixup(); case 3:
const bool IsByte = isByteSizedType(Ty); // STRD is not implemented because target lowering handles i64 and double by
// Check for rule violations. // using two (32-bit) store instructions. Note: Intenionally drop to
if ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc)) // default case.
return setNeedsTextFixup(); default:
if (!isBitSet(P, Address) && isBitSet(W, Address)) llvm::report_fatal_error(std::string("Type ") + typeString(Ty) +
return setNeedsTextFixup(); " not implementable using str\n");
if (!IsByte && (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) && case 0: {
isBitSet(P, Address) && !isBitSet(U, Address) && isBitSet(W, Address) && // Handles i1 and i8 stores.
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)) //
// STRB (immediate) - ARM section A8.8.207, encoding A1:
// strb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// strb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// strb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
//
// cccc010pu1w0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, u=1 if +.
constexpr bool IsByte = true;
return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo);
}
case 1: {
// Handles i16 stores.
//
// STRH (immediate) - ARM section A8.*.217, encoding A1:
// strh<c> <Rt>, [<Rn>{, #+/-<Imm8>}]
// strh<c> <Rt>, [<Rn>], #+/-<Imm8>
// strh<c> <Rt>, [<Rn>, #+/-<Imm8>]!
//
// cccc000pu1w0nnnnttttiiii1011iiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiii=Imm8, u=1 if +, pu0w is a BlockAddr, and
// pu0w0nnnn0000iiiiiiiiiiii=Address.
return emitMemOpEnc3(Cond, B7 | B5 | B4, Rt, OpAddress, TInfo);
}
case 2: {
// Note: Handles i32 and float stores. Target lowering handles i64 and
// double by using two (32 bit) store instructions.
//
// STR (immediate) - ARM section A8.8.207, encoding A1:
// str<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// str<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// str<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
//
// cccc010pu1w0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, u=1 if +.
constexpr bool IsByte = false;
return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo);
return setNeedsTextFixup(); return setNeedsTextFixup();
emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); }
}
} }
void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn,
...@@ -1191,7 +1361,7 @@ void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) { ...@@ -1191,7 +1361,7 @@ void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) {
// Same as load instruction. // Same as load instruction.
constexpr bool IsLoad = true; constexpr bool IsLoad = true;
constexpr bool IsByte = false; constexpr bool IsByte = false;
IValueT Address = decodeImmRegOffset(RegARM32::Encoded_Reg_sp, kWordSize, IValueT Address = encodeImmRegOffset(RegARM32::Encoded_Reg_sp, kWordSize,
OperandARM32Mem::PostIndex); OperandARM32Mem::PostIndex);
emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
} }
...@@ -1218,7 +1388,7 @@ void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) { ...@@ -1218,7 +1388,7 @@ void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) {
// Same as store instruction. // Same as store instruction.
constexpr bool isLoad = false; constexpr bool isLoad = false;
constexpr bool isByte = false; constexpr bool isByte = false;
IValueT Address = decodeImmRegOffset(RegARM32::Encoded_Reg_sp, -kWordSize, IValueT Address = encodeImmRegOffset(RegARM32::Encoded_Reg_sp, -kWordSize,
OperandARM32Mem::PreIndex); OperandARM32Mem::PreIndex);
emitMemOp(Cond, kInstTypeMemImmediate, isLoad, isByte, Rt, Address); emitMemOp(Cond, kInstTypeMemImmediate, isLoad, isByte, Rt, Address);
} }
......
...@@ -337,12 +337,20 @@ private: ...@@ -337,12 +337,20 @@ private:
void emitType05(CondARM32::Cond COnd, int32_t Offset, bool Link); void emitType05(CondARM32::Cond COnd, int32_t Offset, bool Link);
// Pattern ccccoooaabalnnnnttttaaaaaaaaaaaa where cccc=Cond, ooo=InstType, // Emit ccccoooaabalnnnnttttaaaaaaaaaaaa where cccc=Cond,
// l=isLoad, b=isByte, and aaa0a0aaaa0000aaaaaaaaaaaa=Address. Note that // ooo=InstType, l=isLoad, b=isByte, and
// Address is assumed to be defined by decodeAddress() in // aaa0a0aaaa0000aaaaaaaaaaaa=Address. Note that Address is assumed to be
// IceAssemblerARM32.cpp. // defined by decodeAddress() in IceAssemblerARM32.cpp.
void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad, void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad,
bool IsByte, uint32_t Rt, uint32_t Address); bool IsByte, IValueT Rt, IValueT Address);
// Emit ldr/ldrb/str/strb instruction with given address.
void emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, IValueT Rt,
const Operand *OpAddress, const TargetInfo &TInfo);
// Emit ldrh/ldrd/strh/strd instruction with given address using encoding 3.
void emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, IValueT Rt,
const Operand *OpAddress, const TargetInfo &TInfo);
// Pattern cccc100aaaalnnnnrrrrrrrrrrrrrrrr where cccc=Cond, // Pattern cccc100aaaalnnnnrrrrrrrrrrrrrrrr where cccc=Cond,
// aaaa<<21=AddressMode, l=IsLoad, nnnn=BaseReg, and // aaaa<<21=AddressMode, l=IsLoad, nnnn=BaseReg, and
......
...@@ -375,9 +375,9 @@ public: ...@@ -375,9 +375,9 @@ public:
Bic, Bic,
Br, Br,
Call, Call,
Clz,
Cmn, Cmn,
Cmp, Cmp,
Clz,
Dmb, Dmb,
Eor, Eor,
Label, Label,
......
...@@ -20,33 +20,30 @@ ...@@ -20,33 +20,30 @@
define internal void @mult_fwd_branches(i32 %a, i32 %b) { define internal void @mult_fwd_branches(i32 %a, i32 %b) {
; ASM-LABEL:mult_fwd_branches: ; ASM-LABEL:mult_fwd_branches:
; ASM-LABEL:.Lmult_fwd_branches$__0:
; ASM-NEXT: sub sp, sp, #12
; ASM-NEXT: str r0, [sp, #8]
; ASM-NEXT: # [sp, #8] = def.pseudo
; ASM-NEXT: str r1, [sp, #4]
; ASM-NEXT: # [sp, #4] = def.pseudo
; DIS-LABEL:00000000 <mult_fwd_branches>: ; DIS-LABEL:00000000 <mult_fwd_branches>:
; DIS-NEXT: 0: e24dd00c
; DIS-NEXT: 4: e58d0008
; DIS-NEXT: 8: e58d1004
; IASM-LABEL:mult_fwd_branches: ; IASM-LABEL:mult_fwd_branches:
; ASM-LABEL:.Lmult_fwd_branches$__0:
; IASM-LABEL:.Lmult_fwd_branches$__0: ; IASM-LABEL:.Lmult_fwd_branches$__0:
; ASM-NEXT: sub sp, sp, #12
; DIS-NEXT: 0: e24dd00c
; IASM-NEXT: .byte 0xc ; IASM-NEXT: .byte 0xc
; 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, #8]
; ASM-NEXT: # [sp, #8] = def.pseudo
; DIS-NEXT: 4: e58d0008
; IASM-NEXT: .byte 0x8 ; IASM-NEXT: .byte 0x8
; 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: str r1, [sp, #4]
; ASM-NEXT: # [sp, #4] = def.pseudo
; DIS-NEXT: 8: e58d1004
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x10 ; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x8d ; IASM-NEXT: .byte 0x8d
...@@ -55,71 +52,73 @@ define internal void @mult_fwd_branches(i32 %a, i32 %b) { ...@@ -55,71 +52,73 @@ define internal void @mult_fwd_branches(i32 %a, i32 %b) {
%cmp = icmp slt i32 %a, %b %cmp = icmp slt i32 %a, %b
; ASM-NEXT: mov r0, #0 ; ASM-NEXT: mov r0, #0
; ASM-NEXT: ldr r1, [sp, #8]
; ASM-NEXT: ldr r2, [sp, #4]
; ASM-NEXT: cmp r1, r2
; ASM-NEXT: movlt r0, #1
; ASM-NEXT: strb r0, [sp]
; ASM-NEXT: # [sp] = def.pseudo
; DIS-NEXT: c: e3a00000 ; DIS-NEXT: c: e3a00000
; DIS-NEXT: 10: e59d1008
; DIS-NEXT: 14: e59d2004
; DIS-NEXT: 18: e1510002
; DIS-NEXT: 1c: b3a00001
; DIS-NEXT: 20: e5cd0000
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xa0 ; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe3 ; IASM-NEXT: .byte 0xe3
; ASM-NEXT: ldr r1, [sp, #8]
; DIS-NEXT: 10: e59d1008
; IASM-NEXT: .byte 0x8 ; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0x10 ; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x9d ; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
; ASM-NEXT: ldr r2, [sp, #4]
; DIS-NEXT: 14: e59d2004
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x20 ; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x9d ; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
; ASM-NEXT: cmp r1, r2
; DIS-NEXT: 18: e1510002
; IASM-NEXT: .byte 0x2 ; IASM-NEXT: .byte 0x2
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x51 ; IASM-NEXT: .byte 0x51
; IASM-NEXT: .byte 0xe1 ; IASM-NEXT: .byte 0xe1
; ASM-NEXT: movlt r0, #1
; DIS-NEXT: 1c: b3a00001
; IASM-NEXT: .byte 0x1 ; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xa0 ; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xb3 ; IASM-NEXT: .byte 0xb3
; IASM-NEXT: strb r0, [sp] ; ASM-NEXT: strb r0, [sp]
; ASM-NEXT: # [sp] = def.pseudo
; DIS-NEXT: 20: e5cd0000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xcd
; IASM-NEXT: .byte 0xe5
br i1 %cmp, label %then, label %else br i1 %cmp, label %then, label %else
; ASM-NEXT: ldrb r0, [sp] ; ASM-NEXT: ldrb r0, [sp]
; ASM-NEXT: tst r0, #1
; ASM-NEXT: bne .Lmult_fwd_branches$then
; ASM-NEXT: b .Lmult_fwd_branches$else
; DIS-NEXT: 24: e5dd0000 ; DIS-NEXT: 24: e5dd0000
; DIS-NEXT: 28: e3100001 ; IASM-NEXT: .byte 0x0
; DIS-NEXT: 2c: 1a000000 ; IASM-NEXT: .byte 0x0
; DIS-NEXT: 30: ea000000 ; IASM-NEXT: .byte 0xdd
; IASM-NEXT: .byte 0xe5
; IASM-NEXT: ldrb r0, [sp]
; ASM-NEXT: tst r0, #1
; DIS-NEXT: 28: e3100001
; IASM-NEXT: .byte 0x1 ; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x10 ; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0xe3 ; IASM-NEXT: .byte 0xe3
; ASM-NEXT: bne .Lmult_fwd_branches$then
; DIS-NEXT: 2c: 1a000000
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x1a ; IASM-NEXT: .byte 0x1a
; ASM-NEXT: b .Lmult_fwd_branches$else
; DIS-NEXT: 30: ea000000
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
...@@ -130,10 +129,9 @@ then: ...@@ -130,10 +129,9 @@ then:
; IASM-LABEL:.Lmult_fwd_branches$then: ; IASM-LABEL:.Lmult_fwd_branches$then:
br label %end br label %end
; ASM-NEXT: b .Lmult_fwd_branches$end
; ASM-NEXT: b .Lmult_fwd_branches$end
; DIS-NEXT: 34: ea000000 ; DIS-NEXT: 34: ea000000
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
...@@ -145,9 +143,7 @@ else: ...@@ -145,9 +143,7 @@ else:
br label %end br label %end
; ASM-NEXT: b .Lmult_fwd_branches$end ; ASM-NEXT: b .Lmult_fwd_branches$end
; DIS-NEXT: 38: eaffffff ; DIS-NEXT: 38: eaffffff
; IASM-NEXT: .byte 0xff ; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xff ; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xff ; IASM-NEXT: .byte 0xff
...@@ -161,16 +157,14 @@ end: ...@@ -161,16 +157,14 @@ end:
ret void ret void
; ASM-NEXT: add sp, sp, #12 ; ASM-NEXT: add sp, sp, #12
; ASM-NEXT: bx lr
; DIS-NEXT: 3c: e28dd00c ; DIS-NEXT: 3c: e28dd00c
; DIS-NEXT: 40: e12fff1e
; IASM-NEXT: .byte 0xc ; IASM-NEXT: .byte 0xc
; 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
; DIS-NEXT: 40: e12fff1e
; IASM-NEXT: .byte 0x1e ; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff ; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f ; IASM-NEXT: .byte 0x2f
......
; Show that we know how to translate LDR (register). ; Show that we know how to translate LDR/LDRH (register) instructions.
; NOTE: We use -O2 to get rid of memory stores. ; NOTE: We use -O2 to get rid of memory stores.
...@@ -20,70 +20,97 @@ ...@@ -20,70 +20,97 @@
; RUN: %lc2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \ ; RUN: %lc2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS ; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
; Define some global arrays to access.
@ArrayInitPartial = internal global [40 x i8] c"<\00\00\00F\00\00\00P\00\00\00Z\00\00\00d\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", align 4 @ArrayInitPartial = internal global [40 x i8] c"<\00\00\00F\00\00\00P\00\00\00Z\00\00\00d\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", align 4
@NumArraysElements = internal global [4 x i8] c"\01\00\00\00", align 4
@Arrays = internal constant <{ i32, [4 x i8] }> <{ i32 ptrtoint ([40 x i8]* @ArrayInitPartial to i32), [4 x i8] c"\14\00\00\00" }>, align 4 @Arrays = internal constant <{ i32, [4 x i8] }> <{ i32 ptrtoint ([40 x i8]* @ArrayInitPartial to i32), [4 x i8] c"\14\00\00\00" }>, align 4
define internal void @_Z8getArrayjRj(i32 %WhichArray, i32 %Len) { ; Index elements of an array.
; ASM-LABEL:_Z8getArrayjRj: define internal i32 @IndexArray(i32 %WhichArray, i32 %Len) {
; DIS-LABEL:00000000 <_Z8getArrayjRj>: ; ASM-LABEL:IndexArray:
; IASM-LABEL:_Z8getArrayjRj: ; DIS-LABEL:00000000 <IndexArray>:
; IASM-LABEL:IndexArray:
entry: entry:
; ASM-NEXT:.L_Z8getArrayjRj$entry: ; ASM-NEXT:.LIndexArray$entry:
; IASM-NEXT:.L_Z8getArrayjRj$entry: ; IASM-NEXT:.LIndexArray$entry:
%gep_array = mul i32 %WhichArray, 8 %gep_array = mul i32 %WhichArray, 8
; ASM-NEXT: push {r4}
; DIS-NEXT: 0: e52d4004
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0x2d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: lsl r2, r0, #3
; DIS-NEXT: 4: e1a02180
; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0x21
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1
%expanded1 = ptrtoint <{ i32, [4 x i8] }>* @Arrays to i32 %expanded1 = ptrtoint <{ i32, [4 x i8] }>* @Arrays to i32
%gep = add i32 %expanded1, %gep_array %gep = add i32 %expanded1, %gep_array
; ASM-NEXT: movw r2, #:lower16:Arrays ; ASM-NEXT: movw r3, #:lower16:Arrays
; ASM-NEXT: movt r2, #:upper16:Arrays ; DIS-NEXT: 8: e3003000
; DIS-NEXT: 0: e3002000 ; IASM-NEXT: movw r3, #:lower16:Arrays @ .word e3003000
; DIS-NEXT: 4: e3402000
; IASM-NEXT: movw r2, #:lower16:Arrays @ .word e3002000 ; ASM-NEXT: movt r3, #:upper16:Arrays
; IASM-NEXT: movt r2, #:upper16:Arrays @ .word e3402000 ; DIS-NEXT: c: e3403000
; IASM-NEXT: movt r3, #:upper16:Arrays @ .word e3403000
%gep3 = add i32 %gep, 4 %gep3 = add i32 %gep, 4
; ASM-NEXT: add r2, r2, #4 ; ASM-NEXT: add r4, r3, #4
; DIS-NEXT: 8: e2822004 ; DIS-NEXT: 10: e2834004
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x20 ; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0x82 ; IASM-NEXT: .byte 0x83
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
; ***** Here is the use of a LDR (register) instruction. ; ***** Here is the use of a LDR (register) instruction.
%gep3.asptr = inttoptr i32 %gep3 to i32* %gep3.asptr = inttoptr i32 %gep3 to i32*
%v1 = load i32, i32* %gep3.asptr, align 1 %v1 = load i32, i32* %gep3.asptr, align 1
; ASM-NEXT: ldr r2, [r2, r0, lsl #3] ; ASM-NEXT: ldr r4, [r4, r0, lsl #3]
; DIS-NEXT: c: e7922180 ; DIS-NEXT: 14: e7944180
; IASM-NEXT: .byte 0x80 ; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0x21 ; IASM-NEXT: .byte 0x41
; IASM-NEXT: .byte 0x92 ; IASM-NEXT: .byte 0x94
; IASM-NEXT: .byte 0xe7 ; IASM-NEXT: .byte 0xe7
%Len.asptr3 = inttoptr i32 %Len to i32* %Len.asptr3 = inttoptr i32 %Len to i32*
store i32 %v1, i32* %Len.asptr3, align 1 store i32 %v1, i32* %Len.asptr3, align 1
; ASM-NEXT: str r2, [r1] ; ASM-NEXT: str r4, [r1]
; DIS-NEXT: 10: e5812000 ; DIS-NEXT: 18: e5814000
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x20 ; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0x81 ; IASM-NEXT: .byte 0x81
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
ret void ; Now read the value as an i16 to test ldrh (register).
%gep3.i16ptr = inttoptr i32 %gep3 to i16*
; ASM-NEXT: bx lr %v16 = load i16, i16* %gep3.i16ptr, align 1
; DIS-NEXT: 14: e12fff1e
; IASM-NEXT: .byte 0x1e ; ASM-NEXT: add r3, r3, #4
; IASM-NEXT: .byte 0xff ; DIS-NEXT: 1c: e2833004
; IASM-NEXT: .byte 0x2f ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xe1 ; IASM-NEXT: .byte 0x30
; IASM-NEXT: .byte 0x83
; IASM-NEXT: .byte 0xe2
; ***** Here is the use of a LDRH (register) instruction.
; ASM-NEXT: ldrh r3, [r3, r2]
; DIS-NEXT: 20: e19330b2
; IASM-NEXT: .byte 0xb2
; IASM-NEXT: .byte 0x30
; IASM-NEXT: .byte 0x93
; IASM-NEXT: .byte 0xe1
%ret = sext i16 %v16 to i32
ret i32 %ret
} }
; More ldr/str examples (byte and half word).
; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %lc2i --filetype=asm -i %s --target=arm32 --args -Om1 \
; RUN: | FileCheck %s --check-prefix=ASM
; Show bytes in assembled standalone code.
; RUN: %lc2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -Om1 | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %lc2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
; RUN: | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %lc2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -Om1 | FileCheck %s --check-prefix=DIS
define internal i32 @LoadStoreI1(i32 %a, i32 %b) {
; ASM-LABEL:LoadStoreI1:
; DIS-LABEL:00000000 <LoadStoreI1>:
; IASM-LABEL:LoadStoreI1:
entry:
; ASM-NEXT:.LLoadStoreI1$entry:
; IASM-NEXT:.LLoadStoreI1$entry:
; ASM-NEXT: sub sp, sp, #32
; DIS-NEXT: 0: e24dd020
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: str r0, [sp, #28]
; ASM-NEXT: # [sp, #28] = def.pseudo
; DIS-NEXT: 4: e58d001c
; IASM-NEXT: .byte 0x1c
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: str r1, [sp, #24]
; ASM-NEXT: # [sp, #24] = def.pseudo
; DIS-NEXT: 8: e58d1018
; IASM-NEXT: .byte 0x18
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
%b.arg_trunc = trunc i32 %b to i1
; ASM-NEXT: ldr r0, [sp, #24]
; DIS-NEXT: c: e59d0018
; IASM-NEXT: .byte 0x18
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: and r0, r0, #1
; DIS-NEXT: 10: e2000001
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: strb r0, [sp, #20]
; ASM-NEXT: # [sp, #20] = def.pseudo
; DIS-NEXT: 14: e5cd0014
; IASM-NEXT: .byte 0x14
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xcd
; IASM-NEXT: .byte 0xe5
%a.arg_trunc = trunc i32 %a to i1
%conv = zext i1 %a.arg_trunc to i32
; ASM-NEXT: ldr r0, [sp, #28]
; DIS-NEXT: 18: e59d001c
; IASM-NEXT: .byte 0x1c
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: and r0, r0, #1
; DIS-NEXT: 1c: e2000001
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: strb r0, [sp, #16]
; ASM-NEXT: # [sp, #16] = def.pseudo
; DIS-NEXT: 20: e5cd0010
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xcd
; IASM-NEXT: .byte 0xe5
%add = sext i1 %b.arg_trunc to i32
; ASM-NEXT: ldrb r0, [sp, #16]
; DIS-NEXT: 24: e5dd0010
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xdd
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: str r0, [sp, #12]
; ASM-NEXT: # [sp, #12] = def.pseudo
; DIS-NEXT: 28: e58d000c
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
%tobool4 = icmp ne i32 %conv, %add
; ASM-NEXT: mov r0, #0
; DIS-NEXT: 2c: e3a00000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe3
; ASM-NEXT: ldrb r1, [sp, #20]
; DIS-NEXT: 30: e5dd1014
; IASM-NEXT: .byte 0x14
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0xdd
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: tst r1, #1
; DIS-NEXT: 34: e3110001
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x11
; IASM-NEXT: .byte 0xe3
; ASM-NEXT: mvn r1, #0
; DIS-NEXT: 38: e3e01000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0xe3
; ASM-NEXT: movne r0, r1
; DIS-NEXT: 3c: 11a00001
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0x11
; ASM-NEXT: str r0, [sp, #8]
; ASM-NEXT: # [sp, #8] = def.pseudo
; DIS-NEXT: 40: e58d0008
; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
%tobool4.ret_ext = zext i1 %tobool4 to i32
; ASM-NEXT: mov r0, #0
; DIS-NEXT: 44: e3a00000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe3
; ASM-NEXT: ldr r1, [sp, #12]
; DIS-NEXT: 48: e59d100c
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: ldr r2, [sp, #8]
; DIS-NEXT: 4c: e59d2008
; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: cmp r1, r2
; DIS-NEXT: 50: e1510002
; IASM-NEXT: .byte 0x2
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x51
; IASM-NEXT: .byte 0xe1
; ASM-NEXT: movne r0, #1
; DIS-NEXT: 54: 13a00001
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0x13
; ASM-NEXT: strb r0, [sp, #4]
; ASM-NEXT: # [sp, #4] = def.pseudo
; DIS-NEXT: 58: e5cd0004
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xcd
; IASM-NEXT: .byte 0xe5
ret i32 %tobool4.ret_ext
; ASM-NEXT: ldrb r0, [sp, #4]
; DIS-NEXT: 5c: e5dd0004
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xdd
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: str r0, [sp]
; ASM-NEXT: # [sp] = def.pseudo
; DIS-NEXT: 60: e58d0000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: ldr r0, [sp]
; DIS-NEXT: 64: e59d0000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: add sp, sp, #32
; DIS-NEXT: 68: e28dd020
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: bx lr
; DIS-NEXT: 6c: e12fff1e
; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
}
define internal i32 @LoadStoreI16(i32 %a, i32 %b) {
; ASM-LABEL:LoadStoreI16:
; DIS-LABEL:00000070 <LoadStoreI16>:
; IASM-LABEL:LoadStoreI16:
entry:
; ASM-NEXT:.LLoadStoreI16$entry:
; IASM-NEXT:.LLoadStoreI16$entry:
; ASM-NEXT: sub sp, sp, #36
; DIS-NEXT: 70: e24dd024
; IASM-NEXT: .byte 0x24
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: str r0, [sp, #32]
; ASM-NEXT: # [sp, #32] = def.pseudo
; DIS-NEXT: 74: e58d0020
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: str r1, [sp, #28]
; ASM-NEXT: # [sp, #28] = def.pseudo
; DIS-NEXT: 78: e58d101c
; IASM-NEXT: .byte 0x1c
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
%b.arg_trunc = trunc i32 %b to i16
; ASM-NEXT: ldr r0, [sp, #28]
; DIS-NEXT: 7c: e59d001c
; IASM-NEXT: .byte 0x1c
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: strh r0, [sp, #24]
; ASM-NEXT: # [sp, #24] = def.pseudo
; DIS-NEXT: 80: e1cd01b8
; IASM-NEXT: .byte 0xb8
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0xcd
; IASM-NEXT: .byte 0xe1
%a.arg_trunc = trunc i32 %a to i16
; ASM-NEXT: ldr r0, [sp, #32]
; DIS-NEXT: 84: e59d0020
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: strh r0, [sp, #20]
; ASM-NEXT: # [sp, #20] = def.pseudo
; DIS-NEXT: 88: e1cd01b4
; IASM-NEXT: .byte 0xb4
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0xcd
; IASM-NEXT: .byte 0xe1
%conv = zext i16 %a.arg_trunc to i32
; ASM-NEXT: ldrh r0, [sp, #20]
; DIS-NEXT: 8c: e1dd01b4
; IASM-NEXT: .byte 0xb4
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0xdd
; IASM-NEXT: .byte 0xe1
; ASM-NEXT: uxth r0, r0
; DIS-NEXT: 90: e6ff0070
; IASM-NEXT: .byte 0x70
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xe6
; ASM-NEXT: str r0, [sp, #16]
; ASM-NEXT: # [sp, #16] = def.pseudo
; DIS-NEXT: 94: e58d0010
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
%conv1 = zext i16 %b.arg_trunc to i32
; ASM-NEXT: ldrh r0, [sp, #24]
; DIS-NEXT: 98: e1dd01b8
; IASM-NEXT: .byte 0xb8
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0xdd
; IASM-NEXT: .byte 0xe1
; ASM-NEXT: uxth r0, r0
; DIS-NEXT: 9c: e6ff0070
; IASM-NEXT: .byte 0x70
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xe6
; ASM-NEXT: str r0, [sp, #12]
; ASM-NEXT: # [sp, #12] = def.pseudo
; DIS-NEXT: a0: e58d000c
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
%add = add i32 %conv1, %conv
; ASM-NEXT: ldr r0, [sp, #12]
; DIS-NEXT: a4: e59d000c
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: ldr r1, [sp, #16]
; DIS-NEXT: a8: e59d1010
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: add r0, r0, r1
; DIS-NEXT: ac: e0800001
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0xe0
; ASM-NEXT: str r0, [sp, #8]
; ASM-NEXT: # [sp, #8] = def.pseudo
; DIS-NEXT: b0: e58d0008
; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
%conv2 = trunc i32 %add to i16
; ASM-NEXT: ldr r0, [sp, #8]
; DIS-NEXT: b4: e59d0008
; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: strh r0, [sp, #4]
; ASM-NEXT: # [sp, #4] = def.pseudo
; DIS-NEXT: b8: e1cd00b4
; IASM-NEXT: .byte 0xb4
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xcd
; IASM-NEXT: .byte 0xe1
%conv2.ret_ext = zext i16 %conv2 to i32
; ASM-NEXT: ldrh r0, [sp, #4]
; DIS-NEXT: bc: e1dd00b4
; IASM-NEXT: .byte 0xb4
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xdd
; IASM-NEXT: .byte 0xe1
; ASM-NEXT: uxth r0, r0
; DIS-NEXT: c0: e6ff0070
; IASM-NEXT: .byte 0x70
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xe6
; ASM-NEXT: str r0, [sp]
; ASM-NEXT: # [sp] = def.pseudo
; DIS-NEXT: c4: e58d0000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
ret i32 %conv2.ret_ext
; ASM-NEXT: ldr r0, [sp]
; DIS-NEXT: c8: e59d0000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: add sp, sp, #36
; DIS-NEXT: cc: e28dd024
; IASM-NEXT: .byte 0x24
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: bx lr
; DIS-NEXT: d0: e12fff1e
; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
}
...@@ -69,7 +69,10 @@ entry: ...@@ -69,7 +69,10 @@ entry:
; ASM-NEXT: strb r0, [sp, #12] ; ASM-NEXT: strb r0, [sp, #12]
; ASM-NEXT: # [sp, #12] = def.pseudo ; ASM-NEXT: # [sp, #12] = def.pseudo
; DIS-NEXT: 14: e5cd000c ; DIS-NEXT: 14: e5cd000c
; IASM-NEXT: strb r0, [sp, #12] ; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xcd
; IASM-NEXT: .byte 0xe5
%a.arg_trunc = trunc i32 %a to i1 %a.arg_trunc = trunc i32 %a to i1
...@@ -90,13 +93,19 @@ entry: ...@@ -90,13 +93,19 @@ entry:
; ASM-NEXT: strb r0, [sp, #8] ; ASM-NEXT: strb r0, [sp, #8]
; ASM-NEXT: # [sp, #8] = def.pseudo ; ASM-NEXT: # [sp, #8] = def.pseudo
; DIS-NEXT: 20: e5cd0008 ; DIS-NEXT: 20: e5cd0008
; IASM-NEXT: strb r0, [sp, #8] ; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xcd
; IASM-NEXT: .byte 0xe5
%conv = zext i1 %a.arg_trunc to i32 %conv = zext i1 %a.arg_trunc to i32
; ASM-NEXT: ldrb r0, [sp, #8] ; ASM-NEXT: ldrb r0, [sp, #8]
; DIS-NEXT: 24: e5dd0008 ; DIS-NEXT: 24: e5dd0008
; IASM-NEXT: ldrb r0, [sp, #8] ; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xdd
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: str r0, [sp, #4] ; ASM-NEXT: str r0, [sp, #4]
; ASM-NEXT: # [sp, #4] = def.pseudo ; ASM-NEXT: # [sp, #4] = def.pseudo
...@@ -117,7 +126,10 @@ entry: ...@@ -117,7 +126,10 @@ entry:
; ASM-NEXT: ldrb r1, [sp, #12] ; ASM-NEXT: ldrb r1, [sp, #12]
; DIS-NEXT: 30: e5dd100c ; DIS-NEXT: 30: e5dd100c
; IASM-NEXT: ldrb r1, [sp, #12] ; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0xdd
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: tst r1, #1 ; ASM-NEXT: tst r1, #1
; DIS-NEXT: 34: e3110001 ; DIS-NEXT: 34: e3110001
......
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