Fix emission of move immediate for ARM integrated assembler.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=4334
R=jpp@chromium.org
Review URL: https://codereview.chromium.org/1397043003 .
diff --git a/src/DartARM32/assembler_arm.cc b/src/DartARM32/assembler_arm.cc
index fee25dc..ec942d0 100644
--- a/src/DartARM32/assembler_arm.cc
+++ b/src/DartARM32/assembler_arm.cc
@@ -71,7 +71,8 @@
buffer_.Emit<int32_t>(value);
}
-
+#if 0
+// Moved to class AssemblerARM32.
void Assembler::EmitType01(Condition cond,
int type,
Opcode opcode,
@@ -90,7 +91,7 @@
o.encoding();
Emit(encoding);
}
-
+#endif
void Assembler::EmitType5(Condition cond, int32_t offset, bool link) {
ASSERT(cond != kNoCondition);
@@ -277,10 +278,13 @@
}
+#if 0
+// Moved to AssemblerARM32::mov(..FlexImm..)
+// TODO(kschimpf) other forms of move.
void Assembler::mov(Register rd, Operand o, Condition cond) {
EmitType01(cond, o.type(), MOV, 0, R0, rd, o);
}
-
+#endif
void Assembler::movs(Register rd, Operand o, Condition cond) {
EmitType01(cond, o.type(), MOV, 1, R0, rd, o);
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index 7893d6f..31c93c4 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -28,7 +28,7 @@
class StubEntry;
#if 0
-// Moved to: ARM32::AssemblerARM32.
+// Moved to: ARM32::AssemblerARM32 as needed
// Instruction encoding bits.
enum {
H = 1 << 5, // halfword (or byte)
@@ -139,12 +139,15 @@
encoding_ = immediate;
}
+#if 0
+ // Moved to AssemblerARM32::encodeImm12FromFlexImm.
// Data-processing operands - Rotated immediate.
Operand(uint32_t rotate, uint32_t immed8) {
ASSERT((rotate < (1 << kRotateBits)) && (immed8 < (1 << kImmed8Bits)));
type_ = 1;
encoding_ = (rotate << kRotateShift) | (immed8 << kImmed8Shift);
}
+#endif
// Data-processing operands - Register.
explicit Operand(Register rm) {
@@ -465,7 +468,11 @@
void orr(Register rd, Register rn, Operand o, Condition cond = AL);
void orrs(Register rd, Register rn, Operand o, Condition cond = AL);
+#if 0
+ // Moved to IceAssemblerARM32::mov(..FlexImm..)
+ // TODO(kschimpf) other forms of move.
void mov(Register rd, Operand o, Condition cond = AL);
+#endif
void movs(Register rd, Operand o, Condition cond = AL);
void bic(Register rd, Register rn, Operand o, Condition cond = AL);
@@ -1084,6 +1091,8 @@
bool is_unique,
Register pp);
+#if 0
+ // Moved to class AssemblerARM32.
void EmitType01(Condition cond,
int type,
Opcode opcode,
@@ -1091,6 +1100,7 @@
Register rn,
Register rd,
Operand o);
+#endif
void EmitType5(Condition cond, int32_t offset, bool link);
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index ab22450..16f1e4a 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -24,6 +24,65 @@
namespace Ice {
+// The following define individual bits.
+static constexpr uint32_t B0 = 1;
+static constexpr uint32_t B2 = 1 << 2;
+static constexpr uint32_t B3 = 1 << 3;
+static constexpr uint32_t B4 = 1 << 4;
+static constexpr uint32_t B5 = 1 << 5;
+static constexpr uint32_t B6 = 1 << 6;
+static constexpr uint32_t B21 = 1 << 21;
+static constexpr uint32_t B24 = 1 << 24;
+
+// Constants used for the decoding or encoding of the individual fields of
+// instructions. Based on ARM section A5.1.
+static constexpr uint32_t kConditionShift = 28;
+static constexpr uint32_t kOpcodeShift = 21;
+static constexpr uint32_t kRdShift = 12;
+static constexpr uint32_t kRmShift = 0;
+static constexpr uint32_t kRnShift = 16;
+static constexpr uint32_t kSShift = 20;
+static constexpr uint32_t kTypeShift = 25;
+
+// Immediate instruction fields encoding.
+static constexpr uint32_t kImmed8Bits = 8;
+static constexpr uint32_t kImmed8Shift = 0;
+static constexpr uint32_t kRotateBits = 4;
+static constexpr uint32_t kRotateShift = 8;
+
+// Types of instructions.
+static constexpr uint32_t kInstTypeImmediate = 1;
+
+inline uint32_t encodeBool(bool b) { return b ? 1 : 0; }
+
+inline uint32_t encodeGPRRegister(RegARM32::GPRRegister Rn) {
+ return static_cast<uint32_t>(Rn);
+}
+
+inline bool isGPRRegisterDefined(RegARM32::GPRRegister R) {
+ return R != RegARM32::Encoded_Not_GPR;
+}
+
+inline bool isGPRRegisterDefined(uint32_t R) {
+ return R != encodeGPRRegister(RegARM32::Encoded_Not_GPR);
+}
+
+inline bool isConditionDefined(CondARM32::Cond Cond) {
+ return Cond != CondARM32::kNone;
+}
+
+inline uint32_t encodeCondition(CondARM32::Cond Cond) {
+ return static_cast<uint32_t>(Cond);
+}
+
+// Converts rotated immediate into imm12.
+inline uint32_t encodeImm12FromFlexImm(const OperandARM32FlexImm &FlexImm) {
+ uint32_t Immed8 = FlexImm.getImm();
+ uint32_t Rotate = FlexImm.getRotateAmt();
+ assert((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)));
+ return (Rotate << kRotateShift) | (Immed8 << kImmed8Shift);
+}
+
Label *ARM32::AssemblerARM32::getOrCreateLabel(SizeT Number,
LabelVector &Labels) {
Label *L = nullptr;
@@ -56,20 +115,47 @@
label->bindTo(bound);
}
-void ARM32::AssemblerARM32::bkpt(uint16_t imm16) {
- AssemblerBuffer::EnsureCapacity ensured(&Buffer);
- emitInt32(BkptEncoding(imm16));
+void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type,
+ uint32_t Opcode, bool SetCc, uint32_t Rn,
+ uint32_t Rd, uint32_t Imm12) {
+ assert(isGPRRegisterDefined(Rd));
+ assert(Cond != CondARM32::kNone);
+ uint32_t Encoding = encodeCondition(Cond) << kConditionShift |
+ (Type << kTypeShift) | (Opcode << kOpcodeShift) |
+ (encodeBool(SetCc) << kSShift) | (Rn << kRnShift) |
+ (Rd << kRdShift) | Imm12;
+ emitInst(Encoding);
}
-void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister rm, CondARM32::Cond cond) {
- // cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond.
- assert(rm != RegARM32::Encoded_Not_GPR);
- assert(cond != CondARM32::kNone);
+void ARM32::AssemblerARM32::bkpt(uint16_t imm16) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | B24 |
- B21 | (0xfff << 8) | B4 |
- (static_cast<int32_t>(rm) << kRmShift);
- emitInt32(encoding);
+ uint32_t Encoding = (CondARM32::AL << kConditionShift) | B24 | B21 |
+ ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf);
+ emitInst(Encoding);
+}
+
+void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) {
+ // cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond.
+ // (ARM section A8.8.27, encoding A1).
+ assert(isGPRRegisterDefined(Rm));
+ assert(isConditionDefined(Cond));
+ AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+ uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | B21 |
+ (0xfff << 8) | B4 | (encodeGPRRegister(Rm) << kRmShift);
+ emitInst(Encoding);
+}
+
+void ARM32::AssemblerARM32::mov(RegARM32::GPRRegister Rd,
+ const OperandARM32FlexImm &FlexImm,
+ CondARM32::Cond Cond) {
+ // cccc0011101s0000ddddiiiiiiiiiiii (ARM section A8.8.102, encoding A1)
+ assert(isConditionDefined(Cond));
+ AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+ bool SetCc = false; // Note: We don't use movs in this assembler.
+ uint32_t Rn = 0;
+ uint32_t Mov = B3 | B2 | B0; // 1101.
+ emitType01(Cond, kInstTypeImmediate, Mov, SetCc, Rn, encodeGPRRegister(Rd),
+ encodeImm12FromFlexImm(FlexImm));
}
} // end of namespace Ice
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index 2b6bbb1..f3885bf 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -18,6 +18,10 @@
/// \file
/// This file implements the Assembler class for ARM32.
///
+/// Note: All references to ARM "section" documentation refers to the "ARM
+/// Architecture Reference Manual, ARMv7-A and ARMv7-R edition". See:
+/// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c
+///
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEASSEMBLERARM32_H
@@ -27,6 +31,7 @@
#include "IceConditionCodesARM32.h"
#include "IceDefs.h"
#include "IceFixups.h"
+#include "IceInstARM32.h"
#include "IceRegistersARM32.h"
#include "IceTargetLowering.h"
@@ -74,8 +79,8 @@
}
Ice::Label *getCfgNodeLabel(SizeT NodeNumber) override {
- (void)NodeNumber;
- llvm_unreachable("Not yet implemented.");
+ assert(NodeNumber < CfgNodeLabels.size());
+ return CfgNodeLabels[NodeNumber];
}
void bindCfgNodeLabel(SizeT NodeNumber) override {
@@ -90,145 +95,18 @@
}
void bind(Label *label);
- void bkpt(uint16_t imm16);
+ void bkpt(uint16_t Imm16);
- void bx(RegARM32::GPRRegister rm, CondARM32::Cond cond = CondARM32::AL);
+ void mov(RegARM32::GPRRegister Rd, const OperandARM32FlexImm &FlexImm,
+ CondARM32::Cond Cond);
+
+ void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL);
static bool classof(const Assembler *Asm) {
return Asm->getKind() == Asm_ARM32;
}
private:
- // Instruction encoding bits.
-
- // halfword (or byte)
- static constexpr uint32_t H = 1 << 5;
- // load (or store)
- static constexpr uint32_t L = 1 << 20;
- // set condition code (or leave unchanged)
- static constexpr uint32_t S = 1 << 20;
- // writeback base register (or leave unchanged)
- static constexpr uint32_t W = 1 << 21;
- // accumulate in multiply instruction (or not)
- static constexpr uint32_t A = 1 << 21;
- // unsigned byte (or word)
- static constexpr uint32_t B = 1 << 22;
- // high/lo bit of start of s/d register range
- static constexpr uint32_t D = 1 << 22;
- // long (or short)
- static constexpr uint32_t N = 1 << 22;
- // positive (or negative) offset/index
- static constexpr uint32_t U = 1 << 23;
- // offset/pre-indexed addressing (or post-indexed addressing)
- static constexpr uint32_t P = 1 << 24;
- // immediate shifter operand (or not)
- static constexpr uint32_t I = 1 << 25;
-
- // The following define individual bits.
- static constexpr uint32_t B0 = 1;
- static constexpr uint32_t B1 = 1 << 1;
- static constexpr uint32_t B2 = 1 << 2;
- static constexpr uint32_t B3 = 1 << 3;
- static constexpr uint32_t B4 = 1 << 4;
- static constexpr uint32_t B5 = 1 << 5;
- static constexpr uint32_t B6 = 1 << 6;
- static constexpr uint32_t B7 = 1 << 7;
- static constexpr uint32_t B8 = 1 << 8;
- static constexpr uint32_t B9 = 1 << 9;
- static constexpr uint32_t B10 = 1 << 10;
- static constexpr uint32_t B11 = 1 << 11;
- static constexpr uint32_t B12 = 1 << 12;
- static constexpr uint32_t B16 = 1 << 16;
- static constexpr uint32_t B17 = 1 << 17;
- static constexpr uint32_t B18 = 1 << 18;
- static constexpr uint32_t B19 = 1 << 19;
- static constexpr uint32_t B20 = 1 << 20;
- static constexpr uint32_t B21 = 1 << 21;
- static constexpr uint32_t B22 = 1 << 22;
- static constexpr uint32_t B23 = 1 << 23;
- static constexpr uint32_t B24 = 1 << 24;
- static constexpr uint32_t B25 = 1 << 25;
- static constexpr uint32_t B26 = 1 << 26;
- static constexpr uint32_t B27 = 1 << 27;
-
- // Constants used for the decoding or encoding of the individual fields of
- // instructions. Based on section A5.1 from the "ARM Architecture Reference
- // Manual, ARMv7-A and ARMv7-R edition". See:
- // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c
- static constexpr uint32_t kConditionShift = 28;
- static constexpr uint32_t kConditionBits = 4;
- static constexpr uint32_t kTypeShift = 25;
- static constexpr uint32_t kTypeBits = 3;
- static constexpr uint32_t kLinkShift = 24;
- static constexpr uint32_t kLinkBits = 1;
- static constexpr uint32_t kUShift = 23;
- static constexpr uint32_t kUBits = 1;
- static constexpr uint32_t kOpcodeShift = 21;
- static constexpr uint32_t kOpcodeBits = 4;
- static constexpr uint32_t kSShift = 20;
- static constexpr uint32_t kSBits = 1;
- static constexpr uint32_t kRnShift = 16;
- static constexpr uint32_t kRnBits = 4;
- static constexpr uint32_t kRdShift = 12;
- static constexpr uint32_t kRdBits = 4;
- static constexpr uint32_t kRsShift = 8;
- static constexpr uint32_t kRsBits = 4;
- static constexpr uint32_t kRmShift = 0;
- static constexpr uint32_t kRmBits = 4;
-
- // Immediate instruction fields encoding.
- static constexpr uint32_t kRotateShift = 8;
- static constexpr uint32_t kRotateBits = 4;
- static constexpr uint32_t kImmed8Shift = 0;
- static constexpr uint32_t kImmed8Bits = 8;
-
- // Shift instruction register fields encodings.
- static constexpr uint32_t kShiftImmShift = 7;
- static constexpr uint32_t kShiftRegisterShift = 8;
- static constexpr uint32_t kShiftImmBits = 5;
- static constexpr uint32_t kShiftShift = 5;
- static constexpr uint32_t kShiftBits = 2;
-
- // Load/store instruction offset field encoding.
- static constexpr uint32_t kOffset12Shift = 0;
- static constexpr uint32_t kOffset12Bits = 12;
- static constexpr uint32_t kOffset12Mask = 0x00000fff;
-
- // Mul instruction register field encodings.
- static constexpr uint32_t kMulRdShift = 16;
- static constexpr uint32_t kMulRdBits = 4;
- static constexpr uint32_t kMulRnShift = 12;
- static constexpr uint32_t kMulRnBits = 4;
-
- // Div instruction register field encodings.
- static constexpr uint32_t kDivRdShift = 16;
- static constexpr uint32_t kDivRdBits = 4;
- static constexpr uint32_t kDivRmShift = 8;
- static constexpr uint32_t kDivRmBints = 4;
- static constexpr uint32_t kDivRnShift = 0;
- static constexpr uint32_t kDivRnBits = 4;
-
- // ldrex/strex register field encodings.
- static constexpr uint32_t kLdExRnShift = 16;
- static constexpr uint32_t kLdExRtShift = 12;
- static constexpr uint32_t kStrExRnShift = 16;
- static constexpr uint32_t kStrExRdShift = 12;
- static constexpr uint32_t kStrExRtShift = 0;
-
- // MRC instruction offset field encoding.
- static constexpr uint32_t kCRmShift = 0;
- static constexpr uint32_t kCRmBits = 4;
- static constexpr uint32_t kOpc2Shift = 5;
- static constexpr uint32_t kOpc2Bits = 3;
- static constexpr uint32_t kCoprocShift = 8;
- static constexpr uint32_t kCoprocBits = 4;
- static constexpr uint32_t kCRnShift = 16;
- static constexpr uint32_t kCRnBits = 4;
- static constexpr uint32_t kOpc1Shift = 21;
- static constexpr uint32_t kOpc1Bits = 3;
-
- static constexpr uint32_t kBranchOffsetMask = 0x00ffffff;
-
// A vector of pool-allocated x86 labels for CFG nodes.
using LabelVector = std::vector<Label *>;
LabelVector CfgNodeLabels;
@@ -238,14 +116,12 @@
return getOrCreateLabel(NodeNumber, CfgNodeLabels);
}
- void emitInt32(int32_t Value) { Buffer.emit<int32_t>(Value); }
+ void emitInst(uint32_t Value) { Buffer.emit<uint32_t>(Value); }
- static int32_t BkptEncoding(uint16_t imm16) {
- // bkpt requires that the cond field is AL.
- // cccc00010010iiiiiiiiiiii0111iiii where cccc=AL and i in imm16
- return (CondARM32::AL << kConditionShift) | B24 | B21 |
- ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf);
- }
+ // Pattern cccctttoooosnnnnddddiiiiiiiiiiii where cccc=Cond, ttt=Type,
+ // oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM section A5.2.3).
+ void emitType01(CondARM32::Cond Cond, uint32_t Type, uint32_t Opcode,
+ bool SetCc, uint32_t Rn, uint32_t Rd, uint32_t imm12);
};
} // end of namespace ARM32
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index b45d2f1..7e510ca 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -592,6 +592,29 @@
}
}
+void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const {
+ ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+ Variable *Dest = getDest();
+ Operand *Src0 = getSrc(0);
+ // Note: Loop is used so that we can short circuit using break.
+ do {
+ if (Dest->hasReg()) {
+ Type DestTy = Dest->getType();
+ const bool DestIsVector = isVectorType(DestTy);
+ const bool DestIsScalarFP = isScalarFloatingType(DestTy);
+ const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
+ if (DestIsVector || DestIsScalarFP || CoreVFPMove)
+ break;
+ if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Src0)) {
+ Asm->mov(static_cast<RegARM32::GPRRegister>(Dest->getRegNum()),
+ *FlexImm, getPredicate());
+ return;
+ }
+ }
+ } while (0);
+ llvm_unreachable("not yet implemented");
+}
+
void InstARM32Mov::emit(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
@@ -612,7 +635,13 @@
void InstARM32Mov::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1);
(void)Func;
- llvm_unreachable("Not yet implemented");
+ assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type.");
+ if (isMultiDest())
+ llvm_unreachable("Not yet implemented");
+ if (isMultiSource())
+ llvm_unreachable("Not yet implemented");
+ // Must be single source/dest.
+ emitIASSingleDestSingleSource(Func);
}
void InstARM32Mov::dump(const Cfg *Func) const {
diff --git a/src/IceInstARM32.h b/src/IceInstARM32.h
index 60b2484..680c30a 100644
--- a/src/IceInstARM32.h
+++ b/src/IceInstARM32.h
@@ -1175,6 +1175,8 @@
void emitSingleDestMultiSource(const Cfg *Func) const;
void emitSingleDestSingleSource(const Cfg *Func) const;
+ void emitIASSingleDestSingleSource(const Cfg *Func) const;
+
Variable *DestHi = nullptr;
};
diff --git a/tests_lit/assembler/arm32/mov-imm.ll b/tests_lit/assembler/arm32/mov-imm.ll
new file mode 100644
index 0000000..3cabd57
--- /dev/null
+++ b/tests_lit/assembler/arm32/mov-imm.ll
@@ -0,0 +1,243 @@
+; Show that we know how to translate move (immediate) ARM instruction.
+
+; RUN: %p2i --filetype=asm -i %s --target=arm32 \
+; RUN: | FileCheck %s --check-prefix=ASM
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 \
+; RUN: | FileCheck %s --check-prefix=IASM
+
+define internal i32 @Imm1() {
+ ret i32 1
+}
+
+; ASM-LABEL: Imm1:
+; ASM: mov r0, #1
+; IASM-LABEL: Imm1:
+; IASM: .byte 0x1
+; IASM: .byte 0x0
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+
+define internal i32 @rotateFImmAA() {
+ ; immediate = 0x000002a8 = b 0000 0000 0000 0000 0000 0010 1010 1000
+ ret i32 680
+}
+
+; ASM-LABEL: rotateFImmAA:
+; ASM: mov r0, #680
+
+; IASM-LABEL: rotateFImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0xf
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotateEImmAA() {
+ ; immediate = 0x00000aa0 = b 0000 0000 0000 0000 0000 1010 1010 0000
+ ret i32 2720
+}
+
+; ASM-LABEL: rotateEImmAA:
+; ASM: mov r0, #2720
+
+; IASM-LABEL: rotateEImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0xe
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotateDImmAA() {
+ ; immediate = 0x00002a80 = b 0000 0000 0000 0000 0010 1010 1000 0000
+ ret i32 10880
+}
+
+; ASM-LABEL: rotateDImmAA:
+; ASM: mov r0, #10880
+
+; IASM-LABEL: rotateDImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0xd
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotateCImmAA() {
+ ; immediate = 0x0000aa00 = b 0000 0000 0000 0000 1010 1010 0000 0000
+ ret i32 43520
+}
+
+; ASM-LABEL: rotateCImmAA:
+; ASM: mov r0, #43520
+
+; IASM-LABEL: rotateCImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0xc
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotateBImmAA() {
+ ; immediate = 0x0002a800 = b 0000 0000 0000 0010 1010 1000 0000 0000
+ ret i32 174080
+}
+
+; ASM-LABEL: rotateBImmAA:
+; ASM: mov r0, #174080
+
+; IASM-LABEL: rotateBImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0xb
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotateAImmAA() {
+ ; immediate = 0x000aa000 = b 0000 0000 0000 1010 1010 0000 0000 0000
+ ret i32 696320
+}
+
+; ASM-LABEL: rotateAImmAA:
+; ASM: mov r0, #696320
+
+; IASM-LABEL: rotateAImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0xa
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotate9ImmAA() {
+ ; immediate = 0x002a8000 = b 0000 0000 0010 1010 1000 0000 0000 0000
+ ret i32 2785280
+}
+
+; ASM-LABEL: rotate9ImmAA:
+; ASM: mov r0, #2785280
+
+; IASM-LABEL: rotate9ImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0x9
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotate8ImmAA() {
+ ; immediate = 0x00aa0000 = b 0000 0000 1010 1010 0000 0000 0000 0000
+ ret i32 11141120
+}
+
+; ASM-LABEL: rotate8ImmAA:
+; ASM: mov r0, #11141120
+
+; IASM-LABEL: rotate8ImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0x8
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotate7ImmAA() {
+ ; immediate = 0x02a80000 = b 0000 0010 1010 1000 0000 0000 0000 0000
+ ret i32 44564480
+}
+
+; ASM-LABEL: rotate7ImmAA:
+; ASM: mov r0, #44564480
+
+; IASM-LABEL: rotate7ImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0x7
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotate6ImmAA() {
+ ; immediate = 0x0aa00000 = b 0000 1010 1010 0000 0000 0000 0000 0000
+ ret i32 178257920
+}
+
+; ASM-LABEL: rotate6ImmAA:
+; ASM: mov r0, #178257920
+
+; IASM-LABEL: rotate6ImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0x6
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotate5ImmAA() {
+ ; immediate = 0x2a800000 = b 0010 1010 1000 0000 0000 0000 0000 0000
+ ret i32 713031680
+}
+
+; ASM-LABEL: rotate5ImmAA:
+; ASM: mov r0, #713031680
+
+; IASM-LABEL: rotate5ImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0x5
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotate4ImmAA() {
+ ; immediate = 0xaa000000 = b 1010 1010 0000 0000 0000 0000 0000 0000
+ ret i32 2852126720
+}
+
+; ASM-LABEL: rotate4ImmAA:
+; ASM: mov r0, #2852126720
+
+; IASM-LABEL: rotate4ImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0x4
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotate3ImmAA() {
+ ; immediate = 0xa8000002 = b 1010 1000 0000 0000 0000 0000 0000 0010
+ ret i32 2818572290
+}
+
+; ASM-LABEL: rotate3ImmAA:
+; ASM: mov r0, #2818572290
+
+; IASM-LABEL: rotate3ImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0x3
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotate2ImmAA() {
+ ; immediate = 0xa000000a = b 1010 0000 0000 0000 0000 0000 0000 1010
+ ret i32 2684354570
+}
+
+; ASM-LABEL: rotate2ImmAA:
+; ASM: mov r0, #2684354570
+
+; IASM-LABEL: rotate2ImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0x2
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotate1ImmAA() {
+ ; immediate = 0x8000002a = b 1000 1000 0000 0000 0000 0000 0010 1010
+ ret i32 2147483690
+}
+
+; ASM-LABEL: rotate1ImmAA:
+; ASM: mov r0, #2147483690
+
+; IASM-LABEL: rotate1ImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0x1
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3
+
+define internal i32 @rotate0ImmAA() {
+ ; immediate = 0x000000aa = b 0000 0000 0000 0000 0000 0000 1010 1010
+ ret i32 170
+}
+
+; ASM-LABEL: rotate0ImmAA:
+; ASM: mov r0, #170
+
+; IASM-LABEL: rotate0ImmAA:
+; IASM: .byte 0xaa
+; IASM: .byte 0x0
+; IASM: .byte 0xa0
+; IASM: .byte 0xe3