John Porto | aff4ccf | 2015-06-10 16:35:06 -0700 | [diff] [blame] | 1 | //===- subzero/src/IceAssemblerARM32.h - Assembler for ARM32 ----*- C++ -*-===// |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 2 | // |
| 3 | // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 4 | // for details. All rights reserved. Use of this source code is governed by a |
| 5 | // BSD-style license that can be found in the LICENSE file. |
| 6 | // |
| 7 | // Modified by the Subzero authors. |
| 8 | // |
| 9 | //===----------------------------------------------------------------------===// |
| 10 | // |
| 11 | // The Subzero Code Generator |
| 12 | // |
| 13 | // This file is distributed under the University of Illinois Open Source |
| 14 | // License. See LICENSE.TXT for details. |
| 15 | // |
| 16 | //===----------------------------------------------------------------------===// |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 17 | /// |
| 18 | /// \file |
Jim Stichnoth | 92a6e5b | 2015-12-02 16:52:44 -0800 | [diff] [blame] | 19 | /// \brief Declares the Assembler class for ARM32. |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 20 | /// |
Karl Schimpf | 85342a7 | 2015-10-13 09:49:31 -0700 | [diff] [blame] | 21 | /// Note: All references to ARM "section" documentation refers to the "ARM |
| 22 | /// Architecture Reference Manual, ARMv7-A and ARMv7-R edition". See: |
| 23 | /// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c |
| 24 | /// |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 25 | //===----------------------------------------------------------------------===// |
| 26 | |
John Porto | aff4ccf | 2015-06-10 16:35:06 -0700 | [diff] [blame] | 27 | #ifndef SUBZERO_SRC_ICEASSEMBLERARM32_H |
| 28 | #define SUBZERO_SRC_ICEASSEMBLERARM32_H |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 29 | |
John Porto | aff4ccf | 2015-06-10 16:35:06 -0700 | [diff] [blame] | 30 | #include "IceAssembler.h" |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 31 | #include "IceConditionCodesARM32.h" |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 32 | #include "IceDefs.h" |
| 33 | #include "IceFixups.h" |
Karl Schimpf | 85342a7 | 2015-10-13 09:49:31 -0700 | [diff] [blame] | 34 | #include "IceInstARM32.h" |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 35 | #include "IceRegistersARM32.h" |
| 36 | #include "IceTargetLowering.h" |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 37 | |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 38 | namespace Ice { |
Jan Voung | 90ccc3f | 2015-04-30 14:15:10 -0700 | [diff] [blame] | 39 | namespace ARM32 { |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 40 | |
Karl Schimpf | 137e62b | 2015-10-27 07:28:09 -0700 | [diff] [blame] | 41 | /// Encoding of an ARM 32-bit instruction. |
| 42 | using IValueT = uint32_t; |
| 43 | |
| 44 | /// An Offset value (+/-) used in an ARM 32-bit instruction. |
| 45 | using IOffsetT = int32_t; |
| 46 | |
Karl Schimpf | 7cb2db3 | 2015-10-29 14:04:12 -0700 | [diff] [blame] | 47 | /// Handles encoding of bottom/top 16 bits of an address using movw/movt. |
Karl Schimpf | 174531e | 2015-11-18 08:19:26 -0800 | [diff] [blame] | 48 | class MoveRelocatableFixup final : public AssemblerFixup { |
Karl Schimpf | 7cb2db3 | 2015-10-29 14:04:12 -0700 | [diff] [blame] | 49 | MoveRelocatableFixup &operator=(const MoveRelocatableFixup &) = delete; |
| 50 | MoveRelocatableFixup(const MoveRelocatableFixup &) = default; |
| 51 | |
| 52 | public: |
| 53 | MoveRelocatableFixup() = default; |
Karl Schimpf | 174531e | 2015-11-18 08:19:26 -0800 | [diff] [blame] | 54 | size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final; |
| 55 | }; |
| 56 | |
| 57 | /// Handles encoding of branch and link to global location. |
| 58 | class BlRelocatableFixup final : public AssemblerFixup { |
| 59 | BlRelocatableFixup(const BlRelocatableFixup &) = delete; |
| 60 | BlRelocatableFixup &operator=(const BlRelocatableFixup &) = delete; |
| 61 | |
| 62 | public: |
| 63 | BlRelocatableFixup() = default; |
| 64 | size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final; |
Karl Schimpf | 7cb2db3 | 2015-10-29 14:04:12 -0700 | [diff] [blame] | 65 | }; |
| 66 | |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 67 | class AssemblerARM32 : public Assembler { |
| 68 | AssemblerARM32(const AssemblerARM32 &) = delete; |
| 69 | AssemblerARM32 &operator=(const AssemblerARM32 &) = delete; |
| 70 | |
| 71 | public: |
Karl Schimpf | bb0bacf | 2015-11-11 15:42:55 -0800 | [diff] [blame] | 72 | // Rotation values. |
| 73 | enum RotationValue { |
| 74 | kRotateNone, // Omitted |
| 75 | kRotate8, // ror #8 |
| 76 | kRotate16, // ror #16 |
| 77 | kRotate24 // ror #24 |
| 78 | }; |
| 79 | |
Karl Schimpf | 2c68d90 | 2015-11-11 15:37:50 -0800 | [diff] [blame] | 80 | class TargetInfo { |
| 81 | TargetInfo(const TargetInfo &) = delete; |
| 82 | TargetInfo &operator=(const TargetInfo &) = delete; |
| 83 | |
| 84 | public: |
David Sehr | 26217e3 | 2015-11-26 13:03:50 -0800 | [diff] [blame] | 85 | TargetInfo(bool HasFramePointer, SizeT FrameOrStackReg) |
| 86 | : HasFramePointer(HasFramePointer), FrameOrStackReg(FrameOrStackReg) {} |
Karl Schimpf | 2c68d90 | 2015-11-11 15:37:50 -0800 | [diff] [blame] | 87 | explicit TargetInfo(const TargetLowering *Target) |
| 88 | : HasFramePointer(Target->hasFramePointer()), |
David Sehr | 26217e3 | 2015-11-26 13:03:50 -0800 | [diff] [blame] | 89 | FrameOrStackReg(Target->getFrameOrStackReg()) {} |
Karl Schimpf | 2c68d90 | 2015-11-11 15:37:50 -0800 | [diff] [blame] | 90 | const bool HasFramePointer; |
| 91 | const SizeT FrameOrStackReg; |
Karl Schimpf | 2c68d90 | 2015-11-11 15:37:50 -0800 | [diff] [blame] | 92 | }; |
| 93 | |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 94 | explicit AssemblerARM32(bool use_far_branches = false) |
| 95 | : Assembler(Asm_ARM32) { |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 96 | // TODO(kschimpf): Add mode if needed when branches are handled. |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 97 | (void)use_far_branches; |
| 98 | } |
Karl Schimpf | 50a3331 | 2015-10-23 09:19:48 -0700 | [diff] [blame] | 99 | ~AssemblerARM32() override { |
| 100 | if (BuildDefs::asserts()) { |
| 101 | for (const Label *Label : CfgNodeLabels) { |
| 102 | Label->finalCheck(); |
| 103 | } |
| 104 | for (const Label *Label : LocalLabels) { |
| 105 | Label->finalCheck(); |
| 106 | } |
| 107 | } |
| 108 | } |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 109 | |
Karl Schimpf | 7cb2db3 | 2015-10-29 14:04:12 -0700 | [diff] [blame] | 110 | MoveRelocatableFixup *createMoveFixup(bool IsMovW, const Constant *Value); |
| 111 | |
Karl Schimpf | 515e8c2 | 2015-11-30 11:19:16 -0800 | [diff] [blame] | 112 | BlRelocatableFixup *createBlFixup(const ConstantRelocatable *BlTarget); |
Karl Schimpf | 174531e | 2015-11-18 08:19:26 -0800 | [diff] [blame] | 113 | |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 114 | void alignFunction() override { |
| 115 | const SizeT Align = 1 << getBundleAlignLog2Bytes(); |
| 116 | SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align); |
Karl Schimpf | 137e62b | 2015-10-27 07:28:09 -0700 | [diff] [blame] | 117 | constexpr IValueT UndefinedInst = 0xe7fedef0; // udf #60896 |
| 118 | constexpr SizeT InstSize = sizeof(IValueT); |
Karl Schimpf | 856734c | 2015-11-05 08:18:26 -0800 | [diff] [blame] | 119 | assert(BytesNeeded % InstARM32::InstSize == 0); |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 120 | while (BytesNeeded > 0) { |
Karl Schimpf | 2fee2a2 | 2015-10-22 08:19:26 -0700 | [diff] [blame] | 121 | AssemblerBuffer::EnsureCapacity ensured(&Buffer); |
| 122 | emitInst(UndefinedInst); |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 123 | BytesNeeded -= InstSize; |
| 124 | } |
| 125 | } |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 126 | |
| 127 | SizeT getBundleAlignLog2Bytes() const override { return 4; } |
| 128 | |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 129 | const char *getAlignDirective() const override { return ".p2alignl"; } |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 130 | |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 131 | llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const override { |
Jan Voung | b2d5084 | 2015-05-12 09:53:50 -0700 | [diff] [blame] | 132 | // Use a particular UDF encoding -- TRAPNaCl in LLVM: 0xE7FEDEF0 |
| 133 | // http://llvm.org/viewvc/llvm-project?view=revision&revision=173943 |
| 134 | static const uint8_t Padding[] = {0xE7, 0xFE, 0xDE, 0xF0}; |
| 135 | return llvm::ArrayRef<uint8_t>(Padding, 4); |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 136 | } |
| 137 | |
Karl Schimpf | 67574d8 | 2015-12-08 15:37:00 -0800 | [diff] [blame] | 138 | void padWithNop(intptr_t Padding) override; |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 139 | |
Jan Voung | c2ec581 | 2015-08-05 09:35:18 -0700 | [diff] [blame] | 140 | Ice::Label *getCfgNodeLabel(SizeT NodeNumber) override { |
Karl Schimpf | 85342a7 | 2015-10-13 09:49:31 -0700 | [diff] [blame] | 141 | assert(NodeNumber < CfgNodeLabels.size()); |
| 142 | return CfgNodeLabels[NodeNumber]; |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 143 | } |
| 144 | |
Karl Schimpf | 137e62b | 2015-10-27 07:28:09 -0700 | [diff] [blame] | 145 | Label *getOrCreateCfgNodeLabel(SizeT NodeNumber) { |
| 146 | return getOrCreateLabel(NodeNumber, CfgNodeLabels); |
| 147 | } |
| 148 | |
| 149 | Label *getOrCreateLocalLabel(SizeT Number) { |
| 150 | return getOrCreateLabel(Number, LocalLabels); |
| 151 | } |
Karl Schimpf | 50a3331 | 2015-10-23 09:19:48 -0700 | [diff] [blame] | 152 | |
Karl Schimpf | cb504ca | 2015-11-04 08:02:07 -0800 | [diff] [blame] | 153 | void bindLocalLabel(const Cfg *Func, const InstARM32Label *InstL, |
| 154 | SizeT Number) { |
| 155 | if (BuildDefs::dump() && |
| 156 | !Func->getContext()->getFlags().getDisableHybridAssembly()) { |
| 157 | constexpr SizeT InstSize = 0; |
| 158 | emitTextInst(InstL->getName(Func) + ":", InstSize); |
| 159 | } |
Karl Schimpf | 50a3331 | 2015-10-23 09:19:48 -0700 | [diff] [blame] | 160 | Label *L = getOrCreateLocalLabel(Number); |
| 161 | if (!getPreliminary()) |
| 162 | this->bind(L); |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | bool fixupIsPCRel(FixupKind Kind) const override { |
| 166 | (void)Kind; |
Karl Schimpf | 2fee2a2 | 2015-10-22 08:19:26 -0700 | [diff] [blame] | 167 | // TODO(kschimpf) Decide if we need this. |
| 168 | return false; |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 169 | } |
Karl Schimpf | 372bdd6 | 2015-10-13 14:39:14 -0700 | [diff] [blame] | 170 | |
Karl Schimpf | 856734c | 2015-11-05 08:18:26 -0800 | [diff] [blame] | 171 | /// Accessors to keep track of the number of bytes generated inside |
| 172 | /// InstARM32::emit() methods, when run inside of |
| 173 | /// InstARM32::emitUsingTextFixup(). |
| 174 | void resetEmitTextSize() { EmitTextSize = 0; } |
| 175 | void incEmitTextSize(size_t Amount) { EmitTextSize += Amount; } |
| 176 | void decEmitTextSize(size_t Amount) { EmitTextSize -= Amount; } |
| 177 | size_t getEmitTextSize() const { return EmitTextSize; } |
| 178 | |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 179 | void bind(Label *label); |
| 180 | |
Karl Schimpf | 372bdd6 | 2015-10-13 14:39:14 -0700 | [diff] [blame] | 181 | // List of instructions implemented by integrated assembler. |
| 182 | |
Karl Schimpf | db09888 | 2015-10-27 07:36:59 -0700 | [diff] [blame] | 183 | void adc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 184 | bool SetFlags, CondARM32::Cond Cond); |
| 185 | |
Karl Schimpf | 372bdd6 | 2015-10-13 14:39:14 -0700 | [diff] [blame] | 186 | void add(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 187 | bool SetFlags, CondARM32::Cond Cond); |
| 188 | |
Karl Schimpf | c33f7bb | 2015-10-29 15:50:32 -0700 | [diff] [blame] | 189 | void and_(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 190 | bool SetFlags, CondARM32::Cond Cond); |
| 191 | |
Karl Schimpf | 3ac9a49 | 2015-12-08 13:41:38 -0800 | [diff] [blame] | 192 | void asr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 193 | bool SetFlags, CondARM32::Cond Cond); |
| 194 | |
Karl Schimpf | 137e62b | 2015-10-27 07:28:09 -0700 | [diff] [blame] | 195 | void b(Label *L, CondARM32::Cond Cond); |
| 196 | |
Karl Schimpf | 85342a7 | 2015-10-13 09:49:31 -0700 | [diff] [blame] | 197 | void bkpt(uint16_t Imm16); |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 198 | |
Karl Schimpf | 4f8805b | 2015-11-02 15:01:56 -0800 | [diff] [blame] | 199 | void bic(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 200 | bool SetFlags, CondARM32::Cond Cond); |
| 201 | |
Karl Schimpf | 174531e | 2015-11-18 08:19:26 -0800 | [diff] [blame] | 202 | void bl(const ConstantRelocatable *Target); |
| 203 | |
| 204 | void blx(const Operand *Target); |
| 205 | |
| 206 | void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL); |
| 207 | |
Karl Schimpf | 65f80d7 | 2015-12-17 08:02:17 -0800 | [diff] [blame^] | 208 | void clz(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); |
| 209 | |
Karl Schimpf | 4c435d3 | 2015-12-08 14:45:28 -0800 | [diff] [blame] | 210 | void cmn(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond); |
| 211 | |
Karl Schimpf | 174531e | 2015-11-18 08:19:26 -0800 | [diff] [blame] | 212 | void cmp(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond); |
| 213 | |
Karl Schimpf | d3f94f7 | 2015-12-09 07:35:00 -0800 | [diff] [blame] | 214 | void dmb(IValueT Option); // Option is a 4-bit value. |
| 215 | |
Karl Schimpf | 62d367b | 2015-10-30 08:06:44 -0700 | [diff] [blame] | 216 | void eor(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 217 | bool SetFlags, CondARM32::Cond Cond); |
| 218 | |
Karl Schimpf | 2c68d90 | 2015-11-11 15:37:50 -0800 | [diff] [blame] | 219 | void ldr(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, |
| 220 | const TargetInfo &TInfo); |
| 221 | |
| 222 | void ldr(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, |
| 223 | const TargetLowering *Lowering) { |
| 224 | const TargetInfo TInfo(Lowering); |
| 225 | ldr(OpRt, OpAddress, Cond, TInfo); |
| 226 | } |
Karl Schimpf | 745ad1d | 2015-10-16 10:31:31 -0700 | [diff] [blame] | 227 | |
Karl Schimpf | f4d0a7a | 2015-11-19 08:10:44 -0800 | [diff] [blame] | 228 | void lsl(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 229 | bool SetFlags, CondARM32::Cond Cond); |
| 230 | |
Karl Schimpf | 4ddce70 | 2015-12-07 10:43:34 -0800 | [diff] [blame] | 231 | void lsr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 232 | bool SetFlags, CondARM32::Cond Cond); |
| 233 | |
Karl Schimpf | 372bdd6 | 2015-10-13 14:39:14 -0700 | [diff] [blame] | 234 | void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); |
Karl Schimpf | 85342a7 | 2015-10-13 09:49:31 -0700 | [diff] [blame] | 235 | |
Karl Schimpf | 7cb2db3 | 2015-10-29 14:04:12 -0700 | [diff] [blame] | 236 | void movw(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); |
| 237 | |
| 238 | void movt(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); |
| 239 | |
Karl Schimpf | 080b65b | 2015-11-05 08:27:51 -0800 | [diff] [blame] | 240 | void mla(const Operand *OpRd, const Operand *OpRn, const Operand *OpRm, |
| 241 | const Operand *OpRa, CondARM32::Cond Cond); |
| 242 | |
Karl Schimpf | b81b901 | 2015-11-04 14:54:52 -0800 | [diff] [blame] | 243 | void mul(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 244 | bool SetFlags, CondARM32::Cond Cond); |
| 245 | |
Karl Schimpf | e559be7 | 2015-11-20 14:26:12 -0800 | [diff] [blame] | 246 | void mvn(const Operand *OpRd, const Operand *OpScc, CondARM32::Cond Cond); |
| 247 | |
Karl Schimpf | 67574d8 | 2015-12-08 15:37:00 -0800 | [diff] [blame] | 248 | void nop(); |
| 249 | |
Karl Schimpf | 9c08bee | 2015-10-30 07:42:00 -0700 | [diff] [blame] | 250 | void orr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 251 | bool SetFlags, CondARM32::Cond Cond); |
| 252 | |
Karl Schimpf | f66a85b | 2015-11-10 14:12:35 -0800 | [diff] [blame] | 253 | void pop(const Operand *OpRt, CondARM32::Cond Cond); |
| 254 | |
| 255 | // Note: Registers is a bitset, where bit n corresponds to register Rn. |
| 256 | void popList(const IValueT Registers, CondARM32::Cond Cond); |
| 257 | |
Karl Schimpf | 6cab561 | 2015-11-06 09:14:10 -0800 | [diff] [blame] | 258 | void push(const Operand *OpRt, CondARM32::Cond Cond); |
| 259 | |
| 260 | // Note: Registers is a bitset, where bit n corresponds to register Rn. |
| 261 | void pushList(const IValueT Registers, CondARM32::Cond Cond); |
| 262 | |
Karl Schimpf | 7e87b61 | 2015-12-11 09:32:28 -0800 | [diff] [blame] | 263 | void rev(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); |
| 264 | |
Karl Schimpf | dca8674 | 2015-12-04 15:11:43 -0800 | [diff] [blame] | 265 | void rsb(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 266 | bool SetFlags, CondARM32::Cond Cond); |
| 267 | |
Karl Schimpf | 337ac9e | 2015-12-11 09:12:07 -0800 | [diff] [blame] | 268 | void rsc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 269 | bool SetFlags, CondARM32::Cond Cond); |
| 270 | |
Karl Schimpf | 3b8a15e | 2015-10-29 09:11:40 -0700 | [diff] [blame] | 271 | void sbc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 272 | bool SetFlags, CondARM32::Cond Cond); |
| 273 | |
Karl Schimpf | 697dc79 | 2015-10-30 13:21:59 -0700 | [diff] [blame] | 274 | void sdiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 275 | CondARM32::Cond Cond); |
| 276 | |
Karl Schimpf | 2c68d90 | 2015-11-11 15:37:50 -0800 | [diff] [blame] | 277 | void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, |
| 278 | const TargetInfo &TInfo); |
| 279 | |
| 280 | void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond, |
| 281 | const TargetLowering *Lowering) { |
| 282 | const TargetInfo TInfo(Lowering); |
| 283 | str(OpRt, OpAddress, Cond, TInfo); |
| 284 | } |
Karl Schimpf | 745ad1d | 2015-10-16 10:31:31 -0700 | [diff] [blame] | 285 | |
Karl Schimpf | e345505 | 2015-10-14 14:30:21 -0700 | [diff] [blame] | 286 | void sub(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 287 | bool SetFlags, CondARM32::Cond Cond); |
| 288 | |
Karl Schimpf | 1e67f91 | 2015-12-08 11:17:23 -0800 | [diff] [blame] | 289 | // Implements sxtb/sxth depending on type of OpSrc0. |
| 290 | void sxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond); |
| 291 | |
Karl Schimpf | b81b901 | 2015-11-04 14:54:52 -0800 | [diff] [blame] | 292 | void tst(const Operand *OpRn, const Operand *OpSrc1, CondARM32::Cond Cond); |
| 293 | |
Karl Schimpf | 1c28550 | 2015-10-30 15:00:24 -0700 | [diff] [blame] | 294 | void udiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, |
| 295 | CondARM32::Cond Cond); |
| 296 | |
Karl Schimpf | 430e844 | 2015-11-09 12:16:20 -0800 | [diff] [blame] | 297 | void umull(const Operand *OpRdLo, const Operand *OpRdHi, const Operand *OpRn, |
| 298 | const Operand *OpRm, CondARM32::Cond Cond); |
| 299 | |
Karl Schimpf | bb0bacf | 2015-11-11 15:42:55 -0800 | [diff] [blame] | 300 | // Implements uxtb/uxth depending on type of OpSrc0. |
| 301 | void uxt(const Operand *OpRd, const Operand *OpSrc0, CondARM32::Cond Cond); |
| 302 | |
John Porto | 2da710c | 2015-06-29 07:57:02 -0700 | [diff] [blame] | 303 | static bool classof(const Assembler *Asm) { |
| 304 | return Asm->getKind() == Asm_ARM32; |
| 305 | } |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 306 | |
Karl Schimpf | 856734c | 2015-11-05 08:18:26 -0800 | [diff] [blame] | 307 | void emitTextInst(const std::string &Text, SizeT InstSize); |
Karl Schimpf | 2fee2a2 | 2015-10-22 08:19:26 -0700 | [diff] [blame] | 308 | |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 309 | private: |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 310 | // A vector of pool-allocated x86 labels for CFG nodes. |
| 311 | using LabelVector = std::vector<Label *>; |
| 312 | LabelVector CfgNodeLabels; |
Karl Schimpf | 50a3331 | 2015-10-23 09:19:48 -0700 | [diff] [blame] | 313 | // A vector of pool-allocated x86 labels for Local labels. |
| 314 | LabelVector LocalLabels; |
Karl Schimpf | 856734c | 2015-11-05 08:18:26 -0800 | [diff] [blame] | 315 | // Number of bytes emitted by InstARM32::emit() methods, when run inside |
| 316 | // InstARM32::emitUsingTextFixup(). |
| 317 | size_t EmitTextSize = 0; |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 318 | |
Karl Schimpf | 6cab561 | 2015-11-06 09:14:10 -0800 | [diff] [blame] | 319 | // Load/store multiple addressing mode. |
| 320 | enum BlockAddressMode { |
| 321 | // bit encoding P U W |
| 322 | DA = (0 | 0 | 0) << 21, // decrement after |
| 323 | IA = (0 | 4 | 0) << 21, // increment after |
| 324 | DB = (8 | 0 | 0) << 21, // decrement before |
| 325 | IB = (8 | 4 | 0) << 21, // increment before |
| 326 | DA_W = (0 | 0 | 1) << 21, // decrement after with writeback to base |
| 327 | IA_W = (0 | 4 | 1) << 21, // increment after with writeback to base |
| 328 | DB_W = (8 | 0 | 1) << 21, // decrement before with writeback to base |
| 329 | IB_W = (8 | 4 | 1) << 21 // increment before with writeback to base |
| 330 | }; |
| 331 | |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 332 | Label *getOrCreateLabel(SizeT Number, LabelVector &Labels); |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 333 | |
Karl Schimpf | 137e62b | 2015-10-27 07:28:09 -0700 | [diff] [blame] | 334 | void bindCfgNodeLabel(const CfgNode *Node) override; |
| 335 | |
| 336 | void emitInst(IValueT Value) { Buffer.emit<IValueT>(Value); } |
Karl Schimpf | c5abdc1 | 2015-10-09 13:29:13 -0700 | [diff] [blame] | 337 | |
Karl Schimpf | b81b901 | 2015-11-04 14:54:52 -0800 | [diff] [blame] | 338 | // List of possible checks to apply when calling emitType01() (below). |
Karl Schimpf | f4d0a7a | 2015-11-19 08:10:44 -0800 | [diff] [blame] | 339 | enum EmitChecks { NoChecks, RdIsPcAndSetFlags }; |
| 340 | |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 341 | // Pattern cccctttoooosnnnnddddiiiiiiiiiiii where cccc=Cond, ttt=InstType, |
Karl Schimpf | f4d0a7a | 2015-11-19 08:10:44 -0800 | [diff] [blame] | 342 | // s=SetFlags, oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM |
| 343 | // section A5.2.3). |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 344 | void emitType01(CondARM32::Cond Cond, IValueT InstType, IValueT Opcode, |
Karl Schimpf | f4d0a7a | 2015-11-19 08:10:44 -0800 | [diff] [blame] | 345 | bool SetFlags, IValueT Rn, IValueT Rd, IValueT imm12, |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 346 | EmitChecks RuleChecks, const char *InstName); |
Karl Schimpf | b81b901 | 2015-11-04 14:54:52 -0800 | [diff] [blame] | 347 | |
| 348 | // Converts appropriate representation on a data operation, and then calls |
| 349 | // emitType01 above. |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 350 | void emitType01(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpRd, |
| 351 | const Operand *OpRn, const Operand *OpSrc1, bool SetFlags, |
| 352 | EmitChecks RuleChecks, const char *InstName); |
Karl Schimpf | b81b901 | 2015-11-04 14:54:52 -0800 | [diff] [blame] | 353 | |
| 354 | // Same as above, but the value for Rd and Rn have already been converted |
| 355 | // into instruction values. |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 356 | void emitType01(CondARM32::Cond Cond, IValueT Opcode, IValueT OpRd, |
| 357 | IValueT OpRn, const Operand *OpSrc1, bool SetFlags, |
| 358 | EmitChecks RuleChecks, const char *InstName); |
Karl Schimpf | 62d367b | 2015-10-30 08:06:44 -0700 | [diff] [blame] | 359 | |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 360 | void emitType05(CondARM32::Cond Cond, int32_t Offset, bool Link, |
| 361 | const char *InstName); |
Karl Schimpf | 745ad1d | 2015-10-16 10:31:31 -0700 | [diff] [blame] | 362 | |
Karl Schimpf | 1956788 | 2015-12-02 10:24:15 -0800 | [diff] [blame] | 363 | // Emit ccccoooaabalnnnnttttaaaaaaaaaaaa where cccc=Cond, |
| 364 | // ooo=InstType, l=isLoad, b=isByte, and |
| 365 | // aaa0a0aaaa0000aaaaaaaaaaaa=Address. Note that Address is assumed to be |
| 366 | // defined by decodeAddress() in IceAssemblerARM32.cpp. |
Karl Schimpf | 137e62b | 2015-10-27 07:28:09 -0700 | [diff] [blame] | 367 | void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad, |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 368 | bool IsByte, IValueT Rt, IValueT Address, |
| 369 | const char *InstName); |
Karl Schimpf | 1956788 | 2015-12-02 10:24:15 -0800 | [diff] [blame] | 370 | |
| 371 | // Emit ldr/ldrb/str/strb instruction with given address. |
| 372 | void emitMemOp(CondARM32::Cond Cond, bool IsLoad, bool IsByte, IValueT Rt, |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 373 | const Operand *OpAddress, const TargetInfo &TInfo, |
| 374 | const char *InstName); |
Karl Schimpf | 1956788 | 2015-12-02 10:24:15 -0800 | [diff] [blame] | 375 | |
| 376 | // Emit ldrh/ldrd/strh/strd instruction with given address using encoding 3. |
| 377 | void emitMemOpEnc3(CondARM32::Cond Cond, IValueT Opcode, IValueT Rt, |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 378 | const Operand *OpAddress, const TargetInfo &TInfo, |
| 379 | const char *InstName); |
Karl Schimpf | 137e62b | 2015-10-27 07:28:09 -0700 | [diff] [blame] | 380 | |
Karl Schimpf | 6cab561 | 2015-11-06 09:14:10 -0800 | [diff] [blame] | 381 | // Pattern cccc100aaaalnnnnrrrrrrrrrrrrrrrr where cccc=Cond, |
| 382 | // aaaa<<21=AddressMode, l=IsLoad, nnnn=BaseReg, and |
| 383 | // rrrrrrrrrrrrrrrr is bitset of Registers. |
| 384 | void emitMultiMemOp(CondARM32::Cond Cond, BlockAddressMode AddressMode, |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 385 | bool IsLoad, IValueT BaseReg, IValueT Registers, |
| 386 | const char *InstName); |
Karl Schimpf | 6cab561 | 2015-11-06 09:14:10 -0800 | [diff] [blame] | 387 | |
Karl Schimpf | 697dc79 | 2015-10-30 13:21:59 -0700 | [diff] [blame] | 388 | // Pattern cccc011100x1dddd1111mmmm0001nnn where cccc=Cond, |
| 389 | // x=Opcode, dddd=Rd, nnnn=Rn, mmmm=Rm. |
| 390 | void emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn, |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 391 | IValueT Rm, const char *InstName); |
Karl Schimpf | 697dc79 | 2015-10-30 13:21:59 -0700 | [diff] [blame] | 392 | |
Karl Schimpf | 396de53 | 2015-10-30 07:25:43 -0700 | [diff] [blame] | 393 | // Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn, |
Karl Schimpf | f4d0a7a | 2015-11-19 08:10:44 -0800 | [diff] [blame] | 394 | // mmmm=Rm, ssss=Rs, f=SetFlags and xxxxxxx=Opcode. |
Karl Schimpf | 396de53 | 2015-10-30 07:25:43 -0700 | [diff] [blame] | 395 | void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn, |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 396 | IValueT Rm, IValueT Rs, bool SetFlags, const char *InstName); |
Karl Schimpf | 396de53 | 2015-10-30 07:25:43 -0700 | [diff] [blame] | 397 | |
Karl Schimpf | 4ddce70 | 2015-12-07 10:43:34 -0800 | [diff] [blame] | 398 | // Pattern cccc0001101s0000ddddxxxxxtt0mmmm where cccc=Cond, s=SetFlags, |
| 399 | // dddd=Rd, mmmm=Rm, tt=Shift, and xxxxx is defined by OpSrc1. OpSrc1 defines |
| 400 | // either xxxxx=Imm5, or xxxxx=ssss0 where ssss=Rs. |
| 401 | void emitShift(const CondARM32::Cond Cond, |
| 402 | const OperandARM32::ShiftKind Shift, const Operand *OpRd, |
| 403 | const Operand *OpRm, const Operand *OpSrc1, |
| 404 | const bool SetFlags, const char *InstName); |
| 405 | |
Karl Schimpf | 1e67f91 | 2015-12-08 11:17:23 -0800 | [diff] [blame] | 406 | // Implements various forms of signed/unsigned extend value, using pattern |
Karl Schimpf | bb0bacf | 2015-11-11 15:42:55 -0800 | [diff] [blame] | 407 | // ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode, |
| 408 | // nnnn=Rn, dddd=Rd, rr=Rotation, and mmmm=Rm. |
Karl Schimpf | 1e67f91 | 2015-12-08 11:17:23 -0800 | [diff] [blame] | 409 | void emitSignExtend(CondARM32::Cond, IValueT Opcode, const Operand *OpRd, |
| 410 | const Operand *OpSrc0, const char *InstName); |
Karl Schimpf | bb0bacf | 2015-11-11 15:42:55 -0800 | [diff] [blame] | 411 | |
Karl Schimpf | b81b901 | 2015-11-04 14:54:52 -0800 | [diff] [blame] | 412 | // Pattern cccctttxxxxnnnn0000iiiiiiiiiiii where cccc=Cond, nnnn=Rn, |
| 413 | // ttt=Instruction type (derived from OpSrc1), iiiiiiiiiiii is derived from |
| 414 | // OpSrc1, and xxxx=Opcode. |
Karl Schimpf | 0437ae8 | 2015-12-04 07:29:10 -0800 | [diff] [blame] | 415 | void emitCompareOp(CondARM32::Cond Cond, IValueT Opcode, const Operand *OpRn, |
| 416 | const Operand *OpSrc1, const char *CmpName); |
Karl Schimpf | b81b901 | 2015-11-04 14:54:52 -0800 | [diff] [blame] | 417 | |
Karl Schimpf | 137e62b | 2015-10-27 07:28:09 -0700 | [diff] [blame] | 418 | void emitBranch(Label *L, CondARM32::Cond, bool Link); |
| 419 | |
| 420 | // Encodes the given Offset into the branch instruction Inst. |
| 421 | IValueT encodeBranchOffset(IOffsetT Offset, IValueT Inst); |
| 422 | |
| 423 | // Returns the offset encoded in the branch instruction Inst. |
| 424 | static IOffsetT decodeBranchOffset(IValueT Inst); |
Karl Schimpf | 5ff0cfb | 2015-11-11 14:47:49 -0800 | [diff] [blame] | 425 | |
Karl Schimpf | 7cfe9a0 | 2015-12-04 15:07:01 -0800 | [diff] [blame] | 426 | // Implements movw/movt, generating pattern ccccxxxxxxxsiiiiddddiiiiiiiiiiii |
| 427 | // where cccc=Cond, xxxxxxx<<21=Opcode, dddd=Rd, s=SetFlags, and |
Karl Schimpf | 5ff0cfb | 2015-11-11 14:47:49 -0800 | [diff] [blame] | 428 | // iiiiiiiiiiiiiiii=Imm16. |
Karl Schimpf | 7cfe9a0 | 2015-12-04 15:07:01 -0800 | [diff] [blame] | 429 | void emitMovwt(CondARM32::Cond Cond, bool IsMovw, const Operand *OpRd, |
| 430 | const Operand *OpSrc, const char *MovName); |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 431 | }; |
| 432 | |
Jan Voung | 90ccc3f | 2015-04-30 14:15:10 -0700 | [diff] [blame] | 433 | } // end of namespace ARM32 |
Jan Voung | b36ad9b | 2015-04-21 17:01:49 -0700 | [diff] [blame] | 434 | } // end of namespace Ice |
| 435 | |
John Porto | aff4ccf | 2015-06-10 16:35:06 -0700 | [diff] [blame] | 436 | #endif // SUBZERO_SRC_ICEASSEMBLERARM32_H |