llvm::Value* LivenessEmitter::emitIsLiveCall(const AST::Type* const type, llvm::Value* const value) { auto& module = irEmitter_.module(); // Call __islive method. if (type->isObject()) { TypeInfo typeInfo(module); if (!typeInfo.objectHasLivenessIndicator(*(type->getObjectType()))) { // Assume value is always live. return ConstantGenerator(module).getBool(true); } // Call __islive method. const auto methodName = module.getCString("__islive"); const auto functionType = type->getObjectType()->getFunction(methodName).type(); MethodInfo methodInfo(type, methodName, functionType, {}); const auto contextArg = RefPendingResult(value, type); CallEmitter callEmitter(irEmitter_); return callEmitter.emitDynamicMethodCall(methodInfo, contextArg, {}); } llvm_unreachable("Unknown __islive value type."); }
void LivenessEmitter::emitSetOuterLive(const AST::TypeInstance& typeInstance, llvm::Value* const objectPointerValue) { auto& module = irEmitter_.module(); const auto livenessIndicator = LivenessInfo(module).getLivenessIndicator(typeInstance); switch (livenessIndicator.kind()) { case LivenessIndicator::NONE: { // Nothing to do. break; } case LivenessIndicator::MEMBER_INVALID_STATE: { // Nothing to do; the expectation is that the member is already in a valid state. break; } case LivenessIndicator::CUSTOM_METHODS: { // Nothing to do; the expectation is that the object is already in a live state // (or that it is in a notionally 'dead' state but it doesn't matter). break; } case LivenessIndicator::SUFFIX_BYTE: case LivenessIndicator::GAP_BYTE: { // Store one into gap/suffix byte to represent live state. const auto bytePtr = emitLivenessBytePtr(typeInstance, livenessIndicator, objectPointerValue); irEmitter_.emitRawStore(ConstantGenerator(module).getI8(1), bytePtr); break; } } }
void CtrGenerator::visit(const P_ConstraintLoop& loop) { const char* name = loop.iter; int begin=ConstantGenerator(scopes.top()).eval_integer(loop.first_value); //scope.it_first_value(name); int end=ConstantGenerator(scopes.top()).eval_integer(loop.last_value); //scope.it_last_value(name); if (!scopes.empty()) scopes.push(scopes.top()); else scopes.push(Scope()); scopes.top().add_iterator(name); for (int i=begin; i<=end; i++) { scopes.top().set_iter_value(name,i); visit(loop.ctrs); } scopes.pop(); }
llvm::Value* LivenessEmitter::emitLivenessByteOffset(const AST::TypeInstance& typeInstance, const LivenessIndicator livenessIndicator) { if (livenessIndicator.isSuffixByte()) { return genSuffixByteOffset(irEmitter_.function(), typeInstance); } else if (livenessIndicator.isGapByte()) { return ConstantGenerator(irEmitter_.module()).getI64(livenessIndicator.gapByteOffset()); } else { llvm_unreachable("Cannot get byte offset of non-byte liveness indicator."); } }
llvm::Value* Function::unwindState() { if (unwindState_ == nullptr) { const auto i8Type = TypeGenerator(module_).getI8Type(); // Zero state means 'normal execution'. const auto zero = ConstantGenerator(module_).getI8(0); unwindState_ = getEntryBuilder().CreateAlloca(i8Type, nullptr, "unwindState"); getEntryBuilder().CreateStore(zero, unwindState_); } return unwindState_; }
llvm::Value* VoidPrimitive::emitMethod(IREmitter& irEmitter, const MethodID methodID, llvm::ArrayRef<AST::Value> /*typeTemplateArguments*/, llvm::ArrayRef<AST::Value> /*functionTemplateArguments*/, PendingResultArray /*args*/, llvm::Value* /*resultPtr*/) const { auto& module = irEmitter.module(); switch (methodID) { case METHOD_MOVE: return ConstantGenerator(module).getVoidUndef(); default: llvm_unreachable("Unknown void_t primitive method."); } }
VirtualMethodComponents getVirtualMethodComponents(Function& function, const bool isStatic, llvm::Value* const interfaceMethodValue) { auto& builder = function.getBuilder(); auto& module = function.module(); if (isStatic) { const auto objectPointer = ConstantGenerator(module).getNull(TypeGenerator(module).getI8PtrType()); const auto typeInfoValue = builder.CreateExtractValue(interfaceMethodValue, { 0 }, "typeInfo"); const VirtualObjectComponents virtualObjectComponents(getTypeInfoComponents(function, typeInfoValue), objectPointer); const auto hashValue = builder.CreateExtractValue(interfaceMethodValue, { 1 }, "methodHash"); return VirtualMethodComponents(virtualObjectComponents, hashValue); } else { const auto interfaceStructValue = builder.CreateExtractValue(interfaceMethodValue, { 0 }, "interface"); const auto hashValue = builder.CreateExtractValue(interfaceMethodValue, { 1 }, "methodHash"); return VirtualMethodComponents(getVirtualObjectComponents(function, interfaceStructValue), hashValue); } }
void ExprGenerator::visit(const P_ExprIndex& e) { int index=ConstantGenerator(scope).eval_integer(e.right); visit(e.left); int real_index=e.matlab_style? index-1 : index; if (real_index<0) throw SyntaxError("negative index. Note: indices in Matlab-style (using parenthesis like in \"x(i)\") start from 1 (not 0)."); if (real_index>LEFT.dim.max_index()) throw SyntaxError("index out of bounds. Note: indices in C-style (using square brackets like in \"x[i]\") start from 0 (not 1)."); if (fold) { const ExprConstant* c=dynamic_cast<const ExprConstant*>(&LEFT); if (c) { clone.insert(e, &ExprConstant::new_(c->get()[real_index])); //delete c; // not now (see comment in ExprCopy.h) return; } } const ExprConstantRef* s=dynamic_cast<const ExprConstantRef*>(&LEFT); if (s) { if (dynamic_cast<const P_ExprIndex*>(e.father)) { clone.insert(e, new ExprConstantRef(s->value[real_index])); } else { // "last time": we cannot keep reference anymore. clone.insert(e, &ExprConstant::new_(s->value[real_index])); } //delete s; // not now: there may be inside a DAG (via a function) (see comment in ExprCopy.h) return; } mark(e.left); clone.insert(e, &(LEFT[real_index])); }
llvm::Value* genFloatPrimitiveMethodCall(Function& function, const SEM::Type* type, const String& methodName, const SEM::FunctionType functionType, llvm::ArrayRef<SEM::Value> templateArgs, PendingResultArray args, llvm::Value* const hintResultValue) { auto& module = function.module(); auto& builder = function.getBuilder(); const auto& typeName = type->getObjectType()->name().first(); const auto methodID = module.context().getMethodID(CanonicalizeMethodName(methodName)); const auto methodOwner = methodID.isConstructor() ? nullptr : args[0].resolveWithoutBind(function); if (methodName == "__move_to") { const auto moveToPtr = args[1].resolve(function); const auto moveToPosition = args[2].resolve(function); const auto destPtr = builder.CreateInBoundsGEP(moveToPtr, moveToPosition); const auto castedDestPtr = builder.CreatePointerCast(destPtr, genPointerType(module, type)); genMoveStore(function, methodOwner, castedDestPtr, type); return ConstantGenerator(module).getVoidUndef(); } else if (methodName == "create") { return ConstantGenerator(module).getPrimitiveFloat(typeName, 0.0); } else if (methodName == "__setdead" || methodName == "__set_dead") { // Do nothing. return ConstantGenerator(module).getVoidUndef(); } else if (methodName == "__islive" || methodName == "__is_live") { return ConstantGenerator(module).getI1(true); } else if (methodName.starts_with("implicit_cast_") || methodName.starts_with("cast_")) { const auto argType = functionType.parameterTypes().front(); const auto operand = args[0].resolve(function); const auto selfType = genType(module, type); if (isFloatType(module, argType)) { if (methodName.starts_with("implicit_cast_")) { return builder.CreateFPExt(operand, selfType); } else { return builder.CreateFPTrunc(operand, selfType); } } else if (isUnsignedIntegerType(module, argType)) { return builder.CreateUIToFP(operand, selfType); } else if (isSignedIntegerType(module, argType)) { return builder.CreateSIToFP(operand, selfType); } else { llvm_unreachable("Unknown float cast source type."); } } else if (isUnaryOp(methodName)) { const auto zero = ConstantGenerator(module).getPrimitiveFloat(typeName, 0.0); if (methodName == "implicit_cast" || methodName == "cast") { return callCastMethod(function, methodOwner, type, methodName, templateArgs.front().typeRefType(), hintResultValue); } else if (methodName == "implicit_copy" || methodName == "copy" || methodName == "plus") { return methodOwner; } else if (methodName == "minus") { return builder.CreateFNeg(methodOwner); } else if (methodName == "isZero") { return builder.CreateFCmpOEQ(methodOwner, zero); } else if (methodName == "isPositive") { return builder.CreateFCmpOGT(methodOwner, zero); } else if (methodName == "isNegative") { return builder.CreateFCmpOLT(methodOwner, zero); } else if (methodName == "abs") { // Generates: (value < 0) ? -value : value. const auto lessThanZero = builder.CreateFCmpOLT(methodOwner, zero); return builder.CreateSelect(lessThanZero, builder.CreateFNeg(methodOwner), methodOwner); } else if (methodName == "sqrt") { llvm::Type* const intrinsicTypes[] = { methodOwner->getType() }; const auto sqrtIntrinsic = llvm::Intrinsic::getDeclaration(module.getLLVMModulePtr(), llvm::Intrinsic::sqrt, intrinsicTypes); llvm::Value* const sqrtArgs[] = { methodOwner }; return builder.CreateCall(sqrtIntrinsic, sqrtArgs); } else { llvm_unreachable("Unknown primitive unary op."); } } else if (isBinaryOp(methodName)) { const auto operand = args[1].resolveWithoutBind(function); if (methodName == "add") { return builder.CreateFAdd(methodOwner, operand); } else if (methodName == "subtract") { return builder.CreateFSub(methodOwner, operand); } else if (methodName == "multiply") { return builder.CreateFMul(methodOwner, operand); } else if (methodName == "divide") { return builder.CreateFDiv(methodOwner, operand); } else if (methodName == "modulo") { return builder.CreateFRem(methodOwner, operand); } else if (methodName == "equal") { return builder.CreateFCmpOEQ(methodOwner, operand); } else if (methodName == "not_equal") { return builder.CreateFCmpONE(methodOwner, operand); } else if (methodName == "less_than") { return builder.CreateFCmpOLT(methodOwner, operand); } else if (methodName == "less_than_or_equal") { return builder.CreateFCmpOLE(methodOwner, operand); } else if (methodName == "greater_than") { return builder.CreateFCmpOGT(methodOwner, operand); } else if (methodName == "greater_than_or_equal") { return builder.CreateFCmpOGE(methodOwner, operand); } else if (methodName == "compare") { const auto isLessThan = builder.CreateFCmpOLT(methodOwner, operand); const auto isGreaterThan = builder.CreateFCmpOGT(methodOwner, operand); const auto minusOne = ConstantGenerator(module).getI8(-1); const auto zero = ConstantGenerator(module).getI8(0); const auto plusOne = ConstantGenerator(module).getI8(1); return builder.CreateSelect(isLessThan, minusOne, builder.CreateSelect(isGreaterThan, plusOne, zero)); } else { llvm_unreachable("Unknown primitive binary op."); } } else { printf("%s\n", methodName.c_str()); llvm_unreachable("Unknown primitive method."); } }
void TemplateBuilder::updateAllInstructions(Module& module) { for (const auto instruction: instructions_) { instruction->setOperand(1, ConstantGenerator(module).getI64(bitsRequired())); } }
llvm::Value* genPtrLvalPrimitiveMethodCall(Function& function, const SEM::Type* type, const String& methodName, SEM::FunctionType /*functionType*/, PendingResultArray args, llvm::Value* const hintResultValue) { auto& module = function.module(); auto& builder = function.getBuilder(); const auto methodOwner = args[0].resolveWithoutBind(function); const auto targetType = type->templateArguments().front().typeRefType(); const auto methodID = module.context().getMethodID(CanonicalizeMethodName(methodName)); switch (methodID) { case METHOD_MOVETO: { const auto moveToPtr = args[1].resolve(function); const auto moveToPosition = args[2].resolve(function); const auto destPtr = builder.CreateInBoundsGEP(moveToPtr, moveToPosition); const auto castedDestPtr = builder.CreatePointerCast(destPtr, genPointerType(module, type)); genMoveStore(function, methodOwner, castedDestPtr, type); return ConstantGenerator(module).getVoidUndef(); } case METHOD_ADDRESS: case METHOD_DISSOLVE: return methodOwner; case METHOD_ASSIGN: { const auto operand = args[1].resolve(function); // Destroy existing value. genDestructorCall(function, targetType, methodOwner); // Assign new value. genMoveStore(function, operand, methodOwner, targetType); return ConstantGenerator(module).getVoidUndef(); } case METHOD_MOVE: { const auto returnValuePtr = genAlloca(function, targetType, hintResultValue); const auto loadedValue = genMoveLoad(function, methodOwner, targetType); genMoveStore(function, loadedValue, returnValuePtr, targetType); return genMoveLoad(function, returnValuePtr, targetType); } case METHOD_SETVALUE: { const auto operand = args[1].resolve(function); // Assign new value. genMoveStore(function, operand, methodOwner, targetType); return ConstantGenerator(module).getVoidUndef(); } case METHOD_EXTRACTVALUE: { return genMoveLoad(function, methodOwner, targetType); } case METHOD_DESTROYVALUE: { // Destroy existing value. genDestructorCall(function, targetType, methodOwner); return ConstantGenerator(module).getVoidUndef(); } default: llvm_unreachable("Unknown ptr_lval primitive method."); } }