Commit 1e67f91a by Karl Schimpf

Add Sxtb/Sxth instructions to ARM integrated assembler.

Refactors code to take advantage of these instructions with Uxtb/Uxth. Note. These instructions are used by Subzero, but not Dart. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1503273002 .
parent 43e8ab38
...@@ -835,21 +835,6 @@ void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, ...@@ -835,21 +835,6 @@ 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,
const char *InstName) {
verifyCondDefined(Cond, InstName);
IValueT Rot = encodeRotation(Rotation);
if (!Utils::IsUint(2, Rot))
llvm::report_fatal_error(std::string(InstName) +
": Illegal rotation value");
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,
...@@ -867,6 +852,51 @@ void AssemblerARM32::emitMultiMemOp(CondARM32::Cond Cond, ...@@ -867,6 +852,51 @@ void AssemblerARM32::emitMultiMemOp(CondARM32::Cond Cond,
emitInst(Encoding); emitInst(Encoding);
} }
void AssemblerARM32::emitSignExtend(CondARM32::Cond Cond, IValueT Opcode,
const Operand *OpRd, const Operand *OpSrc0,
const char *InstName) {
IValueT Rd = encodeRegister(OpRd, "Rd", InstName);
IValueT Rm = encodeRegister(OpSrc0, "Rm", InstName);
// Note: For the moment, we assume no rotation is specified.
RotationValue Rotation = kRotateNone;
constexpr IValueT Rn = RegARM32::Encoded_Reg_pc;
switch (typeWidthInBytes(OpSrc0->getType())) {
default:
llvm::report_fatal_error(std::string(InstName) +
": Type of Rm not understood");
break;
case 1: {
// SXTB/UXTB - Arm sections A8.8.233 and A8.8.274, encoding A1:
// sxtb<c> <Rd>, <Rm>{, <rotate>}
// uxtb<c> <Rd>, <Rm>{, <rotate>}
//
// ccccxxxxxxxx1111ddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode,
// dddd=Rd, mmmm=Rm, and rr defined (RotationValue) rotate.
break;
}
case 2: {
// SXTH/UXTH - ARM sections A8.8.235 and A8.8.276, encoding A1:
// uxth<c> <Rd>< <Rm>{, <rotate>}
//
// cccc01101111nnnnddddrr000111mmmm where cccc=Cond, dddd=Rd, mmmm=Rm, and
// rr defined (RotationValue) rotate.
Opcode |= B20;
break;
}
}
verifyCondDefined(Cond, InstName);
IValueT Rot = encodeRotation(Rotation);
if (!Utils::IsUint(2, Rot))
llvm::report_fatal_error(std::string(InstName) +
": Illegal rotation value");
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::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) {
...@@ -1510,6 +1540,13 @@ void AssemblerARM32::rsb(const Operand *OpRd, const Operand *OpRn, ...@@ -1510,6 +1540,13 @@ void AssemblerARM32::rsb(const Operand *OpRd, const Operand *OpRn,
RsbName); RsbName);
} }
void AssemblerARM32::sxt(const Operand *OpRd, const Operand *OpSrc0,
CondARM32::Cond Cond) {
constexpr const char *SxtName = "sxt";
constexpr IValueT SxtOpcode = B26 | B25 | B23 | B21;
emitSignExtend(Cond, SxtOpcode, OpRd, OpSrc0, SxtName);
}
void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
...@@ -1597,35 +1634,8 @@ void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi, ...@@ -1597,35 +1634,8 @@ void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi,
void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0, void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
constexpr const char *UxtName = "uxt"; constexpr const char *UxtName = "uxt";
IValueT Rd = encodeRegister(OpRd, "Rd", UxtName);
IValueT Rm = encodeRegister(OpSrc0, "Rm", UxtName);
// Note: For the moment, we assume no rotation is specified.
RotationValue Rotation = kRotateNone;
constexpr IValueT Rn = RegARM32::Encoded_Reg_pc;
switch (typeWidthInBytes(OpSrc0->getType())) {
default:
llvm::report_fatal_error("Type of Rm not understood: uxt");
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 UxtOpcode = B26 | B25 | B23 | B22 | B21; constexpr IValueT UxtOpcode = B26 | B25 | B23 | B22 | B21;
emitUxt(Cond, UxtOpcode, Rd, Rn, Rm, Rotation, UxtName); emitSignExtend(Cond, UxtOpcode, OpRd, OpSrc0, UxtName);
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 UxtOpcode = B26 | B25 | B23 | B22 | B21 | B20;
emitUxt(Cond, UxtOpcode, Rd, Rn, Rm, Rotation, UxtName);
return;
}
}
} }
} // end of namespace ARM32 } // end of namespace ARM32
......
...@@ -273,6 +273,9 @@ public: ...@@ -273,6 +273,9 @@ public:
void sub(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, void sub(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond); bool SetFlags, CondARM32::Cond Cond);
// Implements sxtb/sxth depending on type of OpSrc0.
void sxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond);
void tst(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond); void tst(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond);
void udiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, void udiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
...@@ -387,11 +390,11 @@ private: ...@@ -387,11 +390,11 @@ private:
const Operand *OpRm, const Operand *OpSrc1, const Operand *OpRm, const Operand *OpSrc1,
const bool SetFlags, const char *InstName); const bool SetFlags, const char *InstName);
// Implements various forms of Unsigned extend value, using pattern // Implements various forms of signed/unsigned extend value, using pattern
// ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode, // ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode,
// nnnn=Rn, dddd=Rd, rr=Rotation, and mmmm=Rm. // nnnn=Rn, dddd=Rd, rr=Rotation, and mmmm=Rm.
void emitUxt(CondARM32::Cond, IValueT Opcode, IValueT Rd, IValueT Rn, void emitSignExtend(CondARM32::Cond, IValueT Opcode, const Operand *OpRd,
IValueT Rm, RotationValue Rotation, const char *InstName); const Operand *OpSrc0, const char *InstName);
// 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
......
...@@ -1185,6 +1185,14 @@ template <> void InstARM32Mvn::emitIAS(const Cfg *Func) const { ...@@ -1185,6 +1185,14 @@ template <> void InstARM32Mvn::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func); emitUsingTextFixup(Func);
} }
template <> void InstARM32Sxt::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1);
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->sxt(getDest(), getSrc(0), getPredicate());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const { template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1); assert(getSrcSize() == 1);
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
......
; Tests signed/unsigned extend to 32 bits.
; Show that we know how to translate add.
; 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
; NOTE: We use -O2 to get rid of memory stores.
; 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 @testUxtb(i32 %v) {
; ASM-LABEL:testUxtb:
; DIS-LABEL:00000000 <testUxtb>:
; IASM-LABEL:testUxtb:
entry:
; ASM-NEXT:.LtestUxtb$entry:
; IASM-NEXT:.LtestUxtb$entry:
%v.b = trunc i32 %v to i8
%res = zext i8 %v.b 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
ret i32 %res
}
define internal i32 @testSxtb(i32 %v) {
; ASM-LABEL:testSxtb:
; DIS-LABEL:00000010 <testSxtb>:
; IASM-LABEL:testSxtb:
entry:
; ASM-NEXT:.LtestSxtb$entry:
; IASM-NEXT:.LtestSxtb$entry:
%v.b = trunc i32 %v to i8
%res = sext i8 %v.b to i32
; ASM-NEXT: sxtb r0, r0
; DIS-NEXT: 10: e6af0070
; IASM-NEXT: .byte 0x70
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xaf
; IASM-NEXT: .byte 0xe6
ret i32 %res
}
define internal i32 @testUxth(i32 %v) {
; ASM-LABEL:testUxth:
; DIS-LABEL:00000020 <testUxth>:
; IASM-LABEL:testUxth:
entry:
; ASM-NEXT:.LtestUxth$entry:
; IASM-NEXT:.LtestUxth$entry:
%v.h = trunc i32 %v to i16
%res = zext i16 %v.h to i32
; ASM-NEXT: uxth r0, r0
; DIS-NEXT: 20: e6ff0070
; IASM-NEXT: .byte 0x70
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xe6
ret i32 %res
}
define internal i32 @testSxth(i32 %v) {
; ASM-LABEL:testSxth:
; DIS-LABEL:00000030 <testSxth>:
; IASM-LABEL:testSxth:
entry:
; ASM-NEXT:.LtestSxth$entry:
; IASM-NEXT:.LtestSxth$entry:
%v.h = trunc i32 %v to i16
%res = sext i16 %v.h to i32
; ASM-NEXT: sxth r0, r0
; DIS-NEXT: 30: e6bf0070
; IASM-NEXT: .byte 0x70
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xbf
; IASM-NEXT: .byte 0xe6
ret i32 %res
}
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