Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Unified Diff: src/IceAssemblerARM32.cpp

Issue 1516863003: Add various forms of LDREX/STREX to ARM integrated assembler. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Fix issues raised in previous patch. Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/IceAssemblerARM32.h ('k') | src/IceInstARM32.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/IceAssemblerARM32.cpp
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index cbb5bdc71a3289ebb91684064331349ad89b6341..81a3979f360b0c0f4db72f6d55f7a527775d055e 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -100,6 +100,9 @@ static constexpr IValueT kImm12Shift = 0;
// Rotation instructions (uxtb etc.).
static constexpr IValueT kRotationShift = 10;
+// MemEx instructions.
+static constexpr IValueT kMemExOpcodeShift = 20;
+
// Div instruction register field encodings.
static constexpr IValueT kDivRdShift = 16;
static constexpr IValueT kDivRmShift = 8;
@@ -177,6 +180,25 @@ RegARM32::GPRRegister getGPRReg(IValueT Shift, IValueT Value) {
return decodeGPRRegister((Value >> Shift) & 0xF);
}
+// Defines alternate layouts of instruction operands, should the (common)
+// default pattern not be used.
+enum OpEncoding {
+ // No alternate layout specified.
+ DefaultOpEncoding,
+ // Alternate encoding 3 for memory operands (like in strb, strh, ldrb, and
+ // ldrh.
+ OpEncoding3,
+ // Alternate encoding for memory operands for ldrex and strex, which only
+ // actually expect a register.
+ OpEncodingMemEx
+};
+
+IValueT getEncodedGPRegNum(const Variable *Var) {
+ int32_t Reg = Var->getRegNum();
+ return llvm::isa<Variable64On32>(Var) ? RegARM32::getI64PairFirstGPRNum(Reg)
+ : RegARM32::getEncodedGPR(Reg);
+}
+
// The way an operand is encoded into a sequence of bits in functions
// encodeOperand and encodeAddress below.
enum EncodedOperand {
@@ -187,14 +209,25 @@ enum EncodedOperand {
// Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8
// value.
EncodedAsRotatedImm8,
+ // EncodedAsImmRegOffset is a memory operand that can take three forms, based
+ // on OpEncoding:
+ //
+ // ***** DefaultOpEncoding *****
+ //
// Value=0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn,
// p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to
// Rn should be used, and iiiiiiiiiiii defines the rotated Imm8 value.
- EncodedAsImmRegOffset,
+ //
+ // ***** OpEncoding3 *****
+ //
// Value=00000000pu0w0nnnn0000iiii0000jjjj where nnnn=Rn, iiiijjjj=Imm8, p=1
// if pre-indexed addressing, u=1 if offset positive, and w=1 if writeback to
// Rn.
- EncodedAsImmRegOffsetEnc3,
+ //
+ // ***** OpEncodingMemEx *****
+ //
+ // Value=000000000000nnnn0000000000000000 where nnnn=Rn.
+ EncodedAsImmRegOffset,
// Value=0000000pu0w00nnnnttttiiiiiss0mmmm where nnnn is the base register Rn,
// mmmm is the index register Rm, iiiii is the shift amount, ss is the shift
// kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if
@@ -240,7 +273,7 @@ EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value) {
Value = 0; // Make sure initialized.
if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
if (Var->hasReg()) {
- Value = Var->getRegNum();
+ Value = getEncodedGPRegNum(Var);
return EncodedAsRegister;
}
return CantEncode;
@@ -316,14 +349,19 @@ IValueT encodeImmRegOffsetEnc3(IValueT Rn, IOffsetT Imm8,
return Value;
}
-// Defines alternate layouts of instruction operands, should the (common)
-// default pattern not be used.
-enum OpEncoding {
- // No alternate layout specified.
- DefaultOpEncoding,
- // Alternate encoding 3.
- OpEncoding3
-};
+IValueT encodeImmRegOffset(OpEncoding AddressEncoding, IValueT Reg,
+ IOffsetT Offset, OperandARM32Mem::AddrMode Mode) {
+ switch (AddressEncoding) {
+ case DefaultOpEncoding:
+ return encodeImmRegOffset(Reg, Offset, Mode);
+ case OpEncoding3:
+ return encodeImmRegOffsetEnc3(Reg, Offset, Mode);
+ case OpEncodingMemEx:
+ assert(Offset == 0);
+ assert(Mode == OperandARM32Mem::Offset);
+ return Reg << kRnShift;
+ }
+}
// Encodes memory address Opnd, and encodes that information into Value, based
// on how ARM represents the address. Returns how the value was encoded.
@@ -341,34 +379,29 @@ EncodedOperand encodeAddress(const Operand *Opnd, IValueT &Value,
int32_t BaseRegNum = Var->getBaseRegNum();
if (BaseRegNum == Variable::NoRegister)
BaseRegNum = TInfo.FrameOrStackReg;
- Value = encodeImmRegOffset(BaseRegNum, Offset, OperandARM32Mem::Offset);
+ Value = encodeImmRegOffset(AddressEncoding, BaseRegNum, Offset,
+ OperandARM32Mem::Offset);
return EncodedAsImmRegOffset;
}
if (const auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Opnd)) {
Variable *Var = Mem->getBase();
if (!Var->hasReg())
return CantEncode;
- IValueT Rn = Var->getRegNum();
+ IValueT Rn = getEncodedGPRegNum(Var);
if (Mem->isRegReg()) {
const Variable *Index = Mem->getIndex();
if (Var == nullptr)
return CantEncode;
Value = (Rn << kRnShift) | Mem->getAddrMode() |
- encodeShiftRotateImm5(Index->getRegNum(), Mem->getShiftOp(),
+ encodeShiftRotateImm5(getEncodedGPRegNum(Index), Mem->getShiftOp(),
Mem->getShiftAmt());
return EncodedAsShiftRotateImm5;
}
// Encoded as immediate register offset.
ConstantInteger32 *Offset = Mem->getOffset();
- switch (AddressEncoding) {
- case DefaultOpEncoding:
- Value = encodeImmRegOffset(Rn, Offset->getValue(), Mem->getAddrMode());
- return EncodedAsImmRegOffset;
- case OpEncoding3:
- Value =
- encodeImmRegOffsetEnc3(Rn, Offset->getValue(), Mem->getAddrMode());
- return EncodedAsImmRegOffsetEnc3;
- }
+ Value = encodeImmRegOffset(AddressEncoding, Rn, Offset->getValue(),
+ Mem->getAddrMode());
+ return EncodedAsImmRegOffset;
}
return CantEncode;
}
@@ -799,7 +832,7 @@ void AssemblerARM32::emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode,
default:
llvm::report_fatal_error(std::string(InstName) +
": Memory address not understood");
- case EncodedAsImmRegOffsetEnc3: {
+ case EncodedAsImmRegOffset: {
// XXXH (immediate)
// xxxh<c> <Rt>, [<Rn>{, #+-<Imm8>}]
// xxxh<c> <Rt>, [<Rn>, #+/-<Imm8>]
@@ -1170,7 +1203,7 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
// case.
default:
llvm::report_fatal_error(std::string("ldr : Type ") + typeString(Ty) +
- " not implementable\n");
+ " not implementable");
case 0: {
// Handles i1 and i8 loads.
//
@@ -1233,6 +1266,73 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
}
}
+void AssemblerARM32::emitMemExOp(CondARM32::Cond Cond, Type Ty, bool IsLoad,
+ const Operand *OpRd, IValueT Rt,
+ const Operand *OpAddress,
+ const TargetInfo &TInfo,
+ const char *InstName) {
+ IValueT Rd = encodeRegister(OpRd, "Rd", InstName);
+ IValueT MemExOpcode = IsLoad ? B0 : 0;
+ switch (typeWidthInBytesLog2(Ty)) {
+ default:
+ llvm::report_fatal_error(std::string(InstName) + ": Type " +
+ typeString(Ty) + " not implementable");
+ case 0:
+ MemExOpcode |= B2;
+ break;
+ case 1:
+ MemExOpcode |= B2 | B1;
+ break;
+ case 2:
+ break;
+ case 3:
+ MemExOpcode |= B1;
+ }
+ IValueT AddressRn;
+ if (encodeAddress(OpAddress, AddressRn, TInfo, OpEncodingMemEx) !=
+ EncodedAsImmRegOffset)
+ llvm::report_fatal_error(std::string(InstName) +
+ ": Can't extract Rn from address");
+ assert(Utils::IsAbsoluteUint(3, MemExOpcode));
+ verifyRegDefined(Rd, "Rd", InstName);
+ verifyRegDefined(Rt, "Rt", InstName);
+ verifyCondDefined(Cond, InstName);
+ AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+ IValueT Encoding = (Cond << kConditionShift) | B24 | B23 | B11 | B10 | B9 |
+ B8 | B7 | B4 | (MemExOpcode << kMemExOpcodeShift) |
+ AddressRn | (Rd << kRdShift) | (Rt << kRmShift);
+ emitInst(Encoding);
+ return;
+}
+
+void AssemblerARM32::ldrex(const Operand *OpRt, const Operand *OpAddress,
+ CondARM32::Cond Cond, const TargetInfo &TInfo) {
+ // LDREXB - ARM section A8.8.76, encoding A1:
+ // ldrexb<c> <Rt>, [<Rn>]
+ //
+ // cccc00011101nnnntttt111110011111 where cccc=Cond, tttt=Rt, and nnnn=Rn.
+ //
+ // LDREXH - ARM section A8.8.78, encoding A1:
+ // ldrexh<c> <Rt>, [<Rn>]
+ //
+ // cccc00011111nnnntttt111110011111 where cccc=Cond, tttt=Rt, and nnnn=Rn.
+ //
+ // LDREX - ARM section A8.8.75, encoding A1:
+ // ldrex<c> <Rt>, [<Rn>]
+ //
+ // cccc00011001nnnntttt111110011111 where cccc=Cond, tttt=Rt, and nnnn=Rn.
+ //
+ // LDREXD - ARM section A8.
+ // ldrexd<c> <Rt>, [<Rn>]
+ //
+ // cccc00011001nnnntttt111110011111 where cccc=Cond, tttt=Rt, and nnnn=Rn.
+ constexpr const char *LdrexName = "ldrex";
+ const Type Ty = OpRt->getType();
+ constexpr bool IsLoad = true;
+ constexpr IValueT Rm = RegARM32::Encoded_Reg_pc;
+ emitMemExOp(Cond, Ty, IsLoad, OpRt, Rm, OpAddress, TInfo, LdrexName);
+}
+
void AssemblerARM32::emitShift(const CondARM32::Cond Cond,
const OperandARM32::ShiftKind Shift,
const Operand *OpRd, const Operand *OpRm,
@@ -1502,6 +1602,40 @@ void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
}
}
+void AssemblerARM32::strex(const Operand *OpRd, const Operand *OpRt,
+ const Operand *OpAddress, CondARM32::Cond Cond,
+ const TargetInfo &TInfo) {
+ // STREXB - ARM section A8.8.213, encoding A1:
+ // strexb<c> <Rd>, <Rt>, [<Rn>]
+ //
+ // cccc00011100nnnndddd11111001tttt where cccc=Cond, dddd=Rd, tttt=Rt, and
+ // nnnn=Rn.
+ //
+ // STREXH - ARM section A8.8.215, encoding A1:
+ // strexh<c> <Rd>, <Rt>, [<Rn>]
+ //
+ // cccc00011110nnnndddd11111001tttt where cccc=Cond, dddd=Rd, tttt=Rt, and
+ // nnnn=Rn.
+ //
+ // STREX - ARM section A8.8.212, encoding A1:
+ // strex<c> <Rd>, <Rt>, [<Rn>]
+ //
+ // cccc00011000nnnndddd11111001tttt where cccc=Cond, dddd=Rd, tttt=Rt, and
+ // nnnn=Rn.
+ //
+ // STREXD - ARM section A8.8.214, encoding A1:
+ // strexd<c> <Rd>, <Rt>, [<Rn>]
+ //
+ // cccc00011010nnnndddd11111001tttt where cccc=Cond, dddd=Rd, tttt=Rt, and
+ // nnnn=Rn.
+ constexpr const char *StrexName = "strex";
+ // Note: Rt uses Rm shift in encoding.
+ IValueT Rt = encodeRegister(OpRt, "Rt", StrexName);
+ const Type Ty = OpRt->getType();
+ constexpr bool IsLoad = true;
+ emitMemExOp(Cond, Ty, !IsLoad, OpRd, Rt, OpAddress, TInfo, StrexName);
+}
+
void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) {
« no previous file with comments | « src/IceAssemblerARM32.h ('k') | src/IceInstARM32.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698