Commit 866b6b19 by John Porto

Subzero. ARM32. Folding rematerializable offsets in address operands.

parent 92a6e5b0
...@@ -241,6 +241,9 @@ OperandARM32Mem::OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, ...@@ -241,6 +241,9 @@ OperandARM32Mem::OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base,
uint16_t ShiftAmt, AddrMode Mode) uint16_t ShiftAmt, AddrMode Mode)
: OperandARM32(kMem, Ty), Base(Base), ImmOffset(0), Index(Index), : OperandARM32(kMem, Ty), Base(Base), ImmOffset(0), Index(Index),
ShiftOp(ShiftOp), ShiftAmt(ShiftAmt), Mode(Mode) { ShiftOp(ShiftOp), ShiftAmt(ShiftAmt), Mode(Mode) {
if (Index->isRematerializable()) {
llvm::report_fatal_error("Rematerializable Index Register is not allowed.");
}
NumVars = 2; NumVars = 2;
Vars = Func->allocateArrayOf<Variable *>(2); Vars = Func->allocateArrayOf<Variable *>(2);
Vars[0] = Base; Vars[0] = Base;
...@@ -257,6 +260,10 @@ bool OperandARM32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) { ...@@ -257,6 +260,10 @@ bool OperandARM32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) {
return Offset == 0; return Offset == 0;
// Note that encodings for offsets are sign-magnitude for ARM, so we check // Note that encodings for offsets are sign-magnitude for ARM, so we check
// with IsAbsoluteUint(). // with IsAbsoluteUint().
// Scalar fp, and vector types require an offset that is aligned to a multiple
// of 4.
if (isScalarFloatingType(Ty) || isVectorType(Ty))
return Utils::IsAligned(Offset, 4) && Utils::IsAbsoluteUint(Bits, Offset);
return Utils::IsAbsoluteUint(Bits, Offset); return Utils::IsAbsoluteUint(Bits, Offset);
} }
......
...@@ -90,7 +90,7 @@ public: ...@@ -90,7 +90,7 @@ public:
SizeT getFrameOrStackReg() const override { SizeT getFrameOrStackReg() const override {
return UsesFramePointer ? getFrameReg() : getStackReg(); return UsesFramePointer ? getFrameReg() : getStackReg();
} }
SizeT getReservedTmpReg() const { return RegARM32::Reg_ip; } int32_t getReservedTmpReg() const { return RegARM32::Reg_ip; }
size_t typeWidthInBytesOnStack(Type Ty) const override { size_t typeWidthInBytesOnStack(Type Ty) const override {
// Round up to the next multiple of 4 bytes. In particular, i1, i8, and i16 // Round up to the next multiple of 4 bytes. In particular, i1, i8, and i16
...@@ -141,12 +141,12 @@ public: ...@@ -141,12 +141,12 @@ public:
} }
enum OperandLegalization { enum OperandLegalization {
Legal_None = 0,
Legal_Reg = 1 << 0, /// physical register, not stack location Legal_Reg = 1 << 0, /// physical register, not stack location
Legal_Flex = 1 << 1, /// A flexible operand2, which can hold rotated small Legal_Flex = 1 << 1, /// A flexible operand2, which can hold rotated small
/// immediates, shifted registers, or modified fp imm. /// immediates, shifted registers, or modified fp imm.
Legal_Mem = 1 << 2, /// includes [r0, r1 lsl #2] as well as [sp, #12] Legal_Mem = 1 << 2, /// includes [r0, r1 lsl #2] as well as [sp, #12]
Legal_All = ~Legal_None Legal_Rematerializable = 1 << 3,
Legal_All = ~Legal_Rematerializable,
}; };
using LegalMask = uint32_t; using LegalMask = uint32_t;
...@@ -816,35 +816,67 @@ protected: ...@@ -816,35 +816,67 @@ protected:
// method that the Parser could call. // method that the Parser could call.
void findMaxStackOutArgsSize(); void findMaxStackOutArgsSize();
/// Run a pass through stack variables and ensure that the offsets are legal. /// Returns true if the given Offset can be represented in a Load/Store Mem
/// If the offset is not legal, use a new base register that accounts for the /// Operand.
/// offset, such that the addressing mode offset bits are now legal.
void legalizeStackSlots();
/// Returns true if the given Offset can be represented in a ldr/str.
bool isLegalMemOffset(Type Ty, int32_t Offset) const; bool isLegalMemOffset(Type Ty, int32_t Offset) const;
// Creates a new Base register centered around
// [OrigBaseReg, +/- Offset]. void postLowerLegalization();
Variable *newBaseRegister(int32_t Offset, Variable *OrigBaseReg);
/// Creates a new, legal OperandARM32Mem for accessing OrigBase + Offset. The class PostLoweringLegalizer {
/// returned mem operand is a legal operand for accessing memory that is of PostLoweringLegalizer() = delete;
/// type Ty. PostLoweringLegalizer(const PostLoweringLegalizer &) = delete;
/// PostLoweringLegalizer &operator=(const PostLoweringLegalizer &) = delete;
/// If [OrigBaseReg, #Offset] is encodable, then the method returns a Mem
/// operand expressing it. Otherwise, public:
/// explicit PostLoweringLegalizer(TargetARM32 *Target)
/// if [*NewBaseReg, #Offset-*NewBaseOffset] is encodable, the method will : Target(Target), StackOrFrameReg(Target->getPhysicalRegister(
/// return that. Otherwise, Target->getFrameOrStackReg())) {}
///
/// a new base register ip=OrigBaseReg+Offset is created, and the method void resetTempBaseIfClobberedBy(const Inst *Instr);
/// returns [ip, #0].
OperandARM32Mem *createMemOperand(Type Ty, int32_t Offset, // Ensures that the TempBase register held by the this legalizer (if any) is
Variable *OrigBaseReg, // assigned to IP.
Variable **NewBaseReg, void assertNoTempOrAssignedToIP() const {
int32_t *NewBaseOffset); assert(TempBaseReg == nullptr ||
/// Legalizes Mov if its Source (or Destination) is a spilled Variable. Moves TempBaseReg->getRegNum() == Target->getReservedTmpReg());
/// to memory become store instructions, and moves from memory, loads. }
void legalizeMov(InstARM32Mov *Mov, Variable *OrigBaseReg,
Variable **NewBaseReg, int32_t *NewBaseOffset); // Legalizes Mem. if Mem.Base is a Reamaterializable variable, Mem.Offset is
// fixed up.
OperandARM32Mem *legalizeMemOperand(OperandARM32Mem *Mem,
bool AllowOffsets = true);
/// Legalizes Mov if its Source (or Destination) is a spilled Variable, or
/// if its Source is a Rematerializable variable (this form is used in lieu
/// of lea, which is not available in ARM.)
///
/// Moves to memory become store instructions, and moves from memory, loads.
void legalizeMov(InstARM32Mov *Mov);
private:
/// Creates a new Base register centered around [Base, +/- Offset].
Variable *newBaseRegister(Variable *Base, int32_t Offset,
int32_t ScratchRegNum);
/// Creates a new, legal OperandARM32Mem for accessing Base + Offset.
/// The returned mem operand is a legal operand for accessing memory that is
/// of type Ty.
///
/// If [Base, #Offset] is encodable, then the method returns a Mem operand
/// expressing it. Otherwise,
///
/// if [TempBaseReg, #Offset-TempBaseOffset] is a valid memory operand, the
/// method will return that. Otherwise,
///
/// a new base register ip=Base+Offset is created, and the method returns a
/// memory operand expressing [ip, #0].
OperandARM32Mem *createMemOperand(Type Ty, Variable *Base, int32_t Offset,
bool AllowOffsets = true);
TargetARM32 *const Target;
Variable *const StackOrFrameReg;
Variable *TempBaseReg = nullptr;
int32_t TempBaseOffset = 0;
};
TargetARM32Features CPUFeatures; TargetARM32Features CPUFeatures;
bool UsesFramePointer = false; bool UsesFramePointer = false;
......
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