Commit 0437ae82 by Karl Schimpf

Improve error handling in the ARM integrated assembler.

Up to now, all error handling in the ARM integrated assembler was handled by forcing a text fixup. This CL tries to minimize the use of fixup's to only be applied when there is an unimplemented form of an instruction. All other cases now generate fatal error messages. This CL should make it easier to determine what instructions still need to be extended. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1495093002 .
parent 22a5f384
...@@ -86,7 +86,6 @@ static constexpr IValueT kRotateShift = 8; ...@@ -86,7 +86,6 @@ static constexpr IValueT kRotateShift = 8;
static constexpr IValueT kShiftImmShift = 7; static constexpr IValueT kShiftImmShift = 7;
static constexpr IValueT kShiftImmBits = 5; static constexpr IValueT kShiftImmBits = 5;
static constexpr IValueT kShiftShift = 5; static constexpr IValueT kShiftShift = 5;
static constexpr IValueT kImmed12Bits = 12; static constexpr IValueT kImmed12Bits = 12;
static constexpr IValueT kImm12Shift = 0; static constexpr IValueT kImm12Shift = 0;
...@@ -113,33 +112,29 @@ static constexpr IOffsetT kPCReadOffset = 8; ...@@ -113,33 +112,29 @@ static constexpr IOffsetT kPCReadOffset = 8;
static constexpr int kBranchOffsetBits = 24; static constexpr int kBranchOffsetBits = 24;
static constexpr IOffsetT kBranchOffsetMask = 0x00ffffff; static constexpr IOffsetT kBranchOffsetMask = 0x00ffffff;
inline IValueT encodeBool(bool B) { return B ? 1 : 0; } IValueT encodeBool(bool B) { return B ? 1 : 0; }
inline IValueT encodeRotation(ARM32::AssemblerARM32::RotationValue Value) { IValueT encodeRotation(ARM32::AssemblerARM32::RotationValue Value) {
return static_cast<IValueT>(Value); return static_cast<IValueT>(Value);
} }
inline IValueT encodeGPRRegister(RegARM32::GPRRegister Rn) { IValueT encodeGPRRegister(RegARM32::GPRRegister Rn) {
return static_cast<IValueT>(Rn); return static_cast<IValueT>(Rn);
} }
inline RegARM32::GPRRegister decodeGPRRegister(IValueT R) { RegARM32::GPRRegister decodeGPRRegister(IValueT R) {
return static_cast<RegARM32::GPRRegister>(R); return static_cast<RegARM32::GPRRegister>(R);
} }
inline bool isGPRRegisterDefined(RegARM32::GPRRegister R) { bool isGPRRegisterDefined(IValueT R) {
return R != RegARM32::Encoded_Not_GPR;
}
inline bool isGPRRegisterDefined(IValueT R) {
return R != encodeGPRRegister(RegARM32::Encoded_Not_GPR); return R != encodeGPRRegister(RegARM32::Encoded_Not_GPR);
} }
inline bool isConditionDefined(CondARM32::Cond Cond) { bool isConditionDefined(CondARM32::Cond Cond) {
return Cond != CondARM32::kNone; return Cond != CondARM32::kNone;
} }
inline IValueT encodeCondition(CondARM32::Cond Cond) { IValueT encodeCondition(CondARM32::Cond Cond) {
return static_cast<IValueT>(Cond); return static_cast<IValueT>(Cond);
} }
...@@ -157,23 +152,20 @@ IValueT encodeShift(OperandARM32::ShiftKind Shift) { ...@@ -157,23 +152,20 @@ IValueT encodeShift(OperandARM32::ShiftKind Shift) {
case OperandARM32::RRX: case OperandARM32::RRX:
return 3; // 0b11 return 3; // 0b11
} }
llvm::report_fatal_error("Unknown Shift value"); llvm::report_fatal_error("Unknown Shift value");
return 0; return 0;
} }
// Returns the bits in the corresponding masked value. // Returns the bits in the corresponding masked value.
inline IValueT mask(IValueT Value, IValueT Shift, IValueT Bits) { IValueT mask(IValueT Value, IValueT Shift, IValueT Bits) {
return (Value >> Shift) & ((1 << Bits) - 1); return (Value >> Shift) & ((1 << Bits) - 1);
} }
// Extract out a Bit in Value. // Extract out a Bit in Value.
inline bool isBitSet(IValueT Bit, IValueT Value) { bool isBitSet(IValueT Bit, IValueT Value) { return (Value & Bit) == Bit; }
return (Value & Bit) == Bit;
}
// Returns the GPR register at given Shift in Value. // Returns the GPR register at given Shift in Value.
inline RegARM32::GPRRegister getGPRReg(IValueT Shift, IValueT Value) { RegARM32::GPRRegister getGPRReg(IValueT Shift, IValueT Value) {
return decodeGPRRegister((Value >> Shift) & 0xF); return decodeGPRRegister((Value >> Shift) & 0xF);
} }
...@@ -211,7 +203,7 @@ enum EncodedOperand { ...@@ -211,7 +203,7 @@ enum EncodedOperand {
}; };
// Sets Encoding to a rotated Imm8 encoding of Value, if possible. // Sets Encoding to a rotated Imm8 encoding of Value, if possible.
inline IValueT encodeRotatedImm8(IValueT RotateAmt, IValueT Immed8) { IValueT encodeRotatedImm8(IValueT RotateAmt, IValueT Immed8) {
assert(RotateAmt < (1 << kRotateBits)); assert(RotateAmt < (1 << kRotateBits));
assert(Immed8 < (1 << kImmed8Bits)); assert(Immed8 < (1 << kImmed8Bits));
return (RotateAmt << kRotateShift) | (Immed8 << kImmed8Shift); return (RotateAmt << kRotateShift) | (Immed8 << kImmed8Shift);
...@@ -363,6 +355,69 @@ bool canEncodeBranchOffset(IOffsetT Offset) { ...@@ -363,6 +355,69 @@ bool canEncodeBranchOffset(IOffsetT Offset) {
Utils::IsInt(kBranchOffsetBits, Offset >> 2); Utils::IsInt(kBranchOffsetBits, Offset >> 2);
} }
IValueT encodeRegister(const Operand *OpReg, const char *RegName,
const char *InstName) {
IValueT Reg = 0;
if (encodeOperand(OpReg, Reg) != EncodedAsRegister)
llvm::report_fatal_error(std::string(InstName) + ": Can't find register " +
RegName);
return Reg;
}
void verifyRegDefined(IValueT Reg, const char *RegName, const char *InstName) {
if (BuildDefs::minimal())
return;
if (!isGPRRegisterDefined(Reg))
llvm::report_fatal_error(std::string(InstName) + ": Can't find " + RegName);
}
void verifyCondDefined(CondARM32::Cond Cond, const char *InstName) {
if (BuildDefs::minimal())
return;
if (!isConditionDefined(Cond))
llvm::report_fatal_error(std::string(InstName) + ": Condition not defined");
}
void verifyPOrNotW(IValueT Address, const char *InstName) {
if (BuildDefs::minimal())
return;
if (!isBitSet(P, Address) && isBitSet(W, Address))
llvm::report_fatal_error(std::string(InstName) +
": P=0 when W=1 not allowed");
}
void verifyRegsNotEq(IValueT Reg1, const char *Reg1Name, IValueT Reg2,
const char *Reg2Name, const char *InstName) {
if (BuildDefs::minimal())
return;
if (Reg1 == Reg2)
llvm::report_fatal_error(std::string(InstName) + ": " + Reg1Name + "=" +
Reg2Name + " not allowed");
}
void verifyRegNotPc(IValueT Reg, const char *RegName, const char *InstName) {
verifyRegsNotEq(Reg, RegName, RegARM32::Encoded_Reg_pc, "pc", InstName);
}
void verifyAddrRegNotPc(IValueT RegShift, IValueT Address, const char *RegName,
const char *InstName) {
if (BuildDefs::minimal())
return;
if (getGPRReg(RegShift, Address) == RegARM32::Encoded_Reg_pc)
llvm::report_fatal_error(std::string(InstName) + ": " + RegName +
"=pc not allowed");
}
void verifyRegNotPcWhenSetFlags(IValueT Reg, bool SetFlags,
const char *InstName) {
if (BuildDefs::minimal())
return;
if (SetFlags && (Reg == RegARM32::Encoded_Reg_pc))
llvm::report_fatal_error(std::string(InstName) + ": " +
RegARM32::RegNames[Reg] +
"=pc not allowed when CC=1");
}
} // end of anonymous namespace } // end of anonymous namespace
namespace Ice { namespace Ice {
...@@ -490,51 +545,46 @@ void AssemblerARM32::emitTextInst(const std::string &Text, SizeT InstSize) { ...@@ -490,51 +545,46 @@ void AssemblerARM32::emitTextInst(const std::string &Text, SizeT InstSize) {
} }
} }
void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Type, void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT InstType,
IValueT Opcode, bool SetFlags, IValueT Rn, IValueT Opcode, bool SetFlags, IValueT Rn,
IValueT Rd, IValueT Imm12, IValueT Rd, IValueT Imm12,
EmitChecks RuleChecks) { EmitChecks RuleChecks, const char *InstName) {
switch (RuleChecks) { switch (RuleChecks) {
case NoChecks: case NoChecks:
break; break;
case RdIsPcAndSetFlags: case RdIsPcAndSetFlags:
if ((Rd == RegARM32::Encoded_Reg_pc) && SetFlags) verifyRegNotPcWhenSetFlags(Rd, SetFlags, InstName);
// Conditions of rule violated.
return setNeedsTextFixup();
break; break;
} }
verifyRegDefined(Rd, "Rd", InstName);
if (!isGPRRegisterDefined(Rd) || !isConditionDefined(Cond)) verifyCondDefined(Cond, InstName);
return setNeedsTextFixup();
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
(Type << kTypeShift) | (Opcode << kOpcodeShift) | (InstType << kTypeShift) | (Opcode << kOpcodeShift) |
(encodeBool(SetFlags) << kSShift) | (encodeBool(SetFlags) << kSShift) |
(Rn << kRnShift) | (Rd << kRdShift) | Imm12; (Rn << kRnShift) | (Rd << kRdShift) | Imm12;
emitInst(Encoding); emitInst(Encoding);
} }
void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd, void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Opcode,
const Operand *OpRn, const Operand *OpSrc1, const Operand *OpRd, const Operand *OpRn,
bool SetFlags, CondARM32::Cond Cond, const Operand *OpSrc1, bool SetFlags,
EmitChecks RuleChecks) { EmitChecks RuleChecks, const char *InstName) {
IValueT Rd; IValueT Rd = encodeRegister(OpRd, "Rd", InstName);
if (encodeOperand(OpRd, Rd) != EncodedAsRegister) IValueT Rn = encodeRegister(OpRn, "Rn", InstName);
return setNeedsTextFixup(); emitType01(Cond, Opcode, Rd, Rn, OpSrc1, SetFlags, RuleChecks, InstName);
IValueT Rn;
if (encodeOperand(OpRn, Rn) != EncodedAsRegister)
return setNeedsTextFixup();
emitType01(Opcode, Rd, Rn, OpSrc1, SetFlags, Cond, RuleChecks);
} }
void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn, void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Opcode,
const Operand *OpSrc1, bool SetFlags, IValueT Rd, IValueT Rn, const Operand *OpSrc1,
CondARM32::Cond Cond, EmitChecks RuleChecks) { bool SetFlags, EmitChecks RuleChecks,
const char *InstName) {
IValueT Src1Value; IValueT Src1Value;
// TODO(kschimpf) Other possible decodings of data operations. // TODO(kschimpf) Other possible decodings of data operations.
switch (encodeOperand(OpSrc1, Src1Value)) { switch (encodeOperand(OpSrc1, Src1Value)) {
default: default:
// TODO(kschimpf): Figure out what additional cases need to be handled.
return setNeedsTextFixup(); return setNeedsTextFixup();
case EncodedAsRegister: { case EncodedAsRegister: {
// XXX (register) // XXX (register)
...@@ -545,13 +595,13 @@ void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn, ...@@ -545,13 +595,13 @@ void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn,
constexpr IValueT Imm5 = 0; constexpr IValueT Imm5 = 0;
Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, Imm5); Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, Imm5);
emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value, emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value,
RuleChecks); RuleChecks, InstName);
return; return;
} }
case EncodedAsShiftedRegister: { case EncodedAsShiftedRegister: {
// Form is defined in case EncodedAsRegister. (i.e. XXX (register)). // Form is defined in case EncodedAsRegister. (i.e. XXX (register)).
emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value, emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value,
RuleChecks); RuleChecks, InstName);
return; return;
} }
case EncodedAsConstI32: { case EncodedAsConstI32: {
...@@ -559,7 +609,8 @@ void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn, ...@@ -559,7 +609,8 @@ void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn,
IValueT RotateAmt; IValueT RotateAmt;
IValueT Imm8; IValueT Imm8;
if (!OperandARM32FlexImm::canHoldImm(Src1Value, &RotateAmt, &Imm8)) if (!OperandARM32FlexImm::canHoldImm(Src1Value, &RotateAmt, &Imm8))
return setNeedsTextFixup(); llvm::report_fatal_error(std::string(InstName) +
": Immediate rotated constant not valid");
Src1Value = encodeRotatedImm8(RotateAmt, Imm8); Src1Value = encodeRotatedImm8(RotateAmt, Imm8);
// Intentionally fall to next case! // Intentionally fall to next case!
} }
...@@ -570,19 +621,18 @@ void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn, ...@@ -570,19 +621,18 @@ void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn,
// cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
emitType01(Cond, kInstTypeDataImmediate, Opcode, SetFlags, Rn, Rd, emitType01(Cond, kInstTypeDataImmediate, Opcode, SetFlags, Rn, Rd,
Src1Value, RuleChecks); Src1Value, RuleChecks, InstName);
return; return;
} }
} }
} }
void AssemblerARM32::emitType05(CondARM32::Cond Cond, IOffsetT Offset, void AssemblerARM32::emitType05(CondARM32::Cond Cond, IOffsetT Offset,
bool Link) { bool Link, const char *InstName) {
// cccc101liiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond, l=Link, and // cccc101liiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond, l=Link, and
// iiiiiiiiiiiiiiiiiiiiiiii= // iiiiiiiiiiiiiiiiiiiiiiii=
// EncodedBranchOffset(cccc101l000000000000000000000000, Offset); // EncodedBranchOffset(cccc101l000000000000000000000000, Offset);
if (!isConditionDefined(Cond)) verifyCondDefined(Cond, InstName);
return setNeedsTextFixup();
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
IValueT Encoding = static_cast<int32_t>(Cond) << kConditionShift | IValueT Encoding = static_cast<int32_t>(Cond) << kConditionShift |
5 << kTypeShift | (Link ? 1 : 0) << kLinkShift; 5 << kTypeShift | (Link ? 1 : 0) << kLinkShift;
...@@ -592,21 +642,22 @@ void AssemblerARM32::emitType05(CondARM32::Cond Cond, IOffsetT Offset, ...@@ -592,21 +642,22 @@ void AssemblerARM32::emitType05(CondARM32::Cond Cond, IOffsetT Offset,
void AssemblerARM32::emitBranch(Label *L, CondARM32::Cond Cond, bool Link) { void AssemblerARM32::emitBranch(Label *L, CondARM32::Cond Cond, bool Link) {
// TODO(kschimpf): Handle far jumps. // TODO(kschimpf): Handle far jumps.
constexpr const char *BranchName = "b";
if (L->isBound()) { if (L->isBound()) {
const int32_t Dest = L->getPosition() - Buffer.size(); const int32_t Dest = L->getPosition() - Buffer.size();
emitType05(Cond, Dest, Link); emitType05(Cond, Dest, Link, BranchName);
return; return;
} }
const IOffsetT Position = Buffer.size(); const IOffsetT Position = Buffer.size();
// Use the offset field of the branch instruction for linking the sites. // Use the offset field of the branch instruction for linking the sites.
emitType05(Cond, L->getEncodedPosition(), Link); emitType05(Cond, L->getEncodedPosition(), Link, BranchName);
if (!needsTextFixup()) if (!needsTextFixup())
L->linkTo(Position); L->linkTo(Position);
} }
void AssemblerARM32::emitCompareOp(IValueT Opcode, const Operand *OpRn, void AssemblerARM32::emitCompareOp(CondARM32::Cond Cond, IValueT Opcode,
const Operand *OpSrc1, const Operand *OpRn, const Operand *OpSrc1,
CondARM32::Cond Cond) { const char *InstName) {
// XXX (register) // XXX (register)
// XXX<c> <Rn>, <Rm>{, <shift>} // XXX<c> <Rn>, <Rm>{, <shift>}
// //
...@@ -622,17 +673,15 @@ void AssemblerARM32::emitCompareOp(IValueT Opcode, const Operand *OpRn, ...@@ -622,17 +673,15 @@ void AssemblerARM32::emitCompareOp(IValueT Opcode, const Operand *OpRn,
// defining RotatedImm8. // defining RotatedImm8.
constexpr bool SetFlags = true; constexpr bool SetFlags = true;
constexpr IValueT Rd = RegARM32::Encoded_Reg_r0; constexpr IValueT Rd = RegARM32::Encoded_Reg_r0;
IValueT Rn; IValueT Rn = encodeRegister(OpRn, "Rn", InstName);
if (encodeOperand(OpRn, Rn) != EncodedAsRegister) emitType01(Cond, Opcode, Rd, Rn, OpSrc1, SetFlags, NoChecks, InstName);
return setNeedsTextFixup();
emitType01(Opcode, Rd, Rn, OpSrc1, SetFlags, Cond, NoChecks);
} }
void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType, void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType,
bool IsLoad, bool IsByte, IValueT Rt, bool IsLoad, bool IsByte, IValueT Rt,
IValueT Address) { IValueT Address, const char *InstName) {
if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond)) verifyRegDefined(Rt, "Rt", InstName);
return setNeedsTextFixup(); verifyCondDefined(Cond, InstName);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
(InstType << kTypeShift) | (IsLoad ? L : 0) | (InstType << kTypeShift) | (IsLoad ? L : 0) |
...@@ -642,11 +691,12 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType, ...@@ -642,11 +691,12 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType,
void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte,
IValueT Rt, const Operand *OpAddress, IValueT Rt, const Operand *OpAddress,
const TargetInfo &TInfo) { const TargetInfo &TInfo, const char *InstName) {
IValueT Address; IValueT Address;
switch (encodeAddress(OpAddress, Address, TInfo)) { switch (encodeAddress(OpAddress, Address, TInfo)) {
default: default:
return setNeedsTextFixup(); llvm::report_fatal_error(std::string(InstName) +
": Memory address not understood");
case EncodedAsImmRegOffset: { case EncodedAsImmRegOffset: {
// XXX{B} (immediate): // XXX{B} (immediate):
// xxx{b}<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0 // xxx{b}<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
...@@ -659,16 +709,16 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, ...@@ -659,16 +709,16 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte,
RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address); RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
// Check if conditions of rules violated. // Check if conditions of rules violated.
if (Rn == RegARM32::Encoded_Reg_pc) verifyRegNotPc(Rn, "Rn", InstName);
return setNeedsTextFixup(); verifyPOrNotW(Address, InstName);
if (!isBitSet(P, Address) && isBitSet(W, Address))
return setNeedsTextFixup();
if (!IsByte && (Rn == RegARM32::Encoded_Reg_sp) && !isBitSet(P, Address) && if (!IsByte && (Rn == RegARM32::Encoded_Reg_sp) && !isBitSet(P, Address) &&
isBitSet(U, Address) & !isBitSet(W, Address) && isBitSet(U, Address) && !isBitSet(W, Address) &&
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)) (mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))
return setNeedsTextFixup(); llvm::report_fatal_error(std::string(InstName) +
": Use push/pop instead");
return emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); return emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address,
InstName);
} }
case EncodedAsShiftRotateImm5: { case EncodedAsShiftRotateImm5: {
// XXX{B} (register) // XXX{B} (register)
...@@ -682,33 +732,29 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, ...@@ -682,33 +732,29 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte,
RegARM32::GPRRegister Rm = getGPRReg(kRmShift, Address); RegARM32::GPRRegister Rm = getGPRReg(kRmShift, Address);
// Check if conditions of rules violated. // Check if conditions of rules violated.
if (isBitSet(P, Address) && isBitSet(W, Address)) verifyPOrNotW(Address, InstName);
// Instruction XXXBT! verifyRegNotPc(Rm, "Rm", InstName);
return setNeedsTextFixup(); if (IsByte)
if (IsByte && verifyRegNotPc(Rt, "Rt", InstName);
((Rt == RegARM32::Encoded_Reg_pc) || (Rm == RegARM32::Encoded_Reg_pc))) if (isBitSet(W, Address)) {
// Unpredictable. verifyRegNotPc(Rn, "Rn", InstName);
return setNeedsTextFixup(); verifyRegsNotEq(Rn, "Rn", Rt, "Rt", InstName);
if (!IsByte && Rm == RegARM32::Encoded_Reg_pc) }
// Unpredictable. return emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address,
return setNeedsTextFixup(); InstName);
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, void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode,
IValueT Rt, const Operand *OpAddress, IValueT Rt, const Operand *OpAddress,
const TargetInfo &TInfo) { const TargetInfo &TInfo,
const char *InstName) {
IValueT Address; IValueT Address;
switch (encodeAddress(OpAddress, Address, TInfo, OpEncoding3)) { switch (encodeAddress(OpAddress, Address, TInfo, OpEncoding3)) {
default: default:
return setNeedsTextFixup(); llvm::report_fatal_error(std::string(InstName) +
": Memory address not understood");
case EncodedAsImmRegOffsetEnc3: { case EncodedAsImmRegOffsetEnc3: {
// XXXH (immediate) // XXXH (immediate)
// xxxh<c> <Rt>, [<Rn>{, #+-<Imm8>}] // xxxh<c> <Rt>, [<Rn>{, #+-<Imm8>}]
...@@ -718,14 +764,12 @@ void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, ...@@ -718,14 +764,12 @@ void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode,
// cccc000pu0wxnnnnttttiiiiyyyyjjjj where cccc=Cond, nnnn=Rn, tttt=Rt, // cccc000pu0wxnnnnttttiiiiyyyyjjjj where cccc=Cond, nnnn=Rn, tttt=Rt,
// iiiijjjj=Imm8, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode, // iiiijjjj=Imm8, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode,
// and pu0w0nnnn0000iiii0000jjjj=Address. // and pu0w0nnnn0000iiii0000jjjj=Address.
if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond)) verifyRegDefined(Rt, "Rt", InstName);
return setNeedsTextFixup(); verifyCondDefined(Cond, InstName);
if (!isBitSet(P, Address) && isBitSet(W, Address)) verifyPOrNotW(Address, InstName);
return setNeedsTextFixup(); verifyRegNotPc(Rt, "Rt", InstName);
if ((Rt == RegARM32::Encoded_Reg_pc) || if (isBitSet(W, Address))
(isBitSet(W, Address) && verifyRegsNotEq(getGPRReg(kRnShift, Address), "Rn", Rt, "Rt", InstName);
(getGPRReg(kRnShift, Address) == decodeGPRRegister(Rt))))
return setNeedsTextFixup();
const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
Opcode | (Rt << kRdShift) | Address; Opcode | (Rt << kRdShift) | Address;
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
...@@ -739,21 +783,20 @@ void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, ...@@ -739,21 +783,20 @@ void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode,
// cccc000pu0wxnnnntttt00001011mmmm where cccc=Cond, tttt=Rt, nnnn=Rn, // cccc000pu0wxnnnntttt00001011mmmm where cccc=Cond, tttt=Rt, nnnn=Rn,
// mmmm=Rm, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode, and // mmmm=Rm, pu0w<<21 is a BlockAddr, x000000000000yyyy0000=Opcode, and
// pu0w0nnnn000000000000mmmm=Address. // pu0w0nnnn000000000000mmmm=Address.
if (!isGPRRegisterDefined(Rt) || !isConditionDefined(Cond)) verifyRegDefined(Rt, "Rt", InstName);
return setNeedsTextFixup(); verifyCondDefined(Cond, InstName);
if (!isBitSet(P, Address) && isBitSet(W, Address)) verifyPOrNotW(Address, InstName);
return setNeedsTextFixup(); verifyRegNotPc(Rt, "Rt", InstName);
if (Rt == RegARM32::Encoded_Reg_pc) verifyAddrRegNotPc(kRmShift, Address, "Rm", InstName);
return setNeedsTextFixup();
if (getGPRReg(kRmShift, Address) == RegARM32::Encoded_Reg_pc)
return setNeedsTextFixup();
const RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address); const RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
if (isBitSet(W, Address) && if (isBitSet(W, Address)) {
((Rn == RegARM32::Encoded_Reg_pc) || (encodeGPRRegister(Rn) == Rt))) verifyRegNotPc(Rn, "Rn", InstName);
return setNeedsTextFixup(); verifyRegsNotEq(Rn, "Rn", Rt, "Rt", InstName);
}
if (mask(Address, kShiftImmShift, 5) != 0) if (mask(Address, kShiftImmShift, 5) != 0)
// For encoding 3, no shift is allowed. // For encoding 3, no shift is allowed.
return setNeedsTextFixup(); llvm::report_fatal_error(std::string(InstName) +
": Shift constant not allowed");
const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
Opcode | (Rt << kRdShift) | Address; Opcode | (Rt << kRdShift) | Address;
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
...@@ -763,10 +806,11 @@ void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, ...@@ -763,10 +806,11 @@ void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode,
} }
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, const char *InstName) {
if (!isGPRRegisterDefined(Rd) || !isGPRRegisterDefined(Rn) || verifyRegDefined(Rd, "Rd", InstName);
!isGPRRegisterDefined(Rm) || !isConditionDefined(Cond)) verifyRegDefined(Rn, "Rn", InstName);
return setNeedsTextFixup(); verifyRegDefined(Rm, "Rm", InstName);
verifyCondDefined(Cond, InstName);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) | const IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) |
(Rn << kDivRnShift) | (Rd << kDivRdShift) | B26 | (Rn << kDivRnShift) | (Rd << kDivRdShift) | B26 |
...@@ -777,11 +821,12 @@ void AssemblerARM32::emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, ...@@ -777,11 +821,12 @@ void AssemblerARM32::emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
IValueT Rn, IValueT Rm, IValueT Rs, IValueT Rn, IValueT Rm, IValueT Rs,
bool SetFlags) { bool SetFlags, const char *InstName) {
if (!isGPRRegisterDefined(Rd) || !isGPRRegisterDefined(Rn) || verifyRegDefined(Rd, "Rd", InstName);
!isGPRRegisterDefined(Rm) || !isGPRRegisterDefined(Rs) || verifyRegDefined(Rn, "Rn", InstName);
!isConditionDefined(Cond)) verifyRegDefined(Rm, "Rm", InstName);
return setNeedsTextFixup(); verifyRegDefined(Rs, "Rs", InstName);
verifyCondDefined(Cond, InstName);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) | IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) |
(encodeBool(SetFlags) << kSShift) | (Rn << kRnShift) | (encodeBool(SetFlags) << kSShift) | (Rn << kRnShift) |
...@@ -791,10 +836,13 @@ void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, ...@@ -791,10 +836,13 @@ void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
} }
void AssemblerARM32::emitUxt(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, void AssemblerARM32::emitUxt(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
IValueT Rn, IValueT Rm, RotationValue Rotation) { IValueT Rn, IValueT Rm, RotationValue Rotation,
const char *InstName) {
verifyCondDefined(Cond, InstName);
IValueT Rot = encodeRotation(Rotation); IValueT Rot = encodeRotation(Rotation);
if (!isConditionDefined(Cond) || !Utils::IsUint(2, Rot)) if (!Utils::IsUint(2, Rot))
return setNeedsTextFixup(); llvm::report_fatal_error(std::string(InstName) +
": Illegal rotation value");
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | Opcode | IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | Opcode |
(Rn << kRnShift) | (Rd << kRdShift) | (Rn << kRnShift) | (Rd << kRdShift) |
...@@ -804,11 +852,14 @@ void AssemblerARM32::emitUxt(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, ...@@ -804,11 +852,14 @@ void AssemblerARM32::emitUxt(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
void AssemblerARM32::emitMultiMemOp(CondARM32::Cond Cond, void AssemblerARM32::emitMultiMemOp(CondARM32::Cond Cond,
BlockAddressMode AddressMode, bool IsLoad, BlockAddressMode AddressMode, bool IsLoad,
IValueT BaseReg, IValueT Registers) { IValueT BaseReg, IValueT Registers,
const char *InstName) {
constexpr IValueT NumGPRegisters = 16; constexpr IValueT NumGPRegisters = 16;
if (!isConditionDefined(Cond) || !isGPRRegisterDefined(BaseReg) || verifyCondDefined(Cond, InstName);
Registers >= (1 << NumGPRegisters)) verifyRegDefined(BaseReg, "base", InstName);
return setNeedsTextFixup(); if (Registers >= (1 << NumGPRegisters))
llvm::report_fatal_error(std::string(InstName) +
": Register set too large");
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B27 | IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B27 |
AddressMode | (IsLoad ? L : 0) | (BaseReg << kRnShift) | AddressMode | (IsLoad ? L : 0) | (BaseReg << kRnShift) |
...@@ -830,8 +881,10 @@ void AssemblerARM32::adc(const Operand *OpRd, const Operand *OpRn, ...@@ -830,8 +881,10 @@ void AssemblerARM32::adc(const Operand *OpRd, const Operand *OpRn,
// //
// cccc0010101snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010101snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT Adc = B2 | B0; // 0101 constexpr const char *AdcName = "adc";
emitType01(Adc, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); constexpr IValueT AdcOpcode = B2 | B0; // 0101
emitType01(Cond, AdcOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
AdcName);
} }
void AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn,
...@@ -852,8 +905,10 @@ void AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, ...@@ -852,8 +905,10 @@ void AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn,
// //
// cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr const char *AddName = "add";
constexpr IValueT Add = B2; // 0100 constexpr IValueT Add = B2; // 0100
emitType01(Add, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); emitType01(Cond, Add, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
AddName);
} }
void AssemblerARM32::and_(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::and_(const Operand *OpRd, const Operand *OpRn,
...@@ -870,8 +925,10 @@ void AssemblerARM32::and_(const Operand *OpRd, const Operand *OpRn, ...@@ -870,8 +925,10 @@ void AssemblerARM32::and_(const Operand *OpRd, const Operand *OpRn,
// //
// cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr const char *AndName = "and";
constexpr IValueT And = 0; // 0000 constexpr IValueT And = 0; // 0000
emitType01(And, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); emitType01(Cond, And, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
AndName);
} }
void AssemblerARM32::b(Label *L, CondARM32::Cond Cond) { void AssemblerARM32::b(Label *L, CondARM32::Cond Cond) {
...@@ -903,8 +960,10 @@ void AssemblerARM32::bic(const Operand *OpRd, const Operand *OpRn, ...@@ -903,8 +960,10 @@ void AssemblerARM32::bic(const Operand *OpRd, const Operand *OpRn,
// //
// cccc0011110snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rn, nnnn=Rn, // cccc0011110snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rn, nnnn=Rn,
// s=SetFlags, and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags, and iiiiiiiiiiii=Src1Value defining RotatedImm8.
IValueT Opcode = B3 | B2 | B1; // i.e. 1110 constexpr const char *BicName = "bic";
emitType01(Opcode, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); constexpr IValueT BicOpcode = B3 | B2 | B1; // i.e. 1110
emitType01(Cond, BicOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
BicName);
} }
void AssemblerARM32::bl(const ConstantRelocatable *Target) { void AssemblerARM32::bl(const ConstantRelocatable *Target) {
...@@ -914,24 +973,22 @@ void AssemblerARM32::bl(const ConstantRelocatable *Target) { ...@@ -914,24 +973,22 @@ void AssemblerARM32::bl(const ConstantRelocatable *Target) {
// cccc1011iiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond (not currently allowed) // cccc1011iiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond (not currently allowed)
// and iiiiiiiiiiiiiiiiiiiiiiii is the (encoded) Target to branch to. // and iiiiiiiiiiiiiiiiiiiiiiii is the (encoded) Target to branch to.
emitFixup(createBlFixup(Target)); emitFixup(createBlFixup(Target));
constexpr const char *BlName = "bl";
constexpr CondARM32::Cond Cond = CondARM32::AL; constexpr CondARM32::Cond Cond = CondARM32::AL;
constexpr IValueT Immed = 0; constexpr IValueT Immed = 0;
constexpr bool Link = true; constexpr bool Link = true;
emitType05(Cond, Immed, Link); emitType05(Cond, Immed, Link, BlName);
} }
void AssemblerARM32::blx(const Operand *Target) { void AssemblerARM32::blx(const Operand *Target) {
IValueT Rm;
if (encodeOperand(Target, Rm) != EncodedAsRegister)
return setNeedsTextFixup();
// BLX (register) - ARM section A8.8.26, encoding A1: // BLX (register) - ARM section A8.8.26, encoding A1:
// blx<c> <Rm> // blx<c> <Rm>
// //
// cccc000100101111111111110011mmmm where cccc=Cond (not currently allowed) // cccc000100101111111111110011mmmm where cccc=Cond (not currently allowed)
// and mmmm=Rm. // and mmmm=Rm.
if (Rm == RegARM32::Encoded_Reg_pc) constexpr const char *BlxName = "Blx";
// Unpredictable. IValueT Rm = encodeRegister(Target, "Rm", BlxName);
return setNeedsTextFixup(); verifyRegNotPc(Rm, "Rm", BlxName);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
constexpr CondARM32::Cond Cond = CondARM32::AL; constexpr CondARM32::Cond Cond = CondARM32::AL;
int32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | B21 | int32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | B21 |
...@@ -944,8 +1001,9 @@ void AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) { ...@@ -944,8 +1001,9 @@ void 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.
if (!(isGPRRegisterDefined(Rm) && isConditionDefined(Cond))) constexpr const char *BxName = "bx";
return setNeedsTextFixup(); verifyCondDefined(Cond, BxName);
verifyRegDefined(Rm, "Rm", BxName);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B24 |
B21 | (0xfff << 8) | B4 | B21 | (0xfff << 8) | B4 |
...@@ -966,8 +1024,9 @@ void AssemblerARM32::cmp(const Operand *OpRn, const Operand *OpSrc1, ...@@ -966,8 +1024,9 @@ void AssemblerARM32::cmp(const Operand *OpRn, const Operand *OpSrc1,
// //
// cccc00110101nnnn0000iiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc00110101nnnn0000iiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT Opcode = B3 | B1; // ie. 1010 constexpr const char *CmpName = "cmp";
emitCompareOp(Opcode, OpRn, OpSrc1, Cond); constexpr IValueT CmpOpcode = B3 | B1; // ie. 1010
emitCompareOp(Cond, CmpOpcode, OpRn, OpSrc1, CmpName);
} }
void AssemblerARM32::eor(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::eor(const Operand *OpRd, const Operand *OpRn,
...@@ -984,16 +1043,17 @@ void AssemblerARM32::eor(const Operand *OpRd, const Operand *OpRn, ...@@ -984,16 +1043,17 @@ void AssemblerARM32::eor(const Operand *OpRd, const Operand *OpRn,
// //
// cccc0010001snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010001snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT Eor = B0; // 0001 constexpr const char *EorName = "eor";
emitType01(Eor, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); constexpr IValueT EorOpcode = B0; // 0001
emitType01(Cond, EorOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
EorName);
} }
void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
CondARM32::Cond Cond, const TargetInfo &TInfo) { CondARM32::Cond Cond, const TargetInfo &TInfo) {
constexpr const char *LdrName = "ldr";
constexpr bool IsLoad = true; constexpr bool IsLoad = true;
IValueT Rt; IValueT Rt = encodeRegister(OpRt, "Rt", LdrName);
if (encodeOperand(OpRt, Rt) != EncodedAsRegister)
return setNeedsTextFixup();
const Type Ty = OpRt->getType(); const Type Ty = OpRt->getType();
switch (typeWidthInBytesLog2(Ty)) { switch (typeWidthInBytesLog2(Ty)) {
case 3: case 3:
...@@ -1001,8 +1061,8 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, ...@@ -1001,8 +1061,8 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
// using two (32-bit) load instructions. Note: Intenionally drop to default // using two (32-bit) load instructions. Note: Intenionally drop to default
// case. // case.
default: default:
llvm::report_fatal_error(std::string("Type ") + typeString(Ty) + llvm::report_fatal_error(std::string("ldr : Type ") + typeString(Ty) +
" not implementable using ldr\n"); " not implementable\n");
case 0: { case 0: {
// Handles i1 and i8 loads. // Handles i1 and i8 loads.
// //
...@@ -1022,7 +1082,7 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, ...@@ -1022,7 +1082,7 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
// cccc011pu1w1nnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, U=1 if +, pu0b // cccc011pu1w1nnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, U=1 if +, pu0b
// is a BlockAddr, and pu0w0nnnn0000iiiiiss0mmmm=Address. // is a BlockAddr, and pu0w0nnnn0000iiiiiss0mmmm=Address.
constexpr bool IsByte = true; constexpr bool IsByte = true;
return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo); return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo, LdrName);
} }
case 1: { case 1: {
// Handles i16 loads. // Handles i16 loads.
...@@ -1035,7 +1095,8 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, ...@@ -1035,7 +1095,8 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
// cccc000pu1w1nnnnttttiiii1011iiii where cccc=Cond, tttt=Rt, nnnn=Rn, // cccc000pu1w1nnnnttttiiii1011iiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiii=Imm8, u=1 if +, pu0w is a BlockAddr, and // iiiiiiii=Imm8, u=1 if +, pu0w is a BlockAddr, and
// pu0w0nnnn0000iiiiiiiiiiii=Address. // pu0w0nnnn0000iiiiiiiiiiii=Address.
return emitMemOpEnc3(Cond, L | B7 | B5 | B4, Rt, OpAddress, TInfo); constexpr const char *Ldrh = "ldrh";
return emitMemOpEnc3(Cond, L | B7 | B5 | B4, Rt, OpAddress, TInfo, Ldrh);
} }
case 2: { case 2: {
// Note: Handles i32 and float loads. Target lowering handles i64 and // Note: Handles i32 and float loads. Target lowering handles i64 and
...@@ -1056,7 +1117,7 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, ...@@ -1056,7 +1117,7 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
// cccc011pu0w1nnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, U=1 if +, pu0b // cccc011pu0w1nnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt, U=1 if +, pu0b
// is a BlockAddr, and pu0w0nnnn0000iiiiiss0mmmm=Address. // is a BlockAddr, and pu0w0nnnn0000iiiiiss0mmmm=Address.
constexpr bool IsByte = false; constexpr bool IsByte = false;
return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo); return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo, LdrName);
} }
} }
} }
...@@ -1064,27 +1125,25 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, ...@@ -1064,27 +1125,25 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
void AssemblerARM32::lsl(const Operand *OpRd, const Operand *OpRm, void AssemblerARM32::lsl(const Operand *OpRd, const Operand *OpRm,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
constexpr IValueT Lsl = B3 | B2 | B0; // 1101 constexpr const char *LslName = "lsl";
constexpr IValueT Rn = 0; // Rn field is not used. IValueT Rd = encodeRegister(OpRd, "Rd", LslName);
IValueT Rd; IValueT Rm = encodeRegister(OpRm, "Rm", LslName);
if (encodeOperand(OpRd, Rd) != EncodedAsRegister)
return setNeedsTextFixup();
IValueT Rm;
if (encodeOperand(OpRm, Rm) != EncodedAsRegister)
return setNeedsTextFixup();
IValueT Value; IValueT Value;
switch (encodeOperand(OpSrc1, Value)) { switch (encodeOperand(OpSrc1, Value)) {
default: default:
return setNeedsTextFixup(); llvm::report_fatal_error(std::string(LslName) +
": Last operand not understood");
case EncodedAsShiftImm5: { case EncodedAsShiftImm5: {
// LSL (immediate) - ARM section A8.8.94, encoding A1: // LSL (immediate) - ARM section A8.8.94, encoding A1:
// lsl{s}<c> <Rd>, <Rm>, #imm5 // lsl{s}<c> <Rd>, <Rm>, #imm5
// //
// cccc0001101s0000ddddiiiii000mmmm where cccc=Cond, s=SetFlags, dddd=Rd, // cccc0001101s0000ddddiiiii000mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
// iiiii=imm5, and mmmm=Rm. // iiiii=imm5, and mmmm=Rm.
constexpr IValueT LslOpcode = B3 | B2 | B0; // 1101
constexpr IValueT Rn = 0; // Rn field is not used.
Value = Value | (Rm << kRmShift); Value = Value | (Rm << kRmShift);
emitType01(Cond, kInstTypeDataRegShift, Lsl, SetFlags, Rn, Rd, Value, emitType01(Cond, kInstTypeDataRegShift, LslOpcode, SetFlags, Rn, Rd, Value,
RdIsPcAndSetFlags); RdIsPcAndSetFlags, LslName);
return; return;
} }
case EncodedAsRegister: { case EncodedAsRegister: {
...@@ -1093,14 +1152,15 @@ void AssemblerARM32::lsl(const Operand *OpRd, const Operand *OpRm, ...@@ -1093,14 +1152,15 @@ void AssemblerARM32::lsl(const Operand *OpRd, const Operand *OpRm,
// //
// cccc0001101s0000ddddssss0001mmmm where cccc=Cond, s=SetFlags, dddd=Rd, // cccc0001101s0000ddddssss0001mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
// mmmm=Rm, and ssss=Rs. // mmmm=Rm, and ssss=Rs.
IValueT Rs; constexpr IValueT LslOpcode = B3 | B2 | B0; // 1101
if (encodeOperand(OpSrc1, Rs) != EncodedAsRegister) constexpr IValueT Rn = 0; // Rn field is not used.
return setNeedsTextFixup(); IValueT Rs = encodeRegister(OpSrc1, "Rs", LslName);
if ((Rd == RegARM32::Encoded_Reg_pc) || (Rm == RegARM32::Encoded_Reg_pc) || verifyRegNotPc(Rd, "Rd", LslName);
(Rs == RegARM32::Encoded_Reg_pc)) verifyRegNotPc(Rm, "Rm", LslName);
setNeedsTextFixup(); verifyRegNotPc(Rs, "Rs", LslName);
emitType01(Cond, kInstTypeDataRegShift, Lsl, SetFlags, Rn, Rd, emitType01(Cond, kInstTypeDataRegShift, LslOpcode, SetFlags, Rn, Rd,
encodeShiftRotateReg(Rm, OperandARM32::kNoShift, Rs), NoChecks); encodeShiftRotateReg(Rm, OperandARM32::kNoShift, Rs), NoChecks,
LslName);
return; return;
} }
} }
...@@ -1120,19 +1180,21 @@ void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, ...@@ -1120,19 +1180,21 @@ void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
// 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.
IValueT Rd; constexpr const char *MovName = "mov";
if (encodeOperand(OpRd, Rd) != EncodedAsRegister) IValueT Rd = encodeRegister(OpRd, "Rd", MovName);
return setNeedsTextFixup();
constexpr bool SetFlags = false; constexpr bool SetFlags = false;
constexpr IValueT Rn = 0; constexpr IValueT Rn = 0;
constexpr IValueT Mov = B3 | B2 | B0; // 1101. constexpr IValueT MovOpcode = B3 | B2 | B0; // 1101.
emitType01(Mov, Rd, Rn, OpSrc, SetFlags, Cond, RdIsPcAndSetFlags); emitType01(Cond, MovOpcode, Rd, Rn, OpSrc, SetFlags, RdIsPcAndSetFlags,
MovName);
} }
void AssemblerARM32::emitMovw(IValueT Opcode, IValueT Rd, IValueT Imm16, void AssemblerARM32::emitMovw(IValueT Opcode, IValueT Rd, IValueT Imm16,
bool SetFlags, CondARM32::Cond Cond) { bool SetFlags, CondARM32::Cond Cond) {
if (!isConditionDefined(Cond) || !Utils::IsAbsoluteUint(16, Imm16)) constexpr const char *MovwName = "movw";
return setNeedsTextFixup(); verifyCondDefined(Cond, MovwName);
if (!Utils::IsAbsoluteUint(16, Imm16))
llvm::report_fatal_error(std::string(MovwName) + ": Not I16 constant");
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const IValueT Encoding = encodeCondition(Cond) << kConditionShift | Opcode | const IValueT Encoding = encodeCondition(Cond) << kConditionShift | Opcode |
(encodeBool(SetFlags) << kSShift) | (encodeBool(SetFlags) << kSShift) |
...@@ -1143,18 +1205,15 @@ void AssemblerARM32::emitMovw(IValueT Opcode, IValueT Rd, IValueT Imm16, ...@@ -1143,18 +1205,15 @@ void AssemblerARM32::emitMovw(IValueT Opcode, IValueT Rd, IValueT Imm16,
void AssemblerARM32::movw(const Operand *OpRd, const Operand *OpSrc, void AssemblerARM32::movw(const Operand *OpRd, const Operand *OpSrc,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
IValueT Rd; constexpr const char *MovwName = "movw";
if (encodeOperand(OpRd, Rd) != EncodedAsRegister) IValueT Rd = encodeRegister(OpRd, "Rd", MovwName);
return setNeedsTextFixup();
if (const auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc)) { if (const auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc)) {
// MOVW (immediate) - ARM section A8.8.102, encoding A2: // MOVW (immediate) - ARM section A8.8.102, encoding A2:
// movw<c> <Rd>, #<imm16> // movw<c> <Rd>, #<imm16>
// //
// cccc00110000iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, and // cccc00110000iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, and
// iiiiiiiiiiiiiiii=imm16. // iiiiiiiiiiiiiiii=imm16.
if (!isConditionDefined(Cond)) verifyCondDefined(Cond, MovwName);
// Conditions of rule violated.
return setNeedsTextFixup();
// Use 0 for the lower 16 bits of the relocatable, and add a fixup to // Use 0 for the lower 16 bits of the relocatable, and add a fixup to
// install the correct bits. // install the correct bits.
constexpr bool IsMovW = true; constexpr bool IsMovW = true;
...@@ -1166,7 +1225,8 @@ void AssemblerARM32::movw(const Operand *OpRd, const Operand *OpSrc, ...@@ -1166,7 +1225,8 @@ void AssemblerARM32::movw(const Operand *OpRd, const Operand *OpSrc,
} }
IValueT ConstVal; IValueT ConstVal;
if (encodeOperand(OpSrc, ConstVal) != EncodedAsConstI32) if (encodeOperand(OpSrc, ConstVal) != EncodedAsConstI32)
return setNeedsTextFixup(); llvm::report_fatal_error(std::string(MovwName) + ": Constant not i32");
// TODO(kschimpf): Determine if we want to handle rotated immediate 8 values // TODO(kschimpf): Determine if we want to handle rotated immediate 8 values
// to handle cases where the constant is greater than 16 bits (encoding A1 // to handle cases where the constant is greater than 16 bits (encoding A1
// below). For now, handle using encoding A2. // below). For now, handle using encoding A2.
...@@ -1183,20 +1243,18 @@ void AssemblerARM32::movw(const Operand *OpRd, const Operand *OpSrc, ...@@ -1183,20 +1243,18 @@ void AssemblerARM32::movw(const Operand *OpRd, const Operand *OpSrc,
void AssemblerARM32::movt(const Operand *OpRd, const Operand *OpSrc, void AssemblerARM32::movt(const Operand *OpRd, const Operand *OpSrc,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
IValueT Rd;
if (encodeOperand(OpRd, Rd) != EncodedAsRegister)
return setNeedsTextFixup();
auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc);
if (Src == nullptr)
return setNeedsTextFixup();
// MOVT - ARM section A8.8.102, encoding A2: // MOVT - ARM section A8.8.102, encoding A2:
// movt<c> <Rd>, #<imm16> // movt<c> <Rd>, #<imm16>
// //
// cccc00110100iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, and // cccc00110100iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, and
// iiiiiiiiiiiiiiii=imm16. // iiiiiiiiiiiiiiii=imm16.
if (!isConditionDefined(Cond)) constexpr const char *MovtName = "movt";
// Conditions of rule violated. IValueT Rd = encodeRegister(OpRd, "Rd", MovtName);
auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc);
if (!Src)
// TODO(kschimpf) Figure out what else can appear here.
return setNeedsTextFixup(); return setNeedsTextFixup();
verifyCondDefined(Cond, MovtName);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
// Use 0 for the lower 16 bits of the relocatable, and add a fixup to // Use 0 for the lower 16 bits of the relocatable, and add a fixup to
// install the correct bits. // install the correct bits.
...@@ -1222,13 +1280,13 @@ void AssemblerARM32::mvn(const Operand *OpRd, const Operand *OpSrc, ...@@ -1222,13 +1280,13 @@ void AssemblerARM32::mvn(const Operand *OpRd, const Operand *OpSrc,
// //
// cccc0001111s0000ddddiiiiitt0mmmm where cccc=Cond, s=SetFlags=0, dddd=Rd, // cccc0001111s0000ddddiiiiitt0mmmm where cccc=Cond, s=SetFlags=0, dddd=Rd,
// mmmm=Rm, iiii defines shift constant, and tt=ShiftKind. // mmmm=Rm, iiii defines shift constant, and tt=ShiftKind.
IValueT Rd; constexpr const char *MvnName = "mvn";
if (encodeOperand(OpRd, Rd) != EncodedAsRegister) IValueT Rd = encodeRegister(OpRd, "Rd", MvnName);
return setNeedsTextFixup();
constexpr IValueT MvnOpcode = B3 | B2 | B1 | B0; // i.e. 1111 constexpr IValueT MvnOpcode = B3 | B2 | B1 | B0; // i.e. 1111
constexpr IValueT Rn = 0; constexpr IValueT Rn = 0;
constexpr bool SetFlags = false; constexpr bool SetFlags = false;
emitType01(MvnOpcode, Rd, Rn, OpSrc, SetFlags, Cond, RdIsPcAndSetFlags); emitType01(Cond, MvnOpcode, Rd, Rn, OpSrc, SetFlags, RdIsPcAndSetFlags,
MvnName);
} }
void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn,
...@@ -1245,8 +1303,10 @@ void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn, ...@@ -1245,8 +1303,10 @@ void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn,
// //
// cccc0010110snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010110snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT Sbc = B2 | B1; // 0110 constexpr const char *SbcName = "sbc";
emitType01(Sbc, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); constexpr IValueT SbcOpcode = B2 | B1; // 0110
emitType01(Cond, SbcOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
SbcName);
} }
void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn,
...@@ -1256,29 +1316,23 @@ void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn, ...@@ -1256,29 +1316,23 @@ void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn,
// //
// cccc01110001dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and // cccc01110001dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and
// mmmm=Rm. // mmmm=Rm.
IValueT Rd; constexpr const char *SdivName = "sdiv";
if (encodeOperand(OpRd, Rd) != EncodedAsRegister) IValueT Rd = encodeRegister(OpRd, "Rd", SdivName);
return setNeedsTextFixup(); IValueT Rn = encodeRegister(OpRn, "Rn", SdivName);
IValueT Rn; IValueT Rm = encodeRegister(OpSrc1, "Rm", SdivName);
if (encodeOperand(OpRn, Rn) != EncodedAsRegister) verifyRegNotPc(Rd, "Rd", SdivName);
return setNeedsTextFixup(); verifyRegNotPc(Rn, "Rn", SdivName);
IValueT Rm; verifyRegNotPc(Rm, "Rm", SdivName);
if (encodeOperand(OpSrc1, Rm) != EncodedAsRegister)
return setNeedsTextFixup();
if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc ||
Rm == RegARM32::Encoded_Reg_pc)
llvm::report_fatal_error("Sdiv instruction unpredictable on pc");
// Assembler registers rd, rn, rm are encoded as rn, rm, rs. // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
constexpr IValueT Opcode = 0; constexpr IValueT SdivOpcode = 0;
emitDivOp(Cond, Opcode, Rd, Rn, Rm); emitDivOp(Cond, SdivOpcode, Rd, Rn, Rm, SdivName);
} }
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 const char *StrName = "str";
constexpr bool IsLoad = false; constexpr bool IsLoad = false;
IValueT Rt; IValueT Rt = encodeRegister(OpRt, "Rt", StrName);
if (encodeOperand(OpRt, Rt) != EncodedAsRegister)
return setNeedsTextFixup();
const Type Ty = OpRt->getType(); const Type Ty = OpRt->getType();
switch (typeWidthInBytesLog2(Ty)) { switch (typeWidthInBytesLog2(Ty)) {
case 3: case 3:
...@@ -1286,8 +1340,8 @@ void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, ...@@ -1286,8 +1340,8 @@ void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
// using two (32-bit) store instructions. Note: Intenionally drop to // using two (32-bit) store instructions. Note: Intenionally drop to
// default case. // default case.
default: default:
llvm::report_fatal_error(std::string("Type ") + typeString(Ty) + llvm::report_fatal_error(std::string(StrName) + ": Type " + typeString(Ty) +
" not implementable using str\n"); " not implemented");
case 0: { case 0: {
// Handles i1 and i8 stores. // Handles i1 and i8 stores.
// //
...@@ -1299,7 +1353,7 @@ void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, ...@@ -1299,7 +1353,7 @@ void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
// cccc010pu1w0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn, // cccc010pu1w0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, u=1 if +. // iiiiiiiiiiii=imm12, u=1 if +.
constexpr bool IsByte = true; constexpr bool IsByte = true;
return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo); return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo, StrName);
} }
case 1: { case 1: {
// Handles i16 stores. // Handles i16 stores.
...@@ -1312,7 +1366,8 @@ void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, ...@@ -1312,7 +1366,8 @@ void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
// cccc000pu1w0nnnnttttiiii1011iiii where cccc=Cond, tttt=Rt, nnnn=Rn, // cccc000pu1w0nnnnttttiiii1011iiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiii=Imm8, u=1 if +, pu0w is a BlockAddr, and // iiiiiiii=Imm8, u=1 if +, pu0w is a BlockAddr, and
// pu0w0nnnn0000iiiiiiiiiiii=Address. // pu0w0nnnn0000iiiiiiiiiiii=Address.
return emitMemOpEnc3(Cond, B7 | B5 | B4, Rt, OpAddress, TInfo); constexpr const char *Strh = "strh";
return emitMemOpEnc3(Cond, B7 | B5 | B4, Rt, OpAddress, TInfo, Strh);
} }
case 2: { case 2: {
// Note: Handles i32 and float stores. Target lowering handles i64 and // Note: Handles i32 and float stores. Target lowering handles i64 and
...@@ -1326,7 +1381,7 @@ void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, ...@@ -1326,7 +1381,7 @@ void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
// cccc010pu1w0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn, // cccc010pu1w0nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, u=1 if +. // iiiiiiiiiiii=imm12, u=1 if +.
constexpr bool IsByte = false; constexpr bool IsByte = false;
return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo); return emitMemOp(Cond, IsLoad, IsByte, Rt, OpAddress, TInfo, StrName);
return setNeedsTextFixup(); return setNeedsTextFixup();
} }
} }
...@@ -1346,8 +1401,10 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn, ...@@ -1346,8 +1401,10 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn,
// //
// cccc0001100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0001100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT Orr = B3 | B2; // i.e. 1100 constexpr const char *OrrName = "orr";
emitType01(Orr, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); constexpr IValueT OrrOpcode = B3 | B2; // i.e. 1100
emitType01(Cond, OrrOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
OrrName);
} }
void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) { void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) {
...@@ -1355,16 +1412,15 @@ void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) { ...@@ -1355,16 +1412,15 @@ void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) {
// pop<c> {Rt} // pop<c> {Rt}
// //
// cccc010010011101dddd000000000100 where dddd=Rt and cccc=Cond. // cccc010010011101dddd000000000100 where dddd=Rt and cccc=Cond.
IValueT Rt; constexpr const char *Pop = "pop";
if (encodeOperand(OpRt, Rt) != EncodedAsRegister) IValueT Rt = encodeRegister(OpRt, "Rt", Pop);
return setNeedsTextFixup(); verifyRegsNotEq(Rt, "Rt", RegARM32::Encoded_Reg_sp, "sp", Pop);
assert(Rt != RegARM32::Encoded_Reg_sp);
// 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 = encodeImmRegOffset(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, Pop);
} }
void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) { void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) {
...@@ -1373,8 +1429,10 @@ void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) { ...@@ -1373,8 +1429,10 @@ void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) {
// //
// cccc100010111101rrrrrrrrrrrrrrrr where cccc=Cond and // cccc100010111101rrrrrrrrrrrrrrrr where cccc=Cond and
// rrrrrrrrrrrrrrrr=Registers (one bit for each GP register). // rrrrrrrrrrrrrrrr=Registers (one bit for each GP register).
constexpr const char *PopListName = "pop {}";
constexpr bool IsLoad = true; constexpr bool IsLoad = true;
emitMultiMemOp(Cond, IA_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers); emitMultiMemOp(Cond, IA_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers,
PopListName);
} }
void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) { void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) {
...@@ -1382,16 +1440,15 @@ void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) { ...@@ -1382,16 +1440,15 @@ void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) {
// push<c> {Rt} // push<c> {Rt}
// //
// cccc010100101101dddd000000000100 where dddd=Rt and cccc=Cond. // cccc010100101101dddd000000000100 where dddd=Rt and cccc=Cond.
IValueT Rt; constexpr const char *Push = "push";
if (encodeOperand(OpRt, Rt) != EncodedAsRegister) IValueT Rt = encodeRegister(OpRt, "Rt", Push);
return setNeedsTextFixup(); verifyRegsNotEq(Rt, "Rt", RegARM32::Encoded_Reg_sp, "sp", Push);
assert(Rt != RegARM32::Encoded_Reg_sp);
// 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 = encodeImmRegOffset(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, Push);
} }
void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) { void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) {
...@@ -1400,62 +1457,54 @@ void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) { ...@@ -1400,62 +1457,54 @@ void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) {
// //
// cccc100100101101rrrrrrrrrrrrrrrr where cccc=Cond and // cccc100100101101rrrrrrrrrrrrrrrr where cccc=Cond and
// rrrrrrrrrrrrrrrr=Registers (one bit for each GP register). // rrrrrrrrrrrrrrrr=Registers (one bit for each GP register).
constexpr const char *PushListName = "push {}";
constexpr bool IsLoad = false; constexpr bool IsLoad = false;
emitMultiMemOp(Cond, DB_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers); emitMultiMemOp(Cond, DB_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers,
PushListName);
} }
void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn,
const Operand *OpRm, const Operand *OpRa, const Operand *OpRm, const Operand *OpRa,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
IValueT Rd;
if (encodeOperand(OpRd, Rd) != EncodedAsRegister)
return setNeedsTextFixup();
IValueT Rn;
if (encodeOperand(OpRn, Rn) != EncodedAsRegister)
return setNeedsTextFixup();
IValueT Rm;
if (encodeOperand(OpRm, Rm) != EncodedAsRegister)
return setNeedsTextFixup();
IValueT Ra;
if (encodeOperand(OpRa, Ra) != EncodedAsRegister)
return setNeedsTextFixup();
// MLA - ARM section A8.8.114, encoding A1. // MLA - ARM section A8.8.114, encoding A1.
// mla{s}<c> <Rd>, <Rn>, <Rm>, <Ra> // mla{s}<c> <Rd>, <Rn>, <Rm>, <Ra>
// //
// cccc0000001sddddaaaammmm1001nnnn where cccc=Cond, s=SetFlags, dddd=Rd, // cccc0000001sddddaaaammmm1001nnnn where cccc=Cond, s=SetFlags, dddd=Rd,
// aaaa=Ra, mmmm=Rm, and nnnn=Rn. // aaaa=Ra, mmmm=Rm, and nnnn=Rn.
if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc || constexpr const char *MlaName = "mla";
Rm == RegARM32::Encoded_Reg_pc || Ra == RegARM32::Encoded_Reg_pc) IValueT Rd = encodeRegister(OpRd, "Rd", MlaName);
llvm::report_fatal_error("Mul instruction unpredictable on pc"); IValueT Rn = encodeRegister(OpRn, "Rn", MlaName);
IValueT Rm = encodeRegister(OpRm, "Rm", MlaName);
IValueT Ra = encodeRegister(OpRa, "Ra", MlaName);
verifyRegNotPc(Rd, "Rd", MlaName);
verifyRegNotPc(Rn, "Rn", MlaName);
verifyRegNotPc(Rm, "Rm", MlaName);
verifyRegNotPc(Ra, "Ra", MlaName);
constexpr IValueT MlaOpcode = B21; constexpr IValueT MlaOpcode = B21;
constexpr bool SetFlags = false; constexpr bool SetFlags = false;
// Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
emitMulOp(Cond, MlaOpcode, Ra, Rd, Rn, Rm, SetFlags); emitMulOp(Cond, MlaOpcode, Ra, Rd, Rn, Rm, SetFlags, MlaName);
} }
void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
IValueT Rd;
if (encodeOperand(OpRd, Rd) != EncodedAsRegister)
return setNeedsTextFixup();
IValueT Rn;
if (encodeOperand(OpRn, Rn) != EncodedAsRegister)
return setNeedsTextFixup();
IValueT Rm;
if (encodeOperand(OpSrc1, Rm) != EncodedAsRegister)
return setNeedsTextFixup();
// MUL - ARM section A8.8.114, encoding A1. // MUL - ARM section A8.8.114, encoding A1.
// mul{s}<c> <Rd>, <Rn>, <Rm> // mul{s}<c> <Rd>, <Rn>, <Rm>
// //
// cccc0000000sdddd0000mmmm1001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0000000sdddd0000mmmm1001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn,
// mmmm=Rm, and s=SetFlags. // mmmm=Rm, and s=SetFlags.
if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc || constexpr const char *MulName = "mul";
Rm == RegARM32::Encoded_Reg_pc) IValueT Rd = encodeRegister(OpRd, "Rd", MulName);
llvm::report_fatal_error("Mul instruction unpredictable on pc"); IValueT Rn = encodeRegister(OpRn, "Rn", MulName);
IValueT Rm = encodeRegister(OpSrc1, "Rm", MulName);
verifyRegNotPc(Rd, "Rd", MulName);
verifyRegNotPc(Rn, "Rn", MulName);
verifyRegNotPc(Rm, "Rm", MulName);
// Assembler registers rd, rn, rm are encoded as rn, rm, rs. // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
constexpr IValueT MulOpcode = 0; constexpr IValueT MulOpcode = 0;
emitMulOp(Cond, MulOpcode, RegARM32::Encoded_Reg_r0, Rd, Rn, Rm, SetFlags); emitMulOp(Cond, MulOpcode, RegARM32::Encoded_Reg_r0, Rd, Rn, Rm, SetFlags,
MulName);
} }
void AssemblerARM32::udiv(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::udiv(const Operand *OpRd, const Operand *OpRn,
...@@ -1465,21 +1514,16 @@ void AssemblerARM32::udiv(const Operand *OpRd, const Operand *OpRn, ...@@ -1465,21 +1514,16 @@ void AssemblerARM32::udiv(const Operand *OpRd, const Operand *OpRn,
// //
// cccc01110011dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and // cccc01110011dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and
// mmmm=Rm. // mmmm=Rm.
IValueT Rd; constexpr const char *UdivName = "udiv";
if (encodeOperand(OpRd, Rd) != EncodedAsRegister) IValueT Rd = encodeRegister(OpRd, "Rd", UdivName);
return setNeedsTextFixup(); IValueT Rn = encodeRegister(OpRn, "Rn", UdivName);
IValueT Rn; IValueT Rm = encodeRegister(OpSrc1, "Rm", UdivName);
if (encodeOperand(OpRn, Rn) != EncodedAsRegister) verifyRegNotPc(Rd, "Rd", UdivName);
return setNeedsTextFixup(); verifyRegNotPc(Rn, "Rn", UdivName);
IValueT Rm; verifyRegNotPc(Rm, "Rm", UdivName);
if (encodeOperand(OpSrc1, Rm) != EncodedAsRegister)
return setNeedsTextFixup();
if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc ||
Rm == RegARM32::Encoded_Reg_pc)
llvm::report_fatal_error("Udiv instruction unpredictable on pc");
// Assembler registers rd, rn, rm are encoded as rn, rm, rs. // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
constexpr IValueT Opcode = B21; constexpr IValueT UdivOpcode = B21;
emitDivOp(Cond, Opcode, Rd, Rn, Rm); emitDivOp(Cond, UdivOpcode, Rd, Rn, Rm, UdivName);
} }
void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
...@@ -1500,8 +1544,10 @@ void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, ...@@ -1500,8 +1544,10 @@ void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
// //
// cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8
constexpr IValueT Sub = B1; // 0010 constexpr const char *SubName = "sub";
emitType01(Sub, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags); constexpr IValueT SubOpcode = B1; // 0010
emitType01(Cond, SubOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
SubName);
} }
void AssemblerARM32::tst(const Operand *OpRn, const Operand *OpSrc1, void AssemblerARM32::tst(const Operand *OpRn, const Operand *OpSrc1,
...@@ -1517,8 +1563,9 @@ void AssemblerARM32::tst(const Operand *OpRn, const Operand *OpSrc1, ...@@ -1517,8 +1563,9 @@ void AssemblerARM32::tst(const Operand *OpRn, const Operand *OpSrc1,
// //
// cccc00110001nnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn, and // cccc00110001nnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn, and
// iiiiiiiiiiii defines RotatedImm8. // iiiiiiiiiiii defines RotatedImm8.
constexpr IValueT Opcode = B3; // ie. 1000 constexpr const char *TstName = "tst";
emitCompareOp(Opcode, OpRn, OpSrc1, Cond); constexpr IValueT TstOpcode = B3; // ie. 1000
emitCompareOp(Cond, TstOpcode, OpRn, OpSrc1, TstName);
} }
void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi, void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi,
...@@ -1529,45 +1576,40 @@ void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi, ...@@ -1529,45 +1576,40 @@ void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi,
// //
// cccc0000100shhhhllllmmmm1001nnnn where hhhh=RdHi, llll=RdLo, nnnn=Rn, // cccc0000100shhhhllllmmmm1001nnnn where hhhh=RdHi, llll=RdLo, nnnn=Rn,
// mmmm=Rm, and s=SetFlags // mmmm=Rm, and s=SetFlags
IValueT RdLo; constexpr const char *UmullName = "umull";
IValueT RdHi; IValueT RdLo = encodeRegister(OpRdLo, "RdLo", UmullName);
IValueT Rn; IValueT RdHi = encodeRegister(OpRdHi, "RdHi", UmullName);
IValueT Rm; IValueT Rn = encodeRegister(OpRn, "Rn", UmullName);
if (encodeOperand(OpRdLo, RdLo) != EncodedAsRegister || IValueT Rm = encodeRegister(OpRm, "Rm", UmullName);
encodeOperand(OpRdHi, RdHi) != EncodedAsRegister || verifyRegNotPc(RdLo, "RdLo", UmullName);
encodeOperand(OpRn, Rn) != EncodedAsRegister || verifyRegNotPc(RdHi, "RdHi", UmullName);
encodeOperand(OpRm, Rm) != EncodedAsRegister) verifyRegNotPc(Rn, "Rn", UmullName);
return setNeedsTextFixup(); verifyRegNotPc(Rm, "Rm", UmullName);
if (RdHi == RegARM32::Encoded_Reg_pc || RdLo == RegARM32::Encoded_Reg_pc || verifyRegsNotEq(RdHi, "RdHi", RdLo, "RdLo", UmullName);
Rn == RegARM32::Encoded_Reg_pc || Rm == RegARM32::Encoded_Reg_pc || constexpr IValueT UmullOpcode = B23;
RdHi == RdLo)
llvm::report_fatal_error("Umull instruction unpredictable on pc");
constexpr bool SetFlags = false; constexpr bool SetFlags = false;
emitMulOp(Cond, B23, RdLo, RdHi, Rn, Rm, SetFlags); emitMulOp(Cond, UmullOpcode, RdLo, RdHi, Rn, Rm, SetFlags, UmullName);
} }
void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0, void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
IValueT Rd; constexpr const char *UxtName = "uxt";
if (encodeOperand(OpRd, Rd) != EncodedAsRegister) IValueT Rd = encodeRegister(OpRd, "Rd", UxtName);
return setNeedsTextFixup(); IValueT Rm = encodeRegister(OpSrc0, "Rm", UxtName);
// Note: For the moment, we assume no rotation is specified. // Note: For the moment, we assume no rotation is specified.
RotationValue Rotation = kRotateNone; RotationValue Rotation = kRotateNone;
constexpr IValueT Rn = RegARM32::Encoded_Reg_pc; constexpr IValueT Rn = RegARM32::Encoded_Reg_pc;
IValueT Rm;
if (encodeOperand(OpSrc0, Rm) != EncodedAsRegister)
return setNeedsTextFixup();
switch (typeWidthInBytes(OpSrc0->getType())) { switch (typeWidthInBytes(OpSrc0->getType())) {
default: default:
return setNeedsTextFixup(); llvm::report_fatal_error("Type of Rm not understood: uxt");
case 1: { case 1: {
// UXTB - ARM section A8.8.274, encoding A1: // UXTB - ARM section A8.8.274, encoding A1:
// uxtb<c> <Rd>, <Rm>{, <rotate>} // uxtb<c> <Rd>, <Rm>{, <rotate>}
// //
// cccc011011101111ddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and // cccc011011101111ddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and
// rr defined (RotationValue) rotate. // rr defined (RotationValue) rotate.
constexpr IValueT Opcode = B26 | B25 | B23 | B22 | B21; constexpr IValueT UxtOpcode = B26 | B25 | B23 | B22 | B21;
emitUxt(Cond, Opcode, Rd, Rn, Rm, Rotation); emitUxt(Cond, UxtOpcode, Rd, Rn, Rm, Rotation, UxtName);
return; return;
} }
case 2: { case 2: {
...@@ -1576,8 +1618,8 @@ void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0, ...@@ -1576,8 +1618,8 @@ void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0,
// //
// cccc01101111nnnnddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and // cccc01101111nnnnddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and
// rr defined (RotationValue) rotate. // rr defined (RotationValue) rotate.
constexpr IValueT Opcode = B26 | B25 | B23 | B22 | B21 | B20; constexpr IValueT UxtOpcode = B26 | B25 | B23 | B22 | B21 | B20;
emitUxt(Cond, Opcode, Rd, Rn, Rm, Rotation); emitUxt(Cond, UxtOpcode, Rd, Rn, Rm, Rotation, UxtName);
return; return;
} }
} }
......
...@@ -316,69 +316,74 @@ private: ...@@ -316,69 +316,74 @@ private:
// List of possible checks to apply when calling emitType01() (below). // List of possible checks to apply when calling emitType01() (below).
enum EmitChecks { NoChecks, RdIsPcAndSetFlags }; enum EmitChecks { NoChecks, RdIsPcAndSetFlags };
// Pattern cccctttoooosnnnnddddiiiiiiiiiiii where cccc=Cond, ttt=Type, // Pattern cccctttoooosnnnnddddiiiiiiiiiiii where cccc=Cond, ttt=InstType,
// s=SetFlags, oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM // s=SetFlags, oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM
// section A5.2.3). // section A5.2.3).
void emitType01(CondARM32::Cond Cond, IValueT Type, IValueT Opcode, void emitType01(CondARM32::Cond Cond, IValueT InstType, IValueT Opcode,
bool SetFlags, IValueT Rn, IValueT Rd, IValueT imm12, bool SetFlags, IValueT Rn, IValueT Rd, IValueT imm12,
EmitChecks RuleChecks); EmitChecks RuleChecks, const char *InstName);
// Converts appropriate representation on a data operation, and then calls // Converts appropriate representation on a data operation, and then calls
// emitType01 above. // emitType01 above.
void emitType01(IValueT Opcode, const Operand *OpRd, const Operand *OpRn, void emitType01(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpRd,
const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond, const Operand *OpRn, const Operand *OpSrc1, bool SetFlags,
EmitChecks RuleChecks); EmitChecks RuleChecks, const char *InstName);
// Same as above, but the value for Rd and Rn have already been converted // Same as above, but the value for Rd and Rn have already been converted
// into instruction values. // into instruction values.
void emitType01(IValueT Opcode, IValueT OpRd, IValueT OpRn, void emitType01(CondARM32::Cond Cond, IValueT Opcode, IValueT OpRd,
const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond, IValueT OpRn, const Operand *OpSrc1, bool SetFlags,
EmitChecks RuleChecks); EmitChecks RuleChecks, const char *InstName);
void emitType05(CondARM32::Cond COnd, int32_t Offset, bool Link); void emitType05(CondARM32::Cond Cond, int32_t Offset, bool Link,
const char *InstName);
// Emit ccccoooaabalnnnnttttaaaaaaaaaaaa where cccc=Cond, // Emit ccccoooaabalnnnnttttaaaaaaaaaaaa where cccc=Cond,
// ooo=InstType, l=isLoad, b=isByte, and // ooo=InstType, l=isLoad, b=isByte, and
// aaa0a0aaaa0000aaaaaaaaaaaa=Address. Note that Address is assumed to be // aaa0a0aaaa0000aaaaaaaaaaaa=Address. Note that Address is assumed to be
// defined by decodeAddress() in 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, IValueT Rt, IValueT Address); bool IsByte, IValueT Rt, IValueT Address,
const char *InstName);
// Emit ldr/ldrb/str/strb instruction with given address. // Emit ldr/ldrb/str/strb instruction with given address.
void emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, IValueT Rt, void emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, IValueT Rt,
const Operand *OpAddress, const TargetInfo &TInfo); const Operand *OpAddress, const TargetInfo &TInfo,
const char *InstName);
// Emit ldrh/ldrd/strh/strd instruction with given address using encoding 3. // Emit ldrh/ldrd/strh/strd instruction with given address using encoding 3.
void emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, IValueT Rt, void emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, IValueT Rt,
const Operand *OpAddress, const TargetInfo &TInfo); const Operand *OpAddress, const TargetInfo &TInfo,
const char *InstName);
// 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
// rrrrrrrrrrrrrrrr is bitset of Registers. // rrrrrrrrrrrrrrrr is bitset of Registers.
void emitMultiMemOp(CondARM32::Cond Cond, BlockAddressMode AddressMode, void emitMultiMemOp(CondARM32::Cond Cond, BlockAddressMode AddressMode,
bool IsLoad, IValueT BaseReg, IValueT Registers); bool IsLoad, IValueT BaseReg, IValueT Registers,
const char *InstName);
// Pattern cccc011100x1dddd1111mmmm0001nnn where cccc=Cond, // Pattern cccc011100x1dddd1111mmmm0001nnn where cccc=Cond,
// x=Opcode, dddd=Rd, nnnn=Rn, mmmm=Rm. // x=Opcode, dddd=Rd, nnnn=Rn, mmmm=Rm.
void emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn, void emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
IValueT Rm); IValueT Rm, const char *InstName);
// Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn, // Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
// mmmm=Rm, ssss=Rs, f=SetFlags and xxxxxxx=Opcode. // mmmm=Rm, ssss=Rs, f=SetFlags and xxxxxxx=Opcode.
void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn, void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
IValueT Rm, IValueT Rs, bool SetFlags); IValueT Rm, IValueT Rs, bool SetFlags, const char *InstName);
// Implements various forms of Unsigned extend value, using pattern // Implements various forms of Unsigned extend value, using pattern
// ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode, // ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode,
// nnnn=Rn, dddd=Rd, rr=Rotation, and mmmm=Rm. // nnnn=Rn, dddd=Rd, rr=Rotation, and mmmm=Rm.
void emitUxt(CondARM32::Cond, IValueT Opcode, IValueT Rd, IValueT Rn, void emitUxt(CondARM32::Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
IValueT Rm, RotationValue Rotation); IValueT Rm, RotationValue Rotation, const char *InstName);
// Pattern cccctttxxxxnnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn, // Pattern cccctttxxxxnnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn,
// ttt=Instruction type (derived from OpSrc1), iiiiiiiiiiii is derived from // ttt=Instruction type (derived from OpSrc1), iiiiiiiiiiii is derived from
// OpSrc1, and xxxx=Opcode. // OpSrc1, and xxxx=Opcode.
void emitCompareOp(IValueT Opcode, const Operand *OpRn, const Operand *OpSrc1, void emitCompareOp(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpRn,
CondARM32::Cond Cond); const Operand *OpSrc1, const char *CmpName);
void emitBranch(Label *L, CondARM32::Cond, bool Link); void emitBranch(Label *L, CondARM32::Cond, bool Link);
......
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