Commit 6cab5619 by Karl Schimpf

Add the PUSH instruction to ARM integrated assembler.

parent 5b004e30
...@@ -132,7 +132,8 @@ void Assembler::EmitMemOpAddressMode3(Condition cond, ...@@ -132,7 +132,8 @@ void Assembler::EmitMemOpAddressMode3(Condition cond,
Emit(encoding); Emit(encoding);
} }
#if 0
// Moved to ARM32::AssemblerARM32::emitMuliMemOp()
void Assembler::EmitMultiMemOp(Condition cond, void Assembler::EmitMultiMemOp(Condition cond,
BlockAddressMode am, BlockAddressMode am,
bool load, bool load,
...@@ -148,7 +149,7 @@ void Assembler::EmitMultiMemOp(Condition cond, ...@@ -148,7 +149,7 @@ void Assembler::EmitMultiMemOp(Condition cond,
regs; regs;
Emit(encoding); Emit(encoding);
} }
#endif
void Assembler::EmitShiftImmediate(Condition cond, void Assembler::EmitShiftImmediate(Condition cond,
Shift opcode, Shift opcode,
...@@ -555,11 +556,15 @@ void Assembler::ldm(BlockAddressMode am, Register base, RegList regs, ...@@ -555,11 +556,15 @@ void Assembler::ldm(BlockAddressMode am, Register base, RegList regs,
} }
#if 0
// Folded into ARM32::AssemblerARM32::pushList(), since it is its only
// use (and doesn't implement ARM STM instruction).
void Assembler::stm(BlockAddressMode am, Register base, RegList regs, void Assembler::stm(BlockAddressMode am, Register base, RegList regs,
Condition cond) { Condition cond) {
ASSERT(regs != 0); ASSERT(regs != 0);
EmitMultiMemOp(cond, am, false, base, regs); EmitMultiMemOp(cond, am, false, base, regs);
} }
#endif
void Assembler::ldrex(Register rt, Register rn, Condition cond) { void Assembler::ldrex(Register rt, Register rn, Condition cond) {
...@@ -2561,21 +2566,23 @@ bool Address::CanHoldImmediateOffset( ...@@ -2561,21 +2566,23 @@ bool Address::CanHoldImmediateOffset(
} }
} }
#if 0
// Moved to ARM32::AssemblerARM32::push();
void Assembler::Push(Register rd, Condition cond) { void Assembler::Push(Register rd, Condition cond) {
str(rd, Address(SP, -kWordSize, Address::PreIndex), cond); str(rd, Address(SP, -kWordSize, Address::PreIndex), cond);
} }
#endif
void Assembler::Pop(Register rd, Condition cond) { void Assembler::Pop(Register rd, Condition cond) {
ldr(rd, Address(SP, kWordSize, Address::PostIndex), cond); ldr(rd, Address(SP, kWordSize, Address::PostIndex), cond);
} }
#if 0
// Moved to ARM32::AssemblerARM32::pushList();
void Assembler::PushList(RegList regs, Condition cond) { void Assembler::PushList(RegList regs, Condition cond) {
stm(DB_W, SP, regs, cond); stm(DB_W, SP, regs, cond);
} }
#endif
void Assembler::PopList(RegList regs, Condition cond) { void Assembler::PopList(RegList regs, Condition cond) {
ldm(IA_W, SP, regs, cond); ldm(IA_W, SP, regs, cond);
......
...@@ -575,8 +575,12 @@ class Assembler : public ValueObject { ...@@ -575,8 +575,12 @@ class Assembler : public ValueObject {
void ldm(BlockAddressMode am, Register base, void ldm(BlockAddressMode am, Register base,
RegList regs, Condition cond = AL); RegList regs, Condition cond = AL);
#if 0
// Folded into ARM32::AssemblerARM32::pushList(), since it is its only
// use (and doesn't implement ARM STM instruction).
void stm(BlockAddressMode am, Register base, void stm(BlockAddressMode am, Register base,
RegList regs, Condition cond = AL); RegList regs, Condition cond = AL);
#endif
void ldrex(Register rd, Register rn, Condition cond = AL); void ldrex(Register rd, Register rn, Condition cond = AL);
void strex(Register rd, Register rt, Register rn, Condition cond = AL); void strex(Register rd, Register rt, Register rn, Condition cond = AL);
...@@ -926,10 +930,16 @@ class Assembler : public ValueObject { ...@@ -926,10 +930,16 @@ class Assembler : public ValueObject {
void CopyFloat64x2Field(Register dst, Register src, void CopyFloat64x2Field(Register dst, Register src,
Register tmp1, Register tmp2, DRegister dtmp); Register tmp1, Register tmp2, DRegister dtmp);
#if 0
// Moved to ARM32::AssemblerARM32::push().
void Push(Register rd, Condition cond = AL); void Push(Register rd, Condition cond = AL);
#endif
void Pop(Register rd, Condition cond = AL); void Pop(Register rd, Condition cond = AL);
#if 0
// Moved to ARM32::AssemblerARM32::pushList();
void PushList(RegList regs, Condition cond = AL); void PushList(RegList regs, Condition cond = AL);
#endif
void PopList(RegList regs, Condition cond = AL); void PopList(RegList regs, Condition cond = AL);
void MoveRegister(Register rd, Register rm, Condition cond = AL); void MoveRegister(Register rd, Register rm, Condition cond = AL);
...@@ -1166,11 +1176,14 @@ class Assembler : public ValueObject { ...@@ -1166,11 +1176,14 @@ class Assembler : public ValueObject {
Register rd, Register rd,
Address ad); Address ad);
#if 0
// Moved to ARM32::AssemblerARM32::emitMultiMemOp()
void EmitMultiMemOp(Condition cond, void EmitMultiMemOp(Condition cond,
BlockAddressMode am, BlockAddressMode am,
bool load, bool load,
Register base, Register base,
RegList regs); RegList regs);
#endif
void EmitShiftImmediate(Condition cond, void EmitShiftImmediate(Condition cond,
Shift opcode, Shift opcode,
......
...@@ -29,6 +29,9 @@ namespace { ...@@ -29,6 +29,9 @@ namespace {
using namespace Ice; using namespace Ice;
using namespace Ice::ARM32; using namespace Ice::ARM32;
using WordType = uint32_t;
static constexpr IValueT kWordSize = sizeof(WordType);
// The following define individual bits. // The following define individual bits.
static constexpr IValueT B0 = 1; static constexpr IValueT B0 = 1;
static constexpr IValueT B1 = 1 << 1; static constexpr IValueT B1 = 1 << 1;
...@@ -48,6 +51,7 @@ static constexpr IValueT B22 = 1 << 22; ...@@ -48,6 +51,7 @@ static constexpr IValueT B22 = 1 << 22;
static constexpr IValueT B24 = 1 << 24; static constexpr IValueT B24 = 1 << 24;
static constexpr IValueT B25 = 1 << 25; static constexpr IValueT B25 = 1 << 25;
static constexpr IValueT B26 = 1 << 26; static constexpr IValueT B26 = 1 << 26;
static constexpr IValueT B27 = 1 << 27;
// Constants used for the decoding or encoding of the individual fields of // Constants used for the decoding or encoding of the individual fields of
// instructions. Based on ARM section A5.1. // instructions. Based on ARM section A5.1.
...@@ -535,6 +539,20 @@ void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, ...@@ -535,6 +539,20 @@ void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
emitInst(Encoding); emitInst(Encoding);
} }
void AssemblerARM32::emitMultiMemOp(CondARM32::Cond Cond,
BlockAddressMode AddressMode, bool IsLoad,
IValueT BaseReg, IValueT Registers) {
constexpr IValueT NumGPRegisters = 16;
if (!isConditionDefined(Cond) || !isGPRRegisterDefined(BaseReg) ||
Registers >= (1 << NumGPRegisters))
return setNeedsTextFixup();
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | B27 |
AddressMode | (IsLoad ? L : 0) | (BaseReg << kRnShift) |
Registers;
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) {
...@@ -886,6 +904,33 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn, ...@@ -886,6 +904,33 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn,
emitType01(Orr, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Orr, OpRd, OpRn, OpSrc1, SetFlags, Cond);
} }
void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) {
// PUSH - ARM section A8.8.133, encoding A2:
// push<c> {Rt}
//
// cccc010100101101dddd000000000100 where dddd=Rd and cccc=Cond.
IValueT Rt;
if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
return setNeedsTextFixup();
assert(Rt != RegARM32::Encoded_Reg_sp);
// Same as store instruction.
constexpr bool isLoad = false;
constexpr bool isByte = false;
IValueT Address = decodeImmRegOffset(RegARM32::Encoded_Reg_sp, -kWordSize,
OperandARM32Mem::PreIndex);
emitMemOp(Cond, kInstTypeMemImmediate, isLoad, isByte, Rt, Address);
}
void AssemblerARM32::pushList(const IValueT Registers, CondARM32::Cond Cond) {
// PUSH - ARM section A8.8.133, encoding A1:
// push<c> <Registers>
//
// cccc100100101101rrrrrrrrrrrrrrrr where cccc=Cond and
// rrrrrrrrrrrrrrrr=Registers (one bit for each GP register).
constexpr bool IsLoad = false;
emitMultiMemOp(Cond, DB_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers);
}
void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::mla(const Operand *OpRd, const Operand *OpRn,
const Operand *OpRm, const Operand *OpRa, const Operand *OpRm, const Operand *OpRa,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
......
...@@ -189,6 +189,11 @@ public: ...@@ -189,6 +189,11 @@ public:
void orr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, void orr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond); bool SetFlags, CondARM32::Cond Cond);
void push(const Operand *OpRt, CondARM32::Cond Cond);
// Note: Registers is a bitset, where bit n corresponds to register Rn.
void pushList(const IValueT Registers, CondARM32::Cond Cond);
void sbc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, void sbc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond); bool SetFlags, CondARM32::Cond Cond);
...@@ -221,6 +226,19 @@ private: ...@@ -221,6 +226,19 @@ private:
// InstARM32::emitUsingTextFixup(). // InstARM32::emitUsingTextFixup().
size_t EmitTextSize = 0; size_t EmitTextSize = 0;
// Load/store multiple addressing mode.
enum BlockAddressMode {
// bit encoding P U W
DA = (0 | 0 | 0) << 21, // decrement after
IA = (0 | 4 | 0) << 21, // increment after
DB = (8 | 0 | 0) << 21, // decrement before
IB = (8 | 4 | 0) << 21, // increment before
DA_W = (0 | 0 | 1) << 21, // decrement after with writeback to base
IA_W = (0 | 4 | 1) << 21, // increment after with writeback to base
DB_W = (8 | 0 | 1) << 21, // decrement before with writeback to base
IB_W = (8 | 4 | 1) << 21 // increment before with writeback to base
};
Label *getOrCreateLabel(SizeT Number, LabelVector &Labels); Label *getOrCreateLabel(SizeT Number, LabelVector &Labels);
void bindCfgNodeLabel(const CfgNode *Node) override; void bindCfgNodeLabel(const CfgNode *Node) override;
...@@ -259,6 +277,12 @@ private: ...@@ -259,6 +277,12 @@ private:
void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad, void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad,
bool IsByte, uint32_t Rt, uint32_t Address); bool IsByte, uint32_t Rt, uint32_t Address);
// Pattern cccc100aaaalnnnnrrrrrrrrrrrrrrrr where cccc=Cond,
// aaaa<<21=AddressMode, l=IsLoad, nnnn=BaseReg, and
// rrrrrrrrrrrrrrrr is bitset of Registers.
void emitMultiMemOp(CondARM32::Cond Cond, BlockAddressMode AddressMode,
bool IsLoad, IValueT BaseReg, IValueT Registers);
// 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,
......
...@@ -1179,6 +1179,51 @@ void InstARM32Push::emit(const Cfg *Func) const { ...@@ -1179,6 +1179,51 @@ void InstARM32Push::emit(const Cfg *Func) const {
} }
} }
void InstARM32Push::emitIAS(const Cfg *Func) const {
SizeT SrcReg = 0;
SizeT IntegerCount = 0;
ARM32::IValueT GPURegisters = 0;
for (SizeT i = 0; i < getSrcSize(); ++i) {
if (!isScalarIntegerType(getSrc(i)->getType()))
// TODO(kschimpf) Implement vpush.
return emitUsingTextFixup(Func);
auto *Var = llvm::dyn_cast<Variable>(getSrc(i));
assert((Var && Var->hasReg()) && "push only applies to registers");
ARM32::IValueT Reg = Var->getRegNum();
assert(Reg != static_cast<ARM32::IValueT>(RegARM32::Encoded_Not_GPR));
SrcReg = i;
GPURegisters |= (1 << Reg);
++IntegerCount;
}
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
switch (IntegerCount) {
case 0:
return;
case 1: {
if (auto *Var = llvm::dyn_cast<Variable>(getSrc(SrcReg))) {
// Note: Can only apply push register if single register is not sp.
assert((RegARM32::Encoded_Reg_sp != Var->getRegNum()) &&
"Effects of push register SP is undefined!");
// TODO(kschimpf) ARM sandbox does not allow the single register form of
// push, and the pushList form expects multiple registers. Convert this
// assert to a conditional check once it has been shown that pushList
// works.
assert(!Func->getContext()->getFlags().getUseSandboxing() &&
"push register not in ARM sandbox!");
Asm->push(Var, CondARM32::AL);
break;
}
// Intentionally fall to next case.
}
default:
// TODO(kschimpf) Implement pushList in assembler.
Asm->pushList(GPURegisters, CondARM32::AL);
break;
}
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
void InstARM32Push::dump(const Cfg *Func) const { void InstARM32Push::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
......
...@@ -969,6 +969,7 @@ public: ...@@ -969,6 +969,7 @@ public:
return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs);
} }
void emit(const Cfg *Func) const override; void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override; void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, Push); } static bool classof(const Inst *Inst) { return isClassof(Inst, Push); }
......
...@@ -52,7 +52,11 @@ define internal i32 @AllocBigAlign() { ...@@ -52,7 +52,11 @@ define internal i32 @AllocBigAlign() {
; IASM-LABEL:AllocBigAlign: ; IASM-LABEL:AllocBigAlign:
; IASM-NEXT:.LAllocBigAlign$__0: ; IASM-NEXT:.LAllocBigAlign$__0:
; IASM: push {fp} ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xb0
; IASM-NEXT: .byte 0x2d
; IASM-NEXT: .byte 0xe5
; IASM: .byte 0xd ; IASM: .byte 0xd
; IASM-NEXT: .byte 0xb0 ; IASM-NEXT: .byte 0xb0
; IASM-NEXT: .byte 0xa0 ; IASM-NEXT: .byte 0xa0
......
; Show that we know how to translate push and pop.
; TODO(kschimpf) Translate pop instructions.
; 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 -allow-extern \
; 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 -allow-extern | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 -unsafe-ias \
; RUN: -allow-extern | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 -unsafe-ias -allow-extern | FileCheck %s --check-prefix=DIS
declare external void @DoSomething()
define internal void @SinglePushPop() {
call void @DoSomething();
ret void
}
; ASM-LABEL:SinglePushPop:
; ASM-NEXT:.LSinglePushPop$__0:
; ASM-NEXT: push {lr}
; ASM: sub sp, sp, #12
; ASM-NEXT: bl DoSomething
; ASM: add sp, sp, #12
; ASM-NEXT: pop {lr}
; ASM: bx lr
; DIS-LABEL:00000000 <SinglePushPop>:
; DIS-NEXT: 0: e52de004
; DIS-NEXT: 4: e24dd00c
; DIS-NEXT: 8: ebfffffe
; DIS-NEXT: c: e28dd00c
; DIS-NEXT: 10: e49de004
; DIS-NEXT: 14: e12fff1e
; IASM-LABEL:SinglePushPop:
; IASM-NEXT:.LSinglePushPop$__0:
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x2d
; IASM-NEXT: .byte 0xe5
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2
; IASM-NEXT: bl DoSomething
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe2
; IASM-NEXT: pop {lr}
; IASM: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
; This test is based on taking advantage of the over-eager -O2
; register allocator that puts V1 and V2 into callee-save registers,
; since the call instruction kills the scratch registers. This
; requires the callee-save registers to be pushed/popped in the
; prolog/epilog.
define internal i32 @MultPushPop(i32 %v1, i32 %v2) {
call void @DoSomething();
%v3 = add i32 %v1, %v2
ret i32 %v3
}
; ASM-LABEL:MultPushPop:
; ASM-NEXT:.LMultPushPop$__0:
; ASM-NEXT: push {r4, r5, lr}
; ASM: sub sp, sp, #4
; ASM-NEXT: mov r4, r0
; ASM-NEXT: mov r5, r1
; ASM-NEXT: bl DoSomething
; ASM: add r4, r4, r5
; ASM-NEXT: mov r0, r4
; ASM-NEXT: add sp, sp, #4
; ASM-NEXT: pop {r4, r5, lr}
; ASM: bx lr
; DIS-LABEL:00000020 <MultPushPop>:
; DIS-NEXT: 20: e92d4030
; DIS-NEXT: 24: e24dd004
; DIS-NEXT: 28: e1a04000
; DIS-NEXT: 2c: e1a05001
; DIS-NEXT: 30: ebfffffe
; DIS-NEXT: 34: e0844005
; DIS-NEXT: 38: e1a00004
; DIS-NEXT: 3c: e28dd004
; DIS-NEXT: 40: e8bd4030
; DIS-NEXT: 44: e12fff1e
; IASM-LABEL:MultPushPop:
; IASM-NEXT:.LMultPushPop$__0:
; IASM-NEXT: .byte 0x30
; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0x2d
; IASM-NEXT: .byte 0xe9
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x50
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1
; IASM-NEXT: bl DoSomething
; IASM-NEXT: .byte 0x5
; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0x84
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe2
; IASM-NEXT: pop {r4, r5, lr}
; IASM: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; 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