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 .
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index d06ee7b..0d0537c 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -835,21 +835,6 @@
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,
BlockAddressMode AddressMode, bool IsLoad,
IValueT BaseReg, IValueT Registers,
@@ -867,6 +852,51 @@
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,
const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) {
@@ -1510,6 +1540,13 @@
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,
const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) {
@@ -1597,35 +1634,8 @@
void AssemblerARM32::uxt(const Operand *OpRd, const Operand *OpSrc0,
CondARM32::Cond Cond) {
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;
- emitUxt(Cond, UxtOpcode, Rd, Rn, Rm, Rotation, 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;
- }
- }
+ constexpr IValueT UxtOpcode = B26 | B25 | B23 | B22 | B21;
+ emitSignExtend(Cond, UxtOpcode, OpRd, OpSrc0, UxtName);
}
} // end of namespace ARM32
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index 705bfe0..0ac8bc7 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -273,6 +273,9 @@
void sub(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
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 udiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
@@ -387,11 +390,11 @@
const Operand *OpRm, const Operand *OpSrc1,
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,
// nnnn=Rn, dddd=Rd, rr=Rotation, and mmmm=Rm.
- void emitUxt(CondARM32::Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
- IValueT Rm, RotationValue Rotation, const char *InstName);
+ void emitSignExtend(CondARM32::Cond, IValueT Opcode, const Operand *OpRd,
+ const Operand *OpSrc0, const char *InstName);
// Pattern cccctttxxxxnnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn,
// ttt=Instruction type (derived from OpSrc1), iiiiiiiiiiii is derived from
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index 2590a10..7fc5883 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -1185,6 +1185,14 @@
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 {
assert(getSrcSize() == 1);
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
diff --git a/tests_lit/assembler/arm32/int-extend.ll b/tests_lit/assembler/arm32/int-extend.ll
new file mode 100644
index 0000000..5ea1365
--- /dev/null
+++ b/tests_lit/assembler/arm32/int-extend.ll
@@ -0,0 +1,113 @@
+; 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
+}