Skip to content

Commit 269e011

Browse files
committed
Store list types locally in warp scripts
1 parent a2e4ee1 commit 269e011

File tree

5 files changed

+81
-3
lines changed

5 files changed

+81
-3
lines changed

src/engine/internal/llvm/instructions/lists.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "../llvminstruction.h"
55
#include "../llvmbuildutils.h"
66
#include "../llvmconstantregister.h"
7+
#include "../llvmcompilercontext.h"
78

89
using namespace libscratchcpp;
910
using namespace libscratchcpp::llvmins;
@@ -72,6 +73,11 @@ LLVMInstruction *Lists::buildClearList(LLVMInstruction *ins)
7273
// Update size
7374
m_builder.CreateStore(m_builder.getInt64(0), listPtr.size);
7475
}
76+
77+
if (listPtr.type) {
78+
// Update type
79+
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(ValueType::Void)), listPtr.type);
80+
}
7581
}
7682

7783
return ins->next;
@@ -161,6 +167,7 @@ LLVMInstruction *Lists::buildAppendToList(LLVMInstruction *ins)
161167
m_builder.CreateStore(size, listPtr.size);
162168
}
163169

170+
createListTypeUpdate(listPtr, arg.second);
164171
return ins->next;
165172
}
166173

@@ -198,6 +205,7 @@ LLVMInstruction *Lists::buildInsertToList(LLVMInstruction *ins)
198205
m_builder.CreateStore(size, listPtr.size);
199206
}
200207

208+
createListTypeUpdate(listPtr, valueArg.second);
201209
m_builder.CreateBr(nextBlock);
202210

203211
m_builder.SetInsertPoint(nextBlock);
@@ -236,6 +244,7 @@ LLVMInstruction *Lists::buildListReplace(LLVMInstruction *ins)
236244
index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
237245
llvm::Value *itemPtr = m_utils.getListItem(listPtr, index);
238246
m_utils.createValueStore(valueArg.second, itemPtr, listType, type);
247+
createListTypeUpdate(listPtr, valueArg.second);
239248
m_builder.CreateBr(nextBlock);
240249

241250
m_builder.SetInsertPoint(nextBlock);
@@ -276,7 +285,29 @@ LLVMInstruction *Lists::buildGetListItem(LLVMInstruction *ins)
276285
llvm::Value *null = m_utils.createValue(static_cast<LLVMRegister *>(&nullReg));
277286

278287
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+
}
280311

281312
return ins->next;
282313
}
@@ -316,3 +347,21 @@ LLVMInstruction *Lists::buildListContainsItem(LLVMInstruction *ins)
316347

317348
return ins->next;
318349
}
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+
}

src/engine/internal/llvm/instructions/lists.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44

55
#include "instructiongroup.h"
66

7-
namespace libscratchcpp::llvmins
7+
namespace libscratchcpp
8+
{
9+
10+
class LLVMListPtr;
11+
class LLVMRegister;
12+
13+
namespace llvmins
814
{
915

1016
class Lists : public InstructionGroup
@@ -25,6 +31,10 @@ class Lists : public InstructionGroup
2531
LLVMInstruction *buildGetListSize(LLVMInstruction *ins);
2632
LLVMInstruction *buildGetListItemIndex(LLVMInstruction *ins);
2733
LLVMInstruction *buildListContainsItem(LLVMInstruction *ins);
34+
35+
void createListTypeUpdate(const LLVMListPtr &listPtr, const LLVMRegister *newValue);
2836
};
2937

30-
} // namespace libscratchcpp::llvmins
38+
} // namespace llvmins
39+
40+
} // namespace libscratchcpp

src/engine/internal/llvm/llvmbuildutils.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ static std::unordered_map<ValueType, Compiler::StaticType> TYPE_MAP = {
2121
{ ValueType::Pointer, Compiler::StaticType::Pointer }
2222
};
2323

24+
static std::unordered_map<Compiler::StaticType, ValueType> REVERSE_TYPE_MAP = {
25+
{ Compiler::StaticType::Number, ValueType::Number },
26+
{ Compiler::StaticType::Bool, ValueType::Bool },
27+
{ Compiler::StaticType::String, ValueType::String },
28+
{ Compiler::StaticType::Pointer, ValueType::Pointer }
29+
};
30+
2431
LLVMBuildUtils::LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &builder, Compiler::CodeType codeType) :
2532
m_ctx(ctx),
2633
m_llvmCtx(*ctx->llvmCtx()),
@@ -87,6 +94,10 @@ void LLVMBuildUtils::init(llvm::Function *function, BlockPrototype *procedurePro
8794

8895
llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
8996
m_builder.CreateStore(size, listPtr.size);
97+
98+
// Store list type locally to leave static type analysis to LLVM
99+
listPtr.type = m_builder.CreateAlloca(m_builder.getInt32Ty(), nullptr, list->name() + ".type");
100+
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(ValueType::Number | ValueType::Bool | ValueType::String)), listPtr.type);
90101
}
91102
}
92103

@@ -393,6 +404,12 @@ Compiler::StaticType LLVMBuildUtils::mapType(ValueType type)
393404
return TYPE_MAP[type];
394405
}
395406

407+
ValueType LLVMBuildUtils::mapType(Compiler::StaticType type)
408+
{
409+
assert(REVERSE_TYPE_MAP.find(type) != REVERSE_TYPE_MAP.cend());
410+
return REVERSE_TYPE_MAP[type];
411+
}
412+
396413
bool LLVMBuildUtils::isSingleType(Compiler::StaticType type)
397414
{
398415
// Check if the type is a power of 2 (only one bit set)

src/engine/internal/llvm/llvmbuildutils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class LLVMBuildUtils
7676

7777
static Compiler::StaticType optimizeRegisterType(const LLVMRegister *reg);
7878
static Compiler::StaticType mapType(ValueType type);
79+
static ValueType mapType(Compiler::StaticType type);
7980
static bool isSingleType(Compiler::StaticType type);
8081

8182
llvm::Value *addAlloca(llvm::Type *type);

src/engine/internal/llvm/llvmlistptr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct LLVMListPtr
2323
llvm::Value *sizePtr = nullptr;
2424
llvm::Value *allocatedSizePtr = nullptr;
2525
llvm::Value *size = nullptr;
26+
llvm::Value *type = nullptr;
2627
};
2728

2829
} // namespace libscratchcpp

0 commit comments

Comments
 (0)