Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 1 | //===- subzero/src/IceTargetLoweringX8632.cpp - x86-32 lowering -----------===// |
| 2 | // |
| 3 | // The Subzero Code Generator |
| 4 | // |
John Porto | 5d0acff | 2015-06-30 15:29:21 -0700 | [diff] [blame] | 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 8 | //===----------------------------------------------------------------------===// |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 9 | /// |
| 10 | /// \file |
Jim Stichnoth | 92a6e5b | 2015-12-02 16:52:44 -0800 | [diff] [blame] | 11 | /// \brief Implements the TargetLoweringX8632 class, which consists almost |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 12 | /// entirely of the lowering sequence for each high-level instruction. |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 13 | /// |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 14 | //===----------------------------------------------------------------------===// |
| 15 | |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 16 | #include "IceTargetLoweringX8632.h" |
John Porto | 7e93c62 | 2015-06-23 10:58:57 -0700 | [diff] [blame] | 17 | |
John Porto | 5d0acff | 2015-06-30 15:29:21 -0700 | [diff] [blame] | 18 | #include "IceTargetLoweringX8632Traits.h" |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 19 | |
John Porto | 53611e2 | 2015-12-30 07:30:10 -0800 | [diff] [blame] | 20 | namespace X8632 { |
| 21 | std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) { |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 22 | return ::Ice::X8632::TargetX8632::create(Func); |
John Porto | 53611e2 | 2015-12-30 07:30:10 -0800 | [diff] [blame] | 23 | } |
| 24 | |
| 25 | std::unique_ptr<::Ice::TargetDataLowering> |
| 26 | createTargetDataLowering(::Ice::GlobalContext *Ctx) { |
David Sehr | 6b80cf1 | 2016-01-21 23:16:58 -0800 | [diff] [blame] | 27 | return ::Ice::X8632::TargetDataX86<::Ice::X8632::TargetX8632Traits>::create( |
| 28 | Ctx); |
John Porto | 53611e2 | 2015-12-30 07:30:10 -0800 | [diff] [blame] | 29 | } |
| 30 | |
| 31 | std::unique_ptr<::Ice::TargetHeaderLowering> |
| 32 | createTargetHeaderLowering(::Ice::GlobalContext *Ctx) { |
David Sehr | 6b80cf1 | 2016-01-21 23:16:58 -0800 | [diff] [blame] | 33 | return ::Ice::X8632::TargetHeaderX86::create(Ctx); |
John Porto | 53611e2 | 2015-12-30 07:30:10 -0800 | [diff] [blame] | 34 | } |
| 35 | |
Karl Schimpf | 5403f5d | 2016-01-15 11:07:46 -0800 | [diff] [blame] | 36 | void staticInit(::Ice::GlobalContext *Ctx) { |
| 37 | ::Ice::X8632::TargetX8632::staticInit(Ctx); |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 38 | if (Ice::getFlags().getUseNonsfi()) { |
John Porto | 6e8d3fa | 2016-02-04 10:35:20 -0800 | [diff] [blame] | 39 | // In nonsfi, we need to reference the _GLOBAL_OFFSET_TABLE_ for accessing |
| 40 | // globals. The GOT is an external symbol (i.e., it is not defined in the |
| 41 | // pexe) so we need to register it as such so that ELF emission won't barf |
| 42 | // on an "unknown" symbol. The GOT is added to the External symbols list |
| 43 | // here because staticInit() is invoked in a single-thread context. |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 44 | Ctx->getConstantExternSym(Ctx->getGlobalString(::Ice::GlobalOffsetTable)); |
John Porto | 6e8d3fa | 2016-02-04 10:35:20 -0800 | [diff] [blame] | 45 | } |
Jim Stichnoth | 8ff4b28 | 2016-01-04 15:39:06 -0800 | [diff] [blame] | 46 | } |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 47 | |
| 48 | bool shouldBePooled(const class ::Ice::Constant *C) { |
| 49 | return ::Ice::X8632::TargetX8632::shouldBePooled(C); |
| 50 | } |
Nicolas Capens | 32f9cce | 2016-10-19 01:24:27 -0400 | [diff] [blame] | 51 | |
| 52 | ::Ice::Type getPointerType() { |
| 53 | return ::Ice::X8632::TargetX8632::getPointerType(); |
| 54 | } |
| 55 | |
John Porto | 53611e2 | 2015-12-30 07:30:10 -0800 | [diff] [blame] | 56 | } // end of namespace X8632 |
| 57 | |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 58 | namespace Ice { |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 59 | namespace X8632 { |
John Porto | 5d0acff | 2015-06-30 15:29:21 -0700 | [diff] [blame] | 60 | |
John Porto | e0d9afa | 2015-08-05 10:13:44 -0700 | [diff] [blame] | 61 | //------------------------------------------------------------------------------ |
| 62 | // ______ ______ ______ __ ______ ______ |
| 63 | // /\__ _\ /\ == \ /\ __ \ /\ \ /\__ _\ /\ ___\ |
| 64 | // \/_/\ \/ \ \ __< \ \ __ \ \ \ \ \/_/\ \/ \ \___ \ |
| 65 | // \ \_\ \ \_\ \_\ \ \_\ \_\ \ \_\ \ \_\ \/\_____\ |
| 66 | // \/_/ \/_/ /_/ \/_/\/_/ \/_/ \/_/ \/_____/ |
| 67 | // |
| 68 | //------------------------------------------------------------------------------ |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 69 | const TargetX8632Traits::TableFcmpType TargetX8632Traits::TableFcmp[] = { |
Matt Wala | ce0ca8f | 2014-07-24 12:34:20 -0700 | [diff] [blame] | 70 | #define X(val, dflt, swapS, C1, C2, swapV, pred) \ |
John Porto | 5d0acff | 2015-06-30 15:29:21 -0700 | [diff] [blame] | 71 | { \ |
| 72 | dflt, swapS, X8632::Traits::Cond::C1, X8632::Traits::Cond::C2, swapV, \ |
| 73 | X8632::Traits::Cond::pred \ |
| 74 | } \ |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 75 | , |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 76 | FCMPX8632_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 77 | #undef X |
Jim Stichnoth | dd842db | 2015-01-27 12:53:53 -0800 | [diff] [blame] | 78 | }; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 79 | |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 80 | const size_t TargetX8632Traits::TableFcmpSize = llvm::array_lengthof(TableFcmp); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 81 | |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 82 | const TargetX8632Traits::TableIcmp32Type TargetX8632Traits::TableIcmp32[] = { |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 83 | #define X(val, C_32, C1_64, C2_64, C3_64) \ |
John Porto | 5d0acff | 2015-06-30 15:29:21 -0700 | [diff] [blame] | 84 | { X8632::Traits::Cond::C_32 } \ |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 85 | , |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 86 | ICMPX8632_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 87 | #undef X |
Jim Stichnoth | dd842db | 2015-01-27 12:53:53 -0800 | [diff] [blame] | 88 | }; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 89 | |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 90 | const size_t TargetX8632Traits::TableIcmp32Size = |
John Porto | 7e93c62 | 2015-06-23 10:58:57 -0700 | [diff] [blame] | 91 | llvm::array_lengthof(TableIcmp32); |
| 92 | |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 93 | const TargetX8632Traits::TableIcmp64Type TargetX8632Traits::TableIcmp64[] = { |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 94 | #define X(val, C_32, C1_64, C2_64, C3_64) \ |
John Porto | 5d0acff | 2015-06-30 15:29:21 -0700 | [diff] [blame] | 95 | { \ |
| 96 | X8632::Traits::Cond::C1_64, X8632::Traits::Cond::C2_64, \ |
| 97 | X8632::Traits::Cond::C3_64 \ |
| 98 | } \ |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 99 | , |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 100 | ICMPX8632_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 101 | #undef X |
Jim Stichnoth | dd842db | 2015-01-27 12:53:53 -0800 | [diff] [blame] | 102 | }; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 103 | |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 104 | const size_t TargetX8632Traits::TableIcmp64Size = |
John Porto | 7e93c62 | 2015-06-23 10:58:57 -0700 | [diff] [blame] | 105 | llvm::array_lengthof(TableIcmp64); |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 106 | |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 107 | const TargetX8632Traits::TableTypeX8632AttributesType |
| 108 | TargetX8632Traits::TableTypeX8632Attributes[] = { |
Nicolas Capens | 7638e27 | 2016-10-06 11:33:55 -0400 | [diff] [blame] | 109 | #define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld) \ |
| 110 | { IceType_##elty } \ |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 111 | , |
John Porto | 7e93c62 | 2015-06-23 10:58:57 -0700 | [diff] [blame] | 112 | ICETYPEX8632_TABLE |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 113 | #undef X |
Jim Stichnoth | dd842db | 2015-01-27 12:53:53 -0800 | [diff] [blame] | 114 | }; |
John Porto | 7e93c62 | 2015-06-23 10:58:57 -0700 | [diff] [blame] | 115 | |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 116 | const size_t TargetX8632Traits::TableTypeX8632AttributesSize = |
Matt Wala | 4988923 | 2014-07-18 12:45:09 -0700 | [diff] [blame] | 117 | llvm::array_lengthof(TableTypeX8632Attributes); |
| 118 | |
Nicolas Capens | 4e679e5 | 2017-01-12 17:01:06 -0500 | [diff] [blame] | 119 | #if defined(SUBZERO_USE_MICROSOFT_ABI) |
| 120 | // Windows 32-bit only guarantees 4 byte stack alignment |
| 121 | const uint32_t TargetX8632Traits::X86_STACK_ALIGNMENT_BYTES = 4; |
| 122 | #else |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 123 | const uint32_t TargetX8632Traits::X86_STACK_ALIGNMENT_BYTES = 16; |
Nicolas Capens | 4e679e5 | 2017-01-12 17:01:06 -0500 | [diff] [blame] | 124 | #endif |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 125 | const char *TargetX8632Traits::TargetName = "X8632"; |
John Porto | 5d0acff | 2015-06-30 15:29:21 -0700 | [diff] [blame] | 126 | |
Jim Stichnoth | 94844f1 | 2015-11-04 16:06:16 -0800 | [diff] [blame] | 127 | template <> |
John Porto | e82b560 | 2016-02-24 15:58:55 -0800 | [diff] [blame] | 128 | std::array<SmallBitVector, RCX86_NUM> |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 129 | TargetX86Base<X8632::Traits>::TypeToRegisterSet = {{}}; |
Jim Stichnoth | 94844f1 | 2015-11-04 16:06:16 -0800 | [diff] [blame] | 130 | |
| 131 | template <> |
John Porto | e82b560 | 2016-02-24 15:58:55 -0800 | [diff] [blame] | 132 | std::array<SmallBitVector, RCX86_NUM> |
Jim Stichnoth | b40595a | 2016-01-29 06:14:31 -0800 | [diff] [blame] | 133 | TargetX86Base<X8632::Traits>::TypeToRegisterSetUnfiltered = {{}}; |
| 134 | |
| 135 | template <> |
John Porto | e82b560 | 2016-02-24 15:58:55 -0800 | [diff] [blame] | 136 | std::array<SmallBitVector, |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 137 | TargetX86Base<X8632::Traits>::Traits::RegisterSet::Reg_NUM> |
| 138 | TargetX86Base<X8632::Traits>::RegisterAliases = {{}}; |
Jim Stichnoth | 94844f1 | 2015-11-04 16:06:16 -0800 | [diff] [blame] | 139 | |
| 140 | template <> |
Jim Stichnoth | 8ff4b28 | 2016-01-04 15:39:06 -0800 | [diff] [blame] | 141 | FixupKind TargetX86Base<X8632::Traits>::PcRelFixup = |
| 142 | TargetX86Base<X8632::Traits>::Traits::FK_PcRel; |
| 143 | |
| 144 | template <> |
| 145 | FixupKind TargetX86Base<X8632::Traits>::AbsFixup = |
| 146 | TargetX86Base<X8632::Traits>::Traits::FK_Abs; |
| 147 | |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 148 | //------------------------------------------------------------------------------ |
| 149 | // __ ______ __ __ ______ ______ __ __ __ ______ |
| 150 | // /\ \ /\ __ \/\ \ _ \ \/\ ___\/\ == \/\ \/\ "-.\ \/\ ___\ |
| 151 | // \ \ \___\ \ \/\ \ \ \/ ".\ \ \ __\\ \ __<\ \ \ \ \-. \ \ \__ \ |
| 152 | // \ \_____\ \_____\ \__/".~\_\ \_____\ \_\ \_\ \_\ \_\\"\_\ \_____\ |
| 153 | // \/_____/\/_____/\/_/ \/_/\/_____/\/_/ /_/\/_/\/_/ \/_/\/_____/ |
| 154 | // |
| 155 | //------------------------------------------------------------------------------ |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 156 | void TargetX8632::_add_sp(Operand *Adjustment) { |
| 157 | Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); |
| 158 | _add(esp, Adjustment); |
| 159 | } |
| 160 | |
| 161 | void TargetX8632::_mov_sp(Operand *NewValue) { |
| 162 | Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); |
| 163 | _redefined(_mov(esp, NewValue)); |
| 164 | } |
| 165 | |
John Porto | ac2388c | 2016-01-22 07:10:56 -0800 | [diff] [blame] | 166 | Traits::X86OperandMem *TargetX8632::_sandbox_mem_reference(X86OperandMem *Mem) { |
| 167 | switch (SandboxingType) { |
| 168 | case ST_None: |
| 169 | case ST_NaCl: |
| 170 | return Mem; |
| 171 | case ST_Nonsfi: { |
| 172 | if (Mem->getIsRebased()) { |
| 173 | return Mem; |
| 174 | } |
| 175 | // For Non-SFI mode, if the Offset field is a ConstantRelocatable, we |
| 176 | // replace either Base or Index with a legalized RebasePtr. At emission |
| 177 | // time, the ConstantRelocatable will be emitted with the @GOTOFF |
| 178 | // relocation. |
| 179 | if (llvm::dyn_cast_or_null<ConstantRelocatable>(Mem->getOffset()) == |
| 180 | nullptr) { |
| 181 | return Mem; |
| 182 | } |
| 183 | Variable *T; |
| 184 | uint16_t Shift = 0; |
| 185 | if (Mem->getIndex() == nullptr) { |
| 186 | T = Mem->getBase(); |
| 187 | } else if (Mem->getBase() == nullptr) { |
| 188 | T = Mem->getIndex(); |
| 189 | Shift = Mem->getShift(); |
| 190 | } else { |
| 191 | llvm::report_fatal_error( |
| 192 | "Either Base or Index must be unused in Non-SFI mode"); |
| 193 | } |
| 194 | Variable *RebasePtrR = legalizeToReg(RebasePtr); |
| 195 | static constexpr bool IsRebased = true; |
| 196 | return Traits::X86OperandMem::create( |
| 197 | Func, Mem->getType(), RebasePtrR, Mem->getOffset(), T, Shift, |
| 198 | Traits::X86OperandMem::DefaultSegment, IsRebased); |
| 199 | } |
| 200 | } |
| 201 | llvm::report_fatal_error("Unhandled sandboxing type: " + |
| 202 | std::to_string(SandboxingType)); |
| 203 | } |
| 204 | |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 205 | void TargetX8632::_sub_sp(Operand *Adjustment) { |
| 206 | Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); |
| 207 | _sub(esp, Adjustment); |
Jim Stichnoth | f531931 | 2016-06-10 12:21:17 -0700 | [diff] [blame] | 208 | // Add a fake use of the stack pointer, to prevent the stack pointer adustment |
| 209 | // from being dead-code eliminated in a function that doesn't return. |
| 210 | Context.insert<InstFakeUse>(esp); |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 211 | } |
| 212 | |
David Sehr | b9a404d | 2016-01-21 08:09:27 -0800 | [diff] [blame] | 213 | void TargetX8632::_link_bp() { |
| 214 | Variable *ebp = getPhysicalRegister(Traits::RegisterSet::Reg_ebp); |
| 215 | Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); |
| 216 | _push(ebp); |
| 217 | _mov(ebp, esp); |
| 218 | // Keep ebp live for late-stage liveness analysis (e.g. asm-verbose mode). |
| 219 | Context.insert<InstFakeUse>(ebp); |
| 220 | } |
| 221 | |
| 222 | void TargetX8632::_unlink_bp() { |
| 223 | Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); |
| 224 | Variable *ebp = getPhysicalRegister(Traits::RegisterSet::Reg_ebp); |
| 225 | // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake |
| 226 | // use of esp before the assignment of esp=ebp keeps previous esp |
| 227 | // adjustments from being dead-code eliminated. |
| 228 | Context.insert<InstFakeUse>(esp); |
| 229 | _mov(esp, ebp); |
| 230 | _pop(ebp); |
| 231 | } |
| 232 | |
Stephen White | 17078c7 | 2019-02-27 14:39:14 -0500 | [diff] [blame] | 233 | void TargetX8632::_push_reg(RegNumT RegNum) { |
| 234 | _push(getPhysicalRegister(RegNum, Traits::WordType)); |
| 235 | } |
| 236 | |
| 237 | void TargetX8632::_pop_reg(RegNumT RegNum) { |
| 238 | _pop(getPhysicalRegister(RegNum, Traits::WordType)); |
| 239 | } |
David Sehr | b9a404d | 2016-01-21 08:09:27 -0800 | [diff] [blame] | 240 | |
| 241 | void TargetX8632::emitGetIP(CfgNode *Node) { |
| 242 | // If there is a non-deleted InstX86GetIP instruction, we need to move it to |
| 243 | // the point after the stack frame has stabilized but before |
| 244 | // register-allocated in-args are copied into their home registers. It would |
| 245 | // be slightly faster to search for the GetIP instruction before other prolog |
| 246 | // instructions are inserted, but it's more clear to do the whole |
| 247 | // transformation in a single place. |
| 248 | Traits::Insts::GetIP *GetIPInst = nullptr; |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 249 | if (getFlags().getUseNonsfi()) { |
David Sehr | b9a404d | 2016-01-21 08:09:27 -0800 | [diff] [blame] | 250 | for (Inst &Instr : Node->getInsts()) { |
| 251 | if (auto *GetIP = llvm::dyn_cast<Traits::Insts::GetIP>(&Instr)) { |
| 252 | if (!Instr.isDeleted()) |
| 253 | GetIPInst = GetIP; |
| 254 | break; |
| 255 | } |
| 256 | } |
| 257 | } |
| 258 | // Delete any existing InstX86GetIP instruction and reinsert it here. Also, |
| 259 | // insert the call to the helper function and the spill to the stack, to |
| 260 | // simplify emission. |
| 261 | if (GetIPInst) { |
| 262 | GetIPInst->setDeleted(); |
| 263 | Variable *Dest = GetIPInst->getDest(); |
| 264 | Variable *CallDest = |
| 265 | Dest->hasReg() ? Dest |
| 266 | : getPhysicalRegister(Traits::RegisterSet::Reg_eax); |
John Porto | 6e8d3fa | 2016-02-04 10:35:20 -0800 | [diff] [blame] | 267 | auto *BeforeAddReloc = RelocOffset::create(Ctx); |
| 268 | BeforeAddReloc->setSubtract(true); |
| 269 | auto *BeforeAdd = InstX86Label::create(Func, this); |
| 270 | BeforeAdd->setRelocOffset(BeforeAddReloc); |
| 271 | |
| 272 | auto *AfterAddReloc = RelocOffset::create(Ctx); |
| 273 | auto *AfterAdd = InstX86Label::create(Func, this); |
| 274 | AfterAdd->setRelocOffset(AfterAddReloc); |
| 275 | |
John Porto | e82b560 | 2016-02-24 15:58:55 -0800 | [diff] [blame] | 276 | const RelocOffsetT ImmSize = -typeWidthInBytes(IceType_i32); |
John Porto | 6e8d3fa | 2016-02-04 10:35:20 -0800 | [diff] [blame] | 277 | |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 278 | auto *GotFromPc = |
| 279 | llvm::cast<ConstantRelocatable>(Ctx->getConstantSymWithEmitString( |
| 280 | ImmSize, {AfterAddReloc, BeforeAddReloc}, |
| 281 | Ctx->getGlobalString(GlobalOffsetTable), GlobalOffsetTable)); |
John Porto | 6e8d3fa | 2016-02-04 10:35:20 -0800 | [diff] [blame] | 282 | |
David Sehr | b9a404d | 2016-01-21 08:09:27 -0800 | [diff] [blame] | 283 | // Insert a new version of InstX86GetIP. |
| 284 | Context.insert<Traits::Insts::GetIP>(CallDest); |
John Porto | 6e8d3fa | 2016-02-04 10:35:20 -0800 | [diff] [blame] | 285 | |
| 286 | Context.insert(BeforeAdd); |
| 287 | _add(CallDest, GotFromPc); |
| 288 | Context.insert(AfterAdd); |
| 289 | |
David Sehr | b9a404d | 2016-01-21 08:09:27 -0800 | [diff] [blame] | 290 | // Spill the register to its home stack location if necessary. |
John Porto | 6e8d3fa | 2016-02-04 10:35:20 -0800 | [diff] [blame] | 291 | if (Dest != CallDest) { |
David Sehr | b9a404d | 2016-01-21 08:09:27 -0800 | [diff] [blame] | 292 | _mov(Dest, CallDest); |
| 293 | } |
| 294 | } |
| 295 | } |
| 296 | |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 297 | void TargetX8632::lowerIndirectJump(Variable *JumpTarget) { |
John Porto | 3bf335f | 2016-01-15 11:17:55 -0800 | [diff] [blame] | 298 | AutoBundle _(this); |
| 299 | |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 300 | if (NeedSandboxing) { |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 301 | const SizeT BundleSize = |
| 302 | 1 << Func->getAssembler<>()->getBundleAlignLog2Bytes(); |
| 303 | _and(JumpTarget, Ctx->getConstantInt32(~(BundleSize - 1))); |
| 304 | } |
John Porto | 3bf335f | 2016-01-15 11:17:55 -0800 | [diff] [blame] | 305 | |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 306 | _jmp(JumpTarget); |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 307 | } |
| 308 | |
John Porto | ac2388c | 2016-01-22 07:10:56 -0800 | [diff] [blame] | 309 | void TargetX8632::initRebasePtr() { |
| 310 | if (SandboxingType == ST_Nonsfi) { |
| 311 | RebasePtr = Func->makeVariable(IceType_i32); |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | void TargetX8632::initSandbox() { |
| 316 | if (SandboxingType != ST_Nonsfi) { |
| 317 | return; |
| 318 | } |
| 319 | // Insert the RebasePtr assignment as the very first lowered instruction. |
| 320 | // Later, it will be moved into the right place - after the stack frame is set |
| 321 | // up but before in-args are copied into registers. |
| 322 | Context.init(Func->getEntryNode()); |
| 323 | Context.setInsertPoint(Context.getCur()); |
| 324 | Context.insert<Traits::Insts::GetIP>(RebasePtr); |
| 325 | } |
| 326 | |
| 327 | bool TargetX8632::legalizeOptAddrForSandbox(OptAddr *Addr) { |
| 328 | if (Addr->Relocatable == nullptr || SandboxingType != ST_Nonsfi) { |
| 329 | return true; |
| 330 | } |
| 331 | |
| 332 | if (Addr->Base == RebasePtr || Addr->Index == RebasePtr) { |
| 333 | return true; |
| 334 | } |
| 335 | |
| 336 | if (Addr->Base == nullptr) { |
| 337 | Addr->Base = RebasePtr; |
| 338 | return true; |
| 339 | } |
| 340 | |
| 341 | if (Addr->Index == nullptr) { |
| 342 | Addr->Index = RebasePtr; |
| 343 | Addr->Shift = 0; |
| 344 | return true; |
| 345 | } |
| 346 | |
| 347 | return false; |
| 348 | } |
| 349 | |
David Sehr | 0c68bef | 2016-01-20 10:00:23 -0800 | [diff] [blame] | 350 | Inst *TargetX8632::emitCallToTarget(Operand *CallTarget, Variable *ReturnReg) { |
| 351 | std::unique_ptr<AutoBundle> Bundle; |
| 352 | if (NeedSandboxing) { |
| 353 | if (llvm::isa<Constant>(CallTarget)) { |
| 354 | Bundle = makeUnique<AutoBundle>(this, InstBundleLock::Opt_AlignToEnd); |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 355 | } else { |
David Sehr | 0c68bef | 2016-01-20 10:00:23 -0800 | [diff] [blame] | 356 | Variable *CallTargetVar = nullptr; |
| 357 | _mov(CallTargetVar, CallTarget); |
| 358 | Bundle = makeUnique<AutoBundle>(this, InstBundleLock::Opt_AlignToEnd); |
| 359 | const SizeT BundleSize = |
| 360 | 1 << Func->getAssembler<>()->getBundleAlignLog2Bytes(); |
| 361 | _and(CallTargetVar, Ctx->getConstantInt32(~(BundleSize - 1))); |
| 362 | CallTarget = CallTargetVar; |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 363 | } |
| 364 | } |
David Sehr | 0c68bef | 2016-01-20 10:00:23 -0800 | [diff] [blame] | 365 | return Context.insert<Traits::Insts::Call>(ReturnReg, CallTarget); |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 366 | } |
| 367 | |
David Sehr | 0c68bef | 2016-01-20 10:00:23 -0800 | [diff] [blame] | 368 | Variable *TargetX8632::moveReturnValueToRegister(Operand *Value, |
| 369 | Type ReturnType) { |
| 370 | if (isVectorType(ReturnType)) { |
| 371 | return legalizeToReg(Value, Traits::RegisterSet::Reg_xmm0); |
| 372 | } else if (isScalarFloatingType(ReturnType)) { |
| 373 | _fld(Value); |
| 374 | return nullptr; |
| 375 | } else { |
| 376 | assert(ReturnType == IceType_i32 || ReturnType == IceType_i64); |
| 377 | if (ReturnType == IceType_i64) { |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 378 | Variable *eax = |
David Sehr | 0c68bef | 2016-01-20 10:00:23 -0800 | [diff] [blame] | 379 | legalizeToReg(loOperand(Value), Traits::RegisterSet::Reg_eax); |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 380 | Variable *edx = |
David Sehr | 0c68bef | 2016-01-20 10:00:23 -0800 | [diff] [blame] | 381 | legalizeToReg(hiOperand(Value), Traits::RegisterSet::Reg_edx); |
John Porto | 1d937a8 | 2015-12-17 06:19:34 -0800 | [diff] [blame] | 382 | Context.insert<InstFakeUse>(edx); |
David Sehr | 0c68bef | 2016-01-20 10:00:23 -0800 | [diff] [blame] | 383 | return eax; |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 384 | } else { |
David Sehr | 0c68bef | 2016-01-20 10:00:23 -0800 | [diff] [blame] | 385 | Variable *Reg = nullptr; |
| 386 | _mov(Reg, Value, Traits::RegisterSet::Reg_eax); |
| 387 | return Reg; |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 388 | } |
| 389 | } |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 390 | } |
| 391 | |
David Sehr | b9a404d | 2016-01-21 08:09:27 -0800 | [diff] [blame] | 392 | void TargetX8632::emitSandboxedReturn() { |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 393 | // Change the original ret instruction into a sandboxed return sequence. |
| 394 | // t:ecx = pop |
| 395 | // bundle_lock |
| 396 | // and t, ~31 |
| 397 | // jmp *t |
| 398 | // bundle_unlock |
| 399 | // FakeUse <original_ret_operand> |
| 400 | Variable *T_ecx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ecx); |
| 401 | _pop(T_ecx); |
| 402 | lowerIndirectJump(T_ecx); |
John Porto | 729b5f6 | 2015-08-06 07:44:30 -0700 | [diff] [blame] | 403 | } |
| 404 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 405 | // In some cases, there are x-macros tables for both high-level and low-level |
| 406 | // instructions/operands that use the same enum key value. The tables are kept |
| 407 | // separate to maintain a proper separation between abstraction layers. There |
| 408 | // is a risk that the tables could get out of sync if enum values are reordered |
| 409 | // or if entries are added or deleted. The following dummy namespaces use |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 410 | // static_asserts to ensure everything is kept in sync. |
| 411 | |
John Porto | 7e93c62 | 2015-06-23 10:58:57 -0700 | [diff] [blame] | 412 | namespace { |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 413 | // Validate the enum values in FCMPX8632_TABLE. |
| 414 | namespace dummy1 { |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 415 | // Define a temporary set of enum values based on low-level table entries. |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 416 | enum _tmp_enum { |
Matt Wala | ce0ca8f | 2014-07-24 12:34:20 -0700 | [diff] [blame] | 417 | #define X(val, dflt, swapS, C1, C2, swapV, pred) _tmp_##val, |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 418 | FCMPX8632_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 419 | #undef X |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 420 | _num |
| 421 | }; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 422 | // Define a set of constants based on high-level table entries. |
| 423 | #define X(tag, str) static const int _table1_##tag = InstFcmp::tag; |
JF Bastien | 8427ea2 | 2015-01-27 12:56:49 -0800 | [diff] [blame] | 424 | ICEINSTFCMP_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 425 | #undef X |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 426 | // Define a set of constants based on low-level table entries, and ensure the |
| 427 | // table entry keys are consistent. |
Matt Wala | ce0ca8f | 2014-07-24 12:34:20 -0700 | [diff] [blame] | 428 | #define X(val, dflt, swapS, C1, C2, swapV, pred) \ |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 429 | static const int _table2_##val = _tmp_##val; \ |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 430 | static_assert( \ |
| 431 | _table1_##val == _table2_##val, \ |
| 432 | "Inconsistency between FCMPX8632_TABLE and ICEINSTFCMP_TABLE"); |
JF Bastien | 8427ea2 | 2015-01-27 12:56:49 -0800 | [diff] [blame] | 433 | FCMPX8632_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 434 | #undef X |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 435 | // Repeat the static asserts with respect to the high-level table entries in |
| 436 | // case the high-level table has extra entries. |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 437 | #define X(tag, str) \ |
| 438 | static_assert( \ |
| 439 | _table1_##tag == _table2_##tag, \ |
| 440 | "Inconsistency between FCMPX8632_TABLE and ICEINSTFCMP_TABLE"); |
JF Bastien | 8427ea2 | 2015-01-27 12:56:49 -0800 | [diff] [blame] | 441 | ICEINSTFCMP_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 442 | #undef X |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 443 | } // end of namespace dummy1 |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 444 | |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 445 | // Validate the enum values in ICMPX8632_TABLE. |
| 446 | namespace dummy2 { |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 447 | // Define a temporary set of enum values based on low-level table entries. |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 448 | enum _tmp_enum { |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 449 | #define X(val, C_32, C1_64, C2_64, C3_64) _tmp_##val, |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 450 | ICMPX8632_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 451 | #undef X |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 452 | _num |
| 453 | }; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 454 | // Define a set of constants based on high-level table entries. |
Manasij Mukherjee | 0c70417 | 2016-07-21 12:40:24 -0700 | [diff] [blame] | 455 | #define X(tag, reverse, str) static const int _table1_##tag = InstIcmp::tag; |
JF Bastien | 8427ea2 | 2015-01-27 12:56:49 -0800 | [diff] [blame] | 456 | ICEINSTICMP_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 457 | #undef X |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 458 | // Define a set of constants based on low-level table entries, and ensure the |
| 459 | // table entry keys are consistent. |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 460 | #define X(val, C_32, C1_64, C2_64, C3_64) \ |
| 461 | static const int _table2_##val = _tmp_##val; \ |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 462 | static_assert( \ |
| 463 | _table1_##val == _table2_##val, \ |
| 464 | "Inconsistency between ICMPX8632_TABLE and ICEINSTICMP_TABLE"); |
JF Bastien | 8427ea2 | 2015-01-27 12:56:49 -0800 | [diff] [blame] | 465 | ICMPX8632_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 466 | #undef X |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 467 | // Repeat the static asserts with respect to the high-level table entries in |
| 468 | // case the high-level table has extra entries. |
Manasij Mukherjee | 0c70417 | 2016-07-21 12:40:24 -0700 | [diff] [blame] | 469 | #define X(tag, reverse, str) \ |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 470 | static_assert( \ |
| 471 | _table1_##tag == _table2_##tag, \ |
| 472 | "Inconsistency between ICMPX8632_TABLE and ICEINSTICMP_TABLE"); |
JF Bastien | 8427ea2 | 2015-01-27 12:56:49 -0800 | [diff] [blame] | 473 | ICEINSTICMP_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 474 | #undef X |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 475 | } // end of namespace dummy2 |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 476 | |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 477 | // Validate the enum values in ICETYPEX8632_TABLE. |
| 478 | namespace dummy3 { |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 479 | // Define a temporary set of enum values based on low-level table entries. |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 480 | enum _tmp_enum { |
Nicolas Capens | 7638e27 | 2016-10-06 11:33:55 -0400 | [diff] [blame] | 481 | #define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld) \ |
John Porto | ae15f0f | 2016-04-26 04:26:33 -0700 | [diff] [blame] | 482 | _tmp_##tag, |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 483 | ICETYPEX8632_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 484 | #undef X |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 485 | _num |
| 486 | }; |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 487 | // Define a set of constants based on high-level table entries. |
Jim Stichnoth | 2544d4d | 2016-01-22 13:07:46 -0800 | [diff] [blame] | 488 | #define X(tag, sizeLog2, align, elts, elty, str, rcstr) \ |
Jim Stichnoth | c59288b | 2015-11-09 11:38:40 -0800 | [diff] [blame] | 489 | static const int _table1_##tag = IceType_##tag; |
JF Bastien | 8427ea2 | 2015-01-27 12:56:49 -0800 | [diff] [blame] | 490 | ICETYPE_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 491 | #undef X |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 492 | // Define a set of constants based on low-level table entries, and ensure the |
| 493 | // table entry keys are consistent. |
Nicolas Capens | 7638e27 | 2016-10-06 11:33:55 -0400 | [diff] [blame] | 494 | #define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld) \ |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 495 | static const int _table2_##tag = _tmp_##tag; \ |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 496 | static_assert(_table1_##tag == _table2_##tag, \ |
| 497 | "Inconsistency between ICETYPEX8632_TABLE and ICETYPE_TABLE"); |
JF Bastien | 8427ea2 | 2015-01-27 12:56:49 -0800 | [diff] [blame] | 498 | ICETYPEX8632_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 499 | #undef X |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 500 | // Repeat the static asserts with respect to the high-level table entries in |
| 501 | // case the high-level table has extra entries. |
Jim Stichnoth | 2544d4d | 2016-01-22 13:07:46 -0800 | [diff] [blame] | 502 | #define X(tag, sizeLog2, align, elts, elty, str, rcstr) \ |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 503 | static_assert(_table1_##tag == _table2_##tag, \ |
| 504 | "Inconsistency between ICETYPEX8632_TABLE and ICETYPE_TABLE"); |
JF Bastien | 8427ea2 | 2015-01-27 12:56:49 -0800 | [diff] [blame] | 505 | ICETYPE_TABLE |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 506 | #undef X |
Jim Stichnoth | fac5517 | 2014-10-01 13:06:21 -0700 | [diff] [blame] | 507 | } // end of namespace dummy3 |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 508 | } // end of anonymous namespace |
| 509 | |
John Porto | 4a56686 | 2016-01-04 09:33:41 -0800 | [diff] [blame] | 510 | } // end of namespace X8632 |
Jim Stichnoth | 5bc2b1d | 2014-05-22 13:38:48 -0700 | [diff] [blame] | 511 | } // end of namespace Ice |