1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using Debug = System.Diagnostics.Debug;
7 
8 namespace Internal.TypeSystem
9 {
10     /// <summary>
11     /// Specifies the target CPU architecture.
12     /// </summary>
13     public enum TargetArchitecture
14     {
15         Unknown,
16         ARM,
17         ARMEL,
18         ARM64,
19         X64,
20         X86,
21         Wasm32
22     }
23 
24     /// <summary>
25     /// Specifies the target ABI.
26     /// </summary>
27     public enum TargetOS
28     {
29         Unknown,
30         Windows,
31         Linux,
32         OSX,
33         FreeBSD,
34         NetBSD,
35         WebAssembly,
36     }
37 
38     public enum TargetAbi
39     {
40         Unknown,
41         /// <summary>
42         /// Cross-platform console model
43         /// </summary>
44         CoreRT,
45         /// <summary>
46         /// Windows-specific UWP model
47         /// </summary>
48         ProjectN,
49         /// <summary>
50         /// Jit runtime ABI
51         /// </summary>
52         Jit
53     }
54 
55     /// <summary>
56     /// Represents various details about the compilation target that affect
57     /// layout, padding, allocations, or ABI.
58     /// </summary>
59     public partial class TargetDetails
60     {
61         /// <summary>
62         /// Gets the target CPU architecture.
63         /// </summary>
64         public TargetArchitecture Architecture
65         {
66             get;
67         }
68 
69         /// <summary>
70         /// Gets the target ABI.
71         /// </summary>
72         public TargetOS OperatingSystem
73         {
74             get;
75         }
76 
77         public TargetAbi Abi
78         {
79             get;
80         }
81 
82         /// <summary>
83         /// Gets the size of a pointer for the target of the compilation.
84         /// </summary>
85         public int PointerSize
86         {
87             get
88             {
89                 switch (Architecture)
90                 {
91                     case TargetArchitecture.ARM64:
92                     case TargetArchitecture.X64:
93                         return 8;
94                     case TargetArchitecture.ARM:
95                     case TargetArchitecture.ARMEL:
96                     case TargetArchitecture.X86:
97                     case TargetArchitecture.Wasm32:
98                         return 4;
99                     default:
100                         throw new NotSupportedException();
101                 }
102             }
103         }
104 
105         /// <summary>
106         /// Gets the maximum alignment to which something can be aligned
107         /// </summary>
108         public static int MaximumAlignment
109         {
110             get
111             {
112                 return 8;
113             }
114         }
115 
116         public LayoutInt LayoutPointerSize => new LayoutInt(PointerSize);
117 
118         /// <summary>
119         /// Gets the default field packing size.
120         /// </summary>
121         public int DefaultPackingSize
122         {
123             get
124             {
125                 // We use default packing size of 8 irrespective of the platform.
126                 return 8;
127             }
128         }
129 
130         /// <summary>
131         /// Gets the minimum required method alignment.
132         /// </summary>
133         public int MinimumFunctionAlignment
134         {
135             get
136             {
137                 // We use a minimum alignment of 4 irrespective of the platform.
138                 return 4;
139             }
140         }
141 
TargetDetails(TargetArchitecture architecture, TargetOS targetOS, TargetAbi abi)142         public TargetDetails(TargetArchitecture architecture, TargetOS targetOS, TargetAbi abi)
143         {
144             Architecture = architecture;
145             OperatingSystem = targetOS;
146             Abi = abi;
147         }
148 
149         /// <summary>
150         /// Retrieves the size of a well known type.
151         /// </summary>
GetWellKnownTypeSize(DefType type)152         public LayoutInt GetWellKnownTypeSize(DefType type)
153         {
154             switch (type.Category)
155             {
156                 case TypeFlags.Void:
157                     return new LayoutInt(PointerSize);
158                 case TypeFlags.Boolean:
159                     return new LayoutInt(1);
160                 case TypeFlags.Char:
161                     return new LayoutInt(2);
162                 case TypeFlags.Byte:
163                 case TypeFlags.SByte:
164                     return new LayoutInt(1);
165                 case TypeFlags.UInt16:
166                 case TypeFlags.Int16:
167                     return new LayoutInt(2);
168                 case TypeFlags.UInt32:
169                 case TypeFlags.Int32:
170                     return new LayoutInt(4);
171                 case TypeFlags.UInt64:
172                 case TypeFlags.Int64:
173                     return new LayoutInt(8);
174                 case TypeFlags.Single:
175                     return new LayoutInt(4);
176                 case TypeFlags.Double:
177                     return new LayoutInt(8);
178                 case TypeFlags.UIntPtr:
179                 case TypeFlags.IntPtr:
180                     return new LayoutInt(PointerSize);
181             }
182 
183             // Add new well known types if necessary
184 
185             throw new InvalidOperationException();
186         }
187 
188         /// <summary>
189         /// Retrieves the alignment required by a well known type.
190         /// </summary>
GetWellKnownTypeAlignment(DefType type)191         public LayoutInt GetWellKnownTypeAlignment(DefType type)
192         {
193             // Size == Alignment for all platforms.
194             return GetWellKnownTypeSize(type);
195         }
196 
197         /// <summary>
198         /// Given an alignment of the fields of a type, determine the alignment that is necessary for allocating the object on the GC heap
199         /// </summary>
200         /// <returns></returns>
GetObjectAlignment(LayoutInt fieldAlignment)201         public LayoutInt GetObjectAlignment(LayoutInt fieldAlignment)
202         {
203             switch (Architecture)
204             {
205                 case TargetArchitecture.ARM:
206                 case TargetArchitecture.ARMEL:
207                 case TargetArchitecture.Wasm32:
208                     // ARM supports two alignments for objects on the GC heap (4 byte and 8 byte)
209                     if (fieldAlignment.IsIndeterminate)
210                         return LayoutInt.Indeterminate;
211 
212                     if (fieldAlignment.AsInt <= 4)
213                         return new LayoutInt(4);
214                     else
215                         return new LayoutInt(8);
216                 case TargetArchitecture.X64:
217                 case TargetArchitecture.ARM64:
218                     return new LayoutInt(8);
219                 case TargetArchitecture.X86:
220                     return new LayoutInt(4);
221                 default:
222                     throw new NotSupportedException();
223             }
224         }
225 
226         /// <summary>
227         /// Returns True if compiling for Windows
228         /// </summary>
229         public bool IsWindows
230         {
231             get
232             {
233                 return OperatingSystem == TargetOS.Windows;
234             }
235         }
236 
237         /// <summary>
238         /// Maximum number of elements in a HFA type.
239         /// </summary>
240         public int MaximumHfaElementCount
241         {
242             get
243             {
244                 // There is a hard limit of 4 elements on an HFA type, see
245                 // http://blogs.msdn.com/b/vcblog/archive/2013/07/12/introducing-vector-calling-convention.aspx
246                 Debug.Assert(Architecture == TargetArchitecture.ARM ||
247                     Architecture == TargetArchitecture.ARMEL ||
248                     Architecture == TargetArchitecture.ARM64 ||
249                     Architecture == TargetArchitecture.X64 ||
250                     Architecture == TargetArchitecture.X86);
251 
252                 return 4;
253             }
254         }
255     }
256 }
257