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 |