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 anonymous namespaces use |
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 *Src0R = legalizeToReg(Inst->getSrc(0)); |
| 2277 Variable *Src1R = legalizeToReg(Inst->getSrc(1)); |
| 2278 Variable *T = makeReg(IceType_i32); |
| 2279 _vcmp(Src0R, Src1R); |
| 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; |
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 |