1 /**************************************************************************
3 * Copyright 2019 Red Hat.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 **************************************************************************/
27 #include "lp_bld_coro.h"
28 #include "util/os_memory.h"
29 #include "lp_bld_init.h"
30 #include "lp_bld_const.h"
31 #include "lp_bld_intr.h"
32 #include "lp_bld_flow.h"
34 #if LLVM_VERSION_MAJOR < 6
35 /* not a wrapper, just lets it compile */
36 static LLVMTypeRef
LLVMTokenTypeInContext(LLVMContextRef C
)
39 return LLVMVoidTypeInContext(C
);
43 LLVMValueRef
lp_build_coro_id(struct gallivm_state
*gallivm
)
45 LLVMValueRef coro_id_args
[4];
46 coro_id_args
[0] = lp_build_const_int32(gallivm
, 0);
47 coro_id_args
[1] = LLVMConstPointerNull(LLVMPointerType(LLVMInt8TypeInContext(gallivm
->context
), 0));
48 coro_id_args
[2] = coro_id_args
[1];
49 coro_id_args
[3] = coro_id_args
[1];
50 LLVMValueRef coro_id
= lp_build_intrinsic(gallivm
->builder
,
52 LLVMTokenTypeInContext(gallivm
->context
),
57 LLVMValueRef
lp_build_coro_size(struct gallivm_state
*gallivm
)
59 return lp_build_intrinsic(gallivm
->builder
,
61 LLVMInt32TypeInContext(gallivm
->context
),
65 LLVMValueRef
lp_build_coro_begin(struct gallivm_state
*gallivm
,
66 LLVMValueRef coro_id
, LLVMValueRef mem_ptr
)
68 LLVMValueRef coro_begin_args
[2];
69 coro_begin_args
[0] = coro_id
;
70 coro_begin_args
[1] = mem_ptr
;
71 LLVMValueRef coro_hdl
= lp_build_intrinsic(gallivm
->builder
,
73 LLVMPointerType(LLVMInt8TypeInContext(gallivm
->context
), 0),
74 coro_begin_args
, 2, 0);
78 LLVMValueRef
lp_build_coro_free(struct gallivm_state
*gallivm
,
79 LLVMValueRef coro_id
, LLVMValueRef coro_hdl
)
81 LLVMValueRef coro_free_args
[2];
82 coro_free_args
[0] = coro_id
;
83 coro_free_args
[1] = coro_hdl
;
84 return lp_build_intrinsic(gallivm
->builder
,
86 LLVMPointerType(LLVMInt8TypeInContext(gallivm
->context
), 0),
87 coro_free_args
, 2, 0);
90 void lp_build_coro_end(struct gallivm_state
*gallivm
, LLVMValueRef coro_hdl
)
92 LLVMValueRef coro_end_args
[2];
93 coro_end_args
[0] = coro_hdl
;
94 coro_end_args
[1] = LLVMConstInt(LLVMInt1TypeInContext(gallivm
->context
), 0, 0);
95 lp_build_intrinsic(gallivm
->builder
,
97 LLVMInt1TypeInContext(gallivm
->context
),
101 void lp_build_coro_resume(struct gallivm_state
*gallivm
, LLVMValueRef coro_hdl
)
103 lp_build_intrinsic(gallivm
->builder
,
105 LLVMVoidTypeInContext(gallivm
->context
),
109 void lp_build_coro_destroy(struct gallivm_state
*gallivm
, LLVMValueRef coro_hdl
)
111 lp_build_intrinsic(gallivm
->builder
,
113 LLVMVoidTypeInContext(gallivm
->context
),
117 LLVMValueRef
lp_build_coro_done(struct gallivm_state
*gallivm
, LLVMValueRef coro_hdl
)
119 return lp_build_intrinsic(gallivm
->builder
,
121 LLVMInt1TypeInContext(gallivm
->context
),
125 LLVMValueRef
lp_build_coro_suspend(struct gallivm_state
*gallivm
, bool last
)
127 LLVMValueRef coro_susp_args
[2];
128 coro_susp_args
[0] = LLVMConstNull(LLVMTokenTypeInContext(gallivm
->context
));
129 coro_susp_args
[1] = LLVMConstInt(LLVMInt1TypeInContext(gallivm
->context
), last
, 0);
130 LLVMValueRef coro_suspend
= lp_build_intrinsic(gallivm
->builder
,
132 LLVMInt8TypeInContext(gallivm
->context
),
133 coro_susp_args
, 2, 0);
137 LLVMValueRef
lp_build_coro_alloc(struct gallivm_state
*gallivm
, LLVMValueRef id
)
139 return lp_build_intrinsic(gallivm
->builder
,
141 LLVMInt1TypeInContext(gallivm
->context
),
146 coro_malloc(int size
)
148 return os_malloc_aligned(size
, 4096);
154 os_free_aligned(ptr
);
157 LLVMValueRef
lp_build_coro_begin_alloc_mem(struct gallivm_state
*gallivm
, LLVMValueRef coro_id
)
159 LLVMValueRef do_alloc
= lp_build_coro_alloc(gallivm
, coro_id
);
160 LLVMTypeRef mem_ptr_type
= LLVMPointerType(LLVMInt8TypeInContext(gallivm
->context
), 0);
161 LLVMValueRef alloc_mem_store
= lp_build_alloca(gallivm
, mem_ptr_type
, "coro mem");
162 struct lp_build_if_state if_state_coro
;
163 lp_build_if(&if_state_coro
, gallivm
, do_alloc
);
164 LLVMValueRef coro_size
= lp_build_coro_size(gallivm
);
165 LLVMValueRef alloc_mem
;
166 LLVMTypeRef int32_type
= LLVMInt32TypeInContext(gallivm
->context
);
168 LLVMTypeRef malloc_type
= LLVMFunctionType(mem_ptr_type
, &int32_type
, 1, 0);
170 LLVMValueRef func_malloc
= lp_build_const_int_pointer(gallivm
, func_to_pointer((func_pointer
)coro_malloc
));
171 func_malloc
= LLVMBuildBitCast(gallivm
->builder
, func_malloc
, LLVMPointerType(malloc_type
, 0), "coro_malloc");
172 alloc_mem
= LLVMBuildCall(gallivm
->builder
, func_malloc
, &coro_size
, 1, "");
174 LLVMBuildStore(gallivm
->builder
, alloc_mem
, alloc_mem_store
);
175 lp_build_endif(&if_state_coro
);
176 alloc_mem
= LLVMBuildLoad(gallivm
->builder
, alloc_mem_store
, "");
177 LLVMValueRef coro_hdl
= lp_build_coro_begin(gallivm
, coro_id
, alloc_mem
);
181 void lp_build_coro_free_mem(struct gallivm_state
*gallivm
, LLVMValueRef coro_id
, LLVMValueRef coro_hdl
)
183 LLVMValueRef alloc_mem
= lp_build_coro_free(gallivm
, coro_id
, coro_hdl
);
184 LLVMTypeRef ptr_type
= LLVMPointerType(LLVMInt8TypeInContext(gallivm
->context
), 0);
185 LLVMTypeRef free_type
= LLVMFunctionType(LLVMVoidTypeInContext(gallivm
->context
), &ptr_type
, 1, 0);
186 LLVMValueRef func_free
= lp_build_const_int_pointer(gallivm
, func_to_pointer((func_pointer
)coro_free
));
187 func_free
= LLVMBuildBitCast(gallivm
->builder
, func_free
, LLVMPointerType(free_type
, 0), "coro_free");
188 alloc_mem
= LLVMBuildCall(gallivm
->builder
, func_free
, &alloc_mem
, 1, "");
191 void lp_build_coro_suspend_switch(struct gallivm_state
*gallivm
, const struct lp_build_coro_suspend_info
*sus_info
,
192 LLVMBasicBlockRef resume_block
, bool final_suspend
)
194 LLVMValueRef coro_suspend
= lp_build_coro_suspend(gallivm
, final_suspend
);
195 LLVMValueRef myswitch
= LLVMBuildSwitch(gallivm
->builder
, coro_suspend
,
196 sus_info
->suspend
, resume_block
? 2 : 1);
197 LLVMAddCase(myswitch
, LLVMConstInt(LLVMInt8TypeInContext(gallivm
->context
), 1, 0), sus_info
->cleanup
);
199 LLVMAddCase(myswitch
, LLVMConstInt(LLVMInt8TypeInContext(gallivm
->context
), 0, 0), resume_block
);