Joos1W Compiler Framework
All Classes Functions Typedefs Pages
CGFunction.cc
1 #include <sstream>
2 #include <string_view>
3 
4 #include "codegen/CodeGen.h"
5 #include "codegen/Mangling.h"
6 #include "tir/IRBuilder.h"
7 #include "tir/Instructions.h"
8 #include "tir/Type.h"
9 #include "utils/Utils.h"
10 
11 namespace codegen {
12 
13 void CodeGenerator::emitFunctionDecl(ast::MethodDecl const* decl) {
14  // 0. If it's abstract, exit now
15  if(decl->modifiers().isAbstract()) return;
16  // 1. Create the function signature type
17  auto astRetTy = decl->returnTy().type;
18  tir::Type* tirRetTy = tir::Type::getVoidTy(ctx);
19  if(astRetTy) tirRetTy = emitType(astRetTy);
20  std::vector<tir::Type*> paramTys;
21  std::vector<std::string_view> paramNames;
22  // a) If the function is not static, add "this" to the first parameter
23  if(!decl->modifiers().isStatic()) {
24  paramTys.push_back(tir::Type::getPointerTy(ctx));
25  paramNames.push_back("this");
26  }
27  // b) Add the rest of the parameters
28  for(auto* param : decl->parameters()) {
29  paramTys.push_back(emitType(param->type()));
30  paramNames.push_back(param->name());
31  }
32  // c) Create the function type
33  auto* funcTy = tir::FunctionType::get(ctx, tirRetTy, paramTys);
34  // 2. Create the function and set the argument names (for debugging)
35  // 3. However, if it's a native function, we need to "native mangle" it.
36  // Native mangling is inferred from the "runtime.s" file.
37  tir::Function* func = nullptr;
38  if(decl->modifiers().isNative()) {
39  std::ostringstream ss;
40  ss << "NATIVE" << decl->getCanonicalName();
41  func = cu.CreateFunction(funcTy, ss.str());
42  func->setExternalLinkage();
43  } else {
44  Mangler m{nr};
45  m.MangleFunctionName(decl);
46  func = cu.CreateFunction(funcTy, m.getMangledName());
47  // FIXME(kevin): Better way to grab main function?
48  if(decl->name() == "main") {
49  func->setExternalLinkage();
50  }
51  }
52  gvMap[decl] = func;
53  assert(func && "Function already exists");
54  for(auto arg : func->args()) {
55  arg->setName(paramNames[arg->index()]);
56  }
57 }
58 
59 void CodeGenerator::emitFunction(ast::MethodDecl const* decl) {
60  // 0. If it's a native function, exit now
61  if(decl->modifiers().isNative()) return;
62  assert(decl->body() && "Function should not be abstract here");
63  // 1. Grab the function from the gvMap and clear the valueMap
64  auto func = cast<tir::Function>(gvMap[decl]);
65  curFn = func;
66  valueMap.clear();
67  // 2. Emit the function body and add the allocas for the locals
68  auto entry = builder.createBasicBlock(func);
69  builder.setInsertPoint(entry->begin());
70  for(auto* local : decl->decls()) {
71  auto* typedLocal = cast<ast::TypedDecl>(local);
72  auto* localTy = emitType(typedLocal->type());
73  auto* val = func->createAlloca(localTy);
74  val->setName(typedLocal->name());
75  valueMap[local] = cast<tir::AllocaInst>(val);
76  }
77  emitStmt(decl->body());
78  // 3. If the BB we're in does not end in a terminator, add a return
79  if(builder.currentBlock()) {
80  auto term = builder.currentBlock()->terminator();
81  if(!term || !term->isTerminator()) {
82  builder.createReturnInstr();
83  }
84  }
85  // 4. End the function by clearing the curFn
86  curFn = nullptr;
87 }
88 
89 } // namespace codegen