Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// | 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 80 CondARM32::Cond getIcmp32Mapping(InstIcmp::ICond Cond) { | 80 CondARM32::Cond getIcmp32Mapping(InstIcmp::ICond Cond) { |
| 81 size_t Index = static_cast<size_t>(Cond); | 81 size_t Index = static_cast<size_t>(Cond); |
| 82 assert(Index < llvm::array_lengthof(TableIcmp32)); | 82 assert(Index < llvm::array_lengthof(TableIcmp32)); |
| 83 return TableIcmp32[Index].Mapping; | 83 return TableIcmp32[Index].Mapping; |
| 84 } | 84 } |
| 85 | 85 |
| 86 // In some cases, there are x-macros tables for both high-level and low-level | 86 // In some cases, there are x-macros tables for both high-level and low-level |
| 87 // instructions/operands that use the same enum key value. The tables are kept | 87 // instructions/operands that use the same enum key value. The tables are kept |
| 88 // separate to maintain a proper separation between abstraction layers. There | 88 // separate to maintain a proper separation between abstraction layers. There |
| 89 // is a risk that the tables could get out of sync if enum values are reordered | 89 // is a risk that the tables could get out of sync if enum values are reordered |
| 90 // or if entries are added or deleted. The following dummy namespaces use | 90 // or if entries are added or deleted. The following dummy namespaces use |
|
Jim Stichnoth
2015/09/18 19:28:55
s/dummy/anonymous/ ?
(or some suitable rewrite)
A
John
2015/09/18 22:55:53
s/// Done.
The cleanup... let's call it 'Future w
| |
| 91 // static_asserts to ensure everything is kept in sync. | 91 // static_asserts to ensure everything is kept in sync. |
| 92 | 92 |
| 93 // Validate the enum values in ICMPARM32_TABLE. | 93 // Validate the enum values in ICMPARM32_TABLE. |
| 94 namespace dummy1 { | 94 namespace { |
| 95 // Define a temporary set of enum values based on low-level table entries. | 95 // Define a temporary set of enum values based on low-level table entries. |
| 96 enum _tmp_enum { | 96 enum _icmp_ll_enum { |
| 97 #define X(val, signed, swapped64, C_32, C1_64, C2_64) _tmp_##val, | 97 #define X(val, signed, swapped64, C_32, C1_64, C2_64) _icmp_ll_##val, |
| 98 ICMPARM32_TABLE | 98 ICMPARM32_TABLE |
| 99 #undef X | 99 #undef X |
| 100 _num | 100 _num |
| 101 }; | 101 }; |
| 102 // Define a set of constants based on high-level table entries. | 102 // Define a set of constants based on high-level table entries. |
| 103 #define X(tag, str) static const int _table1_##tag = InstIcmp::tag; | 103 #define X(tag, str) static constexpr int _icmp_hl_##tag = InstIcmp::tag; |
| 104 ICEINSTICMP_TABLE | 104 ICEINSTICMP_TABLE |
| 105 #undef X | 105 #undef X |
| 106 // Define a set of constants based on low-level table entries, and ensure the | 106 // Define a set of constants based on low-level table entries, and ensure the |
| 107 // table entry keys are consistent. | 107 // table entry keys are consistent. |
| 108 #define X(val, signed, swapped64, C_32, C1_64, C2_64) \ | 108 #define X(val, signed, swapped64, C_32, C1_64, C2_64) \ |
| 109 static const int _table2_##val = _tmp_##val; \ | |
| 110 static_assert( \ | 109 static_assert( \ |
| 111 _table1_##val == _table2_##val, \ | 110 _icmp_ll_##val == _icmp_hl_##val, \ |
| 112 "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE"); | 111 "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE: " #val); |
| 113 ICMPARM32_TABLE | 112 ICMPARM32_TABLE |
| 114 #undef X | 113 #undef X |
| 115 // Repeat the static asserts with respect to the high-level table entries in | 114 // Repeat the static asserts with respect to the high-level table entries in |
| 116 // case the high-level table has extra entries. | 115 // case the high-level table has extra entries. |
| 117 #define X(tag, str) \ | 116 #define X(tag, str) \ |
| 118 static_assert( \ | 117 static_assert( \ |
| 119 _table1_##tag == _table2_##tag, \ | 118 _icmp_hl_##tag == _icmp_ll_##tag, \ |
| 120 "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE"); | 119 "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE: " #tag); |
| 121 ICEINSTICMP_TABLE | 120 ICEINSTICMP_TABLE |
| 122 #undef X | 121 #undef X |
| 123 } // end of namespace dummy1 | 122 } // end of anonymous namespace |
| 124 | 123 |
| 125 // Stack alignment | 124 // Stack alignment |
| 126 const uint32_t ARM32_STACK_ALIGNMENT_BYTES = 16; | 125 const uint32_t ARM32_STACK_ALIGNMENT_BYTES = 16; |
| 127 | 126 |
| 128 // Value is in bytes. Return Value adjusted to the next highest multiple of the | 127 // Value is in bytes. Return Value adjusted to the next highest multiple of the |
| 129 // stack alignment. | 128 // stack alignment. |
| 130 uint32_t applyStackAlignment(uint32_t Value) { | 129 uint32_t applyStackAlignment(uint32_t Value) { |
| 131 return Utils::applyAlignment(Value, ARM32_STACK_ALIGNMENT_BYTES); | 130 return Utils::applyAlignment(Value, ARM32_STACK_ALIGNMENT_BYTES); |
| 132 } | 131 } |
| 133 | 132 |
| (...skipping 2088 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2222 break; | 2221 break; |
| 2223 } | 2222 } |
| 2224 } | 2223 } |
| 2225 } | 2224 } |
| 2226 | 2225 |
| 2227 void TargetARM32::lowerExtractElement(const InstExtractElement *Inst) { | 2226 void TargetARM32::lowerExtractElement(const InstExtractElement *Inst) { |
| 2228 (void)Inst; | 2227 (void)Inst; |
| 2229 UnimplementedError(Func->getContext()->getFlags()); | 2228 UnimplementedError(Func->getContext()->getFlags()); |
| 2230 } | 2229 } |
| 2231 | 2230 |
| 2231 namespace { | |
| 2232 // Validates FCMPARM32_TABLE's declaration w.r.t. InstFcmp::FCondition ordering | |
| 2233 // (and naming). | |
| 2234 enum { | |
| 2235 #define X(val, CC0, CC1) _fcmp_ll_##val, | |
| 2236 FCMPARM32_TABLE | |
| 2237 #undef X | |
| 2238 _fcmp_ll_NUM | |
| 2239 }; | |
| 2240 | |
| 2241 enum { | |
| 2242 #define X(tag, str) _fcmp_hl_##tag = InstFcmp::tag, | |
| 2243 ICEINSTFCMP_TABLE | |
| 2244 #undef X | |
| 2245 _fcmp_hl_NUM | |
| 2246 }; | |
| 2247 | |
| 2248 static_assert(_fcmp_hl_NUM == _fcmp_ll_NUM, | |
| 2249 "Inconsistency between high-level and low-level fcmp tags."); | |
| 2250 #define X(tag, str) \ | |
| 2251 static_assert( \ | |
| 2252 _fcmp_hl_##tag == _fcmp_ll_##tag, \ | |
| 2253 "Inconsistency between high-level and low-level fcmp tag " #tag); | |
| 2254 ICEINSTFCMP_TABLE | |
| 2255 #undef X | |
| 2256 | |
| 2257 struct { | |
| 2258 CondARM32::Cond CC0; | |
| 2259 CondARM32::Cond CC1; | |
| 2260 } TableFcmp[] = { | |
| 2261 #define X(val, CC0, CC1) \ | |
| 2262 { CondARM32::CC0, CondARM32::CC1 } \ | |
| 2263 , | |
| 2264 FCMPARM32_TABLE | |
| 2265 #undef X | |
| 2266 }; | |
| 2267 } // end of anonymous namespace | |
| 2268 | |
| 2232 void TargetARM32::lowerFcmp(const InstFcmp *Inst) { | 2269 void TargetARM32::lowerFcmp(const InstFcmp *Inst) { |
| 2233 (void)Inst; | 2270 Variable *Dest = Inst->getDest(); |
| 2234 UnimplementedError(Func->getContext()->getFlags()); | 2271 if (isVectorType(Dest->getType())) { |
| 2272 UnimplementedError(Func->getContext()->getFlags()); | |
| 2273 return; | |
| 2274 } | |
| 2275 | |
| 2276 Variable *Src0 = legalizeToReg(Inst->getSrc(0)); | |
|
Jim Stichnoth
2015/09/18 19:28:55
There's a (loosely-held, sadly) convention to name
John
2015/09/18 22:55:53
Done.
| |
| 2277 Variable *Src1 = legalizeToReg(Inst->getSrc(1)); | |
| 2278 Variable *T = makeReg(IceType_i32); | |
| 2279 _vcmp(Src0, Src1); | |
| 2280 _mov(T, Ctx->getConstantZero(IceType_i32)); | |
| 2281 _vmrs(); | |
| 2282 Operand *One = Ctx->getConstantInt32(1); | |
| 2283 InstFcmp::FCond Condition = Inst->getCondition(); | |
| 2284 assert(Condition < llvm::array_lengthof(TableFcmp)); | |
| 2285 CondARM32::Cond CC0 = TableFcmp[Condition].CC0; | |
| 2286 CondARM32::Cond CC1 = TableFcmp[Condition].CC1; | |
| 2287 if (CC0 != CondARM32::kNone) { | |
| 2288 _mov(T, One, CC0); | |
| 2289 // If this mov is not a maybe mov, but an actual mov (i.e., CC0 == AL), we | |
| 2290 // don't want to set_dest_nonkillable so that liveness + dead-code | |
| 2291 // elimination will get rid of the previous assignment (i.e., T = 0) above. | |
| 2292 if (CC0 != CondARM32::AL) | |
| 2293 _set_dest_nonkillable(); | |
| 2294 } | |
| 2295 if (CC1 != CondARM32::kNone) { | |
| 2296 assert(CC0 != CondARM32::kNone); | |
| 2297 assert(CC1 != CondARM32::AL); | |
| 2298 _mov_nonkillable(T, One, CC1); | |
| 2299 } | |
| 2300 _mov(Dest, T); | |
| 2235 } | 2301 } |
| 2236 | 2302 |
| 2237 void TargetARM32::lowerIcmp(const InstIcmp *Inst) { | 2303 void TargetARM32::lowerIcmp(const InstIcmp *Inst) { |
| 2238 Variable *Dest = Inst->getDest(); | 2304 Variable *Dest = Inst->getDest(); |
| 2239 Operand *Src0 = legalizeUndef(Inst->getSrc(0)); | 2305 Operand *Src0 = legalizeUndef(Inst->getSrc(0)); |
| 2240 Operand *Src1 = legalizeUndef(Inst->getSrc(1)); | 2306 Operand *Src1 = legalizeUndef(Inst->getSrc(1)); |
| 2241 | 2307 |
| 2242 if (isVectorType(Dest->getType())) { | 2308 if (isVectorType(Dest->getType())) { |
| 2243 UnimplementedError(Func->getContext()->getFlags()); | 2309 UnimplementedError(Func->getContext()->getFlags()); |
| 2244 return; | 2310 return; |
| (...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2688 Variable *Dest = Inst->getDest(); | 2754 Variable *Dest = Inst->getDest(); |
| 2689 Type DestTy = Dest->getType(); | 2755 Type DestTy = Dest->getType(); |
| 2690 Operand *SrcT = Inst->getTrueOperand(); | 2756 Operand *SrcT = Inst->getTrueOperand(); |
| 2691 Operand *SrcF = Inst->getFalseOperand(); | 2757 Operand *SrcF = Inst->getFalseOperand(); |
| 2692 Operand *Condition = Inst->getCondition(); | 2758 Operand *Condition = Inst->getCondition(); |
| 2693 | 2759 |
| 2694 if (isVectorType(DestTy)) { | 2760 if (isVectorType(DestTy)) { |
| 2695 UnimplementedError(Func->getContext()->getFlags()); | 2761 UnimplementedError(Func->getContext()->getFlags()); |
| 2696 return; | 2762 return; |
| 2697 } | 2763 } |
| 2698 if (isFloatingType(DestTy)) { | |
| 2699 UnimplementedError(Func->getContext()->getFlags()); | |
| 2700 return; | |
| 2701 } | |
| 2702 // TODO(jvoung): handle folding opportunities. | 2764 // TODO(jvoung): handle folding opportunities. |
| 2703 // cmp cond, #0; mov t, SrcF; mov_cond t, SrcT; mov dest, t | 2765 // cmp cond, #0; mov t, SrcF; mov_cond t, SrcT; mov dest, t |
| 2704 Variable *CmpOpnd0 = legalizeToReg(Condition); | 2766 Variable *CmpOpnd0 = legalizeToReg(Condition); |
| 2705 Operand *CmpOpnd1 = Ctx->getConstantZero(IceType_i32); | 2767 Operand *CmpOpnd1 = Ctx->getConstantZero(IceType_i32); |
| 2706 _cmp(CmpOpnd0, CmpOpnd1); | 2768 _cmp(CmpOpnd0, CmpOpnd1); |
| 2707 CondARM32::Cond Cond = CondARM32::NE; | 2769 static constexpr CondARM32::Cond Cond = CondARM32::NE; |
|
Jim Stichnoth
2015/09/18 19:28:55
Hmm... can this just be constexpr, or does it have
John
2015/09/18 22:55:53
static doesn't hurt. I like declaring constexpr st
| |
| 2708 if (DestTy == IceType_i64) { | 2770 if (DestTy == IceType_i64) { |
| 2709 SrcT = legalizeUndef(SrcT); | 2771 SrcT = legalizeUndef(SrcT); |
| 2710 SrcF = legalizeUndef(SrcF); | 2772 SrcF = legalizeUndef(SrcF); |
| 2711 // Set the low portion. | 2773 // Set the low portion. |
| 2712 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); | 2774 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); |
| 2713 Variable *TLo = nullptr; | 2775 Variable *TLo = nullptr; |
| 2714 Operand *SrcFLo = legalize(loOperand(SrcF), Legal_Reg | Legal_Flex); | 2776 Operand *SrcFLo = legalize(loOperand(SrcF), Legal_Reg | Legal_Flex); |
| 2715 _mov(TLo, SrcFLo); | 2777 _mov(TLo, SrcFLo); |
| 2716 Operand *SrcTLo = legalize(loOperand(SrcT), Legal_Reg | Legal_Flex); | 2778 Operand *SrcTLo = legalize(loOperand(SrcT), Legal_Reg | Legal_Flex); |
| 2717 _mov_nonkillable(TLo, SrcTLo, Cond); | 2779 _mov_nonkillable(TLo, SrcTLo, Cond); |
| 2718 _mov(DestLo, TLo); | 2780 _mov(DestLo, TLo); |
| 2719 // Set the high portion. | 2781 // Set the high portion. |
| 2720 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); | 2782 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); |
| 2721 Variable *THi = nullptr; | 2783 Variable *THi = nullptr; |
| 2722 Operand *SrcFHi = legalize(hiOperand(SrcF), Legal_Reg | Legal_Flex); | 2784 Operand *SrcFHi = legalize(hiOperand(SrcF), Legal_Reg | Legal_Flex); |
| 2723 _mov(THi, SrcFHi); | 2785 _mov(THi, SrcFHi); |
| 2724 Operand *SrcTHi = legalize(hiOperand(SrcT), Legal_Reg | Legal_Flex); | 2786 Operand *SrcTHi = legalize(hiOperand(SrcT), Legal_Reg | Legal_Flex); |
| 2725 _mov_nonkillable(THi, SrcTHi, Cond); | 2787 _mov_nonkillable(THi, SrcTHi, Cond); |
| 2726 _mov(DestHi, THi); | 2788 _mov(DestHi, THi); |
| 2727 return; | 2789 return; |
| 2728 } | 2790 } |
| 2791 | |
| 2792 if (isFloatingType(DestTy)) { | |
| 2793 Variable *T = makeReg(DestTy); | |
| 2794 SrcF = legalizeToReg(SrcF); | |
| 2795 assert(DestTy == SrcF->getType()); | |
| 2796 _vmov(T, SrcF); | |
| 2797 SrcT = legalizeToReg(SrcT); | |
| 2798 assert(DestTy == SrcT->getType()); | |
| 2799 _vmov(T, SrcT, Cond); | |
| 2800 _set_dest_nonkillable(); | |
| 2801 _vmov(Dest, T); | |
| 2802 return; | |
| 2803 } | |
| 2804 | |
| 2729 Variable *T = nullptr; | 2805 Variable *T = nullptr; |
| 2730 SrcF = legalize(SrcF, Legal_Reg | Legal_Flex); | 2806 SrcF = legalize(SrcF, Legal_Reg | Legal_Flex); |
| 2731 _mov(T, SrcF); | 2807 _mov(T, SrcF); |
| 2732 SrcT = legalize(SrcT, Legal_Reg | Legal_Flex); | 2808 SrcT = legalize(SrcT, Legal_Reg | Legal_Flex); |
| 2733 _mov_nonkillable(T, SrcT, Cond); | 2809 _mov_nonkillable(T, SrcT, Cond); |
| 2734 _mov(Dest, T); | 2810 _mov(Dest, T); |
| 2735 } | 2811 } |
| 2736 | 2812 |
| 2737 void TargetARM32::lowerStore(const InstStore *Inst) { | 2813 void TargetARM32::lowerStore(const InstStore *Inst) { |
| 2738 Operand *Value = Inst->getData(); | 2814 Operand *Value = Inst->getData(); |
| (...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3278 << ".eabi_attribute 68, 1 @ Tag_Virtualization_use\n"; | 3354 << ".eabi_attribute 68, 1 @ Tag_Virtualization_use\n"; |
| 3279 if (CPUFeatures.hasFeature(TargetARM32Features::HWDivArm)) { | 3355 if (CPUFeatures.hasFeature(TargetARM32Features::HWDivArm)) { |
| 3280 Str << ".eabi_attribute 44, 2 @ Tag_DIV_use\n"; | 3356 Str << ".eabi_attribute 44, 2 @ Tag_DIV_use\n"; |
| 3281 } | 3357 } |
| 3282 // Technically R9 is used for TLS with Sandboxing, and we reserve it. | 3358 // Technically R9 is used for TLS with Sandboxing, and we reserve it. |
| 3283 // However, for compatibility with current NaCl LLVM, don't claim that. | 3359 // However, for compatibility with current NaCl LLVM, don't claim that. |
| 3284 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; | 3360 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; |
| 3285 } | 3361 } |
| 3286 | 3362 |
| 3287 } // end of namespace Ice | 3363 } // end of namespace Ice |
| OLD | NEW |