Skip to content

Commit

Permalink
feat: adds support for literal number suffixes
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Apr 9, 2020
1 parent 5ea272f commit d188cfd
Show file tree
Hide file tree
Showing 14 changed files with 929 additions and 41 deletions.
57 changes: 46 additions & 11 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ use inkwell::{
values::{BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue, StructValue},
AddressSpace, FloatPredicate, IntPredicate,
};
use std::{collections::HashMap, mem, sync::Arc};
use std::{collections::HashMap, sync::Arc};

use crate::ir::ty::ResolveBitness;
use inkwell::basic_block::BasicBlock;
use inkwell::values::{AggregateValueEnum, GlobalValue, PointerValue};

Expand Down Expand Up @@ -200,7 +201,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
let resolver = hir::resolver_for_expr(self.body.clone(), self.db, expr);
Some(self.gen_path_expr(p, expr, &resolver))
}
Expr::Literal(lit) => Some(self.gen_literal(lit)),
Expr::Literal(lit) => Some(self.gen_literal(lit, expr)),
Expr::RecordLit { fields, .. } => Some(self.gen_record_lit(expr, fields)),
Expr::BinaryOp { lhs, rhs, op } => {
self.gen_binary_op(expr, *lhs, *rhs, op.expect("missing op"))
Expand Down Expand Up @@ -246,16 +247,50 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
}

