Commit 4acf11ac by Karl Schimpf

Add VADD instruction to the ARM integrated assembler.

parent 4f69e018
...@@ -880,7 +880,8 @@ void Assembler::vstmd(BlockAddressMode am, Register base, ...@@ -880,7 +880,8 @@ void Assembler::vstmd(BlockAddressMode am, Register base,
EmitMultiVDMemOp(cond, am, false, base, first, count); EmitMultiVDMemOp(cond, am, false, base, first, count);
} }
#if 0
// Moved to ARM32::AssemblerARM32::emitVFPsss
void Assembler::EmitVFPsss(Condition cond, int32_t opcode, void Assembler::EmitVFPsss(Condition cond, int32_t opcode,
SRegister sd, SRegister sn, SRegister sm) { SRegister sd, SRegister sn, SRegister sm) {
ASSERT(TargetCPUFeatures::vfp_supported()); ASSERT(TargetCPUFeatures::vfp_supported());
...@@ -899,7 +900,7 @@ void Assembler::EmitVFPsss(Condition cond, int32_t opcode, ...@@ -899,7 +900,7 @@ void Assembler::EmitVFPsss(Condition cond, int32_t opcode,
Emit(encoding); Emit(encoding);
} }
// Moved to ARM32::AssemblerARM32::emitVFPddd
void Assembler::EmitVFPddd(Condition cond, int32_t opcode, void Assembler::EmitVFPddd(Condition cond, int32_t opcode,
DRegister dd, DRegister dn, DRegister dm) { DRegister dd, DRegister dn, DRegister dm) {
ASSERT(TargetCPUFeatures::vfp_supported()); ASSERT(TargetCPUFeatures::vfp_supported());
...@@ -917,7 +918,7 @@ void Assembler::EmitVFPddd(Condition cond, int32_t opcode, ...@@ -917,7 +918,7 @@ void Assembler::EmitVFPddd(Condition cond, int32_t opcode,
(static_cast<int32_t>(dm) & 0xf); (static_cast<int32_t>(dm) & 0xf);
Emit(encoding); Emit(encoding);
} }
#endif
void Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) { void Assembler::vmovs(SRegister sd, SRegister sm, Condition cond) {
EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm); EmitVFPsss(cond, B23 | B21 | B20 | B6, sd, S0, sm);
...@@ -964,18 +965,19 @@ bool Assembler::vmovd(DRegister dd, double d_imm, Condition cond) { ...@@ -964,18 +965,19 @@ bool Assembler::vmovd(DRegister dd, double d_imm, Condition cond) {
return false; return false;
} }
#if 0
// Moved to Arm32::AssemblerARM32::vadds()
void Assembler::vadds(SRegister sd, SRegister sn, SRegister sm, void Assembler::vadds(SRegister sd, SRegister sn, SRegister sm,
Condition cond) { Condition cond) {
EmitVFPsss(cond, B21 | B20, sd, sn, sm); EmitVFPsss(cond, B21 | B20, sd, sn, sm);
} }
// Moved to Arm32::AssemblerARM32::vaddd()
void Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm, void Assembler::vaddd(DRegister dd, DRegister dn, DRegister dm,
Condition cond) { Condition cond) {
EmitVFPddd(cond, B21 | B20, dd, dn, dm); EmitVFPddd(cond, B21 | B20, dd, dn, dm);
} }
#endif
void Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm, void Assembler::vsubs(SRegister sd, SRegister sn, SRegister sm,
Condition cond) { Condition cond) {
......
...@@ -647,8 +647,12 @@ class Assembler : public ValueObject { ...@@ -647,8 +647,12 @@ class Assembler : public ValueObject {
void vstmd(BlockAddressMode am, Register base, void vstmd(BlockAddressMode am, Register base,
DRegister first, intptr_t count, Condition cond = AL); DRegister first, intptr_t count, Condition cond = AL);
#if 0
// Moved to Arm32::AssemblerARM32::vadds()
void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
// Moved to Arm32::AssemblerARM32::vaddd()
void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL);
#endif
void vaddqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); void vaddqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm);
void vaddqs(QRegister qd, QRegister qn, QRegister qm); void vaddqs(QRegister qd, QRegister qn, QRegister qm);
void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL);
...@@ -1228,7 +1232,7 @@ class Assembler : public ValueObject { ...@@ -1228,7 +1232,7 @@ class Assembler : public ValueObject {
Register rm, Register rm,
Register rs); Register rs);
// Moved to ARM32::AssemblerAR32::emitDivOp(); // Moved to ARM32::AssemblerARM32::emitDivOp();
void EmitDivOp(Condition cond, void EmitDivOp(Condition cond,
int32_t opcode, int32_t opcode,
Register rd, Register rd,
...@@ -1250,17 +1254,21 @@ class Assembler : public ValueObject { ...@@ -1250,17 +1254,21 @@ class Assembler : public ValueObject {
DRegister start, DRegister start,
int32_t count); int32_t count);
#if 0
// Moved to ARM32::AssemblerARM32::emitVFPsss
void EmitVFPsss(Condition cond, void EmitVFPsss(Condition cond,
int32_t opcode, int32_t opcode,
SRegister sd, SRegister sd,
SRegister sn, SRegister sn,
SRegister sm); SRegister sm);
// Moved to ARM32::AssemblerARM32::emitVFPddd
void EmitVFPddd(Condition cond, void EmitVFPddd(Condition cond,
int32_t opcode, int32_t opcode,
DRegister dd, DRegister dd,
DRegister dn, DRegister dn,
DRegister dm); DRegister dm);
#endif
void EmitVFPsd(Condition cond, void EmitVFPsd(Condition cond,
int32_t opcode, int32_t opcode,
......
...@@ -140,14 +140,6 @@ RegARM32::GPRRegister decodeGPRRegister(IValueT R) { ...@@ -140,14 +140,6 @@ RegARM32::GPRRegister decodeGPRRegister(IValueT R) {
return static_cast<RegARM32::GPRRegister>(R); return static_cast<RegARM32::GPRRegister>(R);
} }
bool isGPRRegisterDefined(IValueT R) {
return R != encodeGPRRegister(RegARM32::Encoded_Not_GPR);
}
bool isConditionDefined(CondARM32::Cond Cond) {
return Cond != CondARM32::kNone;
}
IValueT encodeCondition(CondARM32::Cond Cond) { IValueT encodeCondition(CondARM32::Cond Cond) {
return static_cast<IValueT>(Cond); return static_cast<IValueT>(Cond);
} }
...@@ -197,17 +189,28 @@ enum OpEncoding { ...@@ -197,17 +189,28 @@ enum OpEncoding {
}; };
IValueT getEncodedGPRegNum(const Variable *Var) { IValueT getEncodedGPRegNum(const Variable *Var) {
assert(Var->hasReg());
int32_t Reg = Var->getRegNum(); int32_t Reg = Var->getRegNum();
return llvm::isa<Variable64On32>(Var) ? RegARM32::getI64PairFirstGPRNum(Reg) return llvm::isa<Variable64On32>(Var) ? RegARM32::getI64PairFirstGPRNum(Reg)
: RegARM32::getEncodedGPR(Reg); : RegARM32::getEncodedGPReg(Reg);
} }
IValueT getEncodedSRegNum(const Variable *Var) { IValueT getEncodedSRegNum(const Variable *Var) {
assert(Var->hasReg());
assert(RegARM32::isEncodedSReg(Var->getRegNum()));
return RegARM32::getEncodedSReg(Var->getRegNum()); return RegARM32::getEncodedSReg(Var->getRegNum());
} }
IValueT getEncodedDRegNum(const Variable *Var) {
return RegARM32::getEncodedDReg(Var->getRegNum());
}
IValueT getYInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY & 0x1; }
IValueT getXXXXInRegXXXXY(IValueT RegXXXXY) { return RegXXXXY >> 1; }
IValueT getYInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX >> 4; }
IValueT getXXXXInRegYXXXX(IValueT RegYXXXX) { return RegYXXXX & 0x0f; }
// The way an operand is encoded into a sequence of bits in functions // The way an operand is encoded into a sequence of bits in functions
// encodeOperand and encodeAddress below. // encodeOperand and encodeAddress below.
enum EncodedOperand { enum EncodedOperand {
...@@ -278,11 +281,25 @@ IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift, ...@@ -278,11 +281,25 @@ IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift,
(Rm << kRmShift); (Rm << kRmShift);
} }
EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value) { // Defines the set of registers expected in an operand.
enum RegSetWanted { WantGPRegs, WantSRegs, WantDRegs };
EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value,
RegSetWanted WantedRegSet) {
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)) {
if (Var->hasReg()) { if (Var->hasReg()) {
Value = getEncodedGPRegNum(Var); switch (WantedRegSet) {
case WantGPRegs:
Value = getEncodedGPRegNum(Var);
break;
case WantSRegs:
Value = getEncodedSRegNum(Var);
break;
case WantDRegs:
Value = getEncodedDRegNum(Var);
break;
}
return EncodedAsRegister; return EncodedAsRegister;
} }
return CantEncode; return CantEncode;
...@@ -302,11 +319,11 @@ EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value) { ...@@ -302,11 +319,11 @@ EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value) {
if (const auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Opnd)) { if (const auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Opnd)) {
Operand *Amt = FlexReg->getShiftAmt(); Operand *Amt = FlexReg->getShiftAmt();
IValueT Rm; IValueT Rm;
if (encodeOperand(FlexReg->getReg(), Rm) != EncodedAsRegister) if (encodeOperand(FlexReg->getReg(), Rm, WantGPRegs) != EncodedAsRegister)
return CantEncode; return CantEncode;
if (const auto *Var = llvm::dyn_cast<Variable>(Amt)) { if (const auto *Var = llvm::dyn_cast<Variable>(Amt)) {
IValueT Rs; IValueT Rs;
if (encodeOperand(Var, Rs) != EncodedAsRegister) if (encodeOperand(Var, Rs, WantGPRegs) != EncodedAsRegister)
return CantEncode; return CantEncode;
Value = encodeShiftRotateReg(Rm, FlexReg->getShiftOp(), Rs); Value = encodeShiftRotateReg(Rm, FlexReg->getShiftOp(), Rs);
return EncodedAsRegShiftReg; return EncodedAsRegShiftReg;
...@@ -421,27 +438,28 @@ bool canEncodeBranchOffset(IOffsetT Offset) { ...@@ -421,27 +438,28 @@ bool canEncodeBranchOffset(IOffsetT Offset) {
Utils::IsInt(kBranchOffsetBits, Offset >> 2); Utils::IsInt(kBranchOffsetBits, Offset >> 2);
} }
IValueT encodeRegister(const Operand *OpReg, const char *RegName, IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet,
const char *InstName) { const char *RegName, const char *InstName) {
IValueT Reg = 0; IValueT Reg = 0;
if (encodeOperand(OpReg, Reg) != EncodedAsRegister) if (encodeOperand(OpReg, Reg, WantedRegSet) != EncodedAsRegister)
llvm::report_fatal_error(std::string(InstName) + ": Can't find register " + llvm::report_fatal_error(std::string(InstName) + ": Can't find register " +
RegName); RegName);
return Reg; return Reg;
} }
void verifyRegDefined(IValueT Reg, const char *RegName, const char *InstName) { IValueT encodeGPRegister(const Operand *OpReg, const char *RegName,
if (BuildDefs::minimal()) const char *InstName) {
return; return encodeRegister(OpReg, WantGPRegs, RegName, InstName);
if (!isGPRRegisterDefined(Reg))
llvm::report_fatal_error(std::string(InstName) + ": Can't find " + RegName);
} }
void verifyCondDefined(CondARM32::Cond Cond, const char *InstName) { IValueT encodeSRegister(const Operand *OpReg, const char *RegName,
if (BuildDefs::minimal()) const char *InstName) {
return; return encodeRegister(OpReg, WantSRegs, RegName, InstName);
if (!isConditionDefined(Cond)) }
llvm::report_fatal_error(std::string(InstName) + ": Condition not defined");
IValueT encodeDRegister(const Operand *OpReg, const char *RegName,
const char *InstName) {
return encodeRegister(OpReg, WantDRegs, RegName, InstName);
} }
void verifyPOrNotW(IValueT Address, const char *InstName) { void verifyPOrNotW(IValueT Address, const char *InstName) {
...@@ -631,8 +649,8 @@ void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT InstType, ...@@ -631,8 +649,8 @@ void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT InstType,
verifyRegNotPcWhenSetFlags(Rd, SetFlags, InstName); verifyRegNotPcWhenSetFlags(Rd, SetFlags, InstName);
break; break;
} }
verifyRegDefined(Rd, "Rd", InstName); assert(Rd < RegARM32::getNumGPRegs());
verifyCondDefined(Cond, InstName); assert(CondARM32::isDefined(Cond));
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
(InstType << kTypeShift) | (Opcode << kOpcodeShift) | (InstType << kTypeShift) | (Opcode << kOpcodeShift) |
...@@ -645,8 +663,8 @@ void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Opcode, ...@@ -645,8 +663,8 @@ void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Opcode,
const Operand *OpRd, const Operand *OpRn, const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
EmitChecks RuleChecks, const char *InstName) { EmitChecks RuleChecks, const char *InstName) {
IValueT Rd = encodeRegister(OpRd, "Rd", InstName); IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
IValueT Rn = encodeRegister(OpRn, "Rn", InstName); IValueT Rn = encodeGPRegister(OpRn, "Rn", InstName);
emitType01(Cond, Opcode, Rd, Rn, OpSrc1, SetFlags, RuleChecks, InstName); emitType01(Cond, Opcode, Rd, Rn, OpSrc1, SetFlags, RuleChecks, InstName);
} }
...@@ -656,7 +674,7 @@ void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Opcode, ...@@ -656,7 +674,7 @@ void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Opcode,
const char *InstName) { 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, WantGPRegs)) {
default: default:
llvm::report_fatal_error(std::string(InstName) + llvm::report_fatal_error(std::string(InstName) +
": Can't encode instruction"); ": Can't encode instruction");
...@@ -714,11 +732,11 @@ void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Opcode, ...@@ -714,11 +732,11 @@ void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Opcode,
} }
void AssemblerARM32::emitType05(CondARM32::Cond Cond, IOffsetT Offset, void AssemblerARM32::emitType05(CondARM32::Cond Cond, IOffsetT Offset,
bool Link, const char *InstName) { bool Link) {
// cccc101liiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond, l=Link, and // cccc101liiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond, l=Link, and
// iiiiiiiiiiiiiiiiiiiiiiii= // iiiiiiiiiiiiiiiiiiiiiiii=
// EncodedBranchOffset(cccc101l000000000000000000000000, Offset); // EncodedBranchOffset(cccc101l000000000000000000000000, Offset);
verifyCondDefined(Cond, InstName); assert(CondARM32::isDefined(Cond));
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;
...@@ -728,15 +746,14 @@ void AssemblerARM32::emitType05(CondARM32::Cond Cond, IOffsetT Offset, ...@@ -728,15 +746,14 @@ 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, BranchName); emitType05(Cond, Dest, Link);
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, BranchName); emitType05(Cond, L->getEncodedPosition(), Link);
L->linkTo(*this, Position); L->linkTo(*this, Position);
} }
...@@ -758,15 +775,15 @@ void AssemblerARM32::emitCompareOp(CondARM32::Cond Cond, IValueT Opcode, ...@@ -758,15 +775,15 @@ void AssemblerARM32::emitCompareOp(CondARM32::Cond Cond, IValueT Opcode,
// 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 = encodeRegister(OpRn, "Rn", InstName); IValueT Rn = encodeGPRegister(OpRn, "Rn", InstName);
emitType01(Cond, Opcode, Rd, Rn, OpSrc1, SetFlags, NoChecks, InstName); emitType01(Cond, Opcode, Rd, Rn, OpSrc1, SetFlags, NoChecks, InstName);
} }
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, const char *InstName) { IValueT Address) {
verifyRegDefined(Rt, "Rt", InstName); assert(Rt < RegARM32::getNumGPRegs());
verifyCondDefined(Cond, InstName); assert(CondARM32::isDefined(Cond));
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) |
...@@ -802,8 +819,7 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, ...@@ -802,8 +819,7 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte,
llvm::report_fatal_error(std::string(InstName) + llvm::report_fatal_error(std::string(InstName) +
": Use push/pop instead"); ": Use push/pop instead");
emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address, emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
InstName);
return; return;
} }
case EncodedAsShiftRotateImm5: { case EncodedAsShiftRotateImm5: {
...@@ -826,8 +842,7 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, ...@@ -826,8 +842,7 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte,
verifyRegNotPc(Rn, "Rn", InstName); verifyRegNotPc(Rn, "Rn", InstName);
verifyRegsNotEq(Rn, "Rn", Rt, "Rt", InstName); verifyRegsNotEq(Rn, "Rn", Rt, "Rt", InstName);
} }
emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address, emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address);
InstName);
return; return;
} }
} }
...@@ -851,8 +866,8 @@ void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, ...@@ -851,8 +866,8 @@ 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.
verifyRegDefined(Rt, "Rt", InstName); assert(Rt < RegARM32::getNumGPRegs());
verifyCondDefined(Cond, InstName); assert(CondARM32::isDefined(Cond));
verifyPOrNotW(Address, InstName); verifyPOrNotW(Address, InstName);
verifyRegNotPc(Rt, "Rt", InstName); verifyRegNotPc(Rt, "Rt", InstName);
if (isBitSet(W, Address)) if (isBitSet(W, Address))
...@@ -871,8 +886,8 @@ void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, ...@@ -871,8 +886,8 @@ 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.
verifyRegDefined(Rt, "Rt", InstName); assert(Rt < RegARM32::getNumGPRegs());
verifyCondDefined(Cond, InstName); assert(CondARM32::isDefined(Cond));
verifyPOrNotW(Address, InstName); verifyPOrNotW(Address, InstName);
verifyRegNotPc(Rt, "Rt", InstName); verifyRegNotPc(Rt, "Rt", InstName);
verifyAddrRegNotPc(kRmShift, Address, "Rm", InstName); verifyAddrRegNotPc(kRmShift, Address, "Rm", InstName);
...@@ -895,11 +910,11 @@ void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, ...@@ -895,11 +910,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, const char *InstName) { IValueT Rn, IValueT Rm) {
verifyRegDefined(Rd, "Rd", InstName); assert(Rd < RegARM32::getNumGPRegs());
verifyRegDefined(Rn, "Rn", InstName); assert(Rn < RegARM32::getNumGPRegs());
verifyRegDefined(Rm, "Rm", InstName); assert(Rm < RegARM32::getNumGPRegs());
verifyCondDefined(Cond, InstName); assert(CondARM32::isDefined(Cond));
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 |
...@@ -910,12 +925,12 @@ void AssemblerARM32::emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, ...@@ -910,12 +925,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, const char *InstName) { bool SetFlags) {
verifyRegDefined(Rd, "Rd", InstName); assert(Rd < RegARM32::getNumGPRegs());
verifyRegDefined(Rn, "Rn", InstName); assert(Rn < RegARM32::getNumGPRegs());
verifyRegDefined(Rm, "Rm", InstName); assert(Rm < RegARM32::getNumGPRegs());
verifyRegDefined(Rs, "Rs", InstName); assert(Rs < RegARM32::getNumGPRegs());
verifyCondDefined(Cond, InstName); assert(CondARM32::isDefined(Cond));
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) |
...@@ -926,14 +941,10 @@ void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, ...@@ -926,14 +941,10 @@ void AssemblerARM32::emitMulOp(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) { assert(CondARM32::isDefined(Cond));
constexpr IValueT NumGPRegisters = 16; assert(BaseReg < RegARM32::getNumGPRegs());
verifyCondDefined(Cond, InstName); assert(Registers < (1 << RegARM32::getNumGPRegs()));
verifyRegDefined(BaseReg, "base", InstName);
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) |
...@@ -944,8 +955,8 @@ void AssemblerARM32::emitMultiMemOp(CondARM32::Cond Cond, ...@@ -944,8 +955,8 @@ void AssemblerARM32::emitMultiMemOp(CondARM32::Cond Cond,
void AssemblerARM32::emitSignExtend(CondARM32::Cond Cond, IValueT Opcode, void AssemblerARM32::emitSignExtend(CondARM32::Cond Cond, IValueT Opcode,
const Operand *OpRd, const Operand *OpSrc0, const Operand *OpRd, const Operand *OpSrc0,
const char *InstName) { const char *InstName) {
IValueT Rd = encodeRegister(OpRd, "Rd", InstName); IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
IValueT Rm = encodeRegister(OpSrc0, "Rm", InstName); IValueT Rm = encodeGPRegister(OpSrc0, "Rm", InstName);
// 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;
...@@ -976,7 +987,7 @@ void AssemblerARM32::emitSignExtend(CondARM32::Cond Cond, IValueT Opcode, ...@@ -976,7 +987,7 @@ void AssemblerARM32::emitSignExtend(CondARM32::Cond Cond, IValueT Opcode,
} }
} }
verifyCondDefined(Cond, InstName); assert(CondARM32::isDefined(Cond));
IValueT Rot = encodeRotation(Rotation); IValueT Rot = encodeRotation(Rotation);
if (!Utils::IsUint(2, Rot)) if (!Utils::IsUint(2, Rot))
llvm::report_fatal_error(std::string(InstName) + llvm::report_fatal_error(std::string(InstName) +
...@@ -988,6 +999,38 @@ void AssemblerARM32::emitSignExtend(CondARM32::Cond Cond, IValueT Opcode, ...@@ -988,6 +999,38 @@ void AssemblerARM32::emitSignExtend(CondARM32::Cond Cond, IValueT Opcode,
emitInst(Encoding); emitInst(Encoding);
} }
void AssemblerARM32::emitVFPddd(CondARM32::Cond Cond, IValueT Opcode,
IValueT Dd, IValueT Dn, IValueT Dm) {
assert(Dd < RegARM32::getNumDRegs());
assert(Dn < RegARM32::getNumDRegs());
assert(Dm < RegARM32::getNumDRegs());
assert(CondARM32::isDefined(Cond));
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9 | B8;
const IValueT Encoding =
Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) |
(getYInRegYXXXX(Dd) << 22) | (getXXXXInRegYXXXX(Dn) << 16) |
(getXXXXInRegYXXXX(Dn) << 12) | (getYInRegYXXXX(Dn) << 7) |
(getYInRegYXXXX(Dm) << 5) | getXXXXInRegYXXXX(Dm);
emitInst(Encoding);
}
void AssemblerARM32::emitVFPsss(CondARM32::Cond Cond, IValueT Opcode,
IValueT Sd, IValueT Sn, IValueT Sm) {
assert(Sd < RegARM32::getNumSRegs());
assert(Sn < RegARM32::getNumSRegs());
assert(Sm < RegARM32::getNumSRegs());
assert(CondARM32::isDefined(Cond));
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
constexpr IValueT VFPOpcode = B27 | B26 | B25 | B11 | B9;
const IValueT Encoding =
Opcode | VFPOpcode | (encodeCondition(Cond) << kConditionShift) |
(getYInRegXXXXY(Sd) << 22) | (getXXXXInRegXXXXY(Sn) << 16) |
(getXXXXInRegXXXXY(Sd) << 12) | (getYInRegXXXXY(Sn) << 7) |
(getYInRegXXXXY(Sm) << 5) | getXXXXInRegXXXXY(Sm);
emitInst(Encoding);
}
void AssemblerARM32::adc(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::adc(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
...@@ -1094,11 +1137,10 @@ void AssemblerARM32::bl(const ConstantRelocatable *Target) { ...@@ -1094,11 +1137,10 @@ 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, BlName); emitType05(Cond, Immed, Link);
} }
void AssemblerARM32::blx(const Operand *Target) { void AssemblerARM32::blx(const Operand *Target) {
...@@ -1108,7 +1150,7 @@ void AssemblerARM32::blx(const Operand *Target) { ...@@ -1108,7 +1150,7 @@ void AssemblerARM32::blx(const Operand *Target) {
// cccc000100101111111111110011mmmm where cccc=Cond (not currently allowed) // cccc000100101111111111110011mmmm where cccc=Cond (not currently allowed)
// and mmmm=Rm. // and mmmm=Rm.
constexpr const char *BlxName = "Blx"; constexpr const char *BlxName = "Blx";
IValueT Rm = encodeRegister(Target, "Rm", BlxName); IValueT Rm = encodeGPRegister(Target, "Rm", BlxName);
verifyRegNotPc(Rm, "Rm", BlxName); verifyRegNotPc(Rm, "Rm", BlxName);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
constexpr CondARM32::Cond Cond = CondARM32::AL; constexpr CondARM32::Cond Cond = CondARM32::AL;
...@@ -1122,9 +1164,7 @@ void AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) { ...@@ -1122,9 +1164,7 @@ 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.
constexpr const char *BxName = "bx"; assert(CondARM32::isDefined(Cond));
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 |
...@@ -1141,13 +1181,13 @@ void AssemblerARM32::clz(const Operand *OpRd, const Operand *OpSrc, ...@@ -1141,13 +1181,13 @@ void AssemblerARM32::clz(const Operand *OpRd, const Operand *OpSrc,
constexpr const char *ClzName = "clz"; constexpr const char *ClzName = "clz";
constexpr const char *RdName = "Rd"; constexpr const char *RdName = "Rd";
constexpr const char *RmName = "Rm"; constexpr const char *RmName = "Rm";
IValueT Rd = encodeRegister(OpRd, RdName, ClzName); IValueT Rd = encodeGPRegister(OpRd, RdName, ClzName);
verifyRegDefined(Rd, RdName, ClzName); assert(Rd < RegARM32::getNumGPRegs());
verifyRegNotPc(Rd, RdName, ClzName); verifyRegNotPc(Rd, RdName, ClzName);
IValueT Rm = encodeRegister(OpSrc, RmName, ClzName); IValueT Rm = encodeGPRegister(OpSrc, RmName, ClzName);
verifyRegDefined(Rm, RmName, ClzName); assert(Rm < RegARM32::getNumGPRegs());
verifyRegNotPc(Rm, RmName, ClzName); verifyRegNotPc(Rm, RmName, ClzName);
verifyCondDefined(Cond, ClzName); assert(CondARM32::isDefined(Cond));
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
constexpr IValueT PredefinedBits = constexpr IValueT PredefinedBits =
B24 | B22 | B21 | (0xF << 16) | (0xf << 8) | B4; B24 | B22 | B21 | (0xF << 16) | (0xf << 8) | B4;
...@@ -1230,7 +1270,7 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, ...@@ -1230,7 +1270,7 @@ 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 const char *LdrName = "ldr";
constexpr bool IsLoad = true; constexpr bool IsLoad = true;
IValueT Rt = encodeRegister(OpRt, "Rt", LdrName); IValueT Rt = encodeGPRegister(OpRt, "Rt", LdrName);
const Type Ty = OpRt->getType(); const Type Ty = OpRt->getType();
switch (Ty) { switch (Ty) {
case IceType_i64: case IceType_i64:
...@@ -1303,7 +1343,7 @@ void AssemblerARM32::emitMemExOp(CondARM32::Cond Cond, Type Ty, bool IsLoad, ...@@ -1303,7 +1343,7 @@ void AssemblerARM32::emitMemExOp(CondARM32::Cond Cond, Type Ty, bool IsLoad,
const Operand *OpAddress, const Operand *OpAddress,
const TargetInfo &TInfo, const TargetInfo &TInfo,
const char *InstName) { const char *InstName) {
IValueT Rd = encodeRegister(OpRd, "Rd", InstName); IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
IValueT MemExOpcode = IsLoad ? B0 : 0; IValueT MemExOpcode = IsLoad ? B0 : 0;
switch (Ty) { switch (Ty) {
default: default:
...@@ -1327,9 +1367,9 @@ void AssemblerARM32::emitMemExOp(CondARM32::Cond Cond, Type Ty, bool IsLoad, ...@@ -1327,9 +1367,9 @@ void AssemblerARM32::emitMemExOp(CondARM32::Cond Cond, Type Ty, bool IsLoad,
llvm::report_fatal_error(std::string(InstName) + llvm::report_fatal_error(std::string(InstName) +
": Can't extract Rn from address"); ": Can't extract Rn from address");
assert(Utils::IsAbsoluteUint(3, MemExOpcode)); assert(Utils::IsAbsoluteUint(3, MemExOpcode));
verifyRegDefined(Rd, "Rd", InstName); assert(Rd < RegARM32::getNumGPRegs());
verifyRegDefined(Rt, "Rt", InstName); assert(Rt < RegARM32::getNumGPRegs());
verifyCondDefined(Cond, InstName); assert(CondARM32::isDefined(Cond));
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
IValueT Encoding = (Cond << kConditionShift) | B24 | B23 | B11 | B10 | B9 | IValueT Encoding = (Cond << kConditionShift) | B24 | B23 | B11 | B10 | B9 |
B8 | B7 | B4 | (MemExOpcode << kMemExOpcodeShift) | B8 | B7 | B4 | (MemExOpcode << kMemExOpcodeShift) |
...@@ -1372,10 +1412,10 @@ void AssemblerARM32::emitShift(const CondARM32::Cond Cond, ...@@ -1372,10 +1412,10 @@ void AssemblerARM32::emitShift(const CondARM32::Cond Cond,
const Operand *OpSrc1, const bool SetFlags, const Operand *OpSrc1, const bool SetFlags,
const char *InstName) { const char *InstName) {
constexpr IValueT ShiftOpcode = B3 | B2 | B0; // 1101 constexpr IValueT ShiftOpcode = B3 | B2 | B0; // 1101
IValueT Rd = encodeRegister(OpRd, "Rd", InstName); IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
IValueT Rm = encodeRegister(OpRm, "Rm", InstName); IValueT Rm = encodeGPRegister(OpRm, "Rm", InstName);
IValueT Value; IValueT Value;
switch (encodeOperand(OpSrc1, Value)) { switch (encodeOperand(OpSrc1, Value, WantGPRegs)) {
default: default:
llvm::report_fatal_error(std::string(InstName) + llvm::report_fatal_error(std::string(InstName) +
": Last operand not understood"); ": Last operand not understood");
...@@ -1398,7 +1438,7 @@ void AssemblerARM32::emitShift(const CondARM32::Cond Cond, ...@@ -1398,7 +1438,7 @@ void AssemblerARM32::emitShift(const CondARM32::Cond Cond,
// 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.
constexpr IValueT Rn = 0; // Rn field is not used. constexpr IValueT Rn = 0; // Rn field is not used.
IValueT Rs = encodeRegister(OpSrc1, "Rs", InstName); IValueT Rs = encodeGPRegister(OpSrc1, "Rs", InstName);
verifyRegNotPc(Rd, "Rd", InstName); verifyRegNotPc(Rd, "Rd", InstName);
verifyRegNotPc(Rm, "Rm", InstName); verifyRegNotPc(Rm, "Rm", InstName);
verifyRegNotPc(Rs, "Rs", InstName); verifyRegNotPc(Rs, "Rs", InstName);
...@@ -1445,7 +1485,7 @@ void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, ...@@ -1445,7 +1485,7 @@ void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
// and iiiiiiiiiiii=RotatedImm8=Src. Note: We don't use movs in this // and iiiiiiiiiiii=RotatedImm8=Src. Note: We don't use movs in this
// assembler. // assembler.
constexpr const char *MovName = "mov"; constexpr const char *MovName = "mov";
IValueT Rd = encodeRegister(OpRd, "Rd", MovName); IValueT Rd = encodeGPRegister(OpRd, "Rd", MovName);
constexpr bool SetFlags = false; constexpr bool SetFlags = false;
constexpr IValueT Rn = 0; constexpr IValueT Rn = 0;
constexpr IValueT MovOpcode = B3 | B2 | B0; // 1101. constexpr IValueT MovOpcode = B3 | B2 | B0; // 1101.
...@@ -1457,17 +1497,17 @@ void AssemblerARM32::emitMovwt(CondARM32::Cond Cond, bool IsMovW, ...@@ -1457,17 +1497,17 @@ void AssemblerARM32::emitMovwt(CondARM32::Cond Cond, bool IsMovW,
const Operand *OpRd, const Operand *OpSrc, const Operand *OpRd, const Operand *OpSrc,
const char *MovName) { const char *MovName) {
IValueT Opcode = B25 | B24 | (IsMovW ? 0 : B22); IValueT Opcode = B25 | B24 | (IsMovW ? 0 : B22);
IValueT Rd = encodeRegister(OpRd, "Rd", MovName); IValueT Rd = encodeGPRegister(OpRd, "Rd", MovName);
IValueT Imm16; IValueT Imm16;
if (const auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc)) { if (const auto *Src = llvm::dyn_cast<ConstantRelocatable>(OpSrc)) {
emitFixup(createMoveFixup(IsMovW, Src)); emitFixup(createMoveFixup(IsMovW, Src));
// 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.
Imm16 = 0; Imm16 = 0;
} else if (encodeOperand(OpSrc, Imm16) != EncodedAsConstI32) { } else if (encodeOperand(OpSrc, Imm16, WantGPRegs) != EncodedAsConstI32) {
llvm::report_fatal_error(std::string(MovName) + ": Not i32 constant"); llvm::report_fatal_error(std::string(MovName) + ": Not i32 constant");
} }
verifyCondDefined(Cond, MovName); assert(CondARM32::isDefined(Cond));
if (!Utils::IsAbsoluteUint(16, Imm16)) if (!Utils::IsAbsoluteUint(16, Imm16))
llvm::report_fatal_error(std::string(MovName) + ": Constant not i16"); llvm::report_fatal_error(std::string(MovName) + ": Constant not i16");
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
...@@ -1515,7 +1555,7 @@ void AssemblerARM32::mvn(const Operand *OpRd, const Operand *OpSrc, ...@@ -1515,7 +1555,7 @@ 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.
constexpr const char *MvnName = "mvn"; constexpr const char *MvnName = "mvn";
IValueT Rd = encodeRegister(OpRd, "Rd", MvnName); IValueT Rd = encodeGPRegister(OpRd, "Rd", MvnName);
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;
...@@ -1563,22 +1603,22 @@ void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn, ...@@ -1563,22 +1603,22 @@ 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.
constexpr const char *SdivName = "sdiv"; constexpr const char *SdivName = "sdiv";
IValueT Rd = encodeRegister(OpRd, "Rd", SdivName); IValueT Rd = encodeGPRegister(OpRd, "Rd", SdivName);
IValueT Rn = encodeRegister(OpRn, "Rn", SdivName); IValueT Rn = encodeGPRegister(OpRn, "Rn", SdivName);
IValueT Rm = encodeRegister(OpSrc1, "Rm", SdivName); IValueT Rm = encodeGPRegister(OpSrc1, "Rm", SdivName);
verifyRegNotPc(Rd, "Rd", SdivName); verifyRegNotPc(Rd, "Rd", SdivName);
verifyRegNotPc(Rn, "Rn", SdivName); verifyRegNotPc(Rn, "Rn", SdivName);
verifyRegNotPc(Rm, "Rm", SdivName); verifyRegNotPc(Rm, "Rm", SdivName);
// Assembler registers rd, rn, rm are encoded as rn, rm, rs. // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
constexpr IValueT SdivOpcode = 0; constexpr IValueT SdivOpcode = 0;
emitDivOp(Cond, SdivOpcode, Rd, Rn, Rm, SdivName); emitDivOp(Cond, SdivOpcode, Rd, Rn, Rm);
} }
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 const char *StrName = "str";
constexpr bool IsLoad = false; constexpr bool IsLoad = false;
IValueT Rt = encodeRegister(OpRt, "Rt", StrName); IValueT Rt = encodeGPRegister(OpRt, "Rt", StrName);
const Type Ty = OpRt->getType(); const Type Ty = OpRt->getType();
switch (Ty) { switch (Ty) {
case IceType_i64: case IceType_i64:
...@@ -1662,7 +1702,7 @@ void AssemblerARM32::strex(const Operand *OpRd, const Operand *OpRt, ...@@ -1662,7 +1702,7 @@ void AssemblerARM32::strex(const Operand *OpRd, const Operand *OpRt,
// nnnn=Rn. // nnnn=Rn.
constexpr const char *StrexName = "strex"; constexpr const char *StrexName = "strex";
// Note: Rt uses Rm shift in encoding. // Note: Rt uses Rm shift in encoding.
IValueT Rt = encodeRegister(OpRt, "Rt", StrexName); IValueT Rt = encodeGPRegister(OpRt, "Rt", StrexName);
const Type Ty = OpRt->getType(); const Type Ty = OpRt->getType();
constexpr bool IsLoad = true; constexpr bool IsLoad = true;
emitMemExOp(Cond, Ty, !IsLoad, OpRd, Rt, OpAddress, TInfo, StrexName); emitMemExOp(Cond, Ty, !IsLoad, OpRd, Rt, OpAddress, TInfo, StrexName);
...@@ -1694,14 +1734,14 @@ void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) { ...@@ -1694,14 +1734,14 @@ void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) {
// //
// cccc010010011101dddd000000000100 where dddd=Rt and cccc=Cond. // cccc010010011101dddd000000000100 where dddd=Rt and cccc=Cond.
constexpr const char *Pop = "pop"; constexpr const char *Pop = "pop";
IValueT Rt = encodeRegister(OpRt, "Rt", Pop); IValueT Rt = encodeGPRegister(OpRt, "Rt", Pop);
verifyRegsNotEq(Rt, "Rt", RegARM32::Encoded_Reg_sp, "sp", Pop); verifyRegsNotEq(Rt, "Rt", RegARM32::Encoded_Reg_sp, "sp", Pop);
// 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, Pop); emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
} }
void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) { void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) {
...@@ -1710,10 +1750,8 @@ void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) { ...@@ -1710,10 +1750,8 @@ 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) {
...@@ -1722,14 +1760,14 @@ void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) { ...@@ -1722,14 +1760,14 @@ void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) {
// //
// cccc010100101101dddd000000000100 where dddd=Rt and cccc=Cond. // cccc010100101101dddd000000000100 where dddd=Rt and cccc=Cond.
constexpr const char *Push = "push"; constexpr const char *Push = "push";
IValueT Rt = encodeRegister(OpRt, "Rt", Push); IValueT Rt = encodeGPRegister(OpRt, "Rt", Push);
verifyRegsNotEq(Rt, "Rt", RegARM32::Encoded_Reg_sp, "sp", Push); verifyRegsNotEq(Rt, "Rt", RegARM32::Encoded_Reg_sp, "sp", Push);
// 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, Push); emitMemOp(Cond, kInstTypeMemImmediate, isLoad, isByte, Rt, Address);
} }
void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) { void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) {
...@@ -1738,10 +1776,8 @@ void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) { ...@@ -1738,10 +1776,8 @@ 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,
...@@ -1753,10 +1789,10 @@ void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn, ...@@ -1753,10 +1789,10 @@ void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn,
// 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.
constexpr const char *MlaName = "mla"; constexpr const char *MlaName = "mla";
IValueT Rd = encodeRegister(OpRd, "Rd", MlaName); IValueT Rd = encodeGPRegister(OpRd, "Rd", MlaName);
IValueT Rn = encodeRegister(OpRn, "Rn", MlaName); IValueT Rn = encodeGPRegister(OpRn, "Rn", MlaName);
IValueT Rm = encodeRegister(OpRm, "Rm", MlaName); IValueT Rm = encodeGPRegister(OpRm, "Rm", MlaName);
IValueT Ra = encodeRegister(OpRa, "Ra", MlaName); IValueT Ra = encodeGPRegister(OpRa, "Ra", MlaName);
verifyRegNotPc(Rd, "Rd", MlaName); verifyRegNotPc(Rd, "Rd", MlaName);
verifyRegNotPc(Rn, "Rn", MlaName); verifyRegNotPc(Rn, "Rn", MlaName);
verifyRegNotPc(Rm, "Rm", MlaName); verifyRegNotPc(Rm, "Rm", MlaName);
...@@ -1764,17 +1800,17 @@ void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn, ...@@ -1764,17 +1800,17 @@ void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn,
constexpr IValueT MlaOpcode = B21; constexpr IValueT MlaOpcode = B21;
constexpr bool SetFlags = true; constexpr bool SetFlags = true;
// 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, MlaName); emitMulOp(Cond, MlaOpcode, Ra, Rd, Rn, Rm, !SetFlags);
} }
void AssemblerARM32::mls(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::mls(const Operand *OpRd, const Operand *OpRn,
const Operand *OpRm, const Operand *OpRa, const Operand *OpRm, const Operand *OpRa,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
constexpr const char *MlsName = "mls"; constexpr const char *MlsName = "mls";
IValueT Rd = encodeRegister(OpRd, "Rd", MlsName); IValueT Rd = encodeGPRegister(OpRd, "Rd", MlsName);
IValueT Rn = encodeRegister(OpRn, "Rn", MlsName); IValueT Rn = encodeGPRegister(OpRn, "Rn", MlsName);
IValueT Rm = encodeRegister(OpRm, "Rm", MlsName); IValueT Rm = encodeGPRegister(OpRm, "Rm", MlsName);
IValueT Ra = encodeRegister(OpRa, "Ra", MlsName); IValueT Ra = encodeGPRegister(OpRa, "Ra", MlsName);
verifyRegNotPc(Rd, "Rd", MlsName); verifyRegNotPc(Rd, "Rd", MlsName);
verifyRegNotPc(Rn, "Rn", MlsName); verifyRegNotPc(Rn, "Rn", MlsName);
verifyRegNotPc(Rm, "Rm", MlsName); verifyRegNotPc(Rm, "Rm", MlsName);
...@@ -1782,7 +1818,7 @@ void AssemblerARM32::mls(const Operand *OpRd, const Operand *OpRn, ...@@ -1782,7 +1818,7 @@ void AssemblerARM32::mls(const Operand *OpRd, const Operand *OpRn,
constexpr IValueT MlsOpcode = B22 | B21; constexpr IValueT MlsOpcode = B22 | B21;
constexpr bool SetFlags = true; constexpr bool SetFlags = true;
// 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, MlsOpcode, Ra, Rd, Rn, Rm, !SetFlags, MlsName); emitMulOp(Cond, MlsOpcode, Ra, Rd, Rn, Rm, !SetFlags);
} }
void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn,
...@@ -1794,23 +1830,22 @@ void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn, ...@@ -1794,23 +1830,22 @@ void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn,
// 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.
constexpr const char *MulName = "mul"; constexpr const char *MulName = "mul";
IValueT Rd = encodeRegister(OpRd, "Rd", MulName); IValueT Rd = encodeGPRegister(OpRd, "Rd", MulName);
IValueT Rn = encodeRegister(OpRn, "Rn", MulName); IValueT Rn = encodeGPRegister(OpRn, "Rn", MulName);
IValueT Rm = encodeRegister(OpSrc1, "Rm", MulName); IValueT Rm = encodeGPRegister(OpSrc1, "Rm", MulName);
verifyRegNotPc(Rd, "Rd", MulName); verifyRegNotPc(Rd, "Rd", MulName);
verifyRegNotPc(Rn, "Rn", MulName); verifyRegNotPc(Rn, "Rn", MulName);
verifyRegNotPc(Rm, "Rm", 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::emitRdRm(CondARM32::Cond Cond, IValueT Opcode, void AssemblerARM32::emitRdRm(CondARM32::Cond Cond, IValueT Opcode,
const Operand *OpRd, const Operand *OpRm, const Operand *OpRd, const Operand *OpRm,
const char *InstName) { const char *InstName) {
IValueT Rd = encodeRegister(OpRd, "Rd", InstName); IValueT Rd = encodeGPRegister(OpRd, "Rd", InstName);
IValueT Rm = encodeRegister(OpRm, "Rm", InstName); IValueT Rm = encodeGPRegister(OpRm, "Rm", InstName);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
IValueT Encoding = IValueT Encoding =
(Cond << kConditionShift) | Opcode | (Rd << kRdShift) | (Rm << kRmShift); (Cond << kConditionShift) | Opcode | (Rd << kRdShift) | (Rm << kRmShift);
...@@ -1965,15 +2000,15 @@ void AssemblerARM32::udiv(const Operand *OpRd, const Operand *OpRn, ...@@ -1965,15 +2000,15 @@ 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.
constexpr const char *UdivName = "udiv"; constexpr const char *UdivName = "udiv";
IValueT Rd = encodeRegister(OpRd, "Rd", UdivName); IValueT Rd = encodeGPRegister(OpRd, "Rd", UdivName);
IValueT Rn = encodeRegister(OpRn, "Rn", UdivName); IValueT Rn = encodeGPRegister(OpRn, "Rn", UdivName);
IValueT Rm = encodeRegister(OpSrc1, "Rm", UdivName); IValueT Rm = encodeGPRegister(OpSrc1, "Rm", UdivName);
verifyRegNotPc(Rd, "Rd", UdivName); verifyRegNotPc(Rd, "Rd", UdivName);
verifyRegNotPc(Rn, "Rn", UdivName); verifyRegNotPc(Rn, "Rn", UdivName);
verifyRegNotPc(Rm, "Rm", UdivName); verifyRegNotPc(Rm, "Rm", UdivName);
// Assembler registers rd, rn, rm are encoded as rn, rm, rs. // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
constexpr IValueT UdivOpcode = B21; constexpr IValueT UdivOpcode = B21;
emitDivOp(Cond, UdivOpcode, Rd, Rn, Rm, UdivName); emitDivOp(Cond, UdivOpcode, Rd, Rn, Rm);
} }
void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi, void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi,
...@@ -1985,10 +2020,10 @@ void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi, ...@@ -1985,10 +2020,10 @@ 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
constexpr const char *UmullName = "umull"; constexpr const char *UmullName = "umull";
IValueT RdLo = encodeRegister(OpRdLo, "RdLo", UmullName); IValueT RdLo = encodeGPRegister(OpRdLo, "RdLo", UmullName);
IValueT RdHi = encodeRegister(OpRdHi, "RdHi", UmullName); IValueT RdHi = encodeGPRegister(OpRdHi, "RdHi", UmullName);
IValueT Rn = encodeRegister(OpRn, "Rn", UmullName); IValueT Rn = encodeGPRegister(OpRn, "Rn", UmullName);
IValueT Rm = encodeRegister(OpRm, "Rm", UmullName); IValueT Rm = encodeGPRegister(OpRm, "Rm", UmullName);
verifyRegNotPc(RdLo, "RdLo", UmullName); verifyRegNotPc(RdLo, "RdLo", UmullName);
verifyRegNotPc(RdHi, "RdHi", UmullName); verifyRegNotPc(RdHi, "RdHi", UmullName);
verifyRegNotPc(Rn, "Rn", UmullName); verifyRegNotPc(Rn, "Rn", UmullName);
...@@ -1996,7 +2031,7 @@ void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi, ...@@ -1996,7 +2031,7 @@ void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi,
verifyRegsNotEq(RdHi, "RdHi", RdLo, "RdLo", UmullName); verifyRegsNotEq(RdHi, "RdHi", RdLo, "RdLo", UmullName);
constexpr IValueT UmullOpcode = B23; constexpr IValueT UmullOpcode = B23;
constexpr bool SetFlags = false; constexpr bool SetFlags = false;
emitMulOp(Cond, UmullOpcode, RdLo, RdHi, Rn, Rm, SetFlags, UmullName); emitMulOp(Cond, UmullOpcode, RdLo, RdHi, Rn, Rm, SetFlags);
} }
void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0, void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0,
...@@ -2006,10 +2041,39 @@ void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0, ...@@ -2006,10 +2041,39 @@ void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0,
emitSignExtend(Cond, UxtOpcode, OpRd, OpSrc0, UxtName); emitSignExtend(Cond, UxtOpcode, OpRd, OpSrc0, UxtName);
} }
void AssemblerARM32::vadds(const Operand *OpSd, const Operand *OpSn,
const Operand *OpSm, CondARM32::Cond Cond) {
// VADD (floating-point) - ARM section A8.8.283, encoding A2:
// vadd<c>.f32 <Sd>, <Sn>, <Sm>
//
// cccc11100D11nnnndddd101sN0M0mmmm where cccc=Cond, s=0, ddddD=Rd, nnnnN=Rn,
// and mmmmM=Rm.
constexpr const char *Vadds = "vadds";
IValueT Sd = encodeSRegister(OpSd, "Sd", Vadds);
IValueT Sn = encodeSRegister(OpSn, "Sn", Vadds);
IValueT Sm = encodeSRegister(OpSm, "Sm", Vadds);
constexpr IValueT VaddsOpcode = B21 | B20;
emitVFPsss(Cond, VaddsOpcode, Sd, Sn, Sm);
}
void AssemblerARM32::vaddd(const Operand *OpDd, const Operand *OpDn,
const Operand *OpDm, CondARM32::Cond Cond) {
// VADD (floating-point) - ARM section A8.8.283, encoding A2:
// vadd<c>.f64 <Dd>, <Dn>, <Dm>
//
// cccc11100D11nnnndddd101sN0M0mmmm where cccc=Cond, s=1, Ddddd=Rd, Nnnnn=Rn,
// and Mmmmm=Rm.
constexpr const char *Vaddd = "vaddd";
IValueT Dd = encodeDRegister(OpDd, "Dd", Vaddd);
IValueT Dn = encodeDRegister(OpDn, "Dn", Vaddd);
IValueT Dm = encodeDRegister(OpDm, "Dm", Vaddd);
constexpr IValueT VadddOpcode = B21 | B20;
emitVFPddd(Cond, VadddOpcode, Dd, Dn, Dm);
}
void AssemblerARM32::emitVStackOp(CondARM32::Cond Cond, IValueT Opcode, void AssemblerARM32::emitVStackOp(CondARM32::Cond Cond, IValueT Opcode,
const Variable *OpBaseReg, const Variable *OpBaseReg,
SizeT NumConsecRegs, const char *InstName) { SizeT NumConsecRegs) {
const IValueT BaseReg = getEncodedSRegNum(OpBaseReg); const IValueT BaseReg = getEncodedSRegNum(OpBaseReg);
const IValueT DLastBit = mask(BaseReg, 0, 1); // Last bit of base register. const IValueT DLastBit = mask(BaseReg, 0, 1); // Last bit of base register.
const IValueT Rd = mask(BaseReg, 1, 4); // Top 4 bits of base register. const IValueT Rd = mask(BaseReg, 1, 4); // Top 4 bits of base register.
...@@ -2017,7 +2081,7 @@ void AssemblerARM32::emitVStackOp(CondARM32::Cond Cond, IValueT Opcode, ...@@ -2017,7 +2081,7 @@ void AssemblerARM32::emitVStackOp(CondARM32::Cond Cond, IValueT Opcode,
(void)VpushVpopMaxConsecRegs; (void)VpushVpopMaxConsecRegs;
assert(NumConsecRegs <= VpushVpopMaxConsecRegs); assert(NumConsecRegs <= VpushVpopMaxConsecRegs);
assert((BaseReg + NumConsecRegs) <= RegARM32::getNumSRegs()); assert((BaseReg + NumConsecRegs) <= RegARM32::getNumSRegs());
verifyCondDefined(Cond, InstName); assert(CondARM32::isDefined(Cond));
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const IValueT Encoding = Opcode | (Cond << kConditionShift) | DLastBit | const IValueT Encoding = Opcode | (Cond << kConditionShift) | DLastBit |
(Rd << kRdShift) | NumConsecRegs; (Rd << kRdShift) | NumConsecRegs;
...@@ -2034,10 +2098,9 @@ void AssemblerARM32::vpop(const Variable *OpBaseReg, SizeT NumConsecRegs, ...@@ -2034,10 +2098,9 @@ void AssemblerARM32::vpop(const Variable *OpBaseReg, SizeT NumConsecRegs,
// //
// cccc11001D111101dddd1010iiiiiiii where cccc=Cond, ddddD=BaseReg, and // cccc11001D111101dddd1010iiiiiiii where cccc=Cond, ddddD=BaseReg, and
// iiiiiiii=NumConsecRegs. // iiiiiiii=NumConsecRegs.
constexpr const char *VpopName = "vpop";
constexpr IValueT VpopOpcode = constexpr IValueT VpopOpcode =
B27 | B26 | B23 | B21 | B20 | B19 | B18 | B16 | B11 | B9; B27 | B26 | B23 | B21 | B20 | B19 | B18 | B16 | B11 | B9;
emitVStackOp(Cond, VpopOpcode, OpBaseReg, NumConsecRegs, VpopName); emitVStackOp(Cond, VpopOpcode, OpBaseReg, NumConsecRegs);
} }
void AssemblerARM32::vpush(const Variable *OpBaseReg, SizeT NumConsecRegs, void AssemblerARM32::vpush(const Variable *OpBaseReg, SizeT NumConsecRegs,
...@@ -2050,10 +2113,9 @@ void AssemblerARM32::vpush(const Variable *OpBaseReg, SizeT NumConsecRegs, ...@@ -2050,10 +2113,9 @@ void AssemblerARM32::vpush(const Variable *OpBaseReg, SizeT NumConsecRegs,
// //
// cccc11010D101101dddd1010iiiiiiii where cccc=Cond, ddddD=BaseReg, and // cccc11010D101101dddd1010iiiiiiii where cccc=Cond, ddddD=BaseReg, and
// iiiiiiii=NumConsecRegs. // iiiiiiii=NumConsecRegs.
constexpr const char *VpushName = "vpush";
constexpr IValueT VpushOpcode = constexpr IValueT VpushOpcode =
B27 | B26 | B24 | B21 | B19 | B18 | B16 | B11 | B9; B27 | B26 | B24 | B21 | B19 | B18 | B16 | B11 | B9;
emitVStackOp(Cond, VpushOpcode, OpBaseReg, NumConsecRegs, VpushName); emitVStackOp(Cond, VpushOpcode, OpBaseReg, NumConsecRegs);
} }
} // end of namespace ARM32 } // end of namespace ARM32
......
...@@ -318,6 +318,12 @@ public: ...@@ -318,6 +318,12 @@ public:
// Implements uxtb/uxth depending on type of OpSrc0. // Implements uxtb/uxth depending on type of OpSrc0.
void uxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond); void uxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond);
void vaddd(const Operand *OpDd, const Operand *OpDn, const Operand *OpDm,
CondARM32::Cond Cond);
void vadds(const Operand *OpSd, const Operand *OpSn, const Operand *OpSm,
CondARM32::Cond Cond);
void vpop(const Variable *OpBaseReg, SizeT NumConsecRegs, void vpop(const Variable *OpBaseReg, SizeT NumConsecRegs,
CondARM32::Cond Cond); CondARM32::Cond Cond);
...@@ -383,16 +389,14 @@ private: ...@@ -383,16 +389,14 @@ private:
IValueT OpRn, const Operand *OpSrc1, bool SetFlags, IValueT OpRn, const Operand *OpSrc1, bool SetFlags,
EmitChecks RuleChecks, const char *InstName); 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 ccccxxxxxxxxxxxxddddxxxxxxxxmmmm where cccc=Cond, // Emit ccccxxxxxxxxxxxxddddxxxxxxxxmmmm where cccc=Cond,
// xxxxxxxxxxxx0000xxxxxxxx0000=Opcode, dddd=Rd, and mmmm=Rm. // xxxxxxxxxxxx0000xxxxxxxx0000=Opcode, dddd=Rd, and mmmm=Rm.
...@@ -419,24 +423,22 @@ private: ...@@ -419,24 +423,22 @@ private:
// 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 ccccxxxxxDxxxxxxddddxxxxiiiiiiii where cccc=Cond, ddddD=BaseReg, // Pattern ccccxxxxxDxxxxxxddddxxxxiiiiiiii where cccc=Cond, ddddD=BaseReg,
// iiiiiiii=NumConsecRegs, and xxxxx0xxxxxx0000xxxx00000000=Opcode. // iiiiiiii=NumConsecRegs, and xxxxx0xxxxxx0000xxxx00000000=Opcode.
void emitVStackOp(CondARM32::Cond Cond, IValueT Opcode, void emitVStackOp(CondARM32::Cond Cond, IValueT Opcode,
const Variable *OpBaseReg, SizeT NumConsecRegs, const Variable *OpBaseReg, SizeT NumConsecRegs);
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, const char *InstName); IValueT Rm);
// 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, const char *InstName); IValueT Rm, IValueT Rs, bool SetFlags);
// Pattern cccc0001101s0000ddddxxxxxtt0mmmm where cccc=Cond, s=SetFlags, // Pattern cccc0001101s0000ddddxxxxxtt0mmmm where cccc=Cond, s=SetFlags,
// dddd=Rd, mmmm=Rm, tt=Shift, and xxxxx is defined by OpSrc1. OpSrc1 defines // dddd=Rd, mmmm=Rm, tt=Shift, and xxxxx is defined by OpSrc1. OpSrc1 defines
...@@ -471,6 +473,14 @@ private: ...@@ -471,6 +473,14 @@ private:
// iiiiiiiiiiiiiiii=Imm16. // iiiiiiiiiiiiiiii=Imm16.
void emitMovwt(CondARM32::Cond Cond, bool IsMovw, const Operand *OpRd, void emitMovwt(CondARM32::Cond Cond, bool IsMovw, const Operand *OpRd,
const Operand *OpSrc, const char *MovName); const Operand *OpSrc, const char *MovName);
// Emit VFP instruction with 3 D registers.
void emitVFPddd(CondARM32::Cond Cond, IValueT Opcode, IValueT Dd, IValueT Dn,
IValueT Dm);
// Emit VFP instruction with 3 S registers.
void emitVFPsss(CondARM32::Cond Cond, IValueT Opcode, IValueT Sd, IValueT Sn,
IValueT Sm);
}; };
} // end of namespace ARM32 } // end of namespace ARM32
......
...@@ -33,6 +33,8 @@ public: ...@@ -33,6 +33,8 @@ public:
ICEINSTARM32COND_TABLE ICEINSTARM32COND_TABLE
#undef X #undef X
}; };
static bool isDefined(Cond C) { return C != kNone; }
}; };
} // end of namespace Ice } // end of namespace Ice
......
...@@ -226,6 +226,11 @@ void InstARM32FourAddrGPR<K>::emitIAS(const Cfg *Func) const { ...@@ -226,6 +226,11 @@ void InstARM32FourAddrGPR<K>::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func); emitUsingTextFixup(Func);
} }
template <InstARM32::InstKindARM32 K>
void InstARM32ThreeAddrFP<K>::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func);
}
template <> void InstARM32Mla::emitIAS(const Cfg *Func) const { template <> void InstARM32Mla::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 3); assert(getSrcSize() == 3);
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
...@@ -592,6 +597,25 @@ template <> void InstARM32Udiv::emitIAS(const Cfg *Func) const { ...@@ -592,6 +597,25 @@ template <> void InstARM32Udiv::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func); emitUsingTextFixup(Func);
} }
template <> void InstARM32Vadd::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
const Variable *Dest = getDest();
switch (Dest->getType()) {
default:
// TODO(kschimpf) Figure if more cases are needed.
Asm->setNeedsTextFixup();
break;
case IceType_f32:
Asm->vadds(getDest(), getSrc(0), getSrc(1), CondARM32::AL);
break;
case IceType_f64:
Asm->vaddd(getDest(), getSrc(0), getSrc(1), CondARM32::AL);
break;
}
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget) InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget)
: InstARM32(Func, InstARM32::Call, 1, Dest) { : InstARM32(Func, InstARM32::Call, 1, Dest) {
HasSideEffects = true; HasSideEffects = true;
...@@ -1404,7 +1428,7 @@ void InstARM32Pop::emitIAS(const Cfg *Func) const { ...@@ -1404,7 +1428,7 @@ void InstARM32Pop::emitIAS(const Cfg *Func) const {
const Variable *LastDest = nullptr; const Variable *LastDest = nullptr;
for (const Variable *Var : Dests) { for (const Variable *Var : Dests) {
assert(Var->hasReg() && "pop only applies to registers"); assert(Var->hasReg() && "pop only applies to registers");
int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); int32_t Reg = RegARM32::getEncodedGPReg(Var->getRegNum());
LastDest = Var; LastDest = Var;
GPRegisters |= (1 << Reg); GPRegisters |= (1 << Reg);
++IntegerCount; ++IntegerCount;
...@@ -1536,7 +1560,7 @@ void InstARM32Push::emitIAS(const Cfg *Func) const { ...@@ -1536,7 +1560,7 @@ void InstARM32Push::emitIAS(const Cfg *Func) const {
const Variable *LastSrc = nullptr; const Variable *LastSrc = nullptr;
for (SizeT Index = 0; Index < getSrcSize(); ++Index) { for (SizeT Index = 0; Index < getSrcSize(); ++Index) {
const auto *Var = llvm::cast<Variable>(getSrc(Index)); const auto *Var = llvm::cast<Variable>(getSrc(Index));
int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum()); int32_t Reg = RegARM32::getEncodedGPReg(Var->getRegNum());
assert(Reg != RegARM32::Encoded_Not_GPR); assert(Reg != RegARM32::Encoded_Not_GPR);
LastSrc = Var; LastSrc = Var;
GPRegisters |= (1 << Reg); GPRegisters |= (1 << Reg);
......
...@@ -732,6 +732,7 @@ public: ...@@ -732,6 +732,7 @@ public:
return; return;
emitThreeAddrFP(Opcode, this, Func); emitThreeAddrFP(Opcode, this, Func);
} }
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override { void dump(const Cfg *Func) const override {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
......
...@@ -146,56 +146,99 @@ public: ...@@ -146,56 +146,99 @@ public:
#undef X #undef X
}; };
static inline GPRRegister getEncodedGPR(int32_t RegNum) { static inline void assertRegisterDefined(int32_t RegNum) {
assert(Reg_GPR_First <= RegNum); (void)RegNum;
assert(RegNum <= Reg_GPR_Last); assert(RegNum >= 0);
assert(RegNum < Reg_NUM);
}
static inline bool isGPRegister(int32_t RegNum) {
assertRegisterDefined(RegNum);
return Table[RegNum].IsGPR;
}
static constexpr inline SizeT getNumGPRegs() {
return 0
#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
+(isGPR)
REGARM32_TABLE
#undef X
;
}
static inline GPRRegister getEncodedGPReg(int32_t RegNum) {
assert(isGPRegister(RegNum));
return GPRRegister(Table[RegNum].Encoding); return GPRRegister(Table[RegNum].Encoding);
} }
static inline GPRRegister getI64PairFirstGPRNum(int32_t RegNum) { static inline GPRRegister getI64PairFirstGPRNum(int32_t RegNum) {
assert(Reg_I64PAIR_First <= RegNum); assert(isI64RegisterPair(RegNum));
assert(RegNum <= Reg_I64PAIR_Last);
return GPRRegister(Table[RegNum].Encoding); return GPRRegister(Table[RegNum].Encoding);
} }
static inline GPRRegister getI64PairSecondGPRNum(int32_t RegNum) { static inline GPRRegister getI64PairSecondGPRNum(int32_t RegNum) {
assert(Reg_I64PAIR_First <= RegNum); assert(isI64RegisterPair(RegNum));
assert(RegNum <= Reg_I64PAIR_Last);
return GPRRegister(Table[RegNum].Encoding + 1); return GPRRegister(Table[RegNum].Encoding + 1);
} }
static inline bool isI64RegisterPair(int32_t RegNum) { static inline bool isI64RegisterPair(int32_t RegNum) {
assertRegisterDefined(RegNum);
return Table[RegNum].IsI64Pair; return Table[RegNum].IsI64Pair;
} }
static inline bool isEncodedSReg(int32_t RegNum) { static inline bool isEncodedSReg(int32_t RegNum) {
assertRegisterDefined(RegNum);
return Table[RegNum].IsFP32; return Table[RegNum].IsFP32;
} }
static inline SizeT getNumSRegs() { static constexpr inline SizeT getNumSRegs() {
return Reg_SREG_Last + 1 - Reg_SREG_First; return 0
#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
+(isFP32)
REGARM32_TABLE
#undef X
;
} }
static inline SRegister getEncodedSReg(int32_t RegNum) { static inline SRegister getEncodedSReg(int32_t RegNum) {
assert(Reg_SREG_First <= RegNum); assert(isEncodedSReg(RegNum));
assert(RegNum <= Reg_SREG_Last);
return SRegister(Table[RegNum].Encoding); return SRegister(Table[RegNum].Encoding);
} }
static inline bool isEncodedDReg(int32_t RegNum) {
assertRegisterDefined(RegNum);
return Table[RegNum].IsFP64;
}
static constexpr inline SizeT getNumDRegs() {
return 0
#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
+(isFP64)
REGARM32_TABLE
#undef X
;
}
static inline DRegister getEncodedDReg(int32_t RegNum) { static inline DRegister getEncodedDReg(int32_t RegNum) {
assert(Reg_DREG_First <= RegNum); assert(isEncodedDReg(RegNum));
assert(RegNum <= Reg_DREG_Last);
return DRegister(Table[RegNum].Encoding); return DRegister(Table[RegNum].Encoding);
} }
static inline bool isEncodedQReg(int32_t RegNum) {
assertRegisterDefined(RegNum);
return Table[RegNum].IsVec128;
}
static inline QRegister getEncodedQReg(int32_t RegNum) { static inline QRegister getEncodedQReg(int32_t RegNum) {
assert(Reg_QREG_First <= RegNum); assert(isEncodedQReg(RegNum));
assert(RegNum <= Reg_QREG_Last);
return QRegister(Table[RegNum].Encoding); return QRegister(Table[RegNum].Encoding);
} }
static inline IceString getRegName(SizeT RegNum) { static inline IceString getRegName(int32_t RegNum) {
assert(RegNum < Reg_NUM); assertRegisterDefined(RegNum);
return Table[RegNum].Name; return Table[RegNum].Name;
} }
}; };
......
; Show that we know how to translate vadd.
; NOTE: We use -O2 to get rid of memory stores.
; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=ASM
; Show bytes in assembled standalone code.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
define internal float @testVadd(float %v1, float %v2) {
; ASM-LABEL: testVadd:
; DIS-LABEL: 00000000 <testVadd>:
; IASM-LABEL: testVadd:
entry:
; ASM-NEXT: .LtestVadd$entry:
; IASM-NEXT: .LtestVadd$entry:
%res = fadd float %v1, %v2
; ASM-NEXT: vadd.f32 s0, s0, s1
; DIS-NEXT: 0: ee300a20
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0xa
; IASM-NEXT: .byte 0x30
; IASM-NEXT: .byte 0xee
ret float %res
}
...@@ -33,65 +33,68 @@ entry: ...@@ -33,65 +33,68 @@ entry:
; ASM-NEXT: vpush {s28, s29, s30, s31} ; ASM-NEXT: vpush {s28, s29, s30, s31}
; DIS-NEXT: 0: ed2dea04 ; DIS-NEXT: 0: ed2dea04
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xea ; IASM-NEXT: .byte 0xea
; IASM-NEXT: .byte 0x2d ; IASM-NEXT: .byte 0x2d
; IASM-NEXT: .byte 0xed ; IASM-NEXT: .byte 0xed
; ASM-NEXT: push {lr} ; ASM-NEXT: push {lr}
; DIS-NEXT: 4: e52de004 ; DIS-NEXT: 4: e52de004
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xe0 ; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x2d ; IASM-NEXT: .byte 0x2d
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
; ASM-NEXT: sub sp, sp, #12 ; ASM-NEXT: sub sp, sp, #12
; DIS-NEXT: 8: e24dd00c ; DIS-NEXT: 8: 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: vmov.f64 d15, d0 ; ASM-NEXT: vmov.f64 d15, d0
; DIS-NEXT: c: eeb0fb40 ; DIS-NEXT: c: eeb0fb40
; IASM-NEXT: vmov.f64 d15, d0 ; IASM-NEXT: vmov.f64 d15, d0
; ASM-NEXT: vmov.f64 d14, d1 ; ASM-NEXT: vmov.f64 d14, d1
; DIS-NEXT: 10: eeb0eb41 ; DIS-NEXT: 10: eeb0eb41
; IASM-NEXT: vmov.f64 d14, d1 ; IASM-NEXT: vmov.f64 d14, d1
call void @foo() call void @foo()
; ASM-NEXT: bl foo ; ASM-NEXT: bl foo
; DIS-NEXT: 14: ebfffffe ; DIS-NEXT: 14: ebfffffe
; IASM-NEXT: bl foo @ .word ebfffffe ; IASM-NEXT: bl foo @ .word ebfffffe
%res = fadd double %v1, %v2 %res = fadd double %v1, %v2
; ASM-NEXT: vadd.f64 d15, d15, d14 ; ASM-NEXT: vadd.f64 d15, d15, d14
; DIS-NEXT: 18: ee3ffb0e ; DIS-NEXT: 18: ee3ffb0e
; IASM-NEXT: vadd.f64 d15, d15, d14 ; IASM-NEXT: .byte 0xe
; IASM-NEXT: .byte 0xfb
; IASM-NEXT: .byte 0x3f
; IASM-NEXT: .byte 0xee
; ASM-NEXT: vmov.f64 d0, d15 ; ASM-NEXT: vmov.f64 d0, d15
; DIS-NEXT: 1c: eeb00b4f ; DIS-NEXT: 1c: eeb00b4f
; IASM-NEXT: vmov.f64 d0, d15 ; IASM-NEXT: vmov.f64 d0, d15
ret double %res ret double %res
; ASM-NEXT: add sp, sp, #12 ; ASM-NEXT: add sp, sp, #12
; DIS-NEXT: 20: e28dd00c ; DIS-NEXT: 20: e28dd00c
; 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: pop {lr} ; ASM-NEXT: pop {lr}
; ASM-NEXT: # lr = def.pseudo ; ASM-NEXT: # lr = def.pseudo
; DIS-NEXT: 24: e49de004 ; DIS-NEXT: 24: e49de004
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xe0 ; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x9d ; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe4 ; IASM-NEXT: .byte 0xe4
; ASM-NEXT: vpop {s28, s29, s30, s31} ; ASM-NEXT: vpop {s28, s29, s30, s31}
; ASM-NEXT: # s28 = def.pseudo ; ASM-NEXT: # s28 = def.pseudo
...@@ -99,17 +102,17 @@ entry: ...@@ -99,17 +102,17 @@ entry:
; ASM-NEXT: # s30 = def.pseudo ; ASM-NEXT: # s30 = def.pseudo
; ASM-NEXT: # s31 = def.pseudo ; ASM-NEXT: # s31 = def.pseudo
; DIS-NEXT: 28: ecbdea04 ; DIS-NEXT: 28: ecbdea04
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xea ; IASM-NEXT: .byte 0xea
; IASM-NEXT: .byte 0xbd ; IASM-NEXT: .byte 0xbd
; IASM-NEXT: .byte 0xec ; IASM-NEXT: .byte 0xec
; ASM-NEXT: bx lr ; ASM-NEXT: bx lr
; DIS-NEXT: 2c: e12fff1e ; DIS-NEXT: 2c: 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
; IASM-NEXT: .byte 0xe1 ; IASM-NEXT: .byte 0xe1
} }
......
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