903 if (compilerCtx->getBuildConfig()->buildMode == IRBuildConfig::BuildMode::debug) {
909 auto* debugStrConst = llvm::ConstantDataArray::getString(*llvmModCtx.
TheContext, debugStr,
true);
910 auto* debugStrGlobal =
new llvm::GlobalVariable(*llvmModCtx.
TheModule, debugStrConst->getType(),
true, llvm::GlobalVariable::PrivateLinkage, debugStrConst,
"debug_str");
911 auto debugArgs = std::array<llvm::Value*, 1>{ debugStrGlobal };
912 llvmModCtx.
Builder->CreateCall(llvmModCtx.
runtimeFunctions.at(L
"runtime_debug_print"), llvm::ArrayRef<llvm::Value*>(debugArgs));
915 case IR::Opcode::push_integer: {
916 auto val = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), instr.
operands[0].value.integer,
true);
920 case IR::Opcode::push_decimal: {
921 auto val = llvm::ConstantFP::get(llvmModCtx.
Builder->getDoubleTy(), instr.
operands[0].value.decimal);
925 case IR::Opcode::push_boolean: {
926 auto val = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt1Ty(), instr.
operands[0].value.boolean);
930 case IR::Opcode::push_short: {
931 auto val = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt16Ty(), instr.
operands[0].value.shortV);
935 case IR::Opcode::push_unsigned: {
936 auto val = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), instr.
operands[0].value.unsignedV,
false);
940 case IR::Opcode::push_string: {
941 auto& str = yoiModule->stringLiteralPool.getStringLiteral(instr.
operands[1].value.stringLiteralIndex);
944 auto *globalStr = llvmModCtx.
Builder->CreateGlobalString(
wstring2string(str),
"global_string_literal");
948 case IR::Opcode::push_character: {
949 auto val = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt8Ty(), instr.
operands[0].value.character);
954 case IR::Opcode::basic_cast_char: {
956 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
957 llvm::Value* castedVal =
nullptr;
959 if (rawVal->getType()->isDoubleTy()) {
960 castedVal = llvmModCtx.
Builder->CreateFPToSI(rawVal, llvmModCtx.
Builder->getInt8Ty(),
"deci_to_char_cast");
961 }
else if (rawVal->getType()->isIntegerTy(1)) {
962 castedVal = llvmModCtx.
Builder->CreateTrunc(rawVal, llvmModCtx.
Builder->getInt8Ty(),
"bool_to_char_cast");
963 }
else if (rawVal->getType()->isIntegerTy(64)) {
964 castedVal = llvmModCtx.
Builder->CreateTrunc(rawVal, llvmModCtx.
Builder->getInt8Ty(),
"int_to_char_cast");
965 }
else if (rawVal->getType()->isIntegerTy(8)) {
972 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
975 case IR::Opcode::basic_cast_int: {
977 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
978 llvm::Value* castedVal =
nullptr;
980 if (rawVal->getType()->isDoubleTy()) {
981 castedVal = llvmModCtx.
Builder->CreateFPToSI(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"deci_to_int_cast");
982 }
else if (rawVal->getType()->isIntegerTy(1)) {
983 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"bool_to_int_cast");
984 }
else if (rawVal->getType()->isIntegerTy(8)) {
985 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"char_to_int_cast");
986 }
else if (rawVal->getType()->isIntegerTy(16)) {
987 castedVal = llvmModCtx.
Builder->CreateSExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"short_to_int_cast");
988 }
else if (rawVal->getType()->isIntegerTy(64)) {
991 panic(0, 0,
"LLVM Codegen: Unsupported type for basic_cast_int");
995 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
998 case IR::Opcode::basic_cast_deci: {
1000 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1001 llvm::Value* castedVal =
nullptr;
1003 if (rawVal->getType()->isIntegerTy(64)) {
1004 castedVal = llvmModCtx.
Builder->CreateSIToFP(rawVal, llvmModCtx.
Builder->getDoubleTy(),
"int_to_deci_cast");
1005 }
else if (rawVal->getType()->isIntegerTy(1)) {
1006 castedVal = llvmModCtx.
Builder->CreateUIToFP(rawVal, llvmModCtx.
Builder->getDoubleTy(),
"bool_to_deci_cast");
1007 }
else if (rawVal->getType()->isIntegerTy(8)) {
1008 castedVal = llvmModCtx.
Builder->CreateUIToFP(rawVal, llvmModCtx.
Builder->getDoubleTy(),
"char_to_deci_cast");
1009 }
else if (rawVal->getType()->isIntegerTy(16)) {
1010 castedVal = llvmModCtx.
Builder->CreateSIToFP(rawVal, llvmModCtx.
Builder->getDoubleTy(),
"short_to_deci_cast");
1011 }
else if (rawVal->getType()->isDoubleTy()) {
1014 panic(0, 0,
"LLVM Codegen: Unsupported type for basic_cast_deci");
1018 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1021 case IR::Opcode::basic_cast_unsigned: {
1023 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1024 llvm::Value* castedVal =
nullptr;
1026 if (rawVal->getType()->isIntegerTy(64)) {
1027 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"int_to_unsigned_cast");
1028 }
else if (rawVal->getType()->isDoubleTy()) {
1029 castedVal = llvmModCtx.
Builder->CreateFPToUI(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"deci_to_unsigned_cast");
1030 }
else if (rawVal->getType()->isIntegerTy(16)) {
1031 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"short_to_unsigned_cast");
1032 }
else if (rawVal->getType()->isIntegerTy(8)) {
1033 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"char_to_unsigned_cast");
1034 }
else if (rawVal->getType()->isIntegerTy(1)) {
1035 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"bool_to_unsigned_cast");
1037 panic(0, 0,
"LLVM Codegen: Unsupported type for basic_cast_unsigned");
1041 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1044 case IR::Opcode::basic_cast_short: {
1046 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1047 llvm::Value* castedVal =
nullptr;
1049 if (rawVal->getType()->isIntegerTy(64)) {
1050 castedVal = llvmModCtx.
Builder->CreateTrunc(rawVal, llvmModCtx.
Builder->getInt16Ty(),
"int_to_short_cast");
1051 }
else if (rawVal->getType()->isDoubleTy()) {
1052 castedVal = llvmModCtx.
Builder->CreateFPToSI(rawVal, llvmModCtx.
Builder->getInt16Ty(),
"deci_to_short_cast");
1053 }
else if (rawVal->getType()->isIntegerTy(8)) {
1054 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt16Ty(),
"char_to_short_cast");
1055 }
else if (rawVal->getType()->isIntegerTy(1)) {
1056 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt16Ty(),
"bool_to_short_cast");
1058 panic(0, 0,
"LLVM Codegen: Unsupported type for basic_cast_short");
1062 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1065 case IR::Opcode::basic_cast_bool: {
1067 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1068 llvm::Value* castedVal =
nullptr;
1070 if (rawVal->getType()->isIntegerTy(64)) {
1071 castedVal = llvmModCtx.
Builder->CreateICmpNE(rawVal, llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), 0),
"int_to_bool_cast");
1072 }
else if (rawVal->getType()->isDoubleTy()) {
1073 castedVal = llvmModCtx.
Builder->CreateFCmpONE(rawVal, llvm::ConstantFP::get(llvmModCtx.
Builder->getDoubleTy(), 0.0),
"deci_to_bool_cast");
1074 }
else if (rawVal->getType()->isIntegerTy(16)) {
1075 castedVal = llvmModCtx.
Builder->CreateICmpNE(rawVal, llvm::ConstantInt::get(llvmModCtx.
Builder->getInt8Ty(), 0),
"short_to_bool_cast");
1076 }
else if (rawVal->getType()->isIntegerTy(8)) {
1077 castedVal = llvmModCtx.
Builder->CreateICmpNE(rawVal, llvm::ConstantInt::get(llvmModCtx.
Builder->getInt8Ty(), 0),
"char_to_bool_cast");
1078 }
else if (rawVal->getType()->isIntegerTy(1)) {
1081 panic(0, 0,
"LLVM Codegen: Unsupported type for basic_cast_bool");
1085 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1089 case IR::Opcode::add: handleBinaryOp(llvmModCtx, llvm::Instruction::Add,
false, fromBlock, toBlock);
break;
1090 case IR::Opcode::sub: handleBinaryOp(llvmModCtx, llvm::Instruction::Sub,
false, fromBlock, toBlock);
break;
1091 case IR::Opcode::mul: handleBinaryOp(llvmModCtx, llvm::Instruction::Mul,
false, fromBlock, toBlock);
break;
1092 case IR::Opcode::div: handleBinaryOp(llvmModCtx, llvm::Instruction::SDiv,
false, fromBlock, toBlock);
break;
1093 case IR::Opcode::mod: handleBinaryOp(llvmModCtx, llvm::Instruction::SRem,
false, fromBlock, toBlock);
break;
1094 case IR::Opcode::bitwise_and: handleBinaryOp(llvmModCtx, llvm::Instruction::And,
false, fromBlock, toBlock);
break;
1095 case IR::Opcode::bitwise_or: handleBinaryOp(llvmModCtx, llvm::Instruction::Or,
false, fromBlock, toBlock);
break;
1096 case IR::Opcode::bitwise_xor: handleBinaryOp(llvmModCtx, llvm::Instruction::Xor,
false, fromBlock, toBlock);
break;
1097 case IR::Opcode::left_shift: handleBinaryOp(llvmModCtx, llvm::Instruction::Shl,
false, fromBlock, toBlock);
break;
1098 case IR::Opcode::right_shift: handleBinaryOp(llvmModCtx, llvm::Instruction::LShr,
false, fromBlock, toBlock);
break;
1100 case IR::Opcode::negate: {
1102 auto* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1103 auto* negatedRaw = rawVal->getType()->isDoubleTy() ? llvmModCtx.
Builder->CreateFNeg(rawVal,
"negtmp") : llvmModCtx.
Builder->CreateNeg(rawVal,
"negtmp");
1106 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1109 case IR::Opcode::bitwise_not: {
1111 auto* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1112 auto* notRaw = llvmModCtx.
Builder->CreateNot(rawVal,
"nottmp");
1115 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1120 case IR::Opcode::equal: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_EQ,
false, fromBlock, toBlock);
break;
1121 case IR::Opcode::not_equal: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_NE,
false, fromBlock, toBlock);
break;
1122 case IR::Opcode::less_than: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_SLT,
false, fromBlock, toBlock);
break;
1123 case IR::Opcode::less_equal: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_SLE,
false, fromBlock, toBlock);
break;
1124 case IR::Opcode::greater_than: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_SGT,
false, fromBlock, toBlock);
break;
1125 case IR::Opcode::greater_equal: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_SGE,
false, fromBlock, toBlock);
break;
1128 case IR::Opcode::load_local: {
1129 auto varIndex = instr.
operands[0].value.symbolIndex;
1130 auto* alloca = llvmModCtx.
namedValues.at(varIndex);
1132 if (yoiType->type == IRValueType::valueType::datastructObject && yoiType->hasAttribute(IRValueType::ValueAttr::Raw)) {
1135 auto loadedPtr = llvmModCtx.
Builder->CreateLoad(yoiTypeToLLVMType(llvmModCtx, yoiType, yoiType->isBasicRawType() || yoiType->hasAttribute(IRValueType::ValueAttr::Raw)), alloca,
"loadtmp");
1136 callGcFunction(llvmModCtx, loadedPtr, yoiType,
true);
1141 case IR::Opcode::store_local: {
1142 auto varIndex = instr.
operands[0].value.symbolIndex;
1143 auto* alloca = llvmModCtx.
namedValues.at(varIndex);
1147 valToStore = yoiType->metadata.hasMetadata(L
"regressed_interface_impl") ? valToStore : promiseInterfaceObjectIfInterface(llvmModCtx, valToStore);
1150 auto* oldPtr = llvmModCtx.
Builder->CreateLoad(alloca->getAllocatedType(), alloca,
"old_ptr_for_store");
1151 if (yoiType->hasAttribute(IRValueType::ValueAttr::Nullable))
1152 callGcFunction(llvmModCtx, oldPtr, yoiType,
false,
true);
1154 generateIfTargetNotNull(llvmModCtx, oldPtr, yoiType, [&] () {
1155 callGcFunction(llvmModCtx, oldPtr, yoiType,
false,
true);
1156 }, !yoiType->hasAttribute(IRValueType::ValueAttr::Raw));
1158 if (llvmModCtx.
currentFunctionDef->variableTable.get(varIndex)->hasAttribute(IRValueType::ValueAttr::Raw)) {
1159 auto unboxedVal = unboxValue(llvmModCtx, valToStore.llvmValue, valToStore.yoiType);
1160 if (yoiType->type == IRValueType::valueType::datastructObject && yoiType->hasAttribute(IRValueType::ValueAttr::Raw)) {
1162 auto fieldType = yoiTypeToLLVMType(llvmModCtx, yoiType,
true);
1163 auto fieldSize = llvmModCtx.
TheModule->getDataLayout().getTypeAllocSize(fieldType);
1164 llvmModCtx.
Builder->CreateMemCpy(alloca, llvm::MaybeAlign(8), unboxedVal, llvm::MaybeAlign(8), fieldSize);
1166 llvmModCtx.
Builder->CreateStore(unboxedVal, alloca);
1169 auto object = ensureObject(llvmModCtx, valToStore.yoiType, valToStore.llvmValue);
1170 if (
object.first->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1171 callGcFunction(llvmModCtx,
object.second, valToStore.yoiType,
true,
true,
true);
1172 llvmModCtx.
Builder->CreateStore(
object.second, alloca);
1177 case IR::Opcode::load_global: {
1178 auto varIndex = instr.
operands[1].value.symbolIndex;
1180 auto yoiType = yoiModule ->globalVariables[varIndex];
1181 yoiType->addAttribute(IRValueType::ValueAttr::Nullable).addAttribute(IRValueType::ValueAttr::PermanentInCurrentScope);
1182 auto loadedPtr = llvmModCtx.
Builder->CreateLoad(global->getValueType(), global,
"loadglobaltmp");
1186 case IR::Opcode::store_global: {
1187 auto varIndex = instr.
operands[1].value.symbolIndex;
1189 auto yoiType = yoiModule->globalVariables[varIndex];
1192 valToStore = promiseInterfaceObjectIfInterface(llvmModCtx, valToStore);
1194 yoiType->addAttribute(IRValueType::ValueAttr::Nullable);
1196 auto* oldPtr = llvmModCtx.
Builder->CreateLoad(global->getValueType(), global,
"old_global_ptr");
1197 callGcFunction(llvmModCtx, oldPtr, yoiType,
false,
true);
1199 auto object = ensureObject(llvmModCtx, valToStore.yoiType, valToStore.llvmValue);
1200 if (
object.first->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1201 callGcFunction(llvmModCtx,
object.second, valToStore.yoiType,
true,
true,
true);
1203 llvmModCtx.
Builder->CreateStore(
object.second, global);
1206 case IR::Opcode::load_member: {
1208 auto memberIndex = instr.
operands[0].value.symbolIndex;
1209 auto llvmMemberIndex = memberIndex + 2;
1211 auto key = std::make_tuple(IRValueType::valueType::structObject, structVal.yoiType->typeAffiliateModule, structVal.yoiType->typeIndex);
1213 auto* gep = llvmModCtx.
Builder->CreateStructGEP(llvmStructType, structVal.llvmValue, llvmMemberIndex,
"memberptr");
1215 auto yoiStructDef = compilerCtx->getIRObjectFile()->compiledModule->structTable[std::get<2>(key)];
1216 auto memberYoiType = yoiStructDef->fieldTypes[memberIndex];
1217 if (structVal.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1223 llvm::Type* loadedType = yoiTypeToLLVMType(llvmModCtx, memberYoiType, memberYoiType->isBasicType() && memberYoiType->hasAttribute(IRValueType::ValueAttr::Raw));
1224 auto* loadedMember =
1225 memberYoiType->type == IRValueType::valueType::datastructObject
1227 : llvmModCtx.
Builder->CreateLoad(loadedType, gep,
"loadmember");
1228 callGcFunction(llvmModCtx, loadedMember, memberYoiType,
true);
1231 callGcFunction(llvmModCtx, structVal.llvmValue, structVal.yoiType,
false);
1234 case IR::Opcode::store_member: {
1238 auto memberIndex = instr.
operands[0].value.symbolIndex;
1239 storeMember(llvmModCtx, valueToStore, structVal, memberIndex);
1241 callGcFunction(llvmModCtx, structVal.llvmValue, structVal.yoiType,
false);
1245 case IR::Opcode::jump: {
1249 case IR::Opcode::jump_if_true:
1250 case IR::Opcode::jump_if_false: {
1252 auto* condRaw = unboxValue(llvmModCtx, condObj.llvmValue, condObj.yoiType);
1253 callGcFunction(llvmModCtx, condObj.llvmValue, condObj.yoiType,
false);
1258 if (instr.
opcode == IR::Opcode::jump_if_true) {
1259 llvmModCtx.
Builder->CreateCondBr(condRaw, destBlock, nextBlock);
1261 llvmModCtx.
Builder->CreateCondBr(condRaw, nextBlock, destBlock);
1263 llvmModCtx.
Builder->SetInsertPoint(nextBlock);
1267 case IR::Opcode::ret: {
1270 if (compilerCtx->getBuildConfig()->buildMode == IRBuildConfig::BuildMode::debug) {
1272 auto* debugStrConst = llvm::ConstantDataArray::getString(*llvmModCtx.
TheContext, funcName,
true);
1273 auto* debugStrGlobal =
new llvm::GlobalVariable(*llvmModCtx.
TheModule, debugStrConst->getType(),
true, llvm::GlobalVariable::PrivateLinkage, debugStrConst,
"debug_str");
1274 auto debugArgs = std::array<llvm::Value*, 1>{ debugStrGlobal };
1275 llvmModCtx.
Builder->CreateCall(llvmModCtx.
runtimeFunctions.at(L
"runtime_debug_report_leave_function"), llvm::ArrayRef<llvm::Value*>(debugArgs));
1278 retVal = promiseInterfaceObjectIfInterface(llvmModCtx, retVal);
1281 if (llvmModCtx.
currentFunctionDef->returnType->hasAttribute(IRValueType::ValueAttr::Raw)) {
1282 auto res = unboxValue(llvmModCtx, retVal.llvmValue, retVal.yoiType);
1284 callGcFunction(llvmModCtx, retVal.llvmValue, retVal.yoiType,
false);
1285 generateFunctionExitCleanup(llvmModCtx);
1286 llvmModCtx.
Builder->CreateRet(res);
1288 auto object = ensureObject(llvmModCtx, retVal.yoiType, retVal.llvmValue);
1289 if (
object.first->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1290 callGcFunction(llvmModCtx,
object.second, retVal.yoiType,
true,
true,
true);
1291 generateFunctionExitCleanup(llvmModCtx);
1292 llvmModCtx.
Builder->CreateRet(
object.second);
1296 case IR::Opcode::ret_none: {
1297 generateFunctionExitCleanup(llvmModCtx);
1299 if (compilerCtx->getBuildConfig()->buildMode == IRBuildConfig::BuildMode::debug) {
1301 auto* debugStrConst = llvm::ConstantDataArray::getString(*llvmModCtx.
TheContext, funcName,
true);
1302 auto* debugStrGlobal =
new llvm::GlobalVariable(*llvmModCtx.
TheModule, debugStrConst->getType(),
true, llvm::GlobalVariable::PrivateLinkage, debugStrConst,
"debug_str");
1303 auto debugArgs = std::array<llvm::Value*, 1>{ debugStrGlobal };
1304 llvmModCtx.
Builder->CreateCall(llvmModCtx.
runtimeFunctions.at(L
"runtime_debug_report_leave_function"), llvm::ArrayRef<llvm::Value*>(debugArgs));
1307 llvmModCtx.
Builder->CreateRetVoid();
1311 case IR::Opcode::invoke: {
1312 auto moduleIndex = instr.
operands[0].value.symbolIndex;
1313 auto funcIndex = instr.
operands[1].value.symbolIndex;
1314 auto argCount = instr.
operands[2].value.symbolIndex;
1316 auto funcDef = yoiModule->functionTable[funcIndex];
1317 auto* function = llvmModCtx.
functionMap.at(funcDef->name);
1319 std::vector<llvm::Value*> args;
1320 std::vector<std::pair<std::shared_ptr<IRValueType>, llvm::Value*>> postCleanup;
1322 for(
size_t i = 0; i < argCount; ++i) {
1326 arg = promiseInterfaceObjectIfInterface(llvmModCtx, arg);
1328 if (funcDef->argumentTypes[argCount - i - 1]->hasAttribute(IRValueType::ValueAttr::Raw)) {
1330 loadIfDataStructObject(llvmModCtx, funcDef->argumentTypes[argCount - i - 1],
1331 unboxValue(llvmModCtx, arg.llvmValue, arg.yoiType)));
1332 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
false);
1333 }
else if (funcDef->argumentTypes[argCount - i - 1]->hasAttribute(IRValueType::ValueAttr::Borrow)) {
1334 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1335 args.push_back(
object.second);
1336 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw));
1337 else postCleanup.push_back(
object);
1339 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1340 args.push_back(
object.second);
1341 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw))
1342 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
true,
true);
1346 std::reverse(args.begin(), args.end());
1348 if (funcDef->returnType->type == IRValueType::valueType::none) {
1349 llvmModCtx.
Builder->CreateCall(function, args);
1351 auto* call = llvmModCtx.
Builder->CreateCall(function, args,
"calltmp");
1356 for (
auto &i : postCleanup) {
1357 callGcFunction(llvmModCtx, i.second, i.first,
false);
1361 case IR::Opcode::invoke_dangling: {
1362 auto moduleIndex = instr.
operands[0].value.symbolIndex;
1363 auto funcIndex = instr.
operands[1].value.symbolIndex;
1364 auto argCount = instr.
operands[2].value.symbolIndex;
1368 auto funcDef = yoiModule->functionTable[funcIndex];
1369 auto* function = llvmModCtx.
functionMap.at(funcDef->name);
1371 std::vector<llvm::Value*> args;
1372 std::vector<std::pair<std::shared_ptr<IRValueType>, llvm::Value*>> postCleanup;
1374 llvm::Value *postponed =
nullptr;
1379 arg = promiseInterfaceObjectIfInterface(llvmModCtx, arg);
1381 if (funcDef->argumentTypes[0]->hasAttribute(IRValueType::ValueAttr::Raw)) {
1382 postponed = loadIfDataStructObject(llvmModCtx, funcDef->argumentTypes[0], unboxValue(llvmModCtx, arg.llvmValue, arg.yoiType));
1383 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
false);
1384 }
else if (funcDef->argumentTypes[0]->hasAttribute(IRValueType::ValueAttr::Borrow)) {
1385 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1386 postponed =
object.second;
1387 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw));
1388 else postCleanup.push_back(
object);
1390 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1391 postponed =
object.second;
1392 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw))
1393 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
true,
true);
1398 for(
size_t i = 1; i < argCount; ++i) {
1402 arg = promiseInterfaceObjectIfInterface(llvmModCtx, arg);
1404 if (funcDef->argumentTypes[argCount - i]->hasAttribute(IRValueType::ValueAttr::Raw)) {
1405 args.push_back(loadIfDataStructObject(llvmModCtx, funcDef->argumentTypes[argCount - i], unboxValue(llvmModCtx, arg.llvmValue, arg.yoiType)));
1406 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
false);
1407 }
else if (funcDef->argumentTypes[argCount - i]->hasAttribute(IRValueType::ValueAttr::Borrow)) {
1408 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1409 args.push_back(
object.second);
1410 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw));
1411 else postCleanup.push_back(
object);
1413 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1414 args.push_back(
object.second);
1415 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw))
1416 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
true,
true);
1421 args.push_back(postponed);
1423 std::reverse(args.begin(), args.end());
1425 if (funcDef->returnType->type == IRValueType::valueType::none) {
1426 llvmModCtx.
Builder->CreateCall(function, args);
1428 auto* call = llvmModCtx.
Builder->CreateCall(function, args,
"calltmp");
1433 for (
auto &i : postCleanup) {
1434 callGcFunction(llvmModCtx, i.second, i.first,
false);
1438 case IR::Opcode::invoke_imported: {
1439 auto libIndex = instr.
operands[0].value.symbolIndex;
1440 auto funcIndex = instr.
operands[1].value.symbolIndex;
1441 auto argCount = instr.
operands[2].value.symbolIndex;
1443 auto funcDef = compilerCtx->getIRFFITable()->importedLibraries[libIndex].importedFunctionTable[funcIndex];
1445 if (funcDef->hasAttribute(IRFunctionDefinition::FunctionAttrs::Intrinsic)) {
1446 handleIntrinsicCall(llvmModCtx, instr);
1450 bool noffi = funcDef->hasAttribute(IRFunctionDefinition::FunctionAttrs::NoFFI);
1452 auto rawFuncName = compilerCtx->getIRFFITable()->importedLibraries[libIndex].importedFunctionTable.getKey(funcIndex);
1453 auto mangledFuncName = L
"imported#" + std::to_wstring(libIndex) + L
"#" + rawFuncName;
1454 if (!noffi) mangledFuncName += L
"#wrapper";
1456 auto* function = llvmModCtx.
functionMap.at(mangledFuncName);
1458 std::vector<std::pair<std::shared_ptr<IRValueType>, llvm::Value*>> postCleanup;
1459 std::vector<llvm::Value*> args;
1461 for(
size_t i = 0; i < argCount; ++i) {
1464 arg = promiseInterfaceObjectIfInterface(llvmModCtx, arg);
1466 if ((arg.yoiType->isBasicType() || arg.yoiType->isBasicRawType()) && !noffi) {
1467 auto *param = unboxValue(llvmModCtx, arg.llvmValue, arg.yoiType);
1468 if (arg.yoiType->type == IRValueType::valueType::stringObject || arg.yoiType->type == IRValueType::valueType::stringLiteral) {
1471 param = llvmModCtx.
Builder->CreatePtrToInt(param, llvm::Type::getInt64Ty(*llvmModCtx.
TheContext),
"string_to_int");
1474 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
false);
1475 args.push_back(param);
1477 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1478 postCleanup.push_back(
object);
1479 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && noffi)
1480 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
true,
true,
true);
1481 args.push_back(postCleanup.back().second);
1486 std::reverse(args.begin(), args.end());
1488 if (funcDef->returnType->type == IRValueType::valueType::none) {
1489 llvmModCtx.
Builder->CreateCall(function, args);
1491 auto* call = llvmModCtx.
Builder->CreateCall(function, args,
"calltmp");
1494 auto onstackType = noffi ? *funcDef->returnType : compilerCtx->normalizeForeignBasicType(funcDef->returnType);
1496 if (noffi && (funcDef->returnType->type == IRValueType::valueType::structObject ||
1497 funcDef->returnType->type == IRValueType::valueType::interfaceObject)) {
1499 auto notNullBlock = llvm::BasicBlock::Create(*llvmModCtx.
TheContext,
"audit_typeid_not_null", llvmModCtx.
currentFunction);
1500 auto continueBlock = llvm::BasicBlock::Create(*llvmModCtx.
TheContext,
"audit_typeid_continue", llvmModCtx.
currentFunction);
1501 llvmModCtx.
Builder->CreateCondBr(llvmModCtx.
Builder->CreateIsNotNull(call,
"audit_typeid_isnotnull"), notNullBlock, continueBlock);
1502 llvmModCtx.
Builder->SetInsertPoint(notNullBlock);
1503 auto typeIdKey = std::make_tuple(IRValueType::valueType::structObject,
1505 funcDef->returnType->typeIndex,
1507 auto structKey = std::make_tuple(IRValueType::valueType::structObject,
1509 funcDef->returnType->typeIndex);
1510 auto typeId = llvmModCtx.
typeIDMap[typeIdKey];
1512 auto *typeIdPtr = llvmModCtx.
Builder->CreateStructGEP(llvmStruct, call, 1,
"typeid_ptr");
1513 llvmModCtx.
Builder->CreateStore(llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), typeId), typeIdPtr);
1514 llvmModCtx.
Builder->CreateBr(continueBlock);
1515 llvmModCtx.
Builder->SetInsertPoint(continueBlock);
1522 for (
auto &i : postCleanup) {
1523 callGcFunction(llvmModCtx, i.second, i.first,
false);
1528 case IR::Opcode::new_struct: {
1529 auto moduleIndex = instr.
operands[0].value.symbolIndex;
1530 auto structIndex = instr.
operands[1].value.symbolIndex;
1532 auto bitcast = createStructObject(llvmModCtx, moduleIndex, structIndex);
1534 auto yoiType = std::make_shared<IRValueType>(IRValueType::valueType::structObject, yoiModule->identifier, structIndex);
1538 case IR::Opcode::new_datastruct: {
1540 auto moduleIndex = instr.
operands[0].value.symbolIndex;
1541 auto dataStructIndex = instr.
operands[1].value.symbolIndex;
1542 auto key = std::make_tuple(IRValueType::valueType::datastructObject, yoiModule->identifier, dataStructIndex);
1546 auto* allocCall = llvmModCtx.
Builder->CreateAlloca(dataRegionType,
nullptr,
"datastruct_alloc");
1548 auto yoiType = std::make_shared<IRValueType>(IRValueType::valueType::datastructObject, yoiModule->identifier, dataStructIndex);
1549 yoiType->addAttribute(IRValueType::ValueAttr::Raw);
1553 case IR::Opcode::initialize_field: {
1561 llvm::Value *dataRegionPtr = top.llvmValue;
1562 if (top.yoiType->hasAttribute(IRValueType::ValueAttr::Raw)) {
1563 dataRegionPtr = top.llvmValue;
1565 auto objectTypeKey = std::make_tuple(IRValueType::valueType::datastructObject, yoiModule->identifier, top.yoiType->typeIndex);
1566 auto *objectType = llvmModCtx.
structTypeMap.at(objectTypeKey);
1567 dataRegionPtr = llvmModCtx.
Builder->CreateStructGEP(objectType, top.llvmValue, 2,
"datastruct_ptr");
1570 auto value = unboxValue(llvmModCtx, values[i].llvmValue, values[i].yoiType);
1571 auto fieldPtr = llvmModCtx.
Builder->CreateStructGEP(dataRegionType, dataRegionPtr, i,
"field_ptr");
1572 auto fieldType = dataRegionType->getStructElementType(i);
1573 if (fieldType->isStructTy()) {
1575 auto size = llvmModCtx.
TheModule->getDataLayout().getTypeAllocSize(fieldType);
1576 auto *sizeVal = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), size);
1577 auto *memCpy = llvmModCtx.
Builder->CreateMemCpy(fieldPtr, llvm::MaybeAlign(8), value, llvm::MaybeAlign(8), sizeVal);
1579 llvmModCtx.
Builder->CreateStore(value, fieldPtr);
1581 callGcFunction(llvmModCtx, values[i].llvmValue, values[i].yoiType,
false);
1586 case IR::Opcode::store_field: {
1593 auto currentType = srcValue.yoiType;
1594 auto val = unboxValue(llvmModCtx, srcValue.llvmValue, srcValue.yoiType);
1595 auto llvmType = yoiTypeToLLVMType(llvmModCtx, currentType,
true);
1597 auto destType = destValue.yoiType;
1598 auto destVal = unboxValue(llvmModCtx, destValue.llvmValue, destValue.yoiType);
1599 llvm::Value *fieldPtr =
nullptr;
1601 for (
auto &operand : instr.
operands) {
1602 auto def = yoiModule->dataStructTable[destType->typeIndex];
1603 auto nextType = def->fieldTypes[operand.value.symbolIndex];
1605 fieldPtr = llvmModCtx.
Builder->CreateStructGEP(llvmType, destVal, operand.value.symbolIndex,
"field_ptr");
1607 destType = nextType;
1610 if (destType->type == IRValueType::valueType::datastructObject) {
1612 auto size = llvmModCtx.
TheModule->getDataLayout().getTypeAllocSize(llvmType);
1613 auto *sizeVal = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), size);
1614 auto *memCpy = llvmModCtx.
Builder->CreateMemCpy(fieldPtr, llvm::MaybeAlign(8), val, llvm::MaybeAlign(8), sizeVal);
1616 llvmModCtx.
Builder->CreateStore(val, fieldPtr);
1619 callGcFunction(llvmModCtx, srcValue.llvmValue, srcValue.yoiType,
false);
1622 case IR::Opcode::load_field: {
1625 auto currentType = top.yoiType;
1626 auto val = unboxValue(llvmModCtx, top.llvmValue, top.yoiType);
1627 for (
auto &operand : instr.
operands) {
1628 auto def = yoiModule->dataStructTable[currentType->typeIndex];
1629 auto nextType = def->fieldTypes[operand.value.symbolIndex];
1631 val = llvmModCtx.
Builder->CreateStructGEP(llvmType, val, operand.value.symbolIndex,
"field_ptr");
1632 currentType = nextType;
1634 if (currentType->isArrayType()) {
1635 auto arrayVal = createArrayObject(llvmModCtx,
managedPtr(currentType->getElementType()), {});
1636 auto llvmType = getArrayLLVMType(llvmModCtx, currentType);
1642 auto dataRegionPtr = llvmModCtx.
Builder->CreateStructGEP(llvmType, val, 3,
"data_region_ptr");
1643 auto dataSize = llvmModCtx.
TheModule->getDataLayout().getTypeAllocSize(llvmType->getStructElementType(3));
1645 llvmModCtx.
Builder->CreateMemCpy(val, llvm::MaybeAlign(8), dataRegionPtr, llvm::MaybeAlign(8), dataSize);
1648 }
else if (currentType->isBasicType()) {
1649 val = llvmModCtx.
Builder->CreateLoad(yoiTypeToLLVMType(llvmModCtx, currentType,
true), val,
"field_val");
1651 currentType->addAttribute(IRValueType::ValueAttr::Raw);
1652 }
else if (currentType->type == IRValueType::valueType::datastructObject) {
1655 currentType->addAttribute(IRValueType::ValueAttr::Raw);
1662 case IR::Opcode::construct_interface_impl: {
1663 auto interfaceImplIndex = instr.
operands[1].value.symbolIndex;
1664 auto interfaceImplDef = yoiModule->interfaceImplementationTable[interfaceImplIndex];
1666 top = promiseInterfaceObjectIfInterface(llvmModCtx, top);
1667 auto object = ensureObject(llvmModCtx, top.yoiType, top.llvmValue);
1668 top.yoiType =
object.first;
1669 top.llvmValue =
object.second;
1673 top.yoiType->type = IRValueType::valueType::interfaceObject;
1675 top.yoiType->typeIndex = interfaceImplDef->implInterfaceIndex.second;
1676 top.yoiType->metadata.setMetadata(L
"regressed_interface_impl", std::pair<yoi::indexT, yoi::indexT>{
ENTRY_MODULE_ID_CONST, interfaceImplIndex});
1679 case IR::Opcode::bind_elements_post:
1680 case IR::Opcode::bind_elements_pred: {
1686 auto arrayLLVMType = getArrayLLVMType(llvmModCtx, array.yoiType);
1688 auto *arrayLen = llvmModCtx.
Builder->CreateStructGEP(arrayLLVMType, array.llvmValue, 2,
"array_len");
1689 auto *loadedArrayLen = llvmModCtx.
Builder->CreateLoad(llvmModCtx.
Builder->getInt64Ty(), arrayLen,
"loaded_array_len");
1691 auto startPos = instr.
opcode == IR::Opcode::bind_elements_post ? llvmModCtx.
Builder->getInt64(0) : llvmModCtx.
Builder->CreateSub(loadedArrayLen, llvmModCtx.
Builder->getInt64(instr.
operands[0].value.symbolIndex),
"start_pos");
1694 auto currentPos = llvmModCtx.
Builder->CreateAdd(startPos, llvmModCtx.
Builder->getInt64(i),
"current_pos");
1695 auto currentValue = loadArrayElement(llvmModCtx, array.yoiType, array.llvmValue, currentPos);
1696 std::shared_ptr<IRValueType> elementType;
1697 if (array.yoiType->isBasicType()) {
1698 elementType =
managedPtr(array.yoiType->getElementType().getBasicRawType());
1699 }
else if (array.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope)) {
1700 elementType =
managedPtr(array.yoiType->getElementType().addAttribute(IRValueType::ValueAttr::PermanentInCurrentScope).addAttribute(IRValueType::ValueAttr::Nullable));
1702 elementType =
managedPtr(array.yoiType->getElementType().addAttribute(IRValueType::ValueAttr::Nullable));
1707 callGcFunction(llvmModCtx, array.llvmValue, array.yoiType,
false);
1710 case IR::Opcode::bind_fields_post:
1711 case IR::Opcode::bind_fields_pred: {
1716 auto structDef = yoiModule->structTable[structVal.yoiType->typeIndex];
1718 auto startPos = instr.
opcode == IR::Opcode::bind_fields_post ? 0 : structDef->fieldTypes.size() - instr.
operands[0].value.symbolIndex;
1719 for (
yoi::indexT memberIndex = startPos; memberIndex < startPos + instr.
operands[0].value.symbolIndex; memberIndex++) {
1720 auto llvmMemberIndex = memberIndex + 2;
1722 auto key = std::make_tuple(IRValueType::valueType::structObject, structVal.yoiType->typeAffiliateModule, structVal.yoiType->typeIndex);
1724 auto* gep = llvmModCtx.
Builder->CreateStructGEP(llvmStructType, structVal.llvmValue, llvmMemberIndex,
"memberptr");
1726 auto yoiStructDef = compilerCtx->getIRObjectFile()->compiledModule->structTable[std::get<2>(key)];
1727 auto memberYoiType = yoiStructDef->fieldTypes[memberIndex];
1728 if (structVal.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1730 memberYoiType->addAttribute(IRValueType::ValueAttr::Nullable);
1731 memberYoiType->removeAttribute(IRValueType::ValueAttr::Raw);
1733 llvm::Type* loadedType = yoiTypeToLLVMType(llvmModCtx, memberYoiType);
1734 auto* loadedMember = llvmModCtx.
Builder->CreateLoad(loadedType, gep,
"loadmember");
1735 callGcFunction(llvmModCtx, loadedMember, memberYoiType,
true);
1739 callGcFunction(llvmModCtx, structVal.llvmValue, structVal.yoiType,
false);
1742 case IR::Opcode::invoke_virtual: {
1743 auto methodVTableIndex = instr.
operands[2].value.symbolIndex;
1744 auto userArgCount = instr.
operands[3].value.symbolIndex;
1746 std::vector<StackValue> userArgs;
1747 std::vector<std::pair<std::shared_ptr<IRValueType>, llvm::Value*>> postCleanup;
1749 for (
size_t i = 0; i < userArgCount - 1; ++i) {
1750 userArgs.push_back(promiseInterfaceObjectIfInterface(llvmModCtx, llvmModCtx.
valueStackPhi.
back()));
1753 std::reverse(userArgs.begin(), userArgs.end());
1758 auto interfaceKey = std::make_tuple(IRValueType::valueType::interfaceObject, interfaceShellVal.yoiType->typeAffiliateModule, interfaceShellVal.yoiType->typeIndex);
1759 auto* interfaceLLVMType = llvmModCtx.
structTypeMap.at(interfaceKey);
1760 auto interfaceDef = yoiModule->interfaceTable[std::get<2>(interfaceKey)];
1763 auto concreteThisPtrRaw = unwrapInterfaceObject(llvmModCtx, interfaceShellVal);
1764 auto* bitcastedPointer = llvmModCtx.
Builder->CreateBitCast(concreteThisPtrRaw, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"casted_this");
1774 std::vector<llvm::Value*> finalArgs;
1775 finalArgs.push_back(concreteThisPtrRaw);
1776 for(
yoi::indexT paramIndex = 0; paramIndex < userArgs.size(); ++paramIndex) {
1777 const auto& arg = userArgs[paramIndex];
1778 auto paramDef = interfaceDef->methodMap[methodVTableIndex]->argumentTypes[paramIndex];
1779 auto object = (paramDef->hasAttribute(IRValueType::ValueAttr::Nullable) || (!paramDef->isBasicType() && !paramDef->isBasicRawType()) || !paramDef->dimensions.empty())
1780 ? ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue)
1781 : std::pair{
managedPtr(arg.yoiType->getBasicRawType()), loadIfDataStructObject(llvmModCtx, paramDef, unboxValue(llvmModCtx, arg.llvmValue, arg.yoiType))};
1782 finalArgs.push_back(
object.second);
1784 if (
object.first->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !
object.first->hasAttribute(IRValueType::ValueAttr::Raw));
1786 else postCleanup.emplace_back(
object);
1789 std::shared_ptr<IRFunctionDefinition> methodDef;
1790 llvm::Value *funcPtrToCall =
nullptr;
1791 llvm::FunctionType *virtualFuncType =
nullptr;
1792 if (interfaceShellVal.yoiType->metadata.hasMetadata(L
"regressed_interface_impl")) {
1793 auto interfaceImplIndex = interfaceShellVal.yoiType->metadata.getMetadata<std::pair<yoi::indexT, yoi::indexT>>(L
"regressed_interface_impl");
1794 auto interfaceImplDef = yoiModule->interfaceImplementationTable[interfaceImplIndex.second];
1795 methodDef = yoiModule->functionTable[interfaceImplDef->virtualMethods[methodVTableIndex]->typeIndex];
1796 funcPtrToCall = llvmModCtx.
functionMap[methodDef->name];
1797 virtualFuncType = llvmModCtx.
functionMap[methodDef->name]->getFunctionType();
1799 auto vtableSlotIndex = methodVTableIndex + 5;
1800 auto* vtableSlotPtr = llvmModCtx.
Builder->CreateStructGEP(interfaceLLVMType, interfaceShellVal.llvmValue, vtableSlotIndex,
"vtable_slot_ptr");
1802 auto interfaceDef = compilerCtx->getIRObjectFile()->compiledModule->interfaceTable[std::get<2>(interfaceKey)];
1803 methodDef = interfaceDef->methodMap[methodVTableIndex];
1804 auto* funcType = getFunctionType(llvmModCtx, methodDef);
1806 std::vector<llvm::Type*> virtualArgTypes;
1807 virtualArgTypes.push_back(llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
1808 for (
size_t i = 0; i < funcType->getNumParams(); ++i) {
1809 virtualArgTypes.push_back(funcType->getParamType(i));
1811 virtualFuncType = llvm::FunctionType::get(funcType->getReturnType(), virtualArgTypes,
false);
1812 auto* virtualFuncPtrType = llvm::PointerType::get(*llvmModCtx.
TheContext, 0);
1813 funcPtrToCall = llvmModCtx.
Builder->CreateLoad(virtualFuncPtrType, vtableSlotPtr,
"func_ptr");
1816 if (methodDef->returnType->type == IRValueType::valueType::none) {
1817 llvmModCtx.
Builder->CreateCall(virtualFuncType, funcPtrToCall, finalArgs);
1819 llvm::CallInst* call = llvmModCtx.
Builder->CreateCall(virtualFuncType, funcPtrToCall, finalArgs,
"virtcall");
1823 for (
auto &i : postCleanup) {
1824 callGcFunction(llvmModCtx, i.second, i.first,
false);
1827 callGcFunction(llvmModCtx, interfaceShellVal.llvmValue, interfaceShellVal.yoiType,
false);
1830 case IR::Opcode::new_array_int:
1831 case IR::Opcode::new_array_bool:
1832 case IR::Opcode::new_array_char:
1833 case IR::Opcode::new_array_deci:
1834 case IR::Opcode::new_array_unsigned:
1835 case IR::Opcode::new_array_short:
1836 case IR::Opcode::new_array_str: {
1841 std::shared_ptr<yoi::IRValueType> elementType;
1843 size *= instr.
operands[i].value.symbolIndex;
1844 dimensions.push_back(instr.
operands[i].value.symbolIndex);
1852 case IR::Opcode::new_array_int:
1853 elementType = compilerCtx->getIntObjectType();
1855 case IR::Opcode::new_array_bool:
1856 elementType = compilerCtx->getBoolObjectType();
1858 case IR::Opcode::new_array_char:
1859 elementType = compilerCtx->getCharObjectType();
1861 case IR::Opcode::new_array_deci:
1862 elementType = compilerCtx->getDeciObjectType();
1864 case IR::Opcode::new_array_str:
1865 elementType = compilerCtx->getStrObjectType();
1867 case IR::Opcode::new_array_unsigned:
1868 elementType = compilerCtx->getUnsignedObjectType();
1870 case IR::Opcode::new_array_short:
1871 elementType = compilerCtx->getShortObjectType();
1878 auto arrayType =
managedPtr(elementType->getArrayType(dimensions));
1879 auto val = createArrayObject(llvmModCtx, arrayType, dimensionsVal);
1889 case IR::Opcode::new_array_struct:
1890 case IR::Opcode::new_array_interface: {
1895 std::shared_ptr<yoi::IRValueType> elementType;
1897 size *= instr.
operands[i].value.symbolIndex;
1898 dimensions.push_back(instr.
operands[i].value.symbolIndex);
1902 if (value.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1903 callGcFunction(llvmModCtx, value.llvmValue, value.yoiType,
true,
true,
true);
1904 dimensionsVal.push_back(value);
1907 elementType =
managedPtr(
IRValueType{instr.
opcode == IR::Opcode::new_array_struct ? IRValueType::valueType::structObject : IRValueType::valueType::interfaceObject, yoiModule->identifier, instr.
operands[1].value.symbolIndex});
1910 auto arrayType =
managedPtr(elementType->getArrayType(dimensions));
1911 auto val = createArrayObject(llvmModCtx, arrayType, dimensionsVal);
1920 case IR::Opcode::new_dynamic_array_int:
1921 case IR::Opcode::new_dynamic_array_bool:
1922 case IR::Opcode::new_dynamic_array_char:
1923 case IR::Opcode::new_dynamic_array_deci:
1924 case IR::Opcode::new_dynamic_array_unsigned:
1925 case IR::Opcode::new_dynamic_array_short:
1926 case IR::Opcode::new_dynamic_array_str: {
1930 auto unboxedSize = unboxValue(llvmModCtx, llvmSize.llvmValue, llvmSize.yoiType);
1933 std::shared_ptr<yoi::IRValueType> elementType;
1940 case IR::Opcode::new_dynamic_array_int:
1941 elementType = compilerCtx->getIntObjectType();
1943 case IR::Opcode::new_dynamic_array_bool:
1944 elementType = compilerCtx->getBoolObjectType();
1946 case IR::Opcode::new_dynamic_array_char:
1947 elementType = compilerCtx->getCharObjectType();
1949 case IR::Opcode::new_dynamic_array_deci:
1950 elementType = compilerCtx->getDeciObjectType();
1952 case IR::Opcode::new_dynamic_array_str:
1953 elementType = compilerCtx->getStrObjectType();
1955 case IR::Opcode::new_dynamic_array_short:
1956 elementType = compilerCtx->getShortObjectType();
1958 case IR::Opcode::new_dynamic_array_unsigned:
1959 elementType = compilerCtx->getUnsignedObjectType();
1966 auto arrayType =
managedPtr(elementType->getDynamicArrayType());
1967 auto val = createDynamicArrayObject(llvmModCtx, arrayType, valuesToStore, unboxedSize);
1977 callGcFunction(llvmModCtx, llvmSize.llvmValue, llvmSize.yoiType,
false);
1980 case IR::Opcode::new_dynamic_array_struct:
1981 case IR::Opcode::new_dynamic_array_interface: {
1985 auto unboxedSize = unboxValue(llvmModCtx, llvmSize.llvmValue, llvmSize.yoiType);
1988 std::shared_ptr<yoi::IRValueType> elementType;
1991 if (value.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1992 callGcFunction(llvmModCtx, value.llvmValue, value.yoiType,
true,
true,
true);
1993 valuesToStore.push_back(value);
1996 elementType =
managedPtr(
IRValueType{instr.
opcode == IR::Opcode::new_dynamic_array_struct ? IRValueType::valueType::structObject : IRValueType::valueType::interfaceObject, yoiModule->identifier, instr.
operands[1].value.symbolIndex});
1999 auto arrayType =
managedPtr(elementType->getDynamicArrayType());
2000 auto val = createDynamicArrayObject(llvmModCtx, arrayType, valuesToStore, unboxedSize);
2007 callGcFunction(llvmModCtx, llvmSize.llvmValue, llvmSize.yoiType,
false);
2010 case IR::Opcode::load_element: {
2014 auto arrayType = arrayVal.yoiType;
2015 std::shared_ptr<yoi::IRValueType> elementType;
2016 if (arrayType->isBasicType()) {
2017 elementType =
managedPtr(arrayType->getElementType().getBasicRawType());
2018 }
else if (arrayType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope)) {
2019 elementType =
managedPtr(arrayType->getElementType().addAttribute(IRValueType::ValueAttr::PermanentInCurrentScope).addAttribute(IRValueType::ValueAttr::Nullable));
2021 elementType =
managedPtr(arrayType->getElementType().addAttribute(IRValueType::ValueAttr::Nullable));
2023 auto unboxedIndexVal = unboxValue(llvmModCtx, indexVal.llvmValue, indexVal.yoiType);
2024 auto result = loadArrayElement(llvmModCtx, arrayType, arrayVal.llvmValue, unboxedIndexVal);
2028 callGcFunction(llvmModCtx, indexVal.llvmValue, indexVal.yoiType,
false);
2029 callGcFunction(llvmModCtx, arrayVal.llvmValue, arrayVal.yoiType,
false);
2032 case IR::Opcode::pop: {
2036 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
2039 case IR::Opcode::direct_assign: {
2043 rhs = promiseInterfaceObjectIfInterface(llvmModCtx, rhs);
2045 auto object = ensureObject(llvmModCtx, rhs.yoiType, rhs.llvmValue);
2046 rhs = {
object.second,
object.first};
2048 auto lhsType = lhs.yoiType;
2049 auto rhsType = rhs.yoiType;
2050 auto lhsLLVMType = llvmModCtx.
structTypeMap.at(std::make_tuple(lhsType->type, lhsType->typeAffiliateModule, lhsType->typeIndex));
2051 auto rhsLLVMType = llvmModCtx.
structTypeMap.at(std::make_tuple(rhsType->type, rhsType->typeAffiliateModule, rhsType->typeIndex));
2055 if (lhsType->type == IRValueType::valueType::structObject) {
2058 for (
const auto& field : yoiModule->structTable[lhsType->typeIndex]->fieldTypes) {
2059 auto fieldPtr = llvmModCtx.
Builder->CreateStructGEP(lhsLLVMType, lhs.llvmValue, fieldIndex,
"field_ptr");
2060 auto loadedFieldPtr = llvmModCtx.
Builder->CreateLoad(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), fieldPtr,
"loaded_field_ptr");
2061 callGcFunction(llvmModCtx, loadedFieldPtr, field,
false);
2065 for (
const auto& field : yoiModule->structTable[rhsType->typeIndex]->fieldTypes) {
2066 auto fieldPtr = llvmModCtx.
Builder->CreateStructGEP(rhsLLVMType, rhs.llvmValue, fieldIndex,
"field_ptr");
2067 auto loadedFieldPtr = llvmModCtx.
Builder->CreateLoad(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), fieldPtr,
"loaded_field_ptr");
2068 callGcFunction(llvmModCtx, loadedFieldPtr, field,
true);
2071 }
else if (lhsType->type == IRValueType::valueType::interfaceObject) {
2074 auto thisPtr = llvmModCtx.
Builder->CreateStructGEP(lhsLLVMType, lhs.llvmValue, 1,
"this_ptr_field");
2075 auto* concreteThisPtrRaw = llvmModCtx.
Builder->CreateLoad(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), thisPtr,
"concrete_this_raw");
2076 auto* implGcDecSlot = llvmModCtx.
Builder->CreateStructGEP(lhsLLVMType, lhs.llvmValue, 3,
"impl_gc_dec_slot");
2077 auto* implGcDecFuncType = llvm::FunctionType::get(llvmModCtx.
Builder->getVoidTy(), {llvm::PointerType::get(*llvmModCtx.TheContext, 0)},
false);
2078 llvmModCtx.
Builder->CreateCall(implGcDecFuncType, implGcDecSlot, {concreteThisPtrRaw});
2079 auto rhsThisPtr = llvmModCtx.
Builder->CreateStructGEP(rhsLLVMType, rhs.llvmValue, 1,
"this_ptr_field");
2080 auto* rhsConcreteThisPtrRaw = llvmModCtx.
Builder->CreateLoad(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), rhsThisPtr,
"rhs_concrete_this_raw");
2081 auto* implGcIncSlot = llvmModCtx.
Builder->CreateStructGEP(rhsLLVMType, rhs.llvmValue, 2,
"impl_gc_inc_slot");
2082 auto* implGcIncFuncType = llvm::FunctionType::get(llvmModCtx.
Builder->getVoidTy(), {llvm::PointerType::get(*llvmModCtx.TheContext, 0)},
false);
2083 llvmModCtx.
Builder->CreateCall(implGcIncFuncType, implGcIncSlot, {rhsConcreteThisPtrRaw});
2086 auto structTypeSize = llvmModCtx.
TheModule->getDataLayout().getTypeAllocSize(lhsLLVMType);
2088 auto* lhsPtr = llvmModCtx.
Builder->CreateBitCast(lhs.llvmValue, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"lhs_ptr");
2089 auto* rhsPtr = llvmModCtx.
Builder->CreateBitCast(rhs.llvmValue, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"rhs_ptr");
2090 auto* offsettedLhsPtr = llvmModCtx.
Builder->CreateGEP(llvm::Type::getInt8Ty(*llvmModCtx.
TheContext), lhsPtr, {llvm::ConstantInt::get(llvmModCtx.Builder->getInt32Ty(), 16, true)});
2091 auto* offsettedRhsPtr = llvmModCtx.
Builder->CreateGEP(llvm::Type::getInt8Ty(*llvmModCtx.
TheContext), rhsPtr, {llvm::ConstantInt::get(llvmModCtx.Builder->getInt32Ty(), 16, true)});
2092 llvmModCtx.
Builder->CreateMemCpy(offsettedLhsPtr, llvm::MaybeAlign(8), offsettedRhsPtr, llvm::MaybeAlign(8), structTypeSize - 16);
2093 callGcFunction(llvmModCtx, rhs.llvmValue, rhs.yoiType,
false);
2097 case IR::Opcode::dyn_cast_any: {
2098 std::tuple<IRValueType::valueType, yoi::indexT, yoi::indexT> structTypeKey;
2099 std::tuple<IRValueType::valueType, yoi::indexT, yoi::indexT, yoi::indexT> structTypeIDKey;
2103 auto structTypeIndex = instr.
operands[1].value.symbolIndex;
2104 std::shared_ptr<IRValueType> structYoiType;
2107 if (instr.
operands[3].value.symbolIndex) {
2114 if (interfaceRhs.yoiType->metadata.hasMetadata(L
"regressed_interface_impl")) {
2115 auto regressedImpl = interfaceRhs.yoiType->metadata.getMetadata<std::pair<yoi::indexT, yoi::indexT>>(L
"regressed_interface_impl");
2116 auto implDef = yoiModule->interfaceImplementationTable[regressedImpl.second];
2117 if (implDef->implStructIndex == structTypeKey) {
2118 llvmModCtx.
valueStackPhi.
push_back({unwrapInterfaceObject(llvmModCtx, interfaceRhs),
managedPtr(
IRValueType{std::get<0>(implDef->implStructIndex), std::get<1>(implDef->implStructIndex), std::get<2>(implDef->implStructIndex)})});
2120 auto nullValue = llvm::ConstantPointerNull::get(llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2124 if (interfaceRhs.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
2125 callGcFunction(llvmModCtx, interfaceRhs.llvmValue, interfaceRhs.yoiType,
true,
true);
2133 auto structTypeId = llvmModCtx.
typeIDMap.at(structTypeIDKey);
2134 auto structTypeLLVMType = structYoiType->isArrayType() || structYoiType->isDynamicArrayType()
2139 auto* interfacePtr = llvmModCtx.
Builder->CreateBitCast(interfaceRhs.llvmValue, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"interface_ptr");
2140 auto* offsettedInterfacePtr = llvmModCtx.
Builder->CreateGEP(llvm::Type::getInt8Ty(*llvmModCtx.
TheContext), interfacePtr, {llvm::ConstantInt::get(llvmModCtx.
Builder->getInt32Ty(), 16,
true)});
2141 auto* structPtrPtr = llvmModCtx.
Builder->CreateBitCast(offsettedInterfacePtr, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"struct_ptr");
2142 auto* loadedStructPtr = llvmModCtx.
Builder->CreateLoad(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), structPtrPtr,
"loaded_struct_ptr");
2144 auto* typeIdPtr = llvmModCtx.
Builder->CreateStructGEP(structTypeLLVMType, loadedStructPtr, 1,
"typeid_ptr");
2145 auto* loadedTypeId = llvmModCtx.
Builder->CreateLoad(llvmModCtx.
Builder->getInt64Ty(), typeIdPtr,
"loaded_typeid");
2146 auto* expectedTypeId = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), structTypeId,
true);
2147 auto* typeIdMatch = llvmModCtx.
Builder->CreateICmpEQ(loadedTypeId, expectedTypeId,
"typeid_match");
2153 llvmModCtx.
Builder->CreateCondBr(typeIdMatch, successBB, failedMatchBB);
2155 llvmModCtx.
Builder->SetInsertPoint(failedMatchBB);
2156 auto* nullValue = llvm::ConstantPointerNull::get(llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2157 llvmModCtx.
Builder->CreateBr(continueBB);
2159 llvmModCtx.
Builder->SetInsertPoint(successBB);
2160 auto* resultObject = loadedStructPtr;
2161 callGcFunction(llvmModCtx, resultObject, structYoiType,
true);
2162 llvmModCtx.
Builder->CreateBr(continueBB);
2164 llvmModCtx.
Builder->SetInsertPoint(continueBB);
2165 auto *finalValue = llvmModCtx.
Builder->CreatePHI(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), 2,
"final_value");
2166 finalValue->addIncoming(resultObject, successBB);
2167 finalValue->addIncoming(nullValue, failedMatchBB);
2168 callGcFunction(llvmModCtx, interfaceRhs.llvmValue, interfaceRhs.yoiType,
false);
2173 case IR::Opcode::push_null: {
2174 auto nullValue = llvm::ConstantPointerNull::get(llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2178 case IR::Opcode::pointer_cast: {
2180 auto value = llvmModCtx.
Builder->CreateBitCast(rhs.llvmValue, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"pointer_cast");
2182 callGcFunction(llvmModCtx, rhs.llvmValue, rhs.yoiType,
false);
2185 case IR::Opcode::store_element: {
2191 yoi_assert(index.yoiType->type == IRValueType::valueType::unsignedObject || index.yoiType->type == IRValueType::valueType::unsignedRaw, instr.
debugInfo.
line, instr.
debugInfo.
column,
"LLVM Codegen: store element with non-integer index.");
2193 rhs = promiseInterfaceObjectIfInterface(llvmModCtx, rhs);
2196 auto* indexValue = unboxValue(llvmModCtx, index.llvmValue, index.yoiType);
2197 if (rhs.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !lhs.yoiType->isBasicType())
2198 callGcFunction(llvmModCtx, rhs.llvmValue, rhs.yoiType,
true,
true,
true);
2199 storeArrayElement(llvmModCtx, lhs.yoiType, rhs.yoiType, lhs.llvmValue, indexValue, rhs.llvmValue);
2202 callGcFunction(llvmModCtx, index.llvmValue, index.yoiType,
false);
2203 callGcFunction(llvmModCtx, rhs.llvmValue, rhs.yoiType,
false);
2204 callGcFunction(llvmModCtx, lhs.llvmValue, lhs.yoiType,
false);
2207 case IR::Opcode::array_length: {
2210 auto arrayLLVMType = getArrayLLVMType(llvmModCtx, array.yoiType);
2212 auto *arrayLen = llvmModCtx.
Builder->CreateStructGEP(arrayLLVMType, array.llvmValue, 2,
"array_len");
2213 auto *loadedArrayLen = llvmModCtx.
Builder->CreateLoad(llvmModCtx.
Builder->getInt64Ty(), arrayLen,
"loaded_array_len");
2215 callGcFunction(llvmModCtx, array.llvmValue, array.yoiType,
false);
2218 case IR::Opcode::interfaceof: {
2221 yoi_assert(typeidValue.yoiType->type == IRValueType::valueType::integerObject || typeidValue.yoiType->type == IRValueType::valueType::integerRaw, instr.
debugInfo.
line, instr.
debugInfo.
column,
"LLVM Codegen: interfaceof with non-integer typeid.");
2226 if (interfaceValue.yoiType->metadata.hasMetadata(L
"regressed_interface_impl")) {
2227 auto regressedImpl = interfaceValue.yoiType->metadata.getMetadata<std::pair<yoi::indexT, yoi::indexT>>(L
"regressed_interface_impl");
2228 auto implDef = yoiModule->interfaceImplementationTable[regressedImpl.second];
2229 if (llvmModCtx.
typeIDMap.contains({std::get<0>(implDef->implStructIndex), std::get<1>(implDef->implStructIndex), std::get<2>(implDef->implStructIndex), 0})) {
2230 auto *trueBoolean = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt1Ty(), 1,
true);
2233 auto *falseBoolean = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt1Ty(), 0,
true);
2236 callGcFunction(llvmModCtx, interfaceValue.llvmValue, interfaceValue.yoiType,
false);
2237 callGcFunction(llvmModCtx, typeidValue.llvmValue, typeidValue.yoiType,
false);
2242 auto interfaceKey = std::make_tuple(interfaceValue.yoiType->type, interfaceValue.yoiType->typeAffiliateModule, interfaceValue.yoiType->typeIndex);
2245 auto loadedThisPtr = unwrapInterfaceObject(llvmModCtx, interfaceValue);
2247 auto* typeIdPtr = llvmModCtx.
Builder->CreateGEP(llvmModCtx.
Builder->getInt64Ty(), loadedThisPtr, {llvm::ConstantInt::get(llvmModCtx.Builder->getInt32Ty(), 1, true)});
2248 auto* loadedTypeId = llvmModCtx.
Builder->CreateLoad(llvmModCtx.
Builder->getInt64Ty(), typeIdPtr,
"loaded_typeid");
2249 auto* expectedTypeId = unboxValue(llvmModCtx, typeidValue.llvmValue, typeidValue.yoiType);
2250 auto* typeIdMatch = llvmModCtx.
Builder->CreateICmpEQ(loadedTypeId, expectedTypeId,
"typeid_match");
2256 llvmModCtx.
Builder->CreateCondBr(typeIdMatch, successBB, failedMatchBB);
2258 llvmModCtx.
Builder->SetInsertPoint(failedMatchBB);
2259 auto *falseBoolean = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt1Ty(), 0,
true);
2260 llvmModCtx.
Builder->CreateBr(continueBB);
2262 llvmModCtx.
Builder->SetInsertPoint(successBB);
2263 auto *trueBoolean = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt1Ty(), 1,
true);
2264 llvmModCtx.
Builder->CreateBr(continueBB);
2267 llvmModCtx.
Builder->SetInsertPoint(continueBB);
2268 auto phiNode = llvmModCtx.
Builder->CreatePHI(llvm::Type::getInt1Ty(*llvmModCtx.
TheContext), 2,
"phi_node");
2269 phiNode->addIncoming(trueBoolean, successBB);
2270 phiNode->addIncoming(falseBoolean, failedMatchBB);
2272 callGcFunction(llvmModCtx, interfaceValue.llvmValue, interfaceValue.yoiType,
false);
2273 callGcFunction(llvmModCtx, typeidValue.llvmValue, typeidValue.yoiType,
false);
2277 case IR::Opcode::typeid_object_non_stack: {
2279 auto typeId = llvmModCtx.
typeIDMap.at(key);
2283 case IR::Opcode::yield: {
2289 auto raw_ctx_ptr = llvmModCtx.
Builder->CreateIntToPtr(unboxValue(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType), llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2290 storeYieldValue(llvmModCtx, item.llvmValue, item.yoiType);
2291 auto coro_suspend = getLLVMCoroIntrinsic(llvmModCtx, llvm::Intrinsic::coro_suspend);
2292 auto suspend_result = llvmModCtx.
Builder->CreateCall(coro_suspend, {
2293 llvm::ConstantTokenNone::get(*llvmModCtx.
TheContext),
2294 llvm::ConstantInt::get(llvm::Type::getInt1Ty(*llvmModCtx.
TheContext), 0)});
2297 switch_inst->addCase(llvm::ConstantInt::get(llvm::Type::getInt8Ty(*llvmModCtx.
TheContext), 0), resumeBB);
2299 callGcFunction(llvmModCtx, item.llvmValue, item.yoiType,
false);
2300 callGcFunction(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType,
false);
2301 llvmModCtx.
Builder->SetInsertPoint(resumeBB);
2304 case IR::Opcode::yield_none: {
2308 auto raw_ctx_ptr = llvmModCtx.
Builder->CreateIntToPtr(unboxValue(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType), llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2309 auto coro_suspend = getLLVMCoroIntrinsic(llvmModCtx, llvm::Intrinsic::coro_suspend);
2310 auto suspend_result = llvmModCtx.
Builder->CreateCall(coro_suspend, {
2311 llvm::ConstantTokenNone::get(*llvmModCtx.
TheContext),
2312 llvm::ConstantInt::get(llvm::Type::getInt1Ty(*llvmModCtx.
TheContext), 0)});
2315 switch_inst->addCase(llvm::ConstantInt::get(llvm::Type::getInt8Ty(*llvmModCtx.
TheContext), 0), resumeBB);
2317 callGcFunction(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType,
false);
2318 llvmModCtx.
Builder->SetInsertPoint(resumeBB);
2321 case IR::Opcode::resume: {
2325 auto raw_ctx_ptr = llvmModCtx.
Builder->CreateIntToPtr(unboxValue(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType), llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2326 auto coroResume = getLLVMCoroIntrinsic(llvmModCtx, llvm::Intrinsic::coro_resume);
2327 auto resume_result = llvmModCtx.
Builder->CreateCall(coroResume, {
2330 callGcFunction(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType,
false);
2333 case IR::Opcode::nop:
3338 llvm::DIType *LLVMCodegen::getDIType(
LLVMModuleContext &llvmModCtx,
const std::shared_ptr<IRValueType> &type) {
3342 auto* di_i8 = llvmModCtx.
DBuilder->createBasicType(
"char", 8, llvm::dwarf::DW_ATE_signed_char);
3343 auto* di_i64 = llvmModCtx.
DBuilder->createBasicType(
"long long", 64, llvm::dwarf::DW_ATE_signed);
3346 llvmModCtx.
basicDITypeMap[L
"di_i16"] = llvmModCtx.
DBuilder->createBasicType(
"short", 16, llvm::dwarf::DW_ATE_signed);
3348 llvmModCtx.
basicDITypeMap[L
"di_i64_u"] = llvmModCtx.
DBuilder->createBasicType(
"unsigned long long", 64, llvm::dwarf::DW_ATE_unsigned);
3349 llvmModCtx.
basicDITypeMap[L
"di_double"] = llvmModCtx.
DBuilder->createBasicType(
"double", 64, llvm::dwarf::DW_ATE_float);
3350 llvmModCtx.
basicDITypeMap[L
"di_i1"] = llvmModCtx.
DBuilder->createBasicType(
"bool", 8, llvm::dwarf::DW_ATE_boolean);
3353 auto* unknown_object_struct = llvmModCtx.
DBuilder->createStructType(
3360 llvm::DINode::FlagZero,
3362 llvmModCtx.
DBuilder->getOrCreateArray({
3363 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"refcount", nullptr, 0, 64, 64, 0, llvm::DINode::FlagZero, di_i64),
3364 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"typeid", nullptr, 0, 64, 64, 64, llvm::DINode::FlagZero, di_i64),
3367 llvmModCtx.
basicDITypeMap[L
"di_unknown_object_ptr"] = llvmModCtx.
DBuilder->createPointerType(unknown_object_struct, 64);
3377 auto* di_unknown_object_ptr = llvmModCtx.
basicDITypeMap[L
"di_unknown_object_ptr"];
3379 if (type->isArrayType() || type->isDynamicArrayType()) {
3381 llvm::SmallVector<llvm::Metadata*, 8> dimensions;
3382 if (type->isArrayType()) {
3385 dimensions.push_back(llvmModCtx.
DBuilder->getOrCreateSubrange(0,
static_cast<int64_t
>(i)));
3388 dimensions.push_back(llvmModCtx.
DBuilder->getOrCreateSubrange(0,
static_cast<int64_t
>(0)));
3391 auto arrayKey = std::make_tuple(type->type, type->typeAffiliateModule, type->typeIndex, type->isArrayType() ? size :
static_cast<yoi::indexT>(-1));
3398 llvm::DIType *elementDIType =
nullptr;
3399 if (type->isBasicType()) {
3400 switch (type->type) {
3401 case IRValueType::valueType::integerObject:
3402 elementDIType = di_i64;
3404 case IRValueType::valueType::decimalObject:
3405 elementDIType = di_double;
3407 case IRValueType::valueType::booleanObject:
3408 elementDIType = di_i1;
3410 case IRValueType::valueType::characterObject:
3411 elementDIType = di_i8;
3413 case IRValueType::valueType::stringObject:
3414 elementDIType = di_i8_ptr;
3416 case IRValueType::valueType::unsignedObject:
3417 elementDIType = di_i64_u;
3419 case IRValueType::valueType::shortObject:
3420 elementDIType = di_i16;
3427 elementDIType = getDIType(llvmModCtx,
managedPtr(type->getElementType()));
3430 auto *llvmElementRawType = yoiTypeToLLVMType(llvmModCtx,
managedPtr(type->getElementType()), type->hasAttribute(IRValueType::ValueAttr::Raw));
3431 auto arraySizeInBits = size * llvmModCtx.
TheModule->getDataLayout().getTypeSizeInBits(llvmElementRawType);
3432 auto* diArray = llvmModCtx.
DBuilder->createArrayType(
3433 arraySizeInBits, llvmModCtx.
TheModule->getDataLayout().getABITypeAlign(llvmElementRawType).value() * 8, elementDIType, {llvmModCtx.DBuilder->getOrCreateArray(dimensions)});
3437 auto *diArrayStruct = llvmModCtx.
DBuilder->createStructType(
3442 64 + 64 + 64 + arraySizeInBits,
3444 llvm::DINode::FlagZero,
3446 llvmModCtx.
DBuilder->getOrCreateArray({
3447 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"refcount", nullptr, 0, 64, 64, 0, llvm::DINode::FlagZero, di_i64),
3448 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"typeid", nullptr, 0, 64, 64, 64, llvm::DINode::FlagZero, di_i64),
3449 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"array_length", nullptr, 0, 64, 64, 128, llvm::DINode::FlagZero, di_i64),
3450 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"array", nullptr, 0, arraySizeInBits, 64, 192, llvm::DINode::FlagZero, diArray)
3453 auto *resultDIType = llvmModCtx.
DBuilder->createPointerType(diArrayStruct, 64);
3455 if (type->hasAttribute(IRValueType::ValueAttr::Raw)) {
3458 return resultDIType;
3461 auto key = std::make_tuple(type->type, type->typeAffiliateModule, type->typeIndex);
3463 if (type->isBasicType() && type->hasAttribute(IRValueType::ValueAttr::Raw)) {
3464 switch (type->type) {
3465 case IRValueType::valueType::integerObject:
3467 case IRValueType::valueType::decimalObject:
3469 case IRValueType::valueType::booleanObject:
3471 case IRValueType::valueType::characterObject:
3473 case IRValueType::valueType::stringObject:
3475 case IRValueType::valueType::unsignedObject:
3477 case IRValueType::valueType::shortObject:
3479 case IRValueType::valueType::datastructObject: {
3487 auto dataStructDef = yoiModule->dataStructTable[type->typeIndex];
3491 if (!diDataRegionType) {
3492 std::string dataRegionTypeName =
"yoi.data_region." +
wstring2string(type->to_string());
3493 llvm::SmallVector<llvm::Metadata *, 8> dataRegionMemberTypes;
3496 auto *layout = &llvmModCtx.
TheModule->getDataLayout();
3497 auto *structLayout = layout->getStructLayout(llvmDataRegionType);
3499 for (
yoi::indexT i = 0; i < dataStructDef->fieldTypes.size(); i++) {
3500 auto memberType =
managedPtr(*dataStructDef->fieldTypes[i]);
3501 memberType->addAttribute(IRValueType::ValueAttr::Raw);
3503 auto memberTypeDI = getDIType(llvmModCtx, memberType);
3504 uint64_t fieldSize = memberTypeDI->getSizeInBits();
3505 uint64_t fieldOffset = structLayout->getElementOffsetInBits(i);
3508 std::string fieldName =
"field" + std::to_string(i);
3509 for (
auto &fieldPair : dataStructDef->fields) {
3510 if (fieldPair.second == i) {
3521 memberTypeDI->getAlignInBits(),
3523 llvm::DINode::FlagZero,
3525 dataRegionMemberTypes.push_back(memberDIType);
3532 structLayout->getSizeInBits(),
3533 structLayout->getAlignment().value() * 8,
3534 llvm::DINode::FlagZero,
3536 llvmModCtx.
DBuilder->getOrCreateArray(dataRegionMemberTypes));
3540 if (type->hasAttribute(IRValueType::ValueAttr::Raw)) {
3541 return diDataRegionType;
3545 std::string structTypeName =
"yoi." +
wstring2string(type->to_string());
3546 llvm::SmallVector<llvm::Metadata *, 8> objectMemberTypes;
3549 objectMemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(
3550 llvmModCtx.
compileUnits[L
"builtin"],
"refcount",
nullptr, 0, 64, 64, 0, llvm::DINode::FlagZero, di_i64));
3551 objectMemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(
3552 llvmModCtx.
compileUnits[L
"builtin"],
"typeid",
nullptr, 0, 64, 64, 64, llvm::DINode::FlagZero, di_i64));
3553 uint64_t objectCurrentSize = 128;
3555 objectMemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
3559 diDataRegionType->getSizeInBits(),
3560 diDataRegionType->getAlignInBits(),
3562 llvm::DINode::FlagZero,
3564 objectCurrentSize += diDataRegionType->getSizeInBits();
3572 llvm::DINode::FlagZero,
3574 llvmModCtx.
DBuilder->getOrCreateArray(objectMemberTypes));
3576 auto diStructTypePtr = llvmModCtx.
DBuilder->createPointerType(diStructType, 64);
3578 return diStructTypePtr;
3592 std::string typeName =
"yoi." +
wstring2string(type->to_string());
3594 llvm::DICompositeType *diFwdDecl = llvmModCtx.
DBuilder->createReplaceableCompositeType(
3595 llvm::dwarf::DW_TAG_structure_type,
3602 auto* resultDIType = llvmModCtx.
DBuilder->createPointerType(diFwdDecl, 64);
3606 llvm::SmallVector<llvm::Metadata*, 8> MemberTypes;
3609 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(
3617 llvm::DINode::FlagZero,
3620 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(
3628 llvm::DINode::FlagZero,
3631 uint64_t currentSize = 128;
3634 switch (type->type) {
3635 case IRValueType::valueType::integerObject: {
3636 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 64, 64, currentSize, llvm::DINode::FlagZero, di_i64));
3640 case IRValueType::valueType::stringObject: {
3641 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 64, 64, currentSize, llvm::DINode::FlagZero, di_i8_ptr));
3645 case IRValueType::valueType::decimalObject: {
3646 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 64, 64, currentSize, llvm::DINode::FlagZero, di_double));
3650 case IRValueType::valueType::booleanObject: {
3651 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 8, 8, currentSize, llvm::DINode::FlagZero, di_i1));
3655 case IRValueType::valueType::characterObject: {
3656 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 8, 8, currentSize, llvm::DINode::FlagZero, di_i8));
3660 case IRValueType::valueType::unsignedObject: {
3661 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 64, 64, currentSize, llvm::DINode::FlagZero, di_i64_u));
3665 case IRValueType::valueType::shortObject: {
3666 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 16, 16, currentSize, llvm::DINode::FlagZero, di_i16));
3670 case IRValueType::valueType::structObject: {
3671 auto structDef = yoiModule->structTable[type->typeIndex];
3673 for (
auto it = structDef->nameIndexMap.begin(); it!= structDef->nameIndexMap.end(); ++it) {
3674 if (it->second.type == IRStructDefinition::nameInfo::nameType::method)
3677 fieldNames[it->second.index] = fieldName;
3679 for (
yoi::indexT i = 0; i < fieldNames.size(); i++) {
3680 auto fieldYoiType = structDef->fieldTypes[i];
3682 auto* fieldDIType = getDIType(llvmModCtx, fieldYoiType);
3683 uint64_t fieldSize = llvmModCtx.
TheModule->getDataLayout().getTypeSizeInBits(yoiTypeToLLVMType(llvmModCtx, fieldYoiType));
3685 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(
3686 llvmModCtx.
compileUnits[L
"builtin"], fieldNames[i],
nullptr, 0,
3687 fieldSize, fieldSize, currentSize,
3688 llvm::DINode::FlagZero, fieldDIType
3690 currentSize += fieldSize;
3694 case IRValueType::valueType::interfaceObject: {
3695 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 64, 64, currentSize, llvm::DINode::FlagZero, di_unknown_object_ptr));
3699 case IRValueType::valueType::none:
3707 auto* diStruct = llvmModCtx.
DBuilder->createStructType(
3714 llvm::DINode::FlagZero,
3716 llvmModCtx.
DBuilder->getOrCreateArray(MemberTypes)
3719 auto node = llvm::TempMDNode(diFwdDecl);
3720 llvmModCtx.
DBuilder->replaceTemporary(std::move(node), diStruct);
3724 return resultDIType;