/// Generates an IR value that represents the given `Literal`.
fn gen_literal(&mut self, lit: &Literal) -> BasicValueEnum {
fn gen_literal(&mut self, lit: &Literal, expr: ExprId) -> BasicValueEnum {
match lit {
Literal::Int(v) => self
.db
.context()
.i64_type()
.const_int(unsafe { mem::transmute::<i64, u64>(*v) }, true)
.into(),

Literal::Float(v) => self.db.context().f64_type().const_float(*v as f64).into(),
Literal::Int(v) => {
let ty = match &self.infer[expr] {
hir::Ty::Apply(hir::ApplicationTy {
ctor: hir::TypeCtor::Int(int_ty),
..
}) => int_ty,
_ => unreachable!(
"cannot construct an IR value for anything but an integral type"
),
};

let context = self.db.context();
let has_sign = ty.signedness == hir::Signedness::Signed;
let ir_ty = match ty.resolve(&self.db.target_data()).bitness {
hir::IntBitness::X8 => context.i8_type().const_int(v.value as u64, has_sign),
hir::IntBitness::X16 => context.i16_type().const_int(v.value as u64, has_sign),
hir::IntBitness::X32 => context.i32_type().const_int(v.value as u64, has_sign),
hir::IntBitness::X64 => context.i64_type().const_int(v.value as u64, has_sign),
_ => unreachable!("unresolved bitness in code generation"),
};

ir_ty.into()
}

Literal::Float(v) => {
let ty = match &self.infer[expr] {
hir::Ty::Apply(hir::ApplicationTy {
ctor: hir::TypeCtor::Float(float_ty),
..
}) => float_ty,
_ => unreachable!("cannot construct an IR value for anything but a float type"),
};

let context = self.db.context();
let ir_ty = match ty.resolve(&self.db.target_data()).bitness {
hir::FloatBitness::X32 => context.f32_type().const_float(v.value),
hir::FloatBitness::X64 => context.f64_type().const_float(v.value),
_ => unreachable!("unresolved bitness in code generation"),
};

ir_ty.into()
}

Literal::Bool(value) => {
let ty = self.db.context().bool_type();
Expand Down
27 changes: 17 additions & 10 deletions crates/mun_codegen/src/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use crate::{
CodeGenParams, IrDatabase,
};
use hir::{ApplicationTy, CallableDef, FloatBitness, FloatTy, IntBitness, IntTy, Ty, TypeCtor};
use inkwell::targets::TargetData;
use inkwell::types::{AnyTypeEnum, BasicType, BasicTypeEnum, FloatType, IntType, StructType};
use inkwell::AddressSpace;
use mun_target::spec::Target;

/// Given a mun type, construct an LLVM IR type
#[rustfmt::skip]
Expand Down Expand Up @@ -57,7 +57,7 @@ pub(crate) fn ir_query(db: &impl IrDatabase, ty: Ty, params: CodeGenParams) -> A
/// Returns the LLVM IR type of the specified float type
fn float_ty_query(db: &impl IrDatabase, fty: FloatTy) -> FloatType {
let context = db.context();
match fty.resolve(&db.target()).bitness {
match fty.resolve(&db.target_data()).bitness {
FloatBitness::X64 => context.f64_type(),
FloatBitness::X32 => context.f32_type(),
_ => unreachable!(),
Expand All @@ -67,7 +67,7 @@ fn float_ty_query(db: &impl IrDatabase, fty: FloatTy) -> FloatType {
/// Returns the LLVM IR type of the specified int type
fn int_ty_query(db: &impl IrDatabase, ity: IntTy) -> IntType {
let context = db.context();
match ity.resolve(&db.target()).bitness {
match ity.resolve(&db.target_data()).bitness {
IntBitness::X64 => context.i64_type(),
IntBitness::X32 => context.i32_type(),
IntBitness::X16 => context.i16_type(),
Expand Down Expand Up @@ -101,7 +101,7 @@ pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo {
let ir_ty = float_ty_query(db, ty);
let type_size = TypeSize::from_ir_type(&ir_ty, target.as_ref());
TypeInfo::new(
format!("core::{}", ty.resolve(&db.target())),
format!("core::{}", ty.resolve(&db.target_data())),
TypeGroup::FundamentalTypes,
type_size,
)
Expand All @@ -110,7 +110,7 @@ pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo {
let ir_ty = int_ty_query(db, ty);
let type_size = TypeSize::from_ir_type(&ir_ty, target.as_ref());
TypeInfo::new(
format!("core::{}", ty.resolve(&db.target())),
format!("core::{}", ty.resolve(&db.target_data())),
TypeGroup::FundamentalTypes,
type_size,
)
Expand All @@ -131,12 +131,12 @@ pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo {
}
}

trait ResolveBitness {
fn resolve(&self, _target: &Target) -> Self;
pub(crate) trait ResolveBitness {
fn resolve(&self, target: &TargetData) -> Self;
}

impl ResolveBitness for FloatTy {
fn resolve(&self, _target: &Target) -> Self {
fn resolve(&self, _target: &TargetData) -> Self {
let bitness = match self.bitness {
FloatBitness::Undefined => FloatBitness::X64,
bitness => bitness,
Expand All @@ -146,10 +146,17 @@ impl ResolveBitness for FloatTy {
}

impl ResolveBitness for IntTy {
fn resolve(&self, _target: &Target) -> Self {
fn resolve(&self, target: &TargetData) -> Self {
let ptr_bit_size = target.ptr_sized_int_type(None).get_bit_width();
let bitness = match ptr_bit_size {
16 => IntBitness::X16,
32 => IntBitness::X32,
64 => IntBitness::X64,
_ => unreachable!("unsupported bit size for pointers"),
};
let bitness = match self.bitness {
IntBitness::Undefined => IntBitness::X64,
IntBitness::Xsize => IntBitness::X64,
IntBitness::Xsize => bitness,
bitness => bitness,
};
IntTy {
Expand Down
55 changes: 55 additions & 0 deletions crates/mun_codegen/src/snapshots/test__literal_types_file_ir.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
source: crates/mun_codegen/src/test.rs
expression: "fn main(){\n let a = 123;\n let a = 123u8;\n let a = 123u16;\n let a = 123u32;\n let a = 123u64;\n let a = 123uint;\n let a = 1_000_000_u32;\n let a = 123i8;\n let a = 123i16;\n let a = 123i32;\n let a = 123i64;\n let a = 123int;\n let a = 1_000_000_i32;\n let a = 1_000_123.0e-2;\n let a = 1_000_123.0e-2f32;\n let a = 1_000_123.0e-2f64;\n let a = 1_000_123.0e-2float;\n}\n\nfn add(a:u32): u32 {\n a + 12u32\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"

define void @main() {
body:
%a16 = alloca double
%a15 = alloca double
%a14 = alloca float
%a13 = alloca double
%a12 = alloca i32
%a11 = alloca i64
%a10 = alloca i64
%a9 = alloca i32
%a8 = alloca i16
%a7 = alloca i8
%a6 = alloca i32
%a5 = alloca i64
%a4 = alloca i64
%a3 = alloca i32
%a2 = alloca i16
%a1 = alloca i8
%a = alloca i64
store i64 123, i64* %a
store i8 123, i8* %a1
store i16 123, i16* %a2
store i32 123, i32* %a3
store i64 123, i64* %a4
store i64 123, i64* %a5
store i32 1000000, i32* %a6
store i8 123, i8* %a7
store i16 123, i16* %a8
store i32 123, i32* %a9
store i64 123, i64* %a10
store i64 123, i64* %a11
store i32 1000000, i32* %a12
store double 0x40C3889D70A3D70A, double* %a13
store float 0x40C3889D80000000, float* %a14
store double 0x40C3889D70A3D70A, double* %a15
store double 0x40C3889D70A3D70A, double* %a16
ret void
}

define i32 @add(i32) {
body:
%a = alloca i32
store i32 %0, i32* %a
%a1 = load i32, i32* %a
%add = add i32 %a1, 12
ret i32 %add
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
source: crates/mun_codegen/src/test.rs
expression: "fn main(){\n 123;\n 123u8;\n 123u16;\n 123u32;\n 123u64;\n 123uint;\n 1_000_000_u32;\n 123i8;\n 123i16;\n 123i32;\n 123i64;\n 123int;\n 1_000_000_i32;\n 1_000_123.0e-2;\n 1_000_123.0e-2f32;\n 1_000_123.0e-2f64;\n 1_000_123.0e-2float;\n}\n\nfn add(a:u32): u32 {\n a + 12u32\n}"
---
; ModuleID = 'group_name'
source_filename = "group_name"

30 changes: 30 additions & 0 deletions crates/mun_codegen/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,36 @@ use mun_target::spec::Target;
use std::cell::RefCell;
use std::sync::Arc;

#[test]
fn literal_types() {
test_snapshot_unoptimized(
r"
fn main(){
let a = 123;
let a = 123u8;
let a = 123u16;
let a = 123u32;
let a = 123u64;
let a = 123uint;
let a = 1_000_000_u32;
let a = 123i8;
let a = 123i16;
let a = 123i32;
let a = 123i64;
let a = 123int;
let a = 1_000_000_i32;
let a = 1_000_123.0e-2;
let a = 1_000_123.0e-2f32;
let a = 1_000_123.0e-2f64;
let a = 1_000_123.0e-2float;
}
fn add(a:u32) -> u32 {
a + 12u32
}",
)
}

#[test]
fn function() {
test_snapshot(
Expand Down
3 changes: 3 additions & 0 deletions crates/mun_hir/src/builtin_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,14 @@ impl BuiltinInt {

pub fn from_suffix(suffix: &str) -> Option<BuiltinInt> {
let res = match suffix {
"int" => Self::INT,
"isize" => Self::ISIZE,
"i8" => Self::I8,
"i16" => Self::I16,
"i32" => Self::I32,
"i64" => Self::I64,

"uint" => Self::UINT,
"usize" => Self::USIZE,
"u8" => Self::U8,
"u16" => Self::U16,
Expand All @@ -146,6 +148,7 @@ impl BuiltinFloat {
let res = match suffix {
"f32" => BuiltinFloat::F32,
"f64" => BuiltinFloat::F64,
"float" => BuiltinFloat::FLOAT,
_ => return None,
};
Some(res)
Expand Down
Loading

0 comments on commit d188cfd

Please sign in to comment.