933 if (compilerCtx->getBuildConfig()->buildMode == IRBuildConfig::BuildMode::debug) {
939 auto* debugStrConst = llvm::ConstantDataArray::getString(*llvmModCtx.
TheContext, debugStr,
true);
940 auto* debugStrGlobal =
new llvm::GlobalVariable(*llvmModCtx.
TheModule, debugStrConst->getType(),
true, llvm::GlobalVariable::PrivateLinkage, debugStrConst,
"debug_str");
941 auto debugArgs = std::array<llvm::Value*, 1>{ debugStrGlobal };
942 llvmModCtx.
Builder->CreateCall(llvmModCtx.
runtimeFunctions.at(L
"runtime_debug_print"), llvm::ArrayRef<llvm::Value*>(debugArgs));
945 case IR::Opcode::push_integer: {
946 auto val = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), instr.
operands[0].value.integer,
true);
950 case IR::Opcode::push_decimal: {
951 auto val = llvm::ConstantFP::get(llvmModCtx.
Builder->getDoubleTy(), instr.
operands[0].value.decimal);
955 case IR::Opcode::push_boolean: {
956 auto val = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt1Ty(), instr.
operands[0].value.boolean);
960 case IR::Opcode::push_short: {
961 auto val = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt16Ty(), instr.
operands[0].value.shortV);
965 case IR::Opcode::push_unsigned: {
966 auto val = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), instr.
operands[0].value.unsignedV,
false);
970 case IR::Opcode::push_string: {
971 auto& str = yoiModule->stringLiteralPool.getStringLiteral(instr.
operands[1].value.stringLiteralIndex);
974 auto *globalStr = llvmModCtx.
Builder->CreateGlobalString(
wstring2string(str),
"global_string_literal");
978 case IR::Opcode::push_character: {
979 auto val = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt8Ty(), instr.
operands[0].value.character);
984 case IR::Opcode::basic_cast_char: {
986 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
987 llvm::Value* castedVal =
nullptr;
989 if (rawVal->getType()->isDoubleTy()) {
990 castedVal = llvmModCtx.
Builder->CreateFPToSI(rawVal, llvmModCtx.
Builder->getInt8Ty(),
"deci_to_char_cast");
991 }
else if (rawVal->getType()->isIntegerTy(1)) {
992 castedVal = llvmModCtx.
Builder->CreateTrunc(rawVal, llvmModCtx.
Builder->getInt8Ty(),
"bool_to_char_cast");
993 }
else if (rawVal->getType()->isIntegerTy(64)) {
994 castedVal = llvmModCtx.
Builder->CreateTrunc(rawVal, llvmModCtx.
Builder->getInt8Ty(),
"int_to_char_cast");
995 }
else if (rawVal->getType()->isIntegerTy(8)) {
1002 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1005 case IR::Opcode::basic_cast_int: {
1007 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1008 llvm::Value* castedVal =
nullptr;
1010 if (rawVal->getType()->isDoubleTy()) {
1011 castedVal = llvmModCtx.
Builder->CreateFPToSI(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"deci_to_int_cast");
1012 }
else if (rawVal->getType()->isIntegerTy(1)) {
1013 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"bool_to_int_cast");
1014 }
else if (rawVal->getType()->isIntegerTy(8)) {
1015 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"char_to_int_cast");
1016 }
else if (rawVal->getType()->isIntegerTy(16)) {
1017 castedVal = llvmModCtx.
Builder->CreateSExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"short_to_int_cast");
1018 }
else if (rawVal->getType()->isIntegerTy(64)) {
1021 panic(0, 0,
"LLVM Codegen: Unsupported type for basic_cast_int");
1025 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1028 case IR::Opcode::basic_cast_deci: {
1030 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1031 llvm::Value* castedVal =
nullptr;
1033 if (rawVal->getType()->isIntegerTy(64)) {
1034 castedVal = llvmModCtx.
Builder->CreateSIToFP(rawVal, llvmModCtx.
Builder->getDoubleTy(),
"int_to_deci_cast");
1035 }
else if (rawVal->getType()->isIntegerTy(1)) {
1036 castedVal = llvmModCtx.
Builder->CreateUIToFP(rawVal, llvmModCtx.
Builder->getDoubleTy(),
"bool_to_deci_cast");
1037 }
else if (rawVal->getType()->isIntegerTy(8)) {
1038 castedVal = llvmModCtx.
Builder->CreateUIToFP(rawVal, llvmModCtx.
Builder->getDoubleTy(),
"char_to_deci_cast");
1039 }
else if (rawVal->getType()->isIntegerTy(16)) {
1040 castedVal = llvmModCtx.
Builder->CreateSIToFP(rawVal, llvmModCtx.
Builder->getDoubleTy(),
"short_to_deci_cast");
1041 }
else if (rawVal->getType()->isDoubleTy()) {
1044 panic(0, 0,
"LLVM Codegen: Unsupported type for basic_cast_deci");
1048 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1051 case IR::Opcode::basic_cast_unsigned: {
1053 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1054 llvm::Value* castedVal =
nullptr;
1056 if (rawVal->getType()->isIntegerTy(64)) {
1057 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"int_to_unsigned_cast");
1058 }
else if (rawVal->getType()->isDoubleTy()) {
1059 castedVal = llvmModCtx.
Builder->CreateFPToUI(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"deci_to_unsigned_cast");
1060 }
else if (rawVal->getType()->isIntegerTy(16)) {
1061 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"short_to_unsigned_cast");
1062 }
else if (rawVal->getType()->isIntegerTy(8)) {
1063 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"char_to_unsigned_cast");
1064 }
else if (rawVal->getType()->isIntegerTy(1)) {
1065 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt64Ty(),
"bool_to_unsigned_cast");
1067 panic(0, 0,
"LLVM Codegen: Unsupported type for basic_cast_unsigned");
1071 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1074 case IR::Opcode::basic_cast_short: {
1076 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1077 llvm::Value* castedVal =
nullptr;
1079 if (rawVal->getType()->isIntegerTy(64)) {
1080 castedVal = llvmModCtx.
Builder->CreateTrunc(rawVal, llvmModCtx.
Builder->getInt16Ty(),
"int_to_short_cast");
1081 }
else if (rawVal->getType()->isDoubleTy()) {
1082 castedVal = llvmModCtx.
Builder->CreateFPToSI(rawVal, llvmModCtx.
Builder->getInt16Ty(),
"deci_to_short_cast");
1083 }
else if (rawVal->getType()->isIntegerTy(8)) {
1084 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt16Ty(),
"char_to_short_cast");
1085 }
else if (rawVal->getType()->isIntegerTy(1)) {
1086 castedVal = llvmModCtx.
Builder->CreateZExt(rawVal, llvmModCtx.
Builder->getInt16Ty(),
"bool_to_short_cast");
1088 panic(0, 0,
"LLVM Codegen: Unsupported type for basic_cast_short");
1092 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1095 case IR::Opcode::basic_cast_bool: {
1097 llvm::Value* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1098 llvm::Value* castedVal =
nullptr;
1100 if (rawVal->getType()->isIntegerTy(64)) {
1101 castedVal = llvmModCtx.
Builder->CreateICmpNE(rawVal, llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), 0),
"int_to_bool_cast");
1102 }
else if (rawVal->getType()->isDoubleTy()) {
1103 castedVal = llvmModCtx.
Builder->CreateFCmpONE(rawVal, llvm::ConstantFP::get(llvmModCtx.
Builder->getDoubleTy(), 0.0),
"deci_to_bool_cast");
1104 }
else if (rawVal->getType()->isIntegerTy(16)) {
1105 castedVal = llvmModCtx.
Builder->CreateICmpNE(rawVal, llvm::ConstantInt::get(llvmModCtx.
Builder->getInt8Ty(), 0),
"short_to_bool_cast");
1106 }
else if (rawVal->getType()->isIntegerTy(8)) {
1107 castedVal = llvmModCtx.
Builder->CreateICmpNE(rawVal, llvm::ConstantInt::get(llvmModCtx.
Builder->getInt8Ty(), 0),
"char_to_bool_cast");
1108 }
else if (rawVal->getType()->isIntegerTy(1)) {
1111 panic(0, 0,
"LLVM Codegen: Unsupported type for basic_cast_bool");
1115 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1119 case IR::Opcode::add: handleBinaryOp(llvmModCtx, llvm::Instruction::Add,
false, fromBlock, toBlock);
break;
1120 case IR::Opcode::sub: handleBinaryOp(llvmModCtx, llvm::Instruction::Sub,
false, fromBlock, toBlock);
break;
1121 case IR::Opcode::mul: handleBinaryOp(llvmModCtx, llvm::Instruction::Mul,
false, fromBlock, toBlock);
break;
1122 case IR::Opcode::div: handleBinaryOp(llvmModCtx, llvm::Instruction::SDiv,
false, fromBlock, toBlock);
break;
1123 case IR::Opcode::mod: handleBinaryOp(llvmModCtx, llvm::Instruction::SRem,
false, fromBlock, toBlock);
break;
1124 case IR::Opcode::bitwise_and: handleBinaryOp(llvmModCtx, llvm::Instruction::And,
false, fromBlock, toBlock);
break;
1125 case IR::Opcode::bitwise_or: handleBinaryOp(llvmModCtx, llvm::Instruction::Or,
false, fromBlock, toBlock);
break;
1126 case IR::Opcode::bitwise_xor: handleBinaryOp(llvmModCtx, llvm::Instruction::Xor,
false, fromBlock, toBlock);
break;
1127 case IR::Opcode::left_shift: handleBinaryOp(llvmModCtx, llvm::Instruction::Shl,
false, fromBlock, toBlock);
break;
1128 case IR::Opcode::right_shift: handleBinaryOp(llvmModCtx, llvm::Instruction::LShr,
false, fromBlock, toBlock);
break;
1130 case IR::Opcode::negate: {
1132 auto* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1133 auto* negatedRaw = rawVal->getType()->isDoubleTy() ? llvmModCtx.
Builder->CreateFNeg(rawVal,
"negtmp") : llvmModCtx.
Builder->CreateNeg(rawVal,
"negtmp");
1136 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1139 case IR::Opcode::bitwise_not: {
1141 auto* rawVal = unboxValue(llvmModCtx, val.llvmValue, val.yoiType);
1142 auto* notRaw = llvmModCtx.
Builder->CreateNot(rawVal,
"nottmp");
1145 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
1150 case IR::Opcode::equal: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_EQ,
false, fromBlock, toBlock);
break;
1151 case IR::Opcode::not_equal: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_NE,
false, fromBlock, toBlock);
break;
1152 case IR::Opcode::less_than: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_SLT,
false, fromBlock, toBlock);
break;
1153 case IR::Opcode::less_equal: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_SLE,
false, fromBlock, toBlock);
break;
1154 case IR::Opcode::greater_than: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_SGT,
false, fromBlock, toBlock);
break;
1155 case IR::Opcode::greater_equal: handleComparison(llvmModCtx, llvm::CmpInst::ICMP_SGE,
false, fromBlock, toBlock);
break;
1158 case IR::Opcode::load_local: {
1159 auto varIndex = instr.
operands[0].value.symbolIndex;
1160 auto* alloca = llvmModCtx.
namedValues.at(varIndex);
1162 if (yoiType->type == IRValueType::valueType::datastructObject && yoiType->hasAttribute(IRValueType::ValueAttr::Raw)) {
1165 auto loadedPtr = llvmModCtx.
Builder->CreateLoad(yoiTypeToLLVMType(llvmModCtx, yoiType, yoiType->isBasicRawType() || yoiType->hasAttribute(IRValueType::ValueAttr::Raw)), alloca,
"loadtmp");
1166 callGcFunction(llvmModCtx, loadedPtr, yoiType,
true);
1171 case IR::Opcode::store_local: {
1172 auto varIndex = instr.
operands[0].value.symbolIndex;
1173 auto* alloca = llvmModCtx.
namedValues.at(varIndex);
1177 valToStore = yoiType->metadata.hasMetadata(L
"regressed_interface_impl") ? valToStore : promiseInterfaceObjectIfInterface(llvmModCtx, valToStore);
1180 auto* oldPtr = llvmModCtx.
Builder->CreateLoad(alloca->getAllocatedType(), alloca,
"old_ptr_for_store");
1181 if (yoiType->hasAttribute(IRValueType::ValueAttr::Nullable))
1182 callGcFunction(llvmModCtx, oldPtr, yoiType,
false,
true);
1184 generateIfTargetNotNull(llvmModCtx, oldPtr, yoiType, [&] () {
1185 callGcFunction(llvmModCtx, oldPtr, yoiType,
false,
true);
1186 }, !yoiType->hasAttribute(IRValueType::ValueAttr::Raw));
1188 if (llvmModCtx.
currentFunctionDef->variableTable.get(varIndex)->hasAttribute(IRValueType::ValueAttr::Raw)) {
1189 auto unboxedVal = unboxValue(llvmModCtx, valToStore.llvmValue, valToStore.yoiType);
1190 if (yoiType->type == IRValueType::valueType::datastructObject && yoiType->hasAttribute(IRValueType::ValueAttr::Raw)) {
1192 auto fieldType = yoiTypeToLLVMType(llvmModCtx, yoiType,
true);
1193 auto fieldSize = llvmModCtx.
TheModule->getDataLayout().getTypeAllocSize(fieldType);
1194 llvmModCtx.
Builder->CreateMemCpy(alloca, llvm::MaybeAlign(8), unboxedVal, llvm::MaybeAlign(8), fieldSize);
1196 llvmModCtx.
Builder->CreateStore(unboxedVal, alloca);
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);
1202 llvmModCtx.
Builder->CreateStore(
object.second, alloca);
1207 case IR::Opcode::load_global: {
1208 auto varIndex = instr.
operands[1].value.symbolIndex;
1210 auto yoiType = yoiModule ->globalVariables[varIndex];
1211 yoiType->addAttribute(IRValueType::ValueAttr::Nullable).addAttribute(IRValueType::ValueAttr::PermanentInCurrentScope);
1212 auto loadedPtr = llvmModCtx.
Builder->CreateLoad(global->getValueType(), global,
"loadglobaltmp");
1216 case IR::Opcode::store_global: {
1217 auto varIndex = instr.
operands[1].value.symbolIndex;
1219 auto yoiType = yoiModule->globalVariables[varIndex];
1222 valToStore = promiseInterfaceObjectIfInterface(llvmModCtx, valToStore);
1224 yoiType->addAttribute(IRValueType::ValueAttr::Nullable);
1226 auto* oldPtr = llvmModCtx.
Builder->CreateLoad(global->getValueType(), global,
"old_global_ptr");
1227 callGcFunction(llvmModCtx, oldPtr, yoiType,
false,
true);
1229 auto object = ensureObject(llvmModCtx, valToStore.yoiType, valToStore.llvmValue);
1230 if (
object.first->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1231 callGcFunction(llvmModCtx,
object.second, valToStore.yoiType,
true,
true,
true);
1233 llvmModCtx.
Builder->CreateStore(
object.second, global);
1236 case IR::Opcode::load_member: {
1238 auto memberIndex = instr.
operands[0].value.symbolIndex;
1239 auto llvmMemberIndex = memberIndex + 2;
1241 auto key = std::make_tuple(IRValueType::valueType::structObject, structVal.yoiType->typeAffiliateModule, structVal.yoiType->typeIndex);
1243 auto* gep = llvmModCtx.
Builder->CreateStructGEP(llvmStructType, structVal.llvmValue, llvmMemberIndex,
"memberptr");
1245 auto yoiStructDef = compilerCtx->getIRObjectFile()->compiledModule->structTable[std::get<2>(key)];
1246 auto memberYoiType = yoiStructDef->fieldTypes[memberIndex];
1247 if (structVal.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1251 if (memberYoiType->hasAttribute(IRValueType::ValueAttr::WeakRef)) {
1252 auto* i8PtrTy = llvm::PointerType::get(*llvmModCtx.
TheContext, 0);
1253 auto* slot = llvmModCtx.
Builder->CreateLoad(i8PtrTy, gep,
"weak_slot");
1254 auto* hasSlot = llvmModCtx.
Builder->CreateIsNotNull(slot,
"has_weak_slot");
1258 llvmModCtx.
Builder->CreateCondBr(hasSlot, loadTargetBB, pushNullBB);
1260 llvmModCtx.
Builder->SetInsertPoint(loadTargetBB);
1261 auto* targetPtr = llvmModCtx.
Builder->CreateLoad(i8PtrTy, slot,
"weak_target_ptr");
1262 auto* hasTarget = llvmModCtx.
Builder->CreateIsNotNull(targetPtr,
"has_weak_target");
1263 auto* retainTargetBB = llvm::BasicBlock::Create(*llvmModCtx.
TheContext,
"retain_weak_target", llvmModCtx.
currentFunction);
1264 llvmModCtx.
Builder->CreateCondBr(hasTarget, retainTargetBB, pushNullBB);
1266 llvmModCtx.
Builder->SetInsertPoint(retainTargetBB);
1268 callGcFunction(llvmModCtx, targetPtr, loadedType,
true);
1269 llvmModCtx.
Builder->CreateBr(doneWeakLoadBB);
1271 llvmModCtx.
Builder->SetInsertPoint(pushNullBB);
1272 llvmModCtx.
Builder->CreateBr(doneWeakLoadBB);
1274 llvmModCtx.
Builder->SetInsertPoint(doneWeakLoadBB);
1276 auto* phi = llvmModCtx.
Builder->CreatePHI(i8PtrTy, 2,
"weak_load_phi");
1277 phi->addIncoming(targetPtr, retainTargetBB);
1278 phi->addIncoming(llvm::ConstantPointerNull::get(i8PtrTy), pushNullBB);
1280 callGcFunction(llvmModCtx, structVal.llvmValue, structVal.yoiType,
false);
1284 llvm::Type* loadedType = yoiTypeToLLVMType(llvmModCtx, memberYoiType, memberYoiType->isBasicType() && memberYoiType->hasAttribute(IRValueType::ValueAttr::Raw));
1285 auto* loadedMember =
1286 memberYoiType->type == IRValueType::valueType::datastructObject
1288 : llvmModCtx.
Builder->CreateLoad(loadedType, gep,
"loadmember");
1289 callGcFunction(llvmModCtx, loadedMember, memberYoiType,
true);
1292 callGcFunction(llvmModCtx, structVal.llvmValue, structVal.yoiType,
false);
1295 case IR::Opcode::store_member: {
1298 valueToStore = promiseInterfaceObjectIfInterface(llvmModCtx, valueToStore);
1300 auto memberIndex = instr.
operands[0].value.symbolIndex;
1301 storeMember(llvmModCtx, valueToStore, structVal, memberIndex);
1303 callGcFunction(llvmModCtx, structVal.llvmValue, structVal.yoiType,
false);
1307 case IR::Opcode::jump: {
1311 case IR::Opcode::jump_if_true:
1312 case IR::Opcode::jump_if_false: {
1314 auto* condRaw = unboxValue(llvmModCtx, condObj.llvmValue, condObj.yoiType);
1315 callGcFunction(llvmModCtx, condObj.llvmValue, condObj.yoiType,
false);
1320 if (instr.
opcode == IR::Opcode::jump_if_true) {
1321 llvmModCtx.
Builder->CreateCondBr(condRaw, destBlock, nextBlock);
1323 llvmModCtx.
Builder->CreateCondBr(condRaw, nextBlock, destBlock);
1325 llvmModCtx.
Builder->SetInsertPoint(nextBlock);
1329 case IR::Opcode::ret: {
1332 if (compilerCtx->getBuildConfig()->buildMode == IRBuildConfig::BuildMode::debug) {
1334 auto* debugStrConst = llvm::ConstantDataArray::getString(*llvmModCtx.
TheContext, funcName,
true);
1335 auto* debugStrGlobal =
new llvm::GlobalVariable(*llvmModCtx.
TheModule, debugStrConst->getType(),
true, llvm::GlobalVariable::PrivateLinkage, debugStrConst,
"debug_str");
1336 auto debugArgs = std::array<llvm::Value*, 1>{ debugStrGlobal };
1337 llvmModCtx.
Builder->CreateCall(llvmModCtx.
runtimeFunctions.at(L
"runtime_debug_report_leave_function"), llvm::ArrayRef<llvm::Value*>(debugArgs));
1340 retVal = promiseInterfaceObjectIfInterface(llvmModCtx, retVal);
1343 if (llvmModCtx.
currentFunctionDef->returnType->hasAttribute(IRValueType::ValueAttr::Raw)) {
1344 auto res = unboxValue(llvmModCtx, retVal.llvmValue, retVal.yoiType);
1346 callGcFunction(llvmModCtx, retVal.llvmValue, retVal.yoiType,
false);
1347 generateFunctionExitCleanup(llvmModCtx);
1348 llvmModCtx.
Builder->CreateRet(res);
1350 auto object = ensureObject(llvmModCtx, retVal.yoiType, retVal.llvmValue);
1351 if (
object.first->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1352 callGcFunction(llvmModCtx,
object.second, retVal.yoiType,
true,
true,
true);
1353 generateFunctionExitCleanup(llvmModCtx);
1354 llvmModCtx.
Builder->CreateRet(
object.second);
1358 case IR::Opcode::ret_none: {
1359 generateFunctionExitCleanup(llvmModCtx);
1361 if (compilerCtx->getBuildConfig()->buildMode == IRBuildConfig::BuildMode::debug) {
1363 auto* debugStrConst = llvm::ConstantDataArray::getString(*llvmModCtx.
TheContext, funcName,
true);
1364 auto* debugStrGlobal =
new llvm::GlobalVariable(*llvmModCtx.
TheModule, debugStrConst->getType(),
true, llvm::GlobalVariable::PrivateLinkage, debugStrConst,
"debug_str");
1365 auto debugArgs = std::array<llvm::Value*, 1>{ debugStrGlobal };
1366 llvmModCtx.
Builder->CreateCall(llvmModCtx.
runtimeFunctions.at(L
"runtime_debug_report_leave_function"), llvm::ArrayRef<llvm::Value*>(debugArgs));
1369 llvmModCtx.
Builder->CreateRetVoid();
1373 case IR::Opcode::invoke: {
1374 auto moduleIndex = instr.
operands[0].value.symbolIndex;
1375 auto funcIndex = instr.
operands[1].value.symbolIndex;
1376 auto argCount = instr.
operands[2].value.symbolIndex;
1378 auto funcDef = yoiModule->functionTable[funcIndex];
1379 auto* function = llvmModCtx.
functionMap.at(funcDef->name);
1381 std::vector<llvm::Value*> args;
1382 std::vector<std::pair<std::shared_ptr<IRValueType>, llvm::Value*>> postCleanup;
1384 for(
size_t i = 0; i < argCount; ++i) {
1388 arg = promiseInterfaceObjectIfInterface(llvmModCtx, arg);
1390 if (funcDef->argumentTypes[argCount - i - 1]->hasAttribute(IRValueType::ValueAttr::Raw)) {
1392 loadIfDataStructObject(llvmModCtx, funcDef->argumentTypes[argCount - i - 1],
1393 unboxValue(llvmModCtx, arg.llvmValue, arg.yoiType)));
1394 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
false);
1395 }
else if (funcDef->argumentTypes[argCount - i - 1]->hasAttribute(IRValueType::ValueAttr::Borrow)) {
1396 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1397 args.push_back(
object.second);
1398 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw));
1399 else postCleanup.push_back(
object);
1401 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1402 args.push_back(
object.second);
1403 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw))
1404 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
true,
true);
1408 std::reverse(args.begin(), args.end());
1410 if (funcDef->returnType->type == IRValueType::valueType::none) {
1411 llvmModCtx.
Builder->CreateCall(function, args);
1413 auto* call = llvmModCtx.
Builder->CreateCall(function, args,
"calltmp");
1418 for (
auto &i : postCleanup) {
1419 callGcFunction(llvmModCtx, i.second, i.first,
false);
1423 case IR::Opcode::invoke_dangling: {
1424 auto moduleIndex = instr.
operands[0].value.symbolIndex;
1425 auto funcIndex = instr.
operands[1].value.symbolIndex;
1426 auto argCount = instr.
operands[2].value.symbolIndex;
1430 auto funcDef = yoiModule->functionTable[funcIndex];
1431 auto* function = llvmModCtx.
functionMap.at(funcDef->name);
1433 std::vector<llvm::Value*> args;
1434 std::vector<std::pair<std::shared_ptr<IRValueType>, llvm::Value*>> postCleanup;
1436 llvm::Value *postponed =
nullptr;
1441 arg = promiseInterfaceObjectIfInterface(llvmModCtx, arg);
1443 if (funcDef->argumentTypes[0]->hasAttribute(IRValueType::ValueAttr::Raw)) {
1444 postponed = loadIfDataStructObject(llvmModCtx, funcDef->argumentTypes[0], unboxValue(llvmModCtx, arg.llvmValue, arg.yoiType));
1445 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
false);
1446 }
else if (funcDef->argumentTypes[0]->hasAttribute(IRValueType::ValueAttr::Borrow)) {
1447 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1448 postponed =
object.second;
1449 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw));
1450 else postCleanup.push_back(
object);
1452 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1453 postponed =
object.second;
1454 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw))
1455 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
true,
true);
1460 for(
size_t i = 1; i < argCount; ++i) {
1464 arg = promiseInterfaceObjectIfInterface(llvmModCtx, arg);
1466 if (funcDef->argumentTypes[argCount - i]->hasAttribute(IRValueType::ValueAttr::Raw)) {
1467 args.push_back(loadIfDataStructObject(llvmModCtx, funcDef->argumentTypes[argCount - i], unboxValue(llvmModCtx, arg.llvmValue, arg.yoiType)));
1468 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
false);
1469 }
else if (funcDef->argumentTypes[argCount - i]->hasAttribute(IRValueType::ValueAttr::Borrow)) {
1470 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1471 args.push_back(
object.second);
1472 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw));
1473 else postCleanup.push_back(
object);
1475 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1476 args.push_back(
object.second);
1477 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !arg.yoiType->hasAttribute(IRValueType::ValueAttr::Raw))
1478 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
true,
true);
1483 args.push_back(postponed);
1485 std::reverse(args.begin(), args.end());
1487 if (funcDef->returnType->type == IRValueType::valueType::none) {
1488 llvmModCtx.
Builder->CreateCall(function, args);
1490 auto* call = llvmModCtx.
Builder->CreateCall(function, args,
"calltmp");
1495 for (
auto &i : postCleanup) {
1496 callGcFunction(llvmModCtx, i.second, i.first,
false);
1500 case IR::Opcode::invoke_imported: {
1501 auto libIndex = instr.
operands[0].value.symbolIndex;
1502 auto funcIndex = instr.
operands[1].value.symbolIndex;
1503 auto argCount = instr.
operands[2].value.symbolIndex;
1505 auto funcDef = compilerCtx->getIRFFITable()->importedLibraries[libIndex].importedFunctionTable[funcIndex];
1507 if (funcDef->hasAttribute(IRFunctionDefinition::FunctionAttrs::Intrinsic)) {
1508 handleIntrinsicCall(llvmModCtx, instr);
1512 bool noffi = funcDef->hasAttribute(IRFunctionDefinition::FunctionAttrs::NoFFI);
1514 auto rawFuncName = compilerCtx->getIRFFITable()->importedLibraries[libIndex].importedFunctionTable.getKey(funcIndex);
1515 auto mangledFuncName = L
"imported#" + std::to_wstring(libIndex) + L
"#" + rawFuncName;
1516 if (!noffi) mangledFuncName += L
"#wrapper";
1518 auto* function = llvmModCtx.
functionMap.at(mangledFuncName);
1520 std::vector<std::pair<std::shared_ptr<IRValueType>, llvm::Value*>> postCleanup;
1521 std::vector<llvm::Value*> args;
1523 for(
size_t i = 0; i < argCount; ++i) {
1526 arg = promiseInterfaceObjectIfInterface(llvmModCtx, arg);
1528 if ((arg.yoiType->isBasicType() || arg.yoiType->isBasicRawType()) && !noffi) {
1529 auto *param = unboxValue(llvmModCtx, arg.llvmValue, arg.yoiType);
1530 if (arg.yoiType->type == IRValueType::valueType::stringObject || arg.yoiType->type == IRValueType::valueType::stringLiteral) {
1533 param = llvmModCtx.
Builder->CreatePtrToInt(param, llvm::Type::getInt64Ty(*llvmModCtx.
TheContext),
"string_to_int");
1536 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
false);
1537 args.push_back(param);
1539 auto object = ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue);
1540 postCleanup.push_back(
object);
1541 if (arg.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && noffi)
1542 callGcFunction(llvmModCtx, arg.llvmValue, arg.yoiType,
true,
true,
true);
1543 args.push_back(postCleanup.back().second);
1548 std::reverse(args.begin(), args.end());
1550 if (funcDef->returnType->type == IRValueType::valueType::none) {
1551 llvmModCtx.
Builder->CreateCall(function, args);
1553 auto* call = llvmModCtx.
Builder->CreateCall(function, args,
"calltmp");
1556 auto onstackType = noffi ? *funcDef->returnType : compilerCtx->normalizeForeignBasicType(funcDef->returnType);
1558 if (noffi && (funcDef->returnType->type == IRValueType::valueType::structObject ||
1559 funcDef->returnType->type == IRValueType::valueType::interfaceObject)) {
1561 auto notNullBlock = llvm::BasicBlock::Create(*llvmModCtx.
TheContext,
"audit_typeid_not_null", llvmModCtx.
currentFunction);
1562 auto continueBlock = llvm::BasicBlock::Create(*llvmModCtx.
TheContext,
"audit_typeid_continue", llvmModCtx.
currentFunction);
1563 llvmModCtx.
Builder->CreateCondBr(llvmModCtx.
Builder->CreateIsNotNull(call,
"audit_typeid_isnotnull"), notNullBlock, continueBlock);
1564 llvmModCtx.
Builder->SetInsertPoint(notNullBlock);
1565 auto typeIdKey = std::make_tuple(IRValueType::valueType::structObject,
1567 funcDef->returnType->typeIndex,
1569 auto structKey = std::make_tuple(IRValueType::valueType::structObject,
1571 funcDef->returnType->typeIndex);
1572 auto typeId = llvmModCtx.
typeIDMap[typeIdKey];
1574 auto *typeIdPtr = llvmModCtx.
Builder->CreateStructGEP(llvmStruct, call, 1,
"typeid_ptr");
1575 llvmModCtx.
Builder->CreateStore(llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), typeId), typeIdPtr);
1576 llvmModCtx.
Builder->CreateBr(continueBlock);
1577 llvmModCtx.
Builder->SetInsertPoint(continueBlock);
1584 for (
auto &i : postCleanup) {
1585 callGcFunction(llvmModCtx, i.second, i.first,
false);
1590 case IR::Opcode::new_struct: {
1591 auto moduleIndex = instr.
operands[0].value.symbolIndex;
1592 auto structIndex = instr.
operands[1].value.symbolIndex;
1594 auto bitcast = createStructObject(llvmModCtx, moduleIndex, structIndex);
1596 auto yoiType = std::make_shared<IRValueType>(IRValueType::valueType::structObject, yoiModule->identifier, structIndex);
1600 case IR::Opcode::new_datastruct: {
1602 auto moduleIndex = instr.
operands[0].value.symbolIndex;
1603 auto dataStructIndex = instr.
operands[1].value.symbolIndex;
1604 auto key = std::make_tuple(IRValueType::valueType::datastructObject, yoiModule->identifier, dataStructIndex);
1608 auto* allocCall = llvmModCtx.
Builder->CreateAlloca(dataRegionType,
nullptr,
"datastruct_alloc");
1610 auto yoiType = std::make_shared<IRValueType>(IRValueType::valueType::datastructObject, yoiModule->identifier, dataStructIndex);
1611 yoiType->addAttribute(IRValueType::ValueAttr::Raw);
1615 case IR::Opcode::initialize_field: {
1623 llvm::Value *dataRegionPtr = top.llvmValue;
1624 if (top.yoiType->hasAttribute(IRValueType::ValueAttr::Raw)) {
1625 dataRegionPtr = top.llvmValue;
1627 auto objectTypeKey = std::make_tuple(IRValueType::valueType::datastructObject, yoiModule->identifier, top.yoiType->typeIndex);
1628 auto *objectType = llvmModCtx.
structTypeMap.at(objectTypeKey);
1629 dataRegionPtr = llvmModCtx.
Builder->CreateStructGEP(objectType, top.llvmValue, 2,
"datastruct_ptr");
1632 auto value = unboxValue(llvmModCtx, values[i].llvmValue, values[i].yoiType);
1633 auto fieldPtr = llvmModCtx.
Builder->CreateStructGEP(dataRegionType, dataRegionPtr, i,
"field_ptr");
1634 auto fieldType = dataRegionType->getStructElementType(i);
1635 if (fieldType->isStructTy()) {
1637 auto size = llvmModCtx.
TheModule->getDataLayout().getTypeAllocSize(fieldType);
1638 auto *sizeVal = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), size);
1639 auto *memCpy = llvmModCtx.
Builder->CreateMemCpy(fieldPtr, llvm::MaybeAlign(8), value, llvm::MaybeAlign(8), sizeVal);
1641 llvmModCtx.
Builder->CreateStore(value, fieldPtr);
1643 callGcFunction(llvmModCtx, values[i].llvmValue, values[i].yoiType,
false);
1648 case IR::Opcode::store_field: {
1655 auto currentType = srcValue.yoiType;
1656 auto val = unboxValue(llvmModCtx, srcValue.llvmValue, srcValue.yoiType);
1657 auto llvmType = yoiTypeToLLVMType(llvmModCtx, currentType,
true);
1659 auto destType = destValue.yoiType;
1660 auto destVal = unboxValue(llvmModCtx, destValue.llvmValue, destValue.yoiType);
1661 llvm::Value *fieldPtr =
nullptr;
1663 for (
auto &operand : instr.
operands) {
1664 auto def = yoiModule->dataStructTable[destType->typeIndex];
1665 auto nextType = def->fieldTypes[operand.value.symbolIndex];
1667 fieldPtr = llvmModCtx.
Builder->CreateStructGEP(llvmType, destVal, operand.value.symbolIndex,
"field_ptr");
1669 destType = nextType;
1672 if (destType->type == IRValueType::valueType::datastructObject) {
1674 auto size = llvmModCtx.
TheModule->getDataLayout().getTypeAllocSize(llvmType);
1675 auto *sizeVal = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), size);
1676 auto *memCpy = llvmModCtx.
Builder->CreateMemCpy(fieldPtr, llvm::MaybeAlign(8), val, llvm::MaybeAlign(8), sizeVal);
1678 llvmModCtx.
Builder->CreateStore(val, fieldPtr);
1681 callGcFunction(llvmModCtx, srcValue.llvmValue, srcValue.yoiType,
false);
1684 case IR::Opcode::load_field: {
1687 auto currentType = top.yoiType;
1688 auto val = unboxValue(llvmModCtx, top.llvmValue, top.yoiType);
1689 for (
auto &operand : instr.
operands) {
1690 auto def = yoiModule->dataStructTable[currentType->typeIndex];
1691 auto nextType = def->fieldTypes[operand.value.symbolIndex];
1693 val = llvmModCtx.
Builder->CreateStructGEP(llvmType, val, operand.value.symbolIndex,
"field_ptr");
1694 currentType = nextType;
1696 if (currentType->isArrayType()) {
1697 auto arrayVal = createArrayObject(llvmModCtx,
managedPtr(currentType->getElementType()), {});
1698 auto llvmType = getArrayLLVMType(llvmModCtx, currentType);
1704 auto dataRegionPtr = llvmModCtx.
Builder->CreateStructGEP(llvmType, val, 3,
"data_region_ptr");
1705 auto dataSize = llvmModCtx.
TheModule->getDataLayout().getTypeAllocSize(llvmType->getStructElementType(3));
1707 llvmModCtx.
Builder->CreateMemCpy(val, llvm::MaybeAlign(8), dataRegionPtr, llvm::MaybeAlign(8), dataSize);
1710 }
else if (currentType->isBasicType()) {
1711 val = llvmModCtx.
Builder->CreateLoad(yoiTypeToLLVMType(llvmModCtx, currentType,
true), val,
"field_val");
1713 currentType->addAttribute(IRValueType::ValueAttr::Raw);
1714 }
else if (currentType->type == IRValueType::valueType::datastructObject) {
1717 currentType->addAttribute(IRValueType::ValueAttr::Raw);
1724 case IR::Opcode::construct_interface_impl: {
1725 auto interfaceImplIndex = instr.
operands[1].value.symbolIndex;
1726 auto interfaceImplDef = yoiModule->interfaceImplementationTable[interfaceImplIndex];
1728 top = promiseInterfaceObjectIfInterface(llvmModCtx, top);
1729 auto object = ensureObject(llvmModCtx, top.yoiType, top.llvmValue);
1730 top.yoiType =
object.first;
1731 top.llvmValue =
object.second;
1735 top.yoiType->type = IRValueType::valueType::interfaceObject;
1737 top.yoiType->typeIndex = interfaceImplDef->implInterfaceIndex.second;
1738 top.yoiType->metadata.setMetadata(L
"regressed_interface_impl", std::pair<yoi::indexT, yoi::indexT>{
ENTRY_MODULE_ID_CONST, interfaceImplIndex});
1741 case IR::Opcode::bind_elements_post:
1742 case IR::Opcode::bind_elements_pred: {
1748 auto arrayLLVMType = getArrayLLVMType(llvmModCtx, array.yoiType);
1750 auto *arrayLen = llvmModCtx.
Builder->CreateStructGEP(arrayLLVMType, array.llvmValue, 2,
"array_len");
1751 auto *loadedArrayLen = llvmModCtx.
Builder->CreateLoad(llvmModCtx.
Builder->getInt64Ty(), arrayLen,
"loaded_array_len");
1753 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");
1756 auto currentPos = llvmModCtx.
Builder->CreateAdd(startPos, llvmModCtx.
Builder->getInt64(i),
"current_pos");
1757 auto currentValue = loadArrayElement(llvmModCtx, array.yoiType, array.llvmValue, currentPos);
1758 std::shared_ptr<IRValueType> elementType;
1759 if (array.yoiType->isBasicType()) {
1760 elementType =
managedPtr(array.yoiType->getElementType().getBasicRawType());
1761 }
else if (array.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope)) {
1762 elementType =
managedPtr(array.yoiType->getElementType().addAttribute(IRValueType::ValueAttr::PermanentInCurrentScope).addAttribute(IRValueType::ValueAttr::Nullable));
1764 elementType =
managedPtr(array.yoiType->getElementType().addAttribute(IRValueType::ValueAttr::Nullable));
1769 callGcFunction(llvmModCtx, array.llvmValue, array.yoiType,
false);
1772 case IR::Opcode::bind_fields_post:
1773 case IR::Opcode::bind_fields_pred: {
1778 auto structDef = yoiModule->structTable[structVal.yoiType->typeIndex];
1780 auto startPos = instr.
opcode == IR::Opcode::bind_fields_post ? 0 : structDef->fieldTypes.size() - instr.
operands[0].value.symbolIndex;
1781 for (
yoi::indexT memberIndex = startPos; memberIndex < startPos + instr.
operands[0].value.symbolIndex; memberIndex++) {
1782 auto llvmMemberIndex = memberIndex + 2;
1784 auto key = std::make_tuple(IRValueType::valueType::structObject, structVal.yoiType->typeAffiliateModule, structVal.yoiType->typeIndex);
1786 auto* gep = llvmModCtx.
Builder->CreateStructGEP(llvmStructType, structVal.llvmValue, llvmMemberIndex,
"memberptr");
1788 auto yoiStructDef = compilerCtx->getIRObjectFile()->compiledModule->structTable[std::get<2>(key)];
1789 auto memberYoiType = yoiStructDef->fieldTypes[memberIndex];
1790 if (structVal.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1792 memberYoiType->addAttribute(IRValueType::ValueAttr::Nullable);
1793 memberYoiType->removeAttribute(IRValueType::ValueAttr::Raw);
1795 llvm::Type* loadedType = yoiTypeToLLVMType(llvmModCtx, memberYoiType);
1796 auto* loadedMember = llvmModCtx.
Builder->CreateLoad(loadedType, gep,
"loadmember");
1797 callGcFunction(llvmModCtx, loadedMember, memberYoiType,
true);
1801 callGcFunction(llvmModCtx, structVal.llvmValue, structVal.yoiType,
false);
1804 case IR::Opcode::invoke_virtual: {
1805 auto methodVTableIndex = instr.
operands[2].value.symbolIndex;
1806 auto userArgCount = instr.
operands[3].value.symbolIndex;
1808 std::vector<StackValue> userArgs;
1809 std::vector<std::pair<std::shared_ptr<IRValueType>, llvm::Value*>> postCleanup;
1811 for (
size_t i = 0; i < userArgCount - 1; ++i) {
1812 userArgs.push_back(promiseInterfaceObjectIfInterface(llvmModCtx, llvmModCtx.
valueStackPhi.
back()));
1815 std::reverse(userArgs.begin(), userArgs.end());
1820 auto interfaceKey = std::make_tuple(IRValueType::valueType::interfaceObject, interfaceShellVal.yoiType->typeAffiliateModule, interfaceShellVal.yoiType->typeIndex);
1821 auto* interfaceLLVMType = llvmModCtx.
structTypeMap.at(interfaceKey);
1822 auto interfaceDef = yoiModule->interfaceTable[std::get<2>(interfaceKey)];
1825 auto concreteThisPtrRaw = unwrapInterfaceObject(llvmModCtx, interfaceShellVal);
1826 auto* bitcastedPointer = llvmModCtx.
Builder->CreateBitCast(concreteThisPtrRaw, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"casted_this");
1836 std::vector<llvm::Value*> finalArgs;
1837 finalArgs.push_back(concreteThisPtrRaw);
1838 for(
yoi::indexT paramIndex = 0; paramIndex < userArgs.size(); ++paramIndex) {
1839 const auto& arg = userArgs[paramIndex];
1840 auto paramDef = interfaceDef->methodMap[methodVTableIndex]->argumentTypes[paramIndex];
1841 auto object = (paramDef->hasAttribute(IRValueType::ValueAttr::Nullable) || (!paramDef->isBasicType() && !paramDef->isBasicRawType()) || !paramDef->dimensions.empty())
1842 ? ensureObject(llvmModCtx, arg.yoiType, arg.llvmValue)
1843 : std::pair{
managedPtr(arg.yoiType->getBasicRawType()), loadIfDataStructObject(llvmModCtx, paramDef, unboxValue(llvmModCtx, arg.llvmValue, arg.yoiType))};
1844 finalArgs.push_back(
object.second);
1846 if (
object.first->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !
object.first->hasAttribute(IRValueType::ValueAttr::Raw));
1848 else postCleanup.emplace_back(
object);
1851 std::shared_ptr<IRFunctionDefinition> methodDef;
1852 llvm::Value *funcPtrToCall =
nullptr;
1853 llvm::FunctionType *virtualFuncType =
nullptr;
1854 if (interfaceShellVal.yoiType->metadata.hasMetadata(L
"regressed_interface_impl")) {
1855 auto interfaceImplIndex = interfaceShellVal.yoiType->metadata.getMetadata<std::pair<yoi::indexT, yoi::indexT>>(L
"regressed_interface_impl");
1856 auto interfaceImplDef = yoiModule->interfaceImplementationTable[interfaceImplIndex.second];
1857 methodDef = yoiModule->functionTable[interfaceImplDef->virtualMethods[methodVTableIndex]->typeIndex];
1858 funcPtrToCall = llvmModCtx.
functionMap[methodDef->name];
1859 virtualFuncType = llvmModCtx.
functionMap[methodDef->name]->getFunctionType();
1861 auto vtableSlotIndex = methodVTableIndex + 5;
1862 auto* vtableSlotPtr = llvmModCtx.
Builder->CreateStructGEP(interfaceLLVMType, interfaceShellVal.llvmValue, vtableSlotIndex,
"vtable_slot_ptr");
1864 auto interfaceDef = compilerCtx->getIRObjectFile()->compiledModule->interfaceTable[std::get<2>(interfaceKey)];
1865 methodDef = interfaceDef->methodMap[methodVTableIndex];
1866 auto* funcType = getFunctionType(llvmModCtx, methodDef);
1868 std::vector<llvm::Type*> virtualArgTypes;
1869 virtualArgTypes.push_back(llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
1870 for (
size_t i = 0; i < funcType->getNumParams(); ++i) {
1871 virtualArgTypes.push_back(funcType->getParamType(i));
1873 virtualFuncType = llvm::FunctionType::get(funcType->getReturnType(), virtualArgTypes,
false);
1874 auto* virtualFuncPtrType = llvm::PointerType::get(*llvmModCtx.
TheContext, 0);
1875 funcPtrToCall = llvmModCtx.
Builder->CreateLoad(virtualFuncPtrType, vtableSlotPtr,
"func_ptr");
1878 if (methodDef->returnType->type == IRValueType::valueType::none) {
1879 llvmModCtx.
Builder->CreateCall(virtualFuncType, funcPtrToCall, finalArgs);
1881 llvm::CallInst* call = llvmModCtx.
Builder->CreateCall(virtualFuncType, funcPtrToCall, finalArgs,
"virtcall");
1885 for (
auto &i : postCleanup) {
1886 callGcFunction(llvmModCtx, i.second, i.first,
false);
1889 callGcFunction(llvmModCtx, interfaceShellVal.llvmValue, interfaceShellVal.yoiType,
false);
1892 case IR::Opcode::new_array_int:
1893 case IR::Opcode::new_array_bool:
1894 case IR::Opcode::new_array_char:
1895 case IR::Opcode::new_array_deci:
1896 case IR::Opcode::new_array_unsigned:
1897 case IR::Opcode::new_array_short:
1898 case IR::Opcode::new_array_str: {
1903 std::shared_ptr<yoi::IRValueType> elementType;
1905 size *= instr.
operands[i].value.symbolIndex;
1906 dimensions.push_back(instr.
operands[i].value.symbolIndex);
1914 case IR::Opcode::new_array_int:
1915 elementType = compilerCtx->getIntObjectType();
1917 case IR::Opcode::new_array_bool:
1918 elementType = compilerCtx->getBoolObjectType();
1920 case IR::Opcode::new_array_char:
1921 elementType = compilerCtx->getCharObjectType();
1923 case IR::Opcode::new_array_deci:
1924 elementType = compilerCtx->getDeciObjectType();
1926 case IR::Opcode::new_array_str:
1927 elementType = compilerCtx->getStrObjectType();
1929 case IR::Opcode::new_array_unsigned:
1930 elementType = compilerCtx->getUnsignedObjectType();
1932 case IR::Opcode::new_array_short:
1933 elementType = compilerCtx->getShortObjectType();
1940 auto arrayType =
managedPtr(elementType->getArrayType(dimensions));
1941 auto val = createArrayObject(llvmModCtx, arrayType, dimensionsVal);
1951 case IR::Opcode::new_array_struct:
1952 case IR::Opcode::new_array_interface: {
1957 std::shared_ptr<yoi::IRValueType> elementType;
1959 size *= instr.
operands[i].value.symbolIndex;
1960 dimensions.push_back(instr.
operands[i].value.symbolIndex);
1964 if (value.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
1965 callGcFunction(llvmModCtx, value.llvmValue, value.yoiType,
true,
true,
true);
1966 dimensionsVal.push_back(value);
1969 elementType =
managedPtr(
IRValueType{instr.
opcode == IR::Opcode::new_array_struct ? IRValueType::valueType::structObject : IRValueType::valueType::interfaceObject, yoiModule->identifier, instr.
operands[1].value.symbolIndex});
1972 auto arrayType =
managedPtr(elementType->getArrayType(dimensions));
1973 auto val = createArrayObject(llvmModCtx, arrayType, dimensionsVal);
1982 case IR::Opcode::new_dynamic_array_int:
1983 case IR::Opcode::new_dynamic_array_bool:
1984 case IR::Opcode::new_dynamic_array_char:
1985 case IR::Opcode::new_dynamic_array_deci:
1986 case IR::Opcode::new_dynamic_array_unsigned:
1987 case IR::Opcode::new_dynamic_array_short:
1988 case IR::Opcode::new_dynamic_array_str: {
1992 auto unboxedSize = unboxValue(llvmModCtx, llvmSize.llvmValue, llvmSize.yoiType);
1995 std::shared_ptr<yoi::IRValueType> elementType;
2002 case IR::Opcode::new_dynamic_array_int:
2003 elementType = compilerCtx->getIntObjectType();
2005 case IR::Opcode::new_dynamic_array_bool:
2006 elementType = compilerCtx->getBoolObjectType();
2008 case IR::Opcode::new_dynamic_array_char:
2009 elementType = compilerCtx->getCharObjectType();
2011 case IR::Opcode::new_dynamic_array_deci:
2012 elementType = compilerCtx->getDeciObjectType();
2014 case IR::Opcode::new_dynamic_array_str:
2015 elementType = compilerCtx->getStrObjectType();
2017 case IR::Opcode::new_dynamic_array_short:
2018 elementType = compilerCtx->getShortObjectType();
2020 case IR::Opcode::new_dynamic_array_unsigned:
2021 elementType = compilerCtx->getUnsignedObjectType();
2028 auto arrayType =
managedPtr(elementType->getDynamicArrayType());
2029 auto val = createDynamicArrayObject(llvmModCtx, arrayType, valuesToStore, unboxedSize);
2039 callGcFunction(llvmModCtx, llvmSize.llvmValue, llvmSize.yoiType,
false);
2042 case IR::Opcode::new_dynamic_array_struct:
2043 case IR::Opcode::new_dynamic_array_interface: {
2047 auto unboxedSize = unboxValue(llvmModCtx, llvmSize.llvmValue, llvmSize.yoiType);
2050 std::shared_ptr<yoi::IRValueType> elementType;
2053 if (value.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
2054 callGcFunction(llvmModCtx, value.llvmValue, value.yoiType,
true,
true,
true);
2055 valuesToStore.push_back(value);
2058 elementType =
managedPtr(
IRValueType{instr.
opcode == IR::Opcode::new_dynamic_array_struct ? IRValueType::valueType::structObject : IRValueType::valueType::interfaceObject, yoiModule->identifier, instr.
operands[1].value.symbolIndex});
2061 auto arrayType =
managedPtr(elementType->getDynamicArrayType());
2062 auto val = createDynamicArrayObject(llvmModCtx, arrayType, valuesToStore, unboxedSize);
2069 callGcFunction(llvmModCtx, llvmSize.llvmValue, llvmSize.yoiType,
false);
2072 case IR::Opcode::load_element: {
2076 auto arrayType = arrayVal.yoiType;
2077 std::shared_ptr<yoi::IRValueType> elementType;
2078 if (arrayType->isBasicType()) {
2079 elementType =
managedPtr(arrayType->getElementType().getBasicRawType());
2080 }
else if (arrayType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope)) {
2081 elementType =
managedPtr(arrayType->getElementType().addAttribute(IRValueType::ValueAttr::PermanentInCurrentScope).addAttribute(IRValueType::ValueAttr::Nullable));
2083 elementType =
managedPtr(arrayType->getElementType().addAttribute(IRValueType::ValueAttr::Nullable));
2085 auto unboxedIndexVal = unboxValue(llvmModCtx, indexVal.llvmValue, indexVal.yoiType);
2086 auto result = loadArrayElement(llvmModCtx, arrayType, arrayVal.llvmValue, unboxedIndexVal);
2090 callGcFunction(llvmModCtx, indexVal.llvmValue, indexVal.yoiType,
false);
2091 callGcFunction(llvmModCtx, arrayVal.llvmValue, arrayVal.yoiType,
false);
2094 case IR::Opcode::pop: {
2098 callGcFunction(llvmModCtx, val.llvmValue, val.yoiType,
false);
2101 case IR::Opcode::direct_assign: {
2105 rhs = promiseInterfaceObjectIfInterface(llvmModCtx, rhs);
2107 auto object = ensureObject(llvmModCtx, rhs.yoiType, rhs.llvmValue);
2108 rhs = {
object.second,
object.first};
2110 auto lhsType = lhs.yoiType;
2111 auto rhsType = rhs.yoiType;
2112 auto lhsLLVMType = llvmModCtx.
structTypeMap.at(std::make_tuple(lhsType->type, lhsType->typeAffiliateModule, lhsType->typeIndex));
2113 auto rhsLLVMType = llvmModCtx.
structTypeMap.at(std::make_tuple(rhsType->type, rhsType->typeAffiliateModule, rhsType->typeIndex));
2117 if (lhsType->type == IRValueType::valueType::structObject) {
2120 for (
const auto& field : yoiModule->structTable[lhsType->typeIndex]->fieldTypes) {
2121 auto fieldPtr = llvmModCtx.
Builder->CreateStructGEP(lhsLLVMType, lhs.llvmValue, fieldIndex,
"field_ptr");
2122 auto loadedFieldPtr = llvmModCtx.
Builder->CreateLoad(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), fieldPtr,
"loaded_field_ptr");
2123 callGcFunction(llvmModCtx, loadedFieldPtr, field,
false);
2127 for (
const auto& field : yoiModule->structTable[rhsType->typeIndex]->fieldTypes) {
2128 auto fieldPtr = llvmModCtx.
Builder->CreateStructGEP(rhsLLVMType, rhs.llvmValue, fieldIndex,
"field_ptr");
2129 auto loadedFieldPtr = llvmModCtx.
Builder->CreateLoad(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), fieldPtr,
"loaded_field_ptr");
2130 callGcFunction(llvmModCtx, loadedFieldPtr, field,
true);
2133 }
else if (lhsType->type == IRValueType::valueType::interfaceObject) {
2136 auto thisPtr = llvmModCtx.
Builder->CreateStructGEP(lhsLLVMType, lhs.llvmValue, 1,
"this_ptr_field");
2137 auto* concreteThisPtrRaw = llvmModCtx.
Builder->CreateLoad(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), thisPtr,
"concrete_this_raw");
2138 auto* implGcDecSlot = llvmModCtx.
Builder->CreateStructGEP(lhsLLVMType, lhs.llvmValue, 3,
"impl_gc_dec_slot");
2139 auto* implGcDecFuncType = llvm::FunctionType::get(llvmModCtx.
Builder->getVoidTy(), {llvm::PointerType::get(*llvmModCtx.TheContext, 0)},
false);
2140 llvmModCtx.
Builder->CreateCall(implGcDecFuncType, implGcDecSlot, {concreteThisPtrRaw});
2141 auto rhsThisPtr = llvmModCtx.
Builder->CreateStructGEP(rhsLLVMType, rhs.llvmValue, 1,
"this_ptr_field");
2142 auto* rhsConcreteThisPtrRaw = llvmModCtx.
Builder->CreateLoad(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), rhsThisPtr,
"rhs_concrete_this_raw");
2143 auto* implGcIncSlot = llvmModCtx.
Builder->CreateStructGEP(rhsLLVMType, rhs.llvmValue, 2,
"impl_gc_inc_slot");
2144 auto* implGcIncFuncType = llvm::FunctionType::get(llvmModCtx.
Builder->getVoidTy(), {llvm::PointerType::get(*llvmModCtx.TheContext, 0)},
false);
2145 llvmModCtx.
Builder->CreateCall(implGcIncFuncType, implGcIncSlot, {rhsConcreteThisPtrRaw});
2148 auto structTypeSize = llvmModCtx.
TheModule->getDataLayout().getTypeAllocSize(lhsLLVMType);
2150 auto* lhsPtr = llvmModCtx.
Builder->CreateBitCast(lhs.llvmValue, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"lhs_ptr");
2151 auto* rhsPtr = llvmModCtx.
Builder->CreateBitCast(rhs.llvmValue, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"rhs_ptr");
2152 auto* offsettedLhsPtr = llvmModCtx.
Builder->CreateGEP(llvm::Type::getInt8Ty(*llvmModCtx.
TheContext), lhsPtr, {llvm::ConstantInt::get(llvmModCtx.Builder->getInt32Ty(), 16, true)});
2153 auto* offsettedRhsPtr = llvmModCtx.
Builder->CreateGEP(llvm::Type::getInt8Ty(*llvmModCtx.
TheContext), rhsPtr, {llvm::ConstantInt::get(llvmModCtx.Builder->getInt32Ty(), 16, true)});
2154 llvmModCtx.
Builder->CreateMemCpy(offsettedLhsPtr, llvm::MaybeAlign(8), offsettedRhsPtr, llvm::MaybeAlign(8), structTypeSize - 16);
2155 callGcFunction(llvmModCtx, rhs.llvmValue, rhs.yoiType,
false);
2159 case IR::Opcode::dyn_cast_any: {
2160 std::tuple<IRValueType::valueType, yoi::indexT, yoi::indexT> structTypeKey;
2161 std::tuple<IRValueType::valueType, yoi::indexT, yoi::indexT, yoi::indexT> structTypeIDKey;
2165 auto structTypeIndex = instr.
operands[1].value.symbolIndex;
2166 std::shared_ptr<IRValueType> structYoiType;
2169 if (instr.
operands[3].value.symbolIndex) {
2176 if (interfaceRhs.yoiType->metadata.hasMetadata(L
"regressed_interface_impl")) {
2177 auto regressedImpl = interfaceRhs.yoiType->metadata.getMetadata<std::pair<yoi::indexT, yoi::indexT>>(L
"regressed_interface_impl");
2178 auto implDef = yoiModule->interfaceImplementationTable[regressedImpl.second];
2179 if (implDef->implStructIndex == structTypeKey) {
2180 llvmModCtx.
valueStackPhi.
push_back({unwrapInterfaceObject(llvmModCtx, interfaceRhs),
managedPtr(
IRValueType{std::get<0>(implDef->implStructIndex), std::get<1>(implDef->implStructIndex), std::get<2>(implDef->implStructIndex)})});
2182 auto nullValue = llvm::ConstantPointerNull::get(llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2186 if (interfaceRhs.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope))
2187 callGcFunction(llvmModCtx, interfaceRhs.llvmValue, interfaceRhs.yoiType,
true,
true);
2195 auto structTypeId = llvmModCtx.
typeIDMap.at(structTypeIDKey);
2196 auto structTypeLLVMType = structYoiType->isArrayType() || structYoiType->isDynamicArrayType()
2201 auto* interfacePtr = llvmModCtx.
Builder->CreateBitCast(interfaceRhs.llvmValue, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"interface_ptr");
2202 auto* offsettedInterfacePtr = llvmModCtx.
Builder->CreateGEP(llvm::Type::getInt8Ty(*llvmModCtx.
TheContext), interfacePtr, {llvm::ConstantInt::get(llvmModCtx.
Builder->getInt32Ty(), 16,
true)});
2203 auto* structPtrPtr = llvmModCtx.
Builder->CreateBitCast(offsettedInterfacePtr, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"struct_ptr");
2204 auto* loadedStructPtr = llvmModCtx.
Builder->CreateLoad(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), structPtrPtr,
"loaded_struct_ptr");
2206 auto* typeIdPtr = llvmModCtx.
Builder->CreateStructGEP(structTypeLLVMType, loadedStructPtr, 1,
"typeid_ptr");
2207 auto* loadedTypeId = llvmModCtx.
Builder->CreateLoad(llvmModCtx.
Builder->getInt64Ty(), typeIdPtr,
"loaded_typeid");
2208 auto* expectedTypeId = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt64Ty(), structTypeId,
true);
2209 auto* typeIdMatch = llvmModCtx.
Builder->CreateICmpEQ(loadedTypeId, expectedTypeId,
"typeid_match");
2215 llvmModCtx.
Builder->CreateCondBr(typeIdMatch, successBB, failedMatchBB);
2217 llvmModCtx.
Builder->SetInsertPoint(failedMatchBB);
2218 auto* nullValue = llvm::ConstantPointerNull::get(llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2219 llvmModCtx.
Builder->CreateBr(continueBB);
2221 llvmModCtx.
Builder->SetInsertPoint(successBB);
2222 auto* resultObject = loadedStructPtr;
2223 callGcFunction(llvmModCtx, resultObject, structYoiType,
true);
2224 llvmModCtx.
Builder->CreateBr(continueBB);
2226 llvmModCtx.
Builder->SetInsertPoint(continueBB);
2227 auto *finalValue = llvmModCtx.
Builder->CreatePHI(llvm::PointerType::get(*llvmModCtx.
TheContext, 0), 2,
"final_value");
2228 finalValue->addIncoming(resultObject, successBB);
2229 finalValue->addIncoming(nullValue, failedMatchBB);
2230 callGcFunction(llvmModCtx, interfaceRhs.llvmValue, interfaceRhs.yoiType,
false);
2235 case IR::Opcode::push_null: {
2236 auto nullValue = llvm::ConstantPointerNull::get(llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2240 case IR::Opcode::pointer_cast: {
2242 auto value = llvmModCtx.
Builder->CreateBitCast(rhs.llvmValue, llvm::PointerType::get(*llvmModCtx.
TheContext, 0),
"pointer_cast");
2244 callGcFunction(llvmModCtx, rhs.llvmValue, rhs.yoiType,
false);
2247 case IR::Opcode::store_element: {
2253 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.");
2255 rhs = promiseInterfaceObjectIfInterface(llvmModCtx, rhs);
2258 auto* indexValue = unboxValue(llvmModCtx, index.llvmValue, index.yoiType);
2259 if (rhs.yoiType->hasAttribute(IRValueType::ValueAttr::PermanentInCurrentScope) && !lhs.yoiType->isBasicType())
2260 callGcFunction(llvmModCtx, rhs.llvmValue, rhs.yoiType,
true,
true,
true);
2261 storeArrayElement(llvmModCtx, lhs.yoiType, rhs.yoiType, lhs.llvmValue, indexValue, rhs.llvmValue);
2264 callGcFunction(llvmModCtx, index.llvmValue, index.yoiType,
false);
2265 callGcFunction(llvmModCtx, rhs.llvmValue, rhs.yoiType,
false);
2266 callGcFunction(llvmModCtx, lhs.llvmValue, lhs.yoiType,
false);
2269 case IR::Opcode::array_length: {
2272 auto arrayLLVMType = getArrayLLVMType(llvmModCtx, array.yoiType);
2274 auto *arrayLen = llvmModCtx.
Builder->CreateStructGEP(arrayLLVMType, array.llvmValue, 2,
"array_len");
2275 auto *loadedArrayLen = llvmModCtx.
Builder->CreateLoad(llvmModCtx.
Builder->getInt64Ty(), arrayLen,
"loaded_array_len");
2277 callGcFunction(llvmModCtx, array.llvmValue, array.yoiType,
false);
2280 case IR::Opcode::interfaceof: {
2283 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.");
2288 if (interfaceValue.yoiType->metadata.hasMetadata(L
"regressed_interface_impl")) {
2289 auto regressedImpl = interfaceValue.yoiType->metadata.getMetadata<std::pair<yoi::indexT, yoi::indexT>>(L
"regressed_interface_impl");
2290 auto implDef = yoiModule->interfaceImplementationTable[regressedImpl.second];
2291 if (llvmModCtx.
typeIDMap.contains({std::get<0>(implDef->implStructIndex), std::get<1>(implDef->implStructIndex), std::get<2>(implDef->implStructIndex), 0})) {
2292 auto *trueBoolean = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt1Ty(), 1,
true);
2295 auto *falseBoolean = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt1Ty(), 0,
true);
2298 callGcFunction(llvmModCtx, interfaceValue.llvmValue, interfaceValue.yoiType,
false);
2299 callGcFunction(llvmModCtx, typeidValue.llvmValue, typeidValue.yoiType,
false);
2304 auto interfaceKey = std::make_tuple(interfaceValue.yoiType->type, interfaceValue.yoiType->typeAffiliateModule, interfaceValue.yoiType->typeIndex);
2307 auto loadedThisPtr = unwrapInterfaceObject(llvmModCtx, interfaceValue);
2309 auto* typeIdPtr = llvmModCtx.
Builder->CreateGEP(llvmModCtx.
Builder->getInt64Ty(), loadedThisPtr, {llvm::ConstantInt::get(llvmModCtx.Builder->getInt32Ty(), 1, true)});
2310 auto* loadedTypeId = llvmModCtx.
Builder->CreateLoad(llvmModCtx.
Builder->getInt64Ty(), typeIdPtr,
"loaded_typeid");
2311 auto* expectedTypeId = unboxValue(llvmModCtx, typeidValue.llvmValue, typeidValue.yoiType);
2312 auto* typeIdMatch = llvmModCtx.
Builder->CreateICmpEQ(loadedTypeId, expectedTypeId,
"typeid_match");
2318 llvmModCtx.
Builder->CreateCondBr(typeIdMatch, successBB, failedMatchBB);
2320 llvmModCtx.
Builder->SetInsertPoint(failedMatchBB);
2321 auto *falseBoolean = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt1Ty(), 0,
true);
2322 llvmModCtx.
Builder->CreateBr(continueBB);
2324 llvmModCtx.
Builder->SetInsertPoint(successBB);
2325 auto *trueBoolean = llvm::ConstantInt::get(llvmModCtx.
Builder->getInt1Ty(), 1,
true);
2326 llvmModCtx.
Builder->CreateBr(continueBB);
2329 llvmModCtx.
Builder->SetInsertPoint(continueBB);
2330 auto phiNode = llvmModCtx.
Builder->CreatePHI(llvm::Type::getInt1Ty(*llvmModCtx.
TheContext), 2,
"phi_node");
2331 phiNode->addIncoming(trueBoolean, successBB);
2332 phiNode->addIncoming(falseBoolean, failedMatchBB);
2334 callGcFunction(llvmModCtx, interfaceValue.llvmValue, interfaceValue.yoiType,
false);
2335 callGcFunction(llvmModCtx, typeidValue.llvmValue, typeidValue.yoiType,
false);
2339 case IR::Opcode::typeid_object_non_stack: {
2341 auto typeId = llvmModCtx.
typeIDMap.at(key);
2345 case IR::Opcode::yield: {
2351 auto raw_ctx_ptr = llvmModCtx.
Builder->CreateIntToPtr(unboxValue(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType), llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2352 storeYieldValue(llvmModCtx, item.llvmValue, item.yoiType);
2353 auto coro_suspend = getLLVMCoroIntrinsic(llvmModCtx, llvm::Intrinsic::coro_suspend);
2354 auto suspend_result = llvmModCtx.
Builder->CreateCall(coro_suspend, {
2355 llvm::ConstantTokenNone::get(*llvmModCtx.
TheContext),
2356 llvm::ConstantInt::get(llvm::Type::getInt1Ty(*llvmModCtx.
TheContext), 0)});
2359 switch_inst->addCase(llvm::ConstantInt::get(llvm::Type::getInt8Ty(*llvmModCtx.
TheContext), 0), resumeBB);
2361 callGcFunction(llvmModCtx, item.llvmValue, item.yoiType,
false);
2362 callGcFunction(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType,
false);
2363 llvmModCtx.
Builder->SetInsertPoint(resumeBB);
2366 case IR::Opcode::yield_none: {
2370 auto raw_ctx_ptr = llvmModCtx.
Builder->CreateIntToPtr(unboxValue(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType), llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2371 auto coro_suspend = getLLVMCoroIntrinsic(llvmModCtx, llvm::Intrinsic::coro_suspend);
2372 auto suspend_result = llvmModCtx.
Builder->CreateCall(coro_suspend, {
2373 llvm::ConstantTokenNone::get(*llvmModCtx.
TheContext),
2374 llvm::ConstantInt::get(llvm::Type::getInt1Ty(*llvmModCtx.
TheContext), 0)});
2377 switch_inst->addCase(llvm::ConstantInt::get(llvm::Type::getInt8Ty(*llvmModCtx.
TheContext), 0), resumeBB);
2379 callGcFunction(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType,
false);
2380 llvmModCtx.
Builder->SetInsertPoint(resumeBB);
2383 case IR::Opcode::resume: {
2387 auto raw_ctx_ptr = llvmModCtx.
Builder->CreateIntToPtr(unboxValue(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType), llvm::PointerType::get(*llvmModCtx.
TheContext, 0));
2388 auto coroResume = getLLVMCoroIntrinsic(llvmModCtx, llvm::Intrinsic::coro_resume);
2389 auto resume_result = llvmModCtx.
Builder->CreateCall(coroResume, {
2392 callGcFunction(llvmModCtx, raw_ctx.llvmValue, raw_ctx.yoiType,
false);
2395 case IR::Opcode::nop:
3413 llvm::DIType *LLVMCodegen::getDIType(
LLVMModuleContext &llvmModCtx,
const std::shared_ptr<IRValueType> &type) {
3417 auto* di_i8 = llvmModCtx.
DBuilder->createBasicType(
"char", 8, llvm::dwarf::DW_ATE_signed_char);
3418 auto* di_i64 = llvmModCtx.
DBuilder->createBasicType(
"long long", 64, llvm::dwarf::DW_ATE_signed);
3421 llvmModCtx.
basicDITypeMap[L
"di_i16"] = llvmModCtx.
DBuilder->createBasicType(
"short", 16, llvm::dwarf::DW_ATE_signed);
3423 llvmModCtx.
basicDITypeMap[L
"di_i64_u"] = llvmModCtx.
DBuilder->createBasicType(
"unsigned long long", 64, llvm::dwarf::DW_ATE_unsigned);
3424 llvmModCtx.
basicDITypeMap[L
"di_double"] = llvmModCtx.
DBuilder->createBasicType(
"double", 64, llvm::dwarf::DW_ATE_float);
3425 llvmModCtx.
basicDITypeMap[L
"di_i1"] = llvmModCtx.
DBuilder->createBasicType(
"bool", 8, llvm::dwarf::DW_ATE_boolean);
3428 auto* unknown_object_struct = llvmModCtx.
DBuilder->createStructType(
3435 llvm::DINode::FlagZero,
3437 llvmModCtx.
DBuilder->getOrCreateArray({
3438 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"refcount", nullptr, 0, 64, 64, 0, llvm::DINode::FlagZero, di_i64),
3439 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"typeid", nullptr, 0, 64, 64, 64, llvm::DINode::FlagZero, di_i64),
3442 llvmModCtx.
basicDITypeMap[L
"di_unknown_object_ptr"] = llvmModCtx.
DBuilder->createPointerType(unknown_object_struct, 64);
3452 auto* di_unknown_object_ptr = llvmModCtx.
basicDITypeMap[L
"di_unknown_object_ptr"];
3454 if (type->isArrayType() || type->isDynamicArrayType()) {
3456 llvm::SmallVector<llvm::Metadata*, 8> dimensions;
3457 if (type->isArrayType()) {
3460 dimensions.push_back(llvmModCtx.
DBuilder->getOrCreateSubrange(0,
static_cast<int64_t
>(i)));
3463 dimensions.push_back(llvmModCtx.
DBuilder->getOrCreateSubrange(0,
static_cast<int64_t
>(0)));
3466 auto arrayKey = std::make_tuple(type->type, type->typeAffiliateModule, type->typeIndex, type->isArrayType() ? size :
static_cast<yoi::indexT>(-1));
3473 llvm::DIType *elementDIType =
nullptr;
3474 if (type->isBasicType()) {
3475 switch (type->type) {
3476 case IRValueType::valueType::integerObject:
3477 elementDIType = di_i64;
3479 case IRValueType::valueType::decimalObject:
3480 elementDIType = di_double;
3482 case IRValueType::valueType::booleanObject:
3483 elementDIType = di_i1;
3485 case IRValueType::valueType::characterObject:
3486 elementDIType = di_i8;
3488 case IRValueType::valueType::stringObject:
3489 elementDIType = di_i8_ptr;
3491 case IRValueType::valueType::unsignedObject:
3492 elementDIType = di_i64_u;
3494 case IRValueType::valueType::shortObject:
3495 elementDIType = di_i16;
3502 elementDIType = getDIType(llvmModCtx,
managedPtr(type->getElementType()));
3505 auto *llvmElementRawType = yoiTypeToLLVMType(llvmModCtx,
managedPtr(type->getElementType()), type->hasAttribute(IRValueType::ValueAttr::Raw));
3506 auto arraySizeInBits = size * llvmModCtx.
TheModule->getDataLayout().getTypeSizeInBits(llvmElementRawType);
3507 auto* diArray = llvmModCtx.
DBuilder->createArrayType(
3508 arraySizeInBits, llvmModCtx.
TheModule->getDataLayout().getABITypeAlign(llvmElementRawType).value() * 8, elementDIType, {llvmModCtx.DBuilder->getOrCreateArray(dimensions)});
3512 auto *diArrayStruct = llvmModCtx.
DBuilder->createStructType(
3517 64 + 64 + 64 + arraySizeInBits,
3519 llvm::DINode::FlagZero,
3521 llvmModCtx.
DBuilder->getOrCreateArray({
3522 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"refcount", nullptr, 0, 64, 64, 0, llvm::DINode::FlagZero, di_i64),
3523 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"typeid", nullptr, 0, 64, 64, 64, llvm::DINode::FlagZero, di_i64),
3524 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"array_length", nullptr, 0, 64, 64, 128, llvm::DINode::FlagZero, di_i64),
3525 llvmModCtx.DBuilder->createMemberType(llvmModCtx.compileUnits[L
"builtin"],
"array", nullptr, 0, arraySizeInBits, 64, 192, llvm::DINode::FlagZero, diArray)
3528 auto *resultDIType = llvmModCtx.
DBuilder->createPointerType(diArrayStruct, 64);
3530 if (type->hasAttribute(IRValueType::ValueAttr::Raw)) {
3533 return resultDIType;
3536 auto key = std::make_tuple(type->type, type->typeAffiliateModule, type->typeIndex);
3538 if (type->isBasicType() && type->hasAttribute(IRValueType::ValueAttr::Raw)) {
3539 switch (type->type) {
3540 case IRValueType::valueType::integerObject:
3542 case IRValueType::valueType::decimalObject:
3544 case IRValueType::valueType::booleanObject:
3546 case IRValueType::valueType::characterObject:
3548 case IRValueType::valueType::stringObject:
3550 case IRValueType::valueType::unsignedObject:
3552 case IRValueType::valueType::shortObject:
3554 case IRValueType::valueType::datastructObject: {
3562 auto dataStructDef = yoiModule->dataStructTable[type->typeIndex];
3566 if (!diDataRegionType) {
3567 std::string dataRegionTypeName =
"yoi.data_region." +
wstring2string(type->to_string());
3568 llvm::SmallVector<llvm::Metadata *, 8> dataRegionMemberTypes;
3571 auto *layout = &llvmModCtx.
TheModule->getDataLayout();
3572 auto *structLayout = layout->getStructLayout(llvmDataRegionType);
3574 for (
yoi::indexT i = 0; i < dataStructDef->fieldTypes.size(); i++) {
3575 auto memberType =
managedPtr(*dataStructDef->fieldTypes[i]);
3576 memberType->addAttribute(IRValueType::ValueAttr::Raw);
3578 auto memberTypeDI = getDIType(llvmModCtx, memberType);
3579 uint64_t fieldSize = memberTypeDI->getSizeInBits();
3580 uint64_t fieldOffset = structLayout->getElementOffsetInBits(i);
3583 std::string fieldName =
"field" + std::to_string(i);
3584 for (
auto &fieldPair : dataStructDef->fields) {
3585 if (fieldPair.second == i) {
3596 memberTypeDI->getAlignInBits(),
3598 llvm::DINode::FlagZero,
3600 dataRegionMemberTypes.push_back(memberDIType);
3607 structLayout->getSizeInBits(),
3608 structLayout->getAlignment().value() * 8,
3609 llvm::DINode::FlagZero,
3611 llvmModCtx.
DBuilder->getOrCreateArray(dataRegionMemberTypes));
3615 if (type->hasAttribute(IRValueType::ValueAttr::Raw)) {
3616 return diDataRegionType;
3620 std::string structTypeName =
"yoi." +
wstring2string(type->to_string());
3621 llvm::SmallVector<llvm::Metadata *, 8> objectMemberTypes;
3624 objectMemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(
3625 llvmModCtx.
compileUnits[L
"builtin"],
"refcount",
nullptr, 0, 64, 64, 0, llvm::DINode::FlagZero, di_i64));
3626 objectMemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(
3627 llvmModCtx.
compileUnits[L
"builtin"],
"typeid",
nullptr, 0, 64, 64, 64, llvm::DINode::FlagZero, di_i64));
3628 uint64_t objectCurrentSize = 128;
3630 objectMemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
3634 diDataRegionType->getSizeInBits(),
3635 diDataRegionType->getAlignInBits(),
3637 llvm::DINode::FlagZero,
3639 objectCurrentSize += diDataRegionType->getSizeInBits();
3647 llvm::DINode::FlagZero,
3649 llvmModCtx.
DBuilder->getOrCreateArray(objectMemberTypes));
3651 auto diStructTypePtr = llvmModCtx.
DBuilder->createPointerType(diStructType, 64);
3653 return diStructTypePtr;
3667 std::string typeName =
"yoi." +
wstring2string(type->to_string());
3669 llvm::DICompositeType *diFwdDecl = llvmModCtx.
DBuilder->createReplaceableCompositeType(
3670 llvm::dwarf::DW_TAG_structure_type,
3677 auto* resultDIType = llvmModCtx.
DBuilder->createPointerType(diFwdDecl, 64);
3681 llvm::SmallVector<llvm::Metadata*, 8> MemberTypes;
3684 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(
3692 llvm::DINode::FlagZero,
3695 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(
3703 llvm::DINode::FlagZero,
3706 uint64_t currentSize = 128;
3709 switch (type->type) {
3710 case IRValueType::valueType::integerObject: {
3711 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 64, 64, currentSize, llvm::DINode::FlagZero, di_i64));
3715 case IRValueType::valueType::stringObject: {
3716 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 64, 64, currentSize, llvm::DINode::FlagZero, di_i8_ptr));
3720 case IRValueType::valueType::decimalObject: {
3721 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 64, 64, currentSize, llvm::DINode::FlagZero, di_double));
3725 case IRValueType::valueType::booleanObject: {
3726 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 8, 8, currentSize, llvm::DINode::FlagZero, di_i1));
3730 case IRValueType::valueType::characterObject: {
3731 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 8, 8, currentSize, llvm::DINode::FlagZero, di_i8));
3735 case IRValueType::valueType::unsignedObject: {
3736 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 64, 64, currentSize, llvm::DINode::FlagZero, di_i64_u));
3740 case IRValueType::valueType::shortObject: {
3741 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 16, 16, currentSize, llvm::DINode::FlagZero, di_i16));
3745 case IRValueType::valueType::structObject: {
3746 auto structDef = yoiModule->structTable[type->typeIndex];
3748 for (
auto it = structDef->nameIndexMap.begin(); it!= structDef->nameIndexMap.end(); ++it) {
3749 if (it->second.type == IRStructDefinition::nameInfo::nameType::method)
3752 fieldNames[it->second.index] = fieldName;
3754 for (
yoi::indexT i = 0; i < fieldNames.size(); i++) {
3755 auto fieldYoiType = structDef->fieldTypes[i];
3757 auto* fieldDIType = getDIType(llvmModCtx, fieldYoiType);
3758 uint64_t fieldSize = llvmModCtx.
TheModule->getDataLayout().getTypeSizeInBits(yoiTypeToLLVMType(llvmModCtx, fieldYoiType));
3760 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(
3761 llvmModCtx.
compileUnits[L
"builtin"], fieldNames[i],
nullptr, 0,
3762 fieldSize, fieldSize, currentSize,
3763 llvm::DINode::FlagZero, fieldDIType
3765 currentSize += fieldSize;
3769 case IRValueType::valueType::interfaceObject: {
3770 MemberTypes.push_back(llvmModCtx.
DBuilder->createMemberType(llvmModCtx.
compileUnits[L
"builtin"],
"value",
nullptr, 0, 64, 64, currentSize, llvm::DINode::FlagZero, di_unknown_object_ptr));
3774 case IRValueType::valueType::none:
3782 auto* diStruct = llvmModCtx.
DBuilder->createStructType(
3789 llvm::DINode::FlagZero,
3791 llvmModCtx.
DBuilder->getOrCreateArray(MemberTypes)
3794 auto node = llvm::TempMDNode(diFwdDecl);
3795 llvmModCtx.
DBuilder->replaceTemporary(std::move(node), diStruct);
3799 return resultDIType;