|
4 | 4 | #include "../llvminstruction.h" |
5 | 5 | #include "../llvmbuildutils.h" |
6 | 6 | #include "../llvmconstantregister.h" |
| 7 | +#include "../llvmcompilercontext.h" |
7 | 8 |
|
8 | 9 | using namespace libscratchcpp; |
9 | 10 | using namespace libscratchcpp::llvmins; |
@@ -72,6 +73,11 @@ LLVMInstruction *Lists::buildClearList(LLVMInstruction *ins) |
72 | 73 | // Update size |
73 | 74 | m_builder.CreateStore(m_builder.getInt64(0), listPtr.size); |
74 | 75 | } |
| 76 | + |
| 77 | + if (listPtr.type) { |
| 78 | + // Update type |
| 79 | + m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(ValueType::Void)), listPtr.type); |
| 80 | + } |
75 | 81 | } |
76 | 82 |
|
77 | 83 | return ins->next; |
@@ -161,6 +167,7 @@ LLVMInstruction *Lists::buildAppendToList(LLVMInstruction *ins) |
161 | 167 | m_builder.CreateStore(size, listPtr.size); |
162 | 168 | } |
163 | 169 |
|
| 170 | + createListTypeUpdate(listPtr, arg.second); |
164 | 171 | return ins->next; |
165 | 172 | } |
166 | 173 |
|
@@ -198,6 +205,7 @@ LLVMInstruction *Lists::buildInsertToList(LLVMInstruction *ins) |
198 | 205 | m_builder.CreateStore(size, listPtr.size); |
199 | 206 | } |
200 | 207 |
|
| 208 | + createListTypeUpdate(listPtr, valueArg.second); |
201 | 209 | m_builder.CreateBr(nextBlock); |
202 | 210 |
|
203 | 211 | m_builder.SetInsertPoint(nextBlock); |
@@ -236,6 +244,7 @@ LLVMInstruction *Lists::buildListReplace(LLVMInstruction *ins) |
236 | 244 | index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty()); |
237 | 245 | llvm::Value *itemPtr = m_utils.getListItem(listPtr, index); |
238 | 246 | m_utils.createValueStore(valueArg.second, itemPtr, listType, type); |
| 247 | + createListTypeUpdate(listPtr, valueArg.second); |
239 | 248 | m_builder.CreateBr(nextBlock); |
240 | 249 |
|
241 | 250 | m_builder.SetInsertPoint(nextBlock); |
@@ -276,7 +285,29 @@ LLVMInstruction *Lists::buildGetListItem(LLVMInstruction *ins) |
276 | 285 | llvm::Value *null = m_utils.createValue(static_cast<LLVMRegister *>(&nullReg)); |
277 | 286 |
|
278 | 287 | index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty()); |
279 | | - ins->functionReturnReg->value = m_builder.CreateSelect(inRange, m_utils.getListItem(listPtr, index), null); |
| 288 | + llvm::Value *itemPtr = m_builder.CreateSelect(inRange, m_utils.getListItem(listPtr, index), null); |
| 289 | + |
| 290 | + ins->functionReturnReg->value = itemPtr; |
| 291 | + |
| 292 | + if (listPtr.type) { |
| 293 | + // Load the runtime list type information |
| 294 | + llvm::Value *listTypeFlags = m_builder.CreateLoad(m_builder.getInt32Ty(), listPtr.type); |
| 295 | + |
| 296 | + // The result is an empty string if index is out of range |
| 297 | + llvm::Value *withString = m_builder.CreateOr(listTypeFlags, m_builder.getInt32(static_cast<uint32_t>(ValueType::String))); |
| 298 | + listTypeFlags = m_builder.CreateSelect(inRange, listTypeFlags, withString); |
| 299 | + |
| 300 | + // Load the actual item type from ValueData |
| 301 | + llvm::Value *itemTypePtr = m_builder.CreateStructGEP(m_utils.compilerCtx()->valueDataType(), itemPtr, 1); |
| 302 | + llvm::Value *actualItemType = m_builder.CreateLoad(m_builder.getInt32Ty(), itemTypePtr); |
| 303 | + |
| 304 | + // Create assumption that the actual type is contained in the list type flags |
| 305 | + llvm::Value *typeIsValid = m_builder.CreateICmpEQ(m_builder.CreateAnd(listTypeFlags, actualItemType), actualItemType); |
| 306 | + |
| 307 | + // Tell LLVM to assume this is true |
| 308 | + llvm::Function *assumeIntrinsic = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::assume); |
| 309 | + m_builder.CreateCall(assumeIntrinsic, typeIsValid); |
| 310 | + } |
280 | 311 |
|
281 | 312 | return ins->next; |
282 | 313 | } |
@@ -316,3 +347,21 @@ LLVMInstruction *Lists::buildListContainsItem(LLVMInstruction *ins) |
316 | 347 |
|
317 | 348 | return ins->next; |
318 | 349 | } |
| 350 | + |
| 351 | +void Lists::createListTypeUpdate(const LLVMListPtr &listPtr, const LLVMRegister *newValue) |
| 352 | +{ |
| 353 | + if (listPtr.type) { |
| 354 | + // Update type |
| 355 | + llvm::Value *currentType = m_builder.CreateLoad(m_builder.getInt32Ty(), listPtr.type); |
| 356 | + llvm::Value *newTypeFlag; |
| 357 | + |
| 358 | + if (newValue->isRawValue) |
| 359 | + newTypeFlag = m_builder.getInt32(static_cast<uint32_t>(m_utils.mapType(newValue->type()))); |
| 360 | + else { |
| 361 | + llvm::Value *typeField = m_builder.CreateStructGEP(m_utils.compilerCtx()->valueDataType(), newValue->value, 1); |
| 362 | + newTypeFlag = m_builder.CreateLoad(m_builder.getInt32Ty(), typeField); |
| 363 | + } |
| 364 | + |
| 365 | + m_builder.CreateStore(m_builder.CreateOr(currentType, newTypeFlag), listPtr.type); |
| 366 | + } |
| 367 | +} |
0 commit comments