Commit bb0bacfd by Karl Schimpf

Implement UXTB and UXTH in the ARM integerated assembler.

parent 2c68d90f
...@@ -1301,6 +1301,12 @@ class Assembler : public ValueObject { ...@@ -1301,6 +1301,12 @@ class Assembler : public ValueObject {
Register new_value, Register new_value,
FieldContent old_content); FieldContent old_content);
#if 0
// Added the following missing operations:
//
// ARM32::AssemblerARM::uxt() (uxtb and uxth).
#endif
DISALLOW_ALLOCATION(); DISALLOW_ALLOCATION();
DISALLOW_COPY_AND_ASSIGN(Assembler); DISALLOW_COPY_AND_ASSIGN(Assembler);
}; };
......
...@@ -90,6 +90,9 @@ static constexpr IValueT kShiftShift = 5; ...@@ -90,6 +90,9 @@ static constexpr IValueT kShiftShift = 5;
static constexpr IValueT kImmed12Bits = 12; static constexpr IValueT kImmed12Bits = 12;
static constexpr IValueT kImm12Shift = 0; static constexpr IValueT kImm12Shift = 0;
// Rotation instructions (uxtb etc.).
static constexpr IValueT kRotationShift = 10;
// Div instruction register field encodings. // Div instruction register field encodings.
static constexpr IValueT kDivRdShift = 16; static constexpr IValueT kDivRdShift = 16;
static constexpr IValueT kDivRmShift = 8; static constexpr IValueT kDivRmShift = 8;
...@@ -110,6 +113,10 @@ static constexpr IOffsetT kBranchOffsetMask = 0x00ffffff; ...@@ -110,6 +113,10 @@ static constexpr IOffsetT kBranchOffsetMask = 0x00ffffff;
inline IValueT encodeBool(bool B) { return B ? 1 : 0; } inline IValueT encodeBool(bool B) { return B ? 1 : 0; }
inline IValueT encodeRotation(ARM32::AssemblerARM32::RotationValue Value) {
return static_cast<IValueT>(Value);
}
inline IValueT encodeGPRRegister(RegARM32::GPRRegister Rn) { inline IValueT encodeGPRRegister(RegARM32::GPRRegister Rn) {
return static_cast<IValueT>(Rn); return static_cast<IValueT>(Rn);
} }
...@@ -545,6 +552,18 @@ void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, ...@@ -545,6 +552,18 @@ void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
emitInst(Encoding); emitInst(Encoding);
} }
void AssemblerARM32::emitUxt(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
IValueT Rn, IValueT Rm, RotationValue Rotation) {
IValueT Rot = encodeRotation(Rotation);
if (!isConditionDefined(Cond) || !Utils::IsUint(2, Rot))
return setNeedsTextFixup();
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | Opcode |
(Rn << kRnShift) | (Rd << kRdShift) |
(Rot << kRotationShift) | B6 | B5 | B4 | (Rm << kRmShift);
emitInst(Encoding);
}
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) {
...@@ -1131,5 +1150,42 @@ void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi, ...@@ -1131,5 +1150,42 @@ void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi,
emitMulOp(Cond, B23, RdLo, RdHi, Rn, Rm, SetFlags); emitMulOp(Cond, B23, RdLo, RdHi, Rn, Rm, SetFlags);
} }
void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0,
CondARM32::Cond Cond) {
IValueT Rd;
if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
return setNeedsTextFixup();
// Note: For the moment, we assume no rotation is specified.
RotationValue Rotation = kRotateNone;
constexpr IValueT Rn = RegARM32::Encoded_Reg_pc;
IValueT Rm;
if (decodeOperand(OpSrc0, Rm) != DecodedAsRegister)
return setNeedsTextFixup();
switch (typeWidthInBytes(OpSrc0->getType())) {
default:
return setNeedsTextFixup();
case 1: {
// UXTB - ARM section A8.8.274, encoding A1:
// uxtb<c> <Rd>, <Rm>{, <rotate>}
//
// cccc011011101111ddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and
// rr defined (RotationValue) rotate.
constexpr IValueT Opcode = B26 | B25 | B23 | B22 | B21;
emitUxt(Cond, Opcode, Rd, Rn, Rm, Rotation);
return;
}
case 2: {
// UXTH - ARM section A8.8.276, encoding A1:
// uxth<c> <Rd>< <Rm>{, <rotate>}
//
// cccc01101111nnnnddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and
// rr defined (RotationValue) rotate.
constexpr IValueT Opcode = B26 | B25 | B23 | B22 | B21 | B20;
emitUxt(Cond, Opcode, Rd, Rn, Rm, Rotation);
return;
}
}
}
} // end of namespace ARM32 } // end of namespace ARM32
} // end of namespace Ice } // end of namespace Ice
...@@ -59,6 +59,14 @@ class AssemblerARM32 : public Assembler { ...@@ -59,6 +59,14 @@ class AssemblerARM32 : public Assembler {
AssemblerARM32 &operator=(const AssemblerARM32 &) = delete; AssemblerARM32 &operator=(const AssemblerARM32 &) = delete;
public: public:
// Rotation values.
enum RotationValue {
kRotateNone, // Omitted
kRotate8, // ror #8
kRotate16, // ror #16
kRotate24 // ror #24
};
class TargetInfo { class TargetInfo {
TargetInfo(const TargetInfo &) = delete; TargetInfo(const TargetInfo &) = delete;
TargetInfo &operator=(const TargetInfo &) = delete; TargetInfo &operator=(const TargetInfo &) = delete;
...@@ -250,6 +258,9 @@ public: ...@@ -250,6 +258,9 @@ public:
void umull(const Operand *OpRdLo, const Operand *OpRdHi, const Operand *OpRn, void umull(const Operand *OpRdLo, const Operand *OpRdHi, const Operand *OpRn,
const Operand *OpRm, CondARM32::Cond Cond); const Operand *OpRm, CondARM32::Cond Cond);
// Implements uxtb/uxth depending on type of OpSrc0.
void uxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond);
static bool classof(const Assembler *Asm) { static bool classof(const Assembler *Asm) {
return Asm->getKind() == Asm_ARM32; return Asm->getKind() == Asm_ARM32;
} }
...@@ -333,6 +344,12 @@ private: ...@@ -333,6 +344,12 @@ private:
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 SetCc); IValueT Rm, IValueT Rs, bool SetCc);
// Implements various forms of Unsigned extend value, using pattern
// ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode,
// nnnn=Rn, dddd=Rd, rr=Rotation, and mmmm=Rm.
void emitUxt(CondARM32::Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
IValueT Rm, RotationValue Rotation);
// Pattern cccctttxxxxnnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn, // Pattern cccctttxxxxnnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn,
// ttt=Instruction type (derived from OpSrc1), iiiiiiiiiiii is derived from // ttt=Instruction type (derived from OpSrc1), iiiiiiiiiiii is derived from
// OpSrc1, and xxxx=Opcode. // OpSrc1, and xxxx=Opcode.
......
...@@ -1077,6 +1077,14 @@ template <> void InstARM32Movt::emitIAS(const Cfg *Func) const { ...@@ -1077,6 +1077,14 @@ template <> void InstARM32Movt::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func); emitUsingTextFixup(Func);
} }
template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1);
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->uxt(getDest(), getSrc(0), getPredicate());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
void InstARM32Pop::emit(const Cfg *Func) const { void InstARM32Pop::emit(const Cfg *Func) const {
// TODO(jpp): Improve FP register save/restore. // TODO(jpp): Improve FP register save/restore.
if (!BuildDefs::dump()) if (!BuildDefs::dump())
......
; Test the UXTB and UXTH 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 \
; 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 i32 @_Z7testAddhh(i32 %a, i32 %b) {
; ASM-LABEL: _Z7testAddhh:
; DIS-LABEL: 00000000 <_Z7testAddhh>:
; IASM-LABEL: _Z7testAddhh:
entry:
; ASM-NEXT: .L_Z7testAddhh$entry:
; IASM-NEXT: .L_Z7testAddhh$entry:
%a.arg_trunc = trunc i32 %a to i8
%conv = zext i8 %a.arg_trunc to i32
; ASM-NEXT: uxtb r0, r0
; DIS-NEXT: 0: e6ef0070
; IASM-NEXT: .byte 0x70
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xef
; IASM-NEXT: .byte 0xe6
%b.arg_trunc = trunc i32 %b to i8
%conv1 = zext i8 %b.arg_trunc to i32
; ASM-NEXT: uxtb r1, r1
; DIS-NEXT: 4: e6ef1071
; IASM-NEXT: .byte 0x71
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0xef
; IASM-NEXT: .byte 0xe6
%add = add i32 %conv1, %conv
; ASM-NEXT: add r1, r1, r0
; DIS-NEXT: 8: e0811000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x81
; IASM-NEXT: .byte 0xe0
%conv2 = trunc i32 %add to i16
%conv2.ret_ext = zext i16 %conv2 to i32
; ASM-NEXT: uxth r1, r1
; DIS-NEXT: c: e6ff1071
; IASM-NEXT: .byte 0x71
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xe6
ret i32 %conv2.ret_ext
; ASM-NEXT: mov r0, r1
; DIS-NEXT: 10: e1a00001
; IASM-NEXT: mov r0, r1
; ASM-NEXT: bx lr
; DIS-NEXT: 14: e12fff1e
; IASM-NEXT: .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