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 void lp_build_coro_add_malloc_hooks(struct gallivm_state
*gallivm
)
159 assert(gallivm
->engine
);
161 assert(gallivm
->coro_malloc_hook
);
162 assert(gallivm
->coro_free_hook
);
163 LLVMAddGlobalMapping(gallivm
->engine
, gallivm
->coro_malloc_hook
, coro_malloc
);
164 LLVMAddGlobalMapping(gallivm
->engine
, gallivm
->coro_free_hook
, coro_free
);
167 void lp_build_coro_declare_malloc_hooks(struct gallivm_state
*gallivm
)
169 LLVMTypeRef int32_type
= LLVMInt32TypeInContext(gallivm
->context
);
170 LLVMTypeRef mem_ptr_type
= LLVMPointerType(LLVMInt8TypeInContext(gallivm
->context
), 0);
171 LLVMTypeRef malloc_type
= LLVMFunctionType(mem_ptr_type
, &int32_type
, 1, 0);
172 gallivm
->coro_malloc_hook
= LLVMAddFunction(gallivm
->module
, "coro_malloc", malloc_type
);
173 LLVMTypeRef free_type
= LLVMFunctionType(LLVMVoidTypeInContext(gallivm
->context
), &mem_ptr_type
, 1, 0);
174 gallivm
->coro_free_hook
= LLVMAddFunction(gallivm
->module
, "coro_free", free_type
);
177 LLVMValueRef
lp_build_coro_begin_alloc_mem(struct gallivm_state
*gallivm
, LLVMValueRef coro_id
)
179 LLVMValueRef do_alloc
= lp_build_coro_alloc(gallivm
, coro_id
);
180 LLVMTypeRef mem_ptr_type
= LLVMPointerType(LLVMInt8TypeInContext(gallivm
->context
), 0);
181 LLVMValueRef alloc_mem_store
= lp_build_alloca(gallivm
, mem_ptr_type
, "coro mem");
182 struct lp_build_if_state if_state_coro
;
183 lp_build_if(&if_state_coro
, gallivm
, do_alloc
);
184 LLVMValueRef coro_size
= lp_build_coro_size(gallivm
);
185 LLVMValueRef alloc_mem
;
187 assert(gallivm
->coro_malloc_hook
);
188 alloc_mem
= LLVMBuildCall(gallivm
->builder
, gallivm
->coro_malloc_hook
, &coro_size
, 1, "");
190 LLVMBuildStore(gallivm
->builder
, alloc_mem
, alloc_mem_store
);
191 lp_build_endif(&if_state_coro
);
192 alloc_mem
= LLVMBuildLoad(gallivm
->builder
, alloc_mem_store
, "");
193 LLVMValueRef coro_hdl
= lp_build_coro_begin(gallivm
, coro_id
, alloc_mem
);
197 void lp_build_coro_free_mem(struct gallivm_state
*gallivm
, LLVMValueRef coro_id
, LLVMValueRef coro_hdl
)
199 LLVMValueRef alloc_mem
= lp_build_coro_free(gallivm
, coro_id
, coro_hdl
);
201 assert(gallivm
->coro_malloc_hook
);
202 alloc_mem
= LLVMBuildCall(gallivm
->builder
, gallivm
->coro_free_hook
, &alloc_mem
, 1, "");
205 void lp_build_coro_suspend_switch(struct gallivm_state
*gallivm
, const struct lp_build_coro_suspend_info
*sus_info
,
206 LLVMBasicBlockRef resume_block
, bool final_suspend
)
208 LLVMValueRef coro_suspend
= lp_build_coro_suspend(gallivm
, final_suspend
);
209 LLVMValueRef myswitch
= LLVMBuildSwitch(gallivm
->builder
, coro_suspend
,
210 sus_info
->suspend
, resume_block
? 2 : 1);
211 LLVMAddCase(myswitch
, LLVMConstInt(LLVMInt8TypeInContext(gallivm
->context
), 1, 0), sus_info
->cleanup
);
213 LLVMAddCase(myswitch
, LLVMConstInt(LLVMInt8TypeInContext(gallivm
->context
), 0, 0), resume_block
);