Commit 2c68d90f by Karl Schimpf

Fix frame pointer loads/stores in the ARM integrated assembler.

This CL passes in context from the ARM target lowering, so that it can figure out what register (SP or FP) and offset to use when loading/storing variables. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1414043015 .
parent 4318a410
......@@ -233,18 +233,23 @@ IValueT decodeImmRegOffset(RegARM32::GPRRegister Reg, IOffsetT Offset,
// Decodes memory address Opnd, and encodes that information into Value,
// based on how ARM represents the address. Returns how the value was encoded.
DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value) {
DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value,
const AssemblerARM32::TargetInfo &TInfo) {
if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
// Should be a stack variable, with an offset.
if (Var->hasReg())
return CantDecode;
const IOffsetT Offset = Var->getStackOffset();
IOffsetT Offset = Var->getStackOffset();
if (!Utils::IsAbsoluteUint(12, Offset))
return CantDecode;
RegARM32::GPRRegister BaseReg = RegARM32::Encoded_Reg_sp;
if (const auto *StackVar = llvm::dyn_cast<StackVariable>(Var))
BaseReg = decodeGPRRegister(StackVar->getBaseRegNum());
Value = decodeImmRegOffset(BaseReg, Offset, OperandARM32Mem::Offset);
int32_t BaseRegNum = Var->getBaseRegNum();
if (BaseRegNum == Variable::NoRegister) {
BaseRegNum = TInfo.FrameOrStackReg;
if (!TInfo.HasFramePointer)
Offset += TInfo.StackAdjustment;
}
Value = decodeImmRegOffset(decodeGPRRegister(BaseRegNum), Offset,
OperandARM32Mem::Offset);
return DecodedAsImmRegOffset;
}
if (const auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Opnd)) {
......@@ -695,12 +700,12 @@ void AssemblerARM32::eor(const Operand *OpRd, const Operand *OpRn,
}
void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
CondARM32::Cond Cond) {
CondARM32::Cond Cond, const TargetInfo &TInfo) {
IValueT Rt;
if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
return setNeedsTextFixup();
IValueT Address;
if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset)
if (decodeAddress(OpAddress, Address, TInfo) != DecodedAsImmRegOffset)
return setNeedsTextFixup();
// LDR (immediate) - ARM section A8.8.63, encoding A1:
// ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
......@@ -877,12 +882,12 @@ void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn,
}
void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
CondARM32::Cond Cond) {
CondARM32::Cond Cond, const TargetInfo &TInfo) {
IValueT Rt;
if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
return setNeedsTextFixup();
IValueT Address;
if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset)
if (decodeAddress(OpAddress, Address, TInfo) != DecodedAsImmRegOffset)
return setNeedsTextFixup();
// STR (immediate) - ARM section A8.8.204, encoding A1:
// str<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
......
......@@ -59,6 +59,24 @@ class AssemblerARM32 : public Assembler {
AssemblerARM32 &operator=(const AssemblerARM32 &) = delete;
public:
class TargetInfo {
TargetInfo(const TargetInfo &) = delete;
TargetInfo &operator=(const TargetInfo &) = delete;
public:
TargetInfo(bool HasFramePointer, SizeT FrameOrStackReg,
int32_t StackAdjustment)
: HasFramePointer(HasFramePointer), FrameOrStackReg(FrameOrStackReg),
StackAdjustment(StackAdjustment) {}
explicit TargetInfo(const TargetLowering *Target)
: HasFramePointer(Target->hasFramePointer()),
FrameOrStackReg(Target->getFrameOrStackReg()),
StackAdjustment(Target->getStackAdjustment()) {}
const bool HasFramePointer;
const SizeT FrameOrStackReg;
const int32_t StackAdjustment;
};
explicit AssemblerARM32(bool use_far_branches = false)
: Assembler(Asm_ARM32) {
// TODO(kschimpf): Add mode if needed when branches are handled.
......@@ -172,7 +190,14 @@ public:
void eor(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond);
void ldr(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond);
void ldr(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond,
const TargetInfo &TInfo);
void ldr(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond,
const TargetLowering *Lowering) {
const TargetInfo TInfo(Lowering);
ldr(OpRt, OpAddress, Cond, TInfo);
}
void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
......@@ -205,7 +230,14 @@ public:
void sdiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
CondARM32::Cond Cond);
void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond);
void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond,
const TargetInfo &TInfo);
void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond,
const TargetLowering *Lowering) {
const TargetInfo TInfo(Lowering);
str(OpRt, OpAddress, Cond, TInfo);
}
void sub(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond);
......
......@@ -765,7 +765,7 @@ void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const {
if (isMemoryAccess(Src0)) {
// TODO(kschimpf) Figure out how to do ldr on CoreVPFMove? (see
// emitSingleDestSingleSource, local variable LoadOpcode).
return Asm->ldr(Dest, Src0, getPredicate());
return Asm->ldr(Dest, Src0, getPredicate(), Func->getTarget());
}
return Asm->mov(Dest, Src0, getPredicate());
} else {
......@@ -775,7 +775,7 @@ void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const {
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
if (Src0IsVector || Src0IsScalarFP || CoreVFPMove)
return Asm->setNeedsTextFixup();
return Asm->str(Src0, Dest, getPredicate());
return Asm->str(Src0, Dest, getPredicate(), Func->getTarget());
}
Asm->setNeedsTextFixup();
}
......@@ -995,7 +995,7 @@ template <> void InstARM32Ldr::emitIAS(const Cfg *Func) const {
// TODO(kschimpf) Handle case.
Asm->setNeedsTextFixup();
else
Asm->ldr(Dest, getSrc(0), getPredicate());
Asm->ldr(Dest, getSrc(0), getPredicate(), Func->getTarget());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
......@@ -1364,7 +1364,7 @@ void InstARM32Str::emitIAS(const Cfg *Func) const {
// TODO(kschimpf) Handle case.
Asm->setNeedsTextFixup();
else
Asm->str(getSrc(0), getSrc(1), getPredicate());
Asm->str(getSrc(0), getSrc(1), getPredicate(), Func->getTarget());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
......
; Sample program that generates "str reg, [fp, #CCCC]", to show that we
; recognize that "fp" should be used instead of "sp".
; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
; RUN: | FileCheck %s --check-prefix=ASM
; Show bytes in assembled standalone code.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -Om1 | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
; RUN: -unsafe-ias | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -Om1 -unsafe-ias | FileCheck %s --check-prefix=DIS
define internal void @test_vla_in_loop(i32 %n) {
; ASM-LABEL: test_vla_in_loop:
; DIS-LABEL: 00000000 <test_vla_in_loop>:
; IASM-LABEL: test_vla_in_loop:
entry:
; ASM-NEXT: .Ltest_vla_in_loop$entry:
; IASM-NEXT: .Ltest_vla_in_loop$entry:
; ASM-NEXT: push {fp}
; DIS-NEXT: 0: e52db004
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xb0
; IASM-NEXT: .byte 0x2d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: mov fp, sp
; DIS-NEXT: 4: e1a0b00d
; IASM-NEXT: .byte 0xd
; IASM-NEXT: .byte 0xb0
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1
; ASM-NEXT: sub sp, sp, #12
; DIS-NEXT: 8: e24dd00c
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2
; **** Example of fixed instruction.
; ASM-NEXT: str r0, [fp, #-4]
; DIS-NEXT: c: e50b0004
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xb
; IASM-NEXT: .byte 0xe5
br label %next
; ASM-NEXT: b .Ltest_vla_in_loop$next
; DIS-NEXT: 10: eaffffff
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xea
; Put the variable-length alloca in a non-entry block, to reduce the
; chance the optimizer putting it before the regular frame creation.
next:
%v = alloca i8, i32 %n, align 4
ret void
}
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