1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BERBERIS_CALLING_CONVENTIONS_CALLING_CONVENTIONS_X86_32_H_
18 #define BERBERIS_CALLING_CONVENTIONS_CALLING_CONVENTIONS_X86_32_H_
19 
20 #include "berberis/base/bit_util.h"
21 #include "berberis/base/logging.h"
22 
23 namespace berberis::x86_32 {
24 
25 enum ArgLocationKind {
26   kArgLocationNone = 0,
27   kArgLocationStack,
28   kArgLocationIntOut,  // eax, edx
29   kArgLocationFp,      // st0, st1
30 };
31 
32 struct ArgLocation {
33   ArgLocationKind kind;
34   unsigned offset;  // meaning of offset depends on kind!
35 };
36 
37 class CallingConventions {
38  public:
39   // ATTENTION: if passing __m256 (__m512) on stack, alignment should be 32 (64)!
40   static constexpr unsigned kStackAlignmentBeforeCall = 16;
41 
GetNextArgLoc(unsigned size,unsigned alignment)42   constexpr ArgLocation GetNextArgLoc(unsigned size, unsigned alignment) {
43     // Arguments of all types except packed (__m64 - __m512) are passed on stack.
44     // Stack is organized in fourbytes.
45     unsigned alignment_in_stack = (alignment < 4u ? 4u : alignment);
46     unsigned size_in_stack = AlignUp(size, alignment_in_stack);
47 
48     unsigned aligned_stack_offset = AlignUp(stack_offset_, alignment_in_stack);
49 
50     ArgLocation loc{kArgLocationStack, aligned_stack_offset};
51     stack_offset_ = aligned_stack_offset + size_in_stack;
52     return loc;
53   }
54 
GetIntResLoc(unsigned size)55   constexpr ArgLocation GetIntResLoc(unsigned size) {
56     // Fundamental integer type - 1/1, 2/2, 4/4, 8/8.
57     CHECK_LE(size, 8u);
58 
59     return {kArgLocationIntOut, 0u};
60   }
61 
GetFpResLoc(unsigned size)62   constexpr ArgLocation GetFpResLoc(unsigned size) {
63     // Fundamental floating-point type - 4/4, 8/8, 16/16.
64     CHECK_LE(size, 16u);
65 
66     return {kArgLocationFp, 0u};
67   }
68 
69  private:
70   unsigned stack_offset_ = 0;
71 };
72 
73 }  // namespace berberis::x86_32
74 
75 #endif  // BERBERIS_CALLING_CONVENTIONS_CALLING_CONVENTIONS_X86_32_H_
76