Skip to content

Commit

Permalink
Refactor names
Browse files Browse the repository at this point in the history
  • Loading branch information
pluralia committed Mar 1, 2024
1 parent 11f6d00 commit 708ec48
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 71 deletions.
36 changes: 19 additions & 17 deletions src/cli/llvm-ir-generator/block.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import llvm from "llvm-bindings";
import { OxElement, ReturnStatement, Parameter, isFunctionDeclaration, isReturnStatement, isVariableDeclaration } from "../../language/generated/ast.js";
import { generateFunction } from "./func.js";
import { DI, IR, getLoc, getScope } from "./util.js";
import { DI, IR, getLoc, getCurrScope } from "./util.js";
import { generateVariableDeclaration } from "./var.js";
import { generateExpression } from "./expr.js";

Expand All @@ -11,15 +11,18 @@ export type BlockInfo = {
inputVars?: Parameter[]
}

export function generateExpressionBlock(ir: IR, di: DI, elements: OxElement[], { name, func, inputVars }: BlockInfo) {
export function generateExpressionBlock(ir: IR, di: DI, elements: OxElement[],
{ name, func, inputVars }: BlockInfo) {

const entryBB = llvm.BasicBlock.Create(ir.context, name, func);
ir.builder.SetInsertPoint(entryBB);

const backupNamedValues = new Map<string, llvm.AllocaInst>(ir.namedValues);
ir.namedValues = new Map<string, llvm.AllocaInst>();
const backupNamedValues = new Map<string, llvm.AllocaInst>(ir.nameToAlloca);
ir.nameToAlloca = new Map<string, llvm.AllocaInst>();
if (func && inputVars) {
for (let i = 0; i < inputVars.length; i++) {
generateParameter(ir, di, inputVars[i], i, func);
const alloca = generateParameter(ir, di, inputVars[i], i, func);
ir.nameToAlloca.set(inputVars[i].name, alloca);
}
}

Expand All @@ -33,34 +36,33 @@ export function generateExpressionBlock(ir: IR, di: DI, elements: OxElement[], {
}
}

ir.namedValues = backupNamedValues;
ir.nameToAlloca = backupNamedValues;
}

function generateParameter(ir: IR, di: DI, param: Parameter, i: number, func: llvm.Function) {
const { line, character: col } = getLoc(param);
const varName = param.name;
const varType = ir.basicTypes.get(param.type.primitive)!;
function generateParameter(ir: IR, di: DI, param: Parameter, i: number, func: llvm.Function): llvm.AllocaInst {
const { name, type } = param;
const { line, col } = getLoc(param);

const alloca = ir.builder.CreateAlloca(varType, null, varName);
const alloca = ir.builder.CreateAlloca(ir.basicTypes.get(type.primitive)!, null, name);
ir.builder.CreateStore(func.getArg(i), alloca);
ir.namedValues.set(varName, alloca);

const diVarType = di.basicTypes.get(param.type.primitive)!;
const diLocalVar = di.builder.createParameterVariable(getScope(di), varName, i + 1, di.file, line, diVarType);

const diLocalVar = di.builder.createParameterVariable(getCurrScope(di), name, i + 1, di.file, line, diVarType);
di.builder.insertDeclare(
alloca, diLocalVar, di.builder.createExpression(),
llvm.DILocation.get(ir.context, line, col, getScope(di)), ir.builder.GetInsertBlock()!
llvm.DILocation.get(ir.context, line, col, getCurrScope(di)), ir.builder.GetInsertBlock()!
);

return alloca;
}

function generateReturn(ir: IR, di: DI, ret: ReturnStatement) {
const { line, character: col } = getLoc(ret);
const { line, col } = getLoc(ret);

const value = ret.value ?
generateExpression(ir, di, ret.value) :
ir.builder.getInt32(0);

ir.builder.SetCurrentDebugLocation(llvm.DILocation.get(ir.context, line, col, getScope(di)));
ir.builder.SetCurrentDebugLocation(llvm.DILocation.get(ir.context, line, col, getCurrScope(di)));
ir.builder.CreateRet(value);
}
24 changes: 12 additions & 12 deletions src/cli/llvm-ir-generator/expr.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import llvm from "llvm-bindings";
import { BinaryExpression, Expression, MemberCall, isBinaryExpression, isBooleanExpression, isFunctionDeclaration, isMemberCall, isNumberExpression } from "../../language/generated/ast.js";
import { DI, IR, getLoc, getScope } from "./util.js";
import { DI, IR, getLoc, getCurrScope } from "./util.js";

export function generateExpression(ir: IR, di: DI, expr: Expression): llvm.Value {
if (isNumberExpression(expr)) {
Expand All @@ -11,20 +11,21 @@ export function generateExpression(ir: IR, di: DI, expr: Expression): llvm.Value
} else if (isMemberCall(expr)) {
return generateMemberCall(ir, di, expr);
} else if (isBinaryExpression(expr)) {
return generateBinExpr(ir, di, expr);
return generateBinaryExpr(ir, di, expr);
}

console.error(`Expression '${expr.$cstNode?.text}' is not supported.`);
process.exit(1);
}

function generateBinExpr(ir: IR, di: DI, expr: BinaryExpression) {
const { line, character: col } = getLoc(expr);
function generateBinaryExpr(ir: IR, di: DI, expr: BinaryExpression) {
const { line, col } = getLoc(expr);
const left = generateExpression(ir, di, expr.left);
const right = generateExpression(ir, di, expr.right);
const op = expr.operator;

if (expr.operator === '+') {
ir.builder.SetCurrentDebugLocation(llvm.DILocation.get(ir.context, line, col, getScope(di)));
ir.builder.SetCurrentDebugLocation(llvm.DILocation.get(ir.context, line, col, getCurrScope(di)));
if (op === '+') {
return ir.builder.CreateFAdd(left, right);
}

Expand All @@ -34,15 +35,14 @@ function generateBinExpr(ir: IR, di: DI, expr: BinaryExpression) {

function generateMemberCall(ir: IR, di: DI, expr: MemberCall): llvm.Value {
const member = expr.element.ref!;
const { line, character: col } = getLoc(expr);
const { line, col } = getLoc(expr);

if (isFunctionDeclaration(member)) {
const func = ir.module.getFunction(member.name);
if (func) {
ir.builder.SetCurrentDebugLocation(llvm.DILocation.get(ir.context, line, col, getScope(di)));
ir.builder.SetCurrentDebugLocation(llvm.DILocation.get(ir.context, line, col, getCurrScope(di)));
return ir.builder.CreateCall(func, expr.arguments.map(a => generateExpression(ir, di, a)));
}

console.error(`Function '${member.name}' is not in scope.`);
process.exit(1);
} else { // if (isParameter(member) || isVariableDeclaration(member))
Expand All @@ -53,9 +53,9 @@ function generateMemberCall(ir: IR, di: DI, expr: MemberCall): llvm.Value {
return ir.builder.CreateLoad(globalValue.getType().getPointerElementType(), globalValue);
}

const allocation = ir.namedValues.get(varName)!;
if (allocation) {
return ir.builder.CreateLoad(allocation.getAllocatedType(), allocation);
const alloca = ir.nameToAlloca.get(varName)!;
if (alloca) {
return ir.builder.CreateLoad(alloca.getAllocatedType(), alloca);
}

console.error(`Variable '${varName}' is not in scope.`);
Expand Down
18 changes: 11 additions & 7 deletions src/cli/llvm-ir-generator/func.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import llvm from "llvm-bindings";
import { FunctionDeclaration } from "../../language/generated/ast.js";
import { DI, IR, getLoc, getScope } from "./util.js";
import { DI, IR, getLoc, getCurrScope } from "./util.js";
import { generateExpressionBlock } from "./block.js";

export function generateFunction(ir: IR, di: DI, funcDecl: FunctionDeclaration) {
const { name, parameters, returnType, body } = funcDecl;
const { line } = getLoc(funcDecl);
const signature = parameters.map(p => p.type);
signature.push(returnType);
const signature = getSignature(funcDecl);

const funcReturnType = ir.basicTypes.get(returnType.primitive)!;
const funcParamTypes = parameters.map(p => ir.basicTypes.get(p.type.primitive)!);
Expand All @@ -17,15 +16,15 @@ export function generateFunction(ir: IR, di: DI, funcDecl: FunctionDeclaration)
const debugInfoParamTypes = di.builder.getOrCreateTypeArray(signature.map(t => di.basicTypes.get(t.primitive)!));
const debugInfoSubroutineType = di.builder.createSubroutineType(debugInfoParamTypes);
const debugInfoFuncSubprogram = di.builder.createFunction(
getScope(di), name, '', di.file, line,
getCurrScope(di), name, '', di.file, line,
debugInfoSubroutineType, line, llvm.DINode.DIFlags.FlagPrototyped, llvm.DISubprogram.DISPFlags.SPFlagDefinition
);

di.scope.push(debugInfoFuncSubprogram);

func.setSubprogram(debugInfoFuncSubprogram);
ir.builder.SetCurrentDebugLocation(new llvm.DebugLoc());

di.scope.push(debugInfoFuncSubprogram);

generateExpressionBlock(ir, di, body.elements, { name: 'entry', func, inputVars: parameters });

di.scope.pop();
Expand All @@ -34,5 +33,10 @@ export function generateFunction(ir: IR, di: DI, funcDecl: FunctionDeclaration)
if (llvm.verifyFunction(func)) {
console.error(`Verifying the ${name} function failed`);
}
return func;
}

function getSignature({ parameters, returnType }: FunctionDeclaration) {
const signature = parameters.map(p => p.type);
signature.push(returnType);
return signature;
}
12 changes: 6 additions & 6 deletions src/cli/llvm-ir-generator/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { FunctionDeclaration, isFunctionDeclaration, type OxProgram } from '../.
import llvm from 'llvm-bindings';
import { DI, IR, initDI, initIR } from './util.js';
import { generateExpressionBlock } from './block.js';
import { initDITypes, initIRTypes } from './typeref.js';
import { initDITypes, initIRTypes } from './type.js';
import { generateFunction } from './func.js';

export function generateLLVMIR(program: OxProgram, filename: string): string {
const ir = initIR(filename);
initIRTypes(ir);

const di = initDI(ir, filename);
const di = initDI(ir, filename, 'Ox compiler');
initDITypes(di);

const funcs = program.elements.filter(e => isFunctionDeclaration(e)) as FunctionDeclaration[];
Expand All @@ -31,25 +31,25 @@ function generateMainFunc(ir: IR, di: DI, program: OxProgram) {
const mainFuncType = llvm.FunctionType.get(mainFuncReturnType, false);
const mainFunc = llvm.Function.Create(mainFuncType, llvm.Function.LinkageTypes.ExternalLinkage, 'main', ir.module);

const debugInfoParamTypes = di.builder.getOrCreateTypeArray([di.basicTypes.get("int")!]);
const debugInfoParamTypes = di.builder.getOrCreateTypeArray([di.basicTypes.get('int')!]);
const debugInfoSubroutineType = di.builder.createSubroutineType(debugInfoParamTypes);
const debugInfoMainFuncSubprogram = di.builder.createFunction(
di.file, 'main', '', di.file, 1,
debugInfoSubroutineType, 1, llvm.DINode.DIFlags.FlagPrototyped, llvm.DISubprogram.DISPFlags.SPFlagDefinition
);

di.scope.push(debugInfoMainFuncSubprogram);

mainFunc.setSubprogram(debugInfoMainFuncSubprogram);
ir.builder.SetCurrentDebugLocation(new llvm.DebugLoc());

di.scope.push(debugInfoMainFuncSubprogram);

generateExpressionBlock(ir, di,
program.elements.filter(e => !isFunctionDeclaration(e)),
{ name: 'entry', func: mainFunc }
);

// generates an artificial `return 0` statement;
// is not represented in the source code, and debugging points on a non-existing line
// it's not represented in the source code, and debugging points on a non-existing line
const endLine = program.$cstNode?.range.end.line! + 2;
ir.builder.SetCurrentDebugLocation(llvm.DILocation.get(ir.context, endLine, 1, debugInfoMainFuncSubprogram));
ir.builder.CreateRet(ir.builder.getInt32(0));
Expand Down
14 changes: 14 additions & 0 deletions src/cli/llvm-ir-generator/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import llvm from 'llvm-bindings';
import { DI, IR } from './util.js';

export function initDITypes(di: DI) {
di.basicTypes.set('int', di.builder.createBasicType('int', 32, llvm.dwarf.TypeKind.DW_ATE_signed));
di.basicTypes.set('boolean', di.builder.createBasicType('boolean', 8, llvm.dwarf.TypeKind.DW_ATE_boolean));
di.basicTypes.set('number', di.builder.createBasicType('double', 64, llvm.dwarf.TypeKind.DW_ATE_float));
}

export function initIRTypes(ir: IR) {
ir.basicTypes.set('int', ir.builder.getInt32Ty());
ir.basicTypes.set('boolean', ir.builder.getInt1Ty());
ir.basicTypes.set('number', ir.builder.getDoubleTy());
}
14 changes: 0 additions & 14 deletions src/cli/llvm-ir-generator/typeref.ts

This file was deleted.

31 changes: 21 additions & 10 deletions src/cli/llvm-ir-generator/util.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { AstNode } from 'langium';
import llvm from 'llvm-bindings';
import { Position } from 'vscode-languageclient';

export type IR = {
context: llvm.LLVMContext,
module: llvm.Module,
builder: llvm.IRBuilder,
basicTypes: Map<string, llvm.Type>,
namedValues: Map<string, llvm.AllocaInst>,
nameToAlloca: Map<string, llvm.AllocaInst>,
globalValues: Map<string, llvm.Constant>,
}

Expand All @@ -23,27 +22,39 @@ export function initIR(filename: string): IR {
const context = new llvm.LLVMContext();
const module = new llvm.Module(filename, context);
const builder = new llvm.IRBuilder(context);
return { context, module, builder, basicTypes: new Map(), namedValues: new Map(), globalValues: new Map() };
return { context, module, builder,
basicTypes: new Map(),
nameToAlloca: new Map(),
globalValues: new Map()
};
}

export function initDI(ir: IR, filename: string): DI {
export function initDI(ir: IR, filename: string, producer: string): DI {
ir.module.addModuleFlag(llvm.Module.ModFlagBehavior.Warning, 'Debug Info Version', llvm.LLVMConstants.DEBUG_METADATA_VERSION);
ir.module.addModuleFlag(llvm.Module.ModFlagBehavior.Warning, 'Dwarf Version', llvm.dwarf.LLVMConstants.DWARF_VERSION);

const builder = new llvm.DIBuilder(ir.module);
const file = builder.createFile(filename, '.');
const unit = builder.createCompileUnit(llvm.dwarf.SourceLanguage.DW_LANG_C, file, 'Ox compiler', false, '', 0);
const scope = [file];
return { builder, file, unit, scope, basicTypes: new Map() };
const unit = builder.createCompileUnit(llvm.dwarf.SourceLanguage.DW_LANG_C, file, producer, false, '', 0);
return { builder, file, unit,
scope: [file],
basicTypes: new Map()
};
}

export type Pos = {
line: number,
col: number
}

export function getLoc(node: AstNode): Position {
export function getLoc(node: AstNode): Pos {
const pos = node.$cstNode!.range.start;
return {
line: pos.line + 1,
character: pos.character
col: pos.character
};
}

export function getScope(di: DI): llvm.DIScope {
export function getCurrScope(di: DI): llvm.DIScope {
return di.scope[di.scope.length - 1];
}
10 changes: 5 additions & 5 deletions src/cli/llvm-ir-generator/var.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import llvm from "llvm-bindings";
import { VariableDeclaration } from "../../language/generated/ast.js";
import { generateExpression } from "./expr.js";
import { DI, IR, getLoc, getScope } from "./util.js";
import { DI, IR, getLoc, getCurrScope } from "./util.js";

export function generateVariableDeclaration(ir: IR, di: DI, varDecl: VariableDeclaration) {
const { name, type, assignment, value: expr } = varDecl;
const { line, character: col } = getLoc(varDecl);
const scope = getScope(di);
const { line, col } = getLoc(varDecl);
const scope = getCurrScope(di);

const alloca = ir.builder.CreateAlloca(ir.basicTypes.get(type.primitive)!, null, name);
ir.namedValues.set(name, alloca);
const diLocalVar = di.builder.createAutoVariable(scope, name, di.file, line, di.basicTypes.get(type.primitive)!);

di.builder.insertDeclare(
alloca,
diLocalVar,
Expand All @@ -25,4 +23,6 @@ export function generateVariableDeclaration(ir: IR, di: DI, varDecl: VariableDec
if (assignment) {
ir.builder.CreateStore(generateExpression(ir, di, expr!), alloca);
}

ir.nameToAlloca.set(name, alloca);
}

0 comments on commit 708ec48

Please sign in to comment.