1 #include "codegen/CGExpr.h"
7 #include "codegen/CodeGen.h"
8 #include "semantic/NameResolver.h"
9 #include "tir/Constant.h"
10 #include "tir/IRBuilder.h"
11 #include "tir/Instructions.h"
13 #include "utils/Utils.h"
16 namespace ex = ast::exprnode;
17 using T = codegen::CGExprEvaluator::T;
24 assert(kind_ == Kind::L || kind_ == Kind::R);
25 auto [_, type, value] = std::get<TirWrapped>(data_);
26 if(kind_ == Kind::L) {
27 assert(!type->isPointerType() || isAstTypeReference(astType()));
28 return builder.createLoadInstr(type, value);
34 tir::
Value* T::asLValue()
const {
36 return std::get<TirWrapped>(data_).value;
39 tir::
Value* T::asFn()
const {
40 assert(kind_ == Kind::StaticFn || kind_ == Kind::MemberFn);
41 return std::get<FnWrapped>(data_).fn;
44 ast::
Type const* T::astType()
const {
45 if(kind_ == Kind::L || kind_ == Kind::R) {
46 return std::get<TirWrapped>(data_).astType;
47 }
else if(kind_ == Kind::AstType) {
48 return std::get<ast::Type
const*>(data_);
53 ast::
Decl const* T::asDecl()
const {
54 if(kind_ == Kind::AstDecl)
55 return std::get<ast::Decl
const*>(data_);
56 else if(kind_ == Kind::StaticFn || kind_ == Kind::MemberFn)
57 return std::get<FnWrapped>(data_).decl;
61 tir::
Type* T::irType()
const {
62 assert(kind_ == Kind::L || kind_ == Kind::R);
63 return std::get<TirWrapped>(data_).type;
71 assert(irType() !=
nullptr);
72 assert(std::get<TirWrapped>(data_).value !=
nullptr);
76 assert(std::get<FnWrapped>(data_).fn !=
nullptr);
79 assert(std::get<ast::Type
const*>(data_) !=
nullptr);
82 assert(std::get<ast::Decl
const*>(data_) !=
nullptr);
86 if(kind_ == Kind::R || kind_ == Kind::L) {
87 auto type = std::get<TirWrapped>(data_).type;
88 auto astTy = std::get<TirWrapped>(data_).astType;
89 assert(type == cg.emitType(astTy));
94 void T::dump()
const {
97 std::cout <<
"L-value: ";
98 std::get<TirWrapped>(data_).value->dump();
101 std::cout <<
"R-value: ";
102 std::get<TirWrapped>(data_).value->dump();
105 std::cout <<
"Static function: ";
109 std::cout <<
"Member function: ";
113 std::cout <<
"AST type: ";
117 std::cout <<
"AST decl: ";
128 T CGExprEvaluator::castIntegerType(ast::
Type const* aTy, tir::
Type* ty,
130 using CastOp = ICastInst::CastOp;
131 auto srcAstTy = cast<ast::BuiltInType>(value.astType());
132 auto dstBits = cast<tir::IntegerType>(ty)->getBitWidth();
133 auto srcBits = srcAstTy->typeSizeBits();
134 auto isSrcSigned = srcAstTy->getKind() != ast::BuiltInType::Kind::Char;
135 auto isNarrowing = dstBits < srcBits;
136 auto isWidening = dstBits > srcBits;
140 castInst = cg.builder.createICastInstr(
141 CastOp::Trunc, value.asRValue(cg.builder), ty);
144 else if(isWidening && isSrcSigned) {
145 castInst = cg.builder.createICastInstr(
146 CastOp::SExt, value.asRValue(cg.builder), ty);
149 else if(isWidening && !isSrcSigned) {
150 castInst = cg.builder.createICastInstr(
151 CastOp::ZExt, value.asRValue(cg.builder), ty);
157 return T
::R(aTy, castInst);
161 static CmpInst::Predicate getPredicate(ex::BinaryOp::OpType op) {
162 using OpType = ex::BinaryOp::OpType;
164 case OpType::GreaterThan:
165 return CmpInst::Predicate::GT;
166 case OpType::GreaterThanOrEqual:
167 return CmpInst::Predicate::GE;
168 case OpType::LessThan:
169 return CmpInst::Predicate::LT;
170 case OpType::LessThanOrEqual:
171 return CmpInst::Predicate::LE;
173 return CmpInst::Predicate::EQ;
174 case OpType::NotEqual:
175 return CmpInst::Predicate::NE;
182 static Instruction::BinOp getBinOp(ex::BinaryOp::OpType op) {
183 using OpType = ex::BinaryOp::OpType;
185 case OpType::BitwiseAnd:
187 case OpType::BitwiseOr:
189 case OpType::BitwiseXor:
193 case OpType::Subtract:
195 case OpType::Multiply:
207 static auto findArrayField(semantic::NameResolver& nr) {
208 for(
auto field : nr.GetArrayPrototype()->fields()) {
209 if(field->name() ==
"length") {
213 assert(
false &&
"Array prototype field not found");
222 T CGExprEvaluator::mapValue(ex::
ExprValue& node)
const {
223 auto aTy = node.type();
224 if(
auto methodName = dyn_cast<ex::MethodName>(node)) {
225 auto* methodDecl = cast<ast::MethodDecl>(methodName->decl());
226 auto kind = methodDecl->modifiers().isStatic() ? T::Kind::StaticFn
228 auto fn = cg.gvMap[methodDecl];
230 return T::Fn(kind, methodDecl, fn);
231 }
else if(
auto memberName = dyn_cast<ex::MemberName>(node)) {
232 auto irTy = cg.emitType(cast<ast::TypedDecl>(memberName->decl())->type());
234 if(
auto* fieldDecl = dyn_cast<ast::FieldDecl>(memberName->decl())) {
236 if(fieldDecl->modifiers().isStatic()) {
237 auto GV = cg.gvMap[fieldDecl];
238 return T::L(aTy, irTy, GV);
247 auto* localDecl = cast<ast::VarDecl>(memberName->decl());
248 return T::L(aTy, irTy, cg.valueMap[localDecl]);
250 }
else if(
auto thisNode = dyn_cast<ex::ThisNode>(node)) {
252 return T
::L(aTy
, cg.emitType(aTy)
, curFn.args().front()
);
253 }
else if(
auto literal = dyn_cast<ex::LiteralNode>(node)) {
254 if(literal->builtinType()->isNumeric()) {
255 auto bits =
static_cast<uint8_t>(literal->builtinType()->typeSizeBits());
256 auto val = literal->getAsInt();
257 return T::R(aTy, Constant::CreateInt(ctx, bits, val));
258 }
else if(literal->builtinType()->isBoolean()) {
259 return T::R(aTy, Constant::CreateBool(ctx, literal->getAsInt()));
260 }
else if(literal->builtinType()->isString()) {
263 aTy,
Type::getPointerTy(ctx),
Constant::CreateNullPointer(ctx));
266 return T
::R(aTy,
Constant::CreateNullPointer(ctx));
268 }
else if(
auto type = dyn_cast<ex::TypeNode>(node)) {
274 T CGExprEvaluator::evalBinaryOp(ex::BinaryOp& op, T lhs, T rhs)
const {
275 using OpType = ex::BinaryOp::OpType;
276 auto aTy = op.resultType();
277 switch(op.opType()) {
279 case OpType::Assignment:
280 cg.builder.createStoreInstr(rhs.asRValue(cg.builder), lhs.asLValue());
284 case OpType::GreaterThan:
285 case OpType::GreaterThanOrEqual:
286 case OpType::LessThan:
287 case OpType::LessThanOrEqual:
289 case OpType::NotEqual: {
290 auto inst = cg.builder.createCmpInstr(getPredicate(op.opType()),
291 lhs.asRValue(cg.builder),
292 rhs.asRValue(cg.builder));
293 return T::R(aTy, inst);
311 auto bb1 = cg.builder.createBasicBlock(&curFn);
312 auto bb2 = cg.builder.createBasicBlock(&curFn);
313 bb1->setName(
"and.true");
314 bb2->setName(
"and.false");
315 auto v0 = lhs.asRValue(cg.builder);
316 cg.builder.createStoreInstr(v0, tmp);
317 cg.builder.createBranchInstr(v0, bb1, bb2);
318 cg.builder.setInsertPoint(bb1);
319 auto v1 = rhs.asRValue(cg.builder);
320 cg.builder.createStoreInstr(v1, tmp);
321 cg.builder.createBranchInstr(bb2);
322 cg.builder.setInsertPoint(bb2);
323 return T
::L(aTy,
Type::getInt1Ty(ctx), tmp);
339 auto bb1 = cg.builder.createBasicBlock(&curFn);
340 auto bb2 = cg.builder.createBasicBlock(&curFn);
341 bb1->setName(
"or.true");
342 bb2->setName(
"or.false");
343 auto v0 = lhs.asRValue(cg.builder);
344 cg.builder.createStoreInstr(v0, tmp);
345 cg.builder.createBranchInstr(v0, bb2, bb1);
346 cg.builder.setInsertPoint(bb1);
347 auto v1 = rhs.asRValue(cg.builder);
348 cg.builder.createStoreInstr(v1, tmp);
349 cg.builder.createBranchInstr(bb2);
350 cg.builder.setInsertPoint(bb2);
351 return T
::L(aTy,
Type::getInt1Ty(ctx), tmp);
355 case OpType::BitwiseAnd:
356 case OpType::BitwiseOr:
357 case OpType::BitwiseXor:
359 case OpType::Subtract:
360 case OpType::Multiply:
362 case OpType::Modulo: {
364 auto lhsP = castIntegerType(aTy,
Type::getInt32Ty(ctx), lhs);
365 auto rhsP = castIntegerType(aTy,
Type::getInt32Ty(ctx), rhs);
367 auto res = cg.builder.createBinaryInstr(getBinOp(op.opType()),
368 lhsP.asRValue(cg.builder),
369 rhsP.asRValue(cg.builder));
371 auto emittedTy = cg.emitType(aTy);
372 assert(res->type() == emittedTy);
373 return castIntegerType(aTy, emittedTy, T::R(aTy, res));
377 case OpType::InstanceOf: {
379 return T
::R(aTy,
Constant::CreateBool(ctx,
false));
388 T CGExprEvaluator::evalUnaryOp(ex::UnaryOp& op, T rhs)
const {
390 using OpType = ex::UnaryOp::OpType;
391 auto aTy = op.resultType();
392 auto value = rhs.asRValue(cg.builder);
393 auto ty = value->type();
394 switch(op.opType()) {
396 case OpType::BitwiseNot: {
398 auto allOnes = ConstantInt::AllOnes(ctx, ty);
399 auto instr = cg.builder.createBinaryInstr(BinOp::Xor, value, allOnes);
400 return T::R(aTy, instr);
406 case OpType::Minus: {
408 auto instr = cg.builder.createBinaryInstr(
409 BinOp::Sub, ConstantInt::Zero(ctx, ty), value);
410 return T::R(aTy, instr);
418 T CGExprEvaluator::evalMemberAccess(ex::MemberAccess& op, T lhs, T field)
const {
419 auto aTy = op.resultType();
420 auto obj = lhs.asRValue(cg.builder);
421 auto decl = field.asDecl();
423 if(field.kind() == T::Kind::MemberFn) {
424 return T::Fn(T::Kind::MemberFn, decl, field.asFn(), obj);
427 else if(decl == findArrayField(cg.nr)) {
428 auto arrTy = cast<StructType>(lhs.irType());
430 cg.builder.createGEPInstr(obj, arrTy, {Constant::CreateInt32(ctx, 0)});
431 auto arrSz = cg.builder.createLoadInstr(Type::getInt32Ty(ctx), arrSzGep);
432 return T::R(aTy, arrSz);
440 T CGExprEvaluator::evalMethodCall(ex::MethodInvocation& op, T method,
441 const op_array& args)
const {
442 auto aTy = op.resultType();
443 std::vector<Value*> argValues;
445 if(method.kind() == T::Kind::MemberFn) {
447 argValues.push_back(method.thisRef());
449 assert(method.kind() == T::Kind::StaticFn);
452 for(
auto& arg : args) {
453 argValues.push_back(arg.asRValue(cg.builder));
455 auto callVal = cg.builder.createCallInstr(method.asFn(), argValues);
456 return T::R(aTy, callVal);
459 T CGExprEvaluator::evalNewObject(ex::ClassInstanceCreation& op, T object,
460 const op_array& args)
const {
465 return T
::L(op.resultType(),
466 Type::getPointerTy(ctx),
470 T CGExprEvaluator::evalNewArray(ex::ArrayInstanceCreation& op, T type,
472 auto aTy = op.resultType();
473 auto arrTy = cast<StructType>(cg.emitType(aTy));
474 auto elemTy = cg.emitType(type.astType());
475 auto arrLength = castIntegerType(
nullptr,
Type::getInt32Ty(ctx), size)
476 .asRValue(cg.builder);
477 auto totalSz = cg.builder.createBinaryInstr(
478 Instruction::BinOp::Mul,
480 Constant::CreateInt32(ctx, elemTy->getSizeInBits() / 8));
481 auto arrPtr = cg.builder.createCallInstr(cu.builtinMalloc(), {totalSz});
483 cg.emitSetArrayPtr(alloca, arrPtr);
484 cg.emitSetArraySz(alloca, arrLength);
485 auto loadArr = cg.builder.createLoadInstr(arrTy, arrPtr);
486 cg.builder.createStoreInstr(loadArr, alloca);
487 totalSz->setName(
"arr.sz");
488 arrPtr->setName(
"arr.ptr");
489 alloca->setName(
"arr.alloca");
490 return T::L(aTy, arrTy, alloca);
493 T CGExprEvaluator::evalArrayAccess(ex::ArrayAccess& op, T array, T index)
const {
494 auto arrAlloca = array.asLValue();
495 auto elemAstTy = op.resultType();
496 auto arrTy = cast<StructType>(array.irType());
497 auto arrPtr = cg.emitGetArrayPtr(arrAlloca);
498 auto arrSz = cg.emitGetArraySz(arrAlloca);
499 auto idxVal = index.asRValue(cg.builder);
501 cg.builder.createCmpInstr(CmpInst::Predicate::LT, idxVal, arrSz);
502 auto bb1 = cg.builder.createBasicBlock(&curFn);
503 bb1->setName(
"array.oob");
504 auto bb2 = cg.builder.createBasicBlock(&curFn);
505 bb2->setName(
"array.inbounds");
506 cg.builder.createBranchInstr(lengthValid, bb2, bb1);
507 cg.builder.setInsertPoint(bb1);
508 cg.builder.createCallInstr(cu.builtinException(), {});
509 cg.builder.setInsertPoint(bb2);
510 auto elemPtr = cg.builder.createGEPInstr(arrPtr, arrTy, {idxVal});
511 return T::L(elemAstTy, cg.emitType(elemAstTy), elemPtr);
514 T CGExprEvaluator::evalCast(ex::Cast& op, T type, T value)
const {
515 auto aTy = op.resultType();
516 auto castType = type.astType();
517 if(castType->isNumeric()) {
519 return castIntegerType(aTy, cg.emitType(castType), value);
520 }
else if(castType->isBoolean()) {
523 }
else if(castType->isString()) {
524 }
else if(castType->isArray()) {
539 CGExprEvaluator eval{*
this};
540 T result = eval.EvaluateList(expr->list());
541 return result.asRValue(builder);