diff --git a/Makefile b/Makefile index aad3186..4ccb3c2 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ else endif LLVM_CXXFLAGS = $(shell $(LLVM_CONFIG) --cxxflags) -LLVM_CXXLFLAGS = $(shell $(LLVM_CONFIG) --ldflags --link-static --system-libs --libs X86AsmParser X86CodeGen Core Support BitReader AsmParser Analysis TransformUtils ScalarOpts Target) +LLVM_CXXLFLAGS = $(shell $(LLVM_CONFIG) --ldflags --link-static) -lLLVMAsmParser -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMGlobalISel -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMDebugInfoCodeView -lLLVMDebugInfoMSF -lLLVMCodeGen -lLLVMTarget -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis -lLLVMProfileData -lLLVMX86Desc -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMMCDisassembler -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMMC -lLLVMX86Utils -lLLVMCore -lLLVMBinaryFormat -lLLVMSupport -lLLVMDemangle -lz -lm LFLAGS = DISABLED_WARNINGS = -Wno-writable-strings -Wno-switch -Wno-c11-extensions -Wno-c99-extensions @@ -53,4 +53,4 @@ install: clean: rm -f $(TARGET) core.o llvm.o $(TEST_TARGET) $(TEST_LOG) $(TEST_MAIN) -.PHONY: all clean debug release tests +.PHONY: all clean debug release tests install diff --git a/src/checker.c b/src/checker.c index d36ba4f..b1bdab5 100644 --- a/src/checker.c +++ b/src/checker.c @@ -167,7 +167,7 @@ CheckerInfo *CheckerInfoForDecl(Package *pkg, Decl *decl) { } b32 declareSymbol(Package *pkg, Scope *scope, const char *name, Symbol **symbol, Decl *decl) { - Symbol *old = Lookup(scope, name); + Symbol *old = LookupNoRecurse(scope, name); if (old) { ReportError(pkg, RedefinitionError, decl->start, "Duplicate definition of symbol %s", name); ReportNote(pkg, old->decl->start, "Previous definition of %s", name); @@ -223,6 +223,10 @@ b32 IsFloat(Type *type) { return type->kind == TypeKind_Float; } +b32 isEnum(Type *type) { + return type->kind == TypeKind_Enum; +} + b32 isFunction(Type *type) { return type->kind == TypeKind_Function; } @@ -267,10 +271,6 @@ b32 isSlice(Type *type) { return type->kind == TypeKind_Slice; } -b32 isEnum(Type *type) { - return type->kind == TypeKind_Enum; -} - b32 isEnumFlags(Type *type) { return isEnum(type) && (type->Flags & TypeFlag_EnumFlags) != 0; } @@ -366,6 +366,10 @@ b32 canCoerce(Type *type, Type *target, CheckerContext *ctx) { return type->Width <= target->Width; } + if (isEnum(type) && IsInteger(target)) { + return canCoerce(type->Enum.backingType, target, ctx); + } + if (IsFloat(type)) { // Coercion between float types requires the target is larger or equal in size. return IsFloat(target) && type->Width <= target->Width; @@ -473,6 +477,10 @@ Conversion conversion(Type *type, Type *target) { return result; } + if (isEnum(type) && IsInteger(target)) { + return ConversionKind_Enum; + } + if (IsFloat(type) && IsInteger(target)) { result |= ConversionKind_FtoI & ConversionFlag_Float; if (IsSigned(target)) result |= ConversionFlag_Signed; @@ -668,6 +676,10 @@ Symbol *Lookup(Scope *scope, const char *name) { return NULL; } +Symbol *LookupNoRecurse(Scope *scope, const char *name) { + return MapGet(&scope->members, name); +} + Type *TypeFromCheckerInfo(CheckerInfo info) { switch (info.kind) { case CheckerInfoKind_BasicExpr: @@ -876,6 +888,87 @@ Type *checkExprTypeVariadic(Expr *expr, CheckerContext *ctx, Package *pkg) { return InvalidType; } +Type *checkExprTypeEnum(Expr *expr, CheckerContext *ctx, Package *pkg) { + ASSERT(expr->kind == ExprKind_TypeEnum); + Expr_TypeEnum enm = expr->TypeEnum; + + b32 hasMinMax = false; + u64 maxValue; + + Type *backingType = NULL; + if (enm.explicitType) { + Type *type = checkExpr(enm.explicitType, ctx, pkg); + if (ctx->mode == ExprMode_Unresolved) goto unresolved; + + if (ctx->mode != ExprMode_Invalid) { + expectType(pkg, type, ctx, enm.explicitType->start); + if (IsInteger(type)) { + // TODO: flags + maxValue = MaxValueForIntOrPointerType(type); + hasMinMax = true; + backingType = type; + } else { + ReportError(pkg, TypeMismatchError, enm.explicitType->start, + "Enum backing type must be an integer. Got: %s", DescribeType(type)); + } + } + } + + DynamicArray(EnumField) fields = NULL; + ArrayFit(fields, ArrayLen(enm.items)); + + u64 currentValue = 0; + u64 largestValue = 0; + + For(enm.items) { + EnumItem item = enm.items[i]; + + if (item.init) { + CheckerContext itemCtx = {.scope = ctx->scope, .desiredType = backingType}; + Type *type = checkExpr(item.init, &itemCtx, pkg); + if (itemCtx.mode == ExprMode_Unresolved) goto unresolved; + + if (!IsConstant(&itemCtx)) { + ReportError(pkg, TODOError, item.init->start, + "Enum cases must be a constant value"); + continue; + } + + if (backingType && !coerceType(item.init, ctx, &type, backingType, pkg)) { + continue; + } + + u64 val = itemCtx.val.u64; + currentValue = val; + largestValue = MAX(largestValue, val); + } + + if (hasMinMax && currentValue > maxValue) { + ReportError(pkg, IntOverflowError, item.init->start, + "Value for enum case exceeds the max value for the enum backing type (%s)", + DescribeType(backingType)); + ReportNote(pkg, item.init->start, + "You can force the overflow by explicitly casting the value '%s(%s)", + DescribeType(backingType), DescribeExpr(item.init)); + continue; + } + + ArrayPush(fields, (EnumField){.name = item.name, .val = currentValue}); + currentValue++; + } + + backingType = backingType ? backingType : SmallestIntTypeForPositiveValue(largestValue); + Type *type = NewTypeEnum(TypeFlag_None, backingType, fields); + storeInfoBasicExpr(pkg, expr, type, ctx); + ctx->mode = ExprMode_Type; + return type; + +unresolved: + if (fields) ArrayFree(fields); + ctx->mode = ExprMode_Unresolved; + return NULL; +} + Type *checkExprTypeFunction(Expr *expr, CheckerContext *ctx, Package *pkg) { ASSERT(expr->kind == ExprKind_TypeFunction); Expr_TypeFunction func = expr->TypeFunction; @@ -886,7 +979,7 @@ Type *checkExprTypeFunction(Expr *expr, CheckerContext *ctx, Package *pkg) { DynamicArray(Type *) params = NULL; ArrayFit(params, ArrayLen(func.params)); - CheckerContext paramCtx = { pushScope(pkg, ctx->scope) }; + CheckerContext paramCtx = { .scope = pushScope(pkg, ctx->scope) }; For (func.params) { Type *type = checkExpr(func.params[i]->value, ¶mCtx, pkg); if (paramCtx.mode == ExprMode_Invalid) goto error; @@ -1011,6 +1104,8 @@ Type *checkExprLitFunction(Expr *expr, CheckerContext *ctx, Package *pkg) { bodyCtx.desiredType = NewTypeTupleFromFunctionResults(TypeFlag_None, type->Function); } + CheckerContext bodyCtx = { .scope = bodyScope, .desiredType = tuple }; + size_t len = ArrayLen(func.body->stmts); for (size_t i = 0; i < len; i++) { checkStmt(func.body->stmts[i], &bodyCtx, pkg); @@ -1626,6 +1721,25 @@ Type *checkExprSelector(Expr *expr, CheckerContext *ctx, Package *pkg) { break; } + case TypeKind_Enum: { + if (ctx->mode == ExprMode_Type) { + EnumFieldLookupResult result = EnumFieldLookup(base->Enum, expr->Selector.name); + if (!result.field) { + ReportError(pkg, TODOError, expr->Selector.start, "Enum %s has no member named %s", + DescribeType(base), expr->Selector.name); + goto error; + } + + ctx->val.u64 = result.field->val; + SelectorValue val = {.Enum.value = result.field->val}; + storeInfoSelector(pkg, expr, base, SelectorKind_Enum, val, ctx); + type = base; + ctx->mode = ExprMode_Addressable; + ctx->flags |= CheckerContextFlag_Constant; + break; + } + } + TypeKind_File: { Symbol *file = pkg->checkerInfo[expr->Selector.expr->id].Ident.symbol; Package *import = (Package *) file->backendUserdata; @@ -1805,6 +1919,9 @@ Type *checkExpr(Expr *expr, CheckerContext *ctx, Package *pkg) { break; case ExprKind_TypeEnum: + type = checkExprTypeEnum(expr, ctx, pkg); + break; + case ExprKind_TypeUnion: case ExprKind_TypePolymorphic: UNIMPLEMENTED(); @@ -1918,8 +2035,12 @@ void checkDeclConstant(Decl *decl, CheckerContext *ctx, Package *pkg) { break; } - case ExprKind_TypeUnion: case ExprKind_TypeEnum: { + symbol->state = SymbolState_Resolving; + symbol->kind = SymbolKind_Type; + } break; + + case ExprKind_TypeUnion: { UNIMPLEMENTED(); } break; @@ -2445,7 +2566,7 @@ void checkStmtSwitch(Stmt *stmt, CheckerContext *ctx, Package *pkg) { Type *switchType = BoolType; if (stmt->Switch.match) { switchType = checkExpr(stmt->Switch.match, &switchCtx, pkg); - if (!isNumericOrPointer(switchType) && !isBoolean(switchType)) { + if (!isNumericOrPointer(switchType) && !isBoolean(switchType) && !isEnum(switchType)) { ReportError(pkg, CannotSwitchError, stmt->Switch.match->start, "Cannot switch on value of type %s", DescribeType(switchType)); } @@ -3270,6 +3391,3 @@ info = GetStmtInfo(&pkg, stmt)->Switch #undef pkg #endif - - - diff --git a/src/checker.h b/src/checker.h index 2fd1a0e..5be274c 100644 --- a/src/checker.h +++ b/src/checker.h @@ -20,7 +20,7 @@ enum Enum_CheckerInfoKind { STATIC_ASSERT(_StmtKind_End <= UINT8_MAX, "enum values overflow storage type"); typedef u8 Conversion; -#define ConversionKind_Mask 0x0F // Lower 3 bits denote the class +#define ConversionKind_Mask 0x0F // Lower 4 bits denote the class #define ConversionKind_None 0 #define ConversionKind_Same 1 #define ConversionKind_FtoI 2 @@ -29,11 +29,13 @@ typedef u8 Conversion; #define ConversionKind_ItoP 5 #define ConversionKind_Bool 6 #define ConversionKind_Tuple 7 // Information on the conversion can be found on their receiver. +#define ConversionKind_Enum 8 #define ConversionKind_Any 15 #define ConversionFlag_Extend 0x10 // 0001 #define ConversionFlag_Signed 0x20 // 0010 #define ConversionFlag_Float 0x40 // 0100 (Source type is a Float) +#define ConversionFlag_Enum 0x80 // 1000 typedef struct CheckerInfo_Constant CheckerInfo_Constant; struct CheckerInfo_Constant { @@ -60,7 +62,8 @@ struct CheckerInfo_Ident { typedef u8 SelectorKind; #define SelectorKind_None 0x0 #define SelectorKind_Struct 0x1 -#define SelectorKind_Import 0x2 +#define SelectorKind_Enum 0x2 +#define SelectorKind_Import 0x3 typedef struct Selector_Struct Selector_Struct; struct Selector_Struct { @@ -68,6 +71,11 @@ struct Selector_Struct { u32 offset; // The member offset in the structure (in bits) }; +typedef struct Selector_Enum Selector_Enum; +struct Selector_Enum { + u64 value; +}; + typedef struct Selector_Import Selector_Import; struct Selector_Import { Symbol *symbol; @@ -77,6 +85,7 @@ struct Selector_Import { typedef union SelectorValue SelectorValue; union SelectorValue { Selector_Struct Struct; + Selector_Enum Enum; Selector_Import Import; }; @@ -154,6 +163,7 @@ struct CheckerInfo { extern "C" { #endif Symbol *Lookup(Scope *scope, const char *name); +Symbol *LookupNoRecurse(Scope *scope, const char *name); Type *TypeFromCheckerInfo(CheckerInfo info); b32 IsInteger(Type *type); b32 IsSigned(Type *type); diff --git a/src/header.c b/src/header.c index 106c55c..aae3cd2 100644 --- a/src/header.c +++ b/src/header.c @@ -11,6 +11,9 @@ void cgenType(String *buffer, const char * name, Type *type) { switch (type->kind) { case TypeKind_Int: + if (type->Width == 1) + return cgenType(buffer, name, I8Type); + ArrayPrintf(*buffer, "Kai%s%d", type->Flags & TypeFlag_Signed ? "I" : "U", type->Width); break; @@ -19,10 +22,19 @@ void cgenType(String *buffer, const char * name, Type *type) { break; case TypeKind_Pointer: { - String pointee = NULL; - cgenType(&pointee, NULL, type->Pointer.pointeeType); - ArrayPrintf(*buffer, "%s*", pointee); - ArrayFree(pointee); + if (type == RawptrType) { + ArrayPrintf(*buffer, "KaiRawptr"); + } else { + String pointee = NULL; + cgenType(&pointee, NULL, type->Pointer.pointeeType); + ArrayPrintf(*buffer, "%s*", pointee); + ArrayFree(pointee); + } + } break; + + case TypeKind_Enum: { + cgenType(buffer, name, type->Enum.backingType); + return; } break; case TypeKind_Struct: { @@ -82,6 +94,19 @@ void cgenDecl(HeaderContext *ctx, DynamicArray(Expr_Ident *) names, Type *type, cgenFuncPrototype(&ctx->functions, it->name, type); break; + case TypeKind_Enum: { + For(type->Enum.cases) { + struct EnumField field = type->Enum.cases[i]; + ArrayPrintf( + ctx->primitiveDecls, + "#define %s_%s %lu\n", + type->Symbol->name, + field.name, + field.val + ); + } + } break; + case TypeKind_Struct: { if (type->Symbol->backendUserdata != HEAD_GENERATED) { ArrayPrintf(ctx->primitiveDecls, "typedef "); @@ -97,7 +122,7 @@ void cgenDecl(HeaderContext *ctx, DynamicArray(Expr_Ident *) names, Type *type, cgenType(&ctx->complexDecls, it.name, it.type); ArrayPrintf(ctx->complexDecls, ";\n"); } - ArrayPrintf(ctx->complexDecls, "};\n"); + ArrayPrintf(ctx->complexDecls, "};\n\n"); } break; default: { @@ -127,7 +152,7 @@ void cgenStmt(HeaderContext *ctx, CheckerInfo *info, Stmt *stmt) { } } -const char *headerPreface = "#ifndef KAI_%s_H\n#define KAI_%s_H\n\n#ifndef KAI_TYPES\n#define KAI_TYPES\n#include \n\ntypedef int8_t KaiI8;\ntypedef int16_t KaiI16;\ntypedef int32_t KaiI32;\ntypedef int64_t KaiI64;\n\ntypedef uint8_t KaiU8;\ntypedef uint16_t KaiU16;\ntypedef uint32_t KaiU32;\ntypedef uint64_t KaiU64;\n\ntypedef float KaiF32;\ntypedef double KaiF64;\n#endif\n"; +const char *headerPreface = "#ifndef KAI_%s_H\n#define KAI_%s_H\n\n#ifndef KAI_TYPES\n#define KAI_TYPES\n#include \n\ntypedef int8_t KaiI8;\ntypedef int16_t KaiI16;\ntypedef int32_t KaiI32;\ntypedef int64_t KaiI64;\n\ntypedef uint8_t KaiU8;\ntypedef uint16_t KaiU16;\ntypedef uint32_t KaiU32;\ntypedef uint64_t KaiU64;\n\ntypedef float KaiF32;\ntypedef double KaiF64;\n\ntypedef void * KaiRawptr;\n#endif\n"; void CodegenCHeader(Package *pkg) { char buff[MAX_PATH]; diff --git a/src/llvm.cpp b/src/llvm.cpp index c9eb127..4df38b9 100644 --- a/src/llvm.cpp +++ b/src/llvm.cpp @@ -98,6 +98,12 @@ struct Context { std::vector deferStack; }; +typedef struct BackendUserdataAndDebug BackendUserdataAndDebug; +struct BackendUserdataAndDebug { + llvm::Type *type; + llvm::DIType *debugType; +}; + typedef struct BackendStructUserdata BackendStructUserdata; struct BackendStructUserdata { llvm::StructType *type; @@ -135,6 +141,10 @@ llvm::Type *canonicalize(Context *ctx, Type *type) { } } break; + case TypeKind_Enum: { + return llvm::IntegerType::get(ctx->m->getContext(), type->Width); + }; + case TypeKind_Array: { return llvm::ArrayType::get(canonicalize(ctx, type->Array.elementType), type->Array.length); } break; @@ -261,6 +271,35 @@ llvm::DIType *debugCanonicalize(Context *ctx, Type *type) { return ctx->d.builder->createSubroutineType(pTypes); } + if (type->kind == TypeKind_Enum) { + if (type->Symbol && type->Symbol->backendUserdata) { + return ((BackendUserdataAndDebug *) type->Symbol->backendUserdata)->debugType; + } + + std::vector enumerations; + For(type->Enum.cases) { + EnumField it = type->Enum.cases[i]; + auto enumeration = ctx->d.builder->createEnumerator( + it.name, + it.val + ); + + enumerations.push_back(enumeration); + } + + auto elements = ctx->d.builder->getOrCreateArray(enumerations); + ctx->d.builder->createEnumerationType( + ctx->d.scope, + type->Symbol->name, + ctx->d.file, + 0, + type->Width, + type->Align, + elements, + debugCanonicalize(ctx, type->Enum.backingType) + ); + } + if (type->kind == TypeKind_Struct) { if (type->Symbol && type->Symbol->backendUserdata) { BackendStructUserdata *userdata = (BackendStructUserdata *) type->Symbol->backendUserdata; @@ -579,6 +618,13 @@ llvm::Value *emitExprCall(Context *ctx, Expr *expr) { return ctx->b.CreateCall(irFunc, args); } +llvm::Value *emitExprCast(Context *ctx, Expr *expr) { + ASSERT(expr->kind == ExprKind_Cast); + CheckerInfo_BasicExpr info = ctx->checkerInfo[expr->id].BasicExpr; + llvm::Value *value = emitExpr(ctx, expr->Cast.expr); + return ctx->b.CreateBitCast(value, canonicalize(ctx, info.type)); +} + llvm::Value *emitExprLitCompound(Context *ctx, Expr *expr) { ASSERT(expr->kind == ExprKind_LitCompound); CheckerInfo_BasicExpr info = ctx->checkerInfo[expr->id].BasicExpr; @@ -661,6 +707,15 @@ llvm::Value *emitExprSelector(Context *ctx, Expr *expr) { return ctx->b.CreateAlignedLoad(addr, BytesFromBits(info.value.Struct.index)); } + case SelectorKind_Enum: { + llvm::Type *type = canonicalize(ctx, info.type); + if (ctx->returnAddress) { + UNIMPLEMENTED(); + } + + return llvm::ConstantInt::get(type, info.value.Enum.value); + } + case SelectorKind_Import: { Symbol *symbol = info.value.Import.symbol; if (!symbol->backendUserdata) { @@ -742,6 +797,11 @@ llvm::Value *emitExpr(Context *ctx, Expr *expr, llvm::Type *desiredType) { break; } + case ExprKind_Paren: { + value = emitExpr(ctx, expr->Paren.expr); + break; + } + case ExprKind_LitCompound: { value = emitExprLitCompound(ctx, expr); break; @@ -766,6 +826,10 @@ llvm::Value *emitExpr(Context *ctx, Expr *expr, llvm::Type *desiredType) { case ExprKind_Call: value = emitExprCall(ctx, expr); break; + + case ExprKind_Cast: + value = emitExprCast(ctx, expr); + break; } if (ctx->checkerInfo[expr->id].coerce != ConversionKind_None && desiredType) { @@ -924,7 +988,11 @@ llvm::Value *emitExprSubscript(Context *ctx, Expr *expr) { std::vector indicies; + bool prevReturn = ctx->returnAddress; + ctx->returnAddress = false; llvm::Value *index = emitExpr(ctx, expr->Subscript.index); + ctx->returnAddress = prevReturn; + Type *indexType = TypeFromCheckerInfo(indexInfo); // NOTE: LLVM doesn't have unsigned integers and an index in the upper-half @@ -959,7 +1027,10 @@ llvm::Value *emitExprSubscript(Context *ctx, Expr *expr) { } break; case TypeKind_Pointer: { + bool previousReturnAddress = ctx->returnAddress; + ctx->returnAddress = false; aggregate = emitExpr(ctx, expr->Subscript.expr); + ctx->returnAddress = previousReturnAddress; indicies.push_back(index); resultType = TypeFromCheckerInfo(recvInfo)->Pointer.pointeeType; } break; @@ -973,7 +1044,7 @@ llvm::Value *emitExprSubscript(Context *ctx, Expr *expr) { if (ctx->returnAddress) { return val; } - + return ctx->b.CreateAlignedLoad(val, BytesFromBits(resultType->Align)); } @@ -1134,6 +1205,63 @@ llvm::Function *emitExprLitFunction(Context *ctx, Expr *expr, llvm::Function *fn return fn; } +llvm::Type *emitExprTypeEnum(Context *ctx, Expr *expr) { + ASSERT(expr->kind == ExprKind_TypeEnum); + + Type *type = TypeFromCheckerInfo(ctx->checkerInfo[expr->id]); + + if (type->Symbol->backendUserdata && !FlagDebug) { + BackendUserdataAndDebug *userdata = (BackendUserdataAndDebug *)type->Symbol->backendUserdata; + return userdata->type; + } + + Type_Enum enm = type->Enum; + + llvm::Type *ty; + if (type->Symbol->backendUserdata) { + ty = ((BackendUserdataAndDebug *)type->Symbol->backendUserdata)->type; + } else { + ty = canonicalize(ctx, enm.backingType); + } + + BackendUserdataAndDebug *userdata; + if (type->Symbol->backendUserdata) { + userdata = (BackendUserdataAndDebug *) type->Symbol->backendUserdata; + ASSERT_MSG(!userdata->debugType, "debugType is only set here, which means this run twice"); + } else { + userdata = (BackendUserdataAndDebug *) ArenaAlloc(&ctx->arena, sizeof(*userdata)); + userdata->type = ty; + type->Symbol->backendUserdata = userdata; + } + + if (FlagDebug) { + llvm::DIType *dbTy = debugCanonicalize(ctx, enm.backingType); + std::vector enumerations; + + For (enm.cases) { + EnumField cse = enm.cases[i]; + llvm::DIEnumerator *e = ctx->d.builder->createEnumerator(cse.name, cse.val); + enumerations.push_back(e); + } + + auto elements = ctx->d.builder->getOrCreateArray(enumerations); + dbTy = ctx->d.builder->createEnumerationType( + ctx->d.scope, + type->Symbol->name, + ctx->d.file, + expr->start.line, + type->Width, + type->Align, + elements, + dbTy + ); + + userdata->debugType = dbTy; + } + + return ty; +} + llvm::StructType *emitExprTypeStruct(Context *ctx, Expr *expr) { ASSERT(expr->kind == ExprKind_TypeStruct); @@ -1153,22 +1281,25 @@ llvm::StructType *emitExprTypeStruct(Context *ctx, Expr *expr) { Type *fieldType = type->Struct.members[index].type; llvm::Type *ty = canonicalize(ctx, fieldType); - llvm::DIType *dty = debugCanonicalize(ctx, fieldType); + llvm::DIType *dty = NULL; + if (FlagDebug) + dty = debugCanonicalize(ctx, fieldType); + for (size_t j = 0; j < ArrayLen(item.names); j++) { if (FlagDebug) { - llvm::DIDerivedType *member = ctx->d.builder->createMemberType( - ctx->d.scope, - item.names[j], - ctx->d.file, - item.start.line, - fieldType->Width, - fieldType->Align, - type->Struct.members[index].offset, - llvm::DINode::DIFlags::FlagZero, - dty - ); + llvm::DIDerivedType *member = ctx->d.builder->createMemberType( + ctx->d.scope, + item.names[j], + ctx->d.file, + item.start.line, + fieldType->Width, + fieldType->Align, + type->Struct.members[index]->offset, + llvm::DINode::DIFlags::FlagZero, + dty + ); - debugMembers.push_back(member); + debugMembers.push_back(member); } elementTypes.push_back(ty); @@ -1178,24 +1309,10 @@ llvm::StructType *emitExprTypeStruct(Context *ctx, Expr *expr) { llvm::StructType *ty; if (type->Symbol->backendUserdata) { - ty = (llvm::StructType *) type->Symbol->backendUserdata; + ty = ((BackendStructUserdata *) type->Symbol->backendUserdata)->type; } else { ty = llvm::StructType::create(ctx->m->getContext(), elementTypes); } - llvm::DICompositeType *debugType; - if (FlagDebug) { - debugType = ctx->d.builder->createStructType( - ctx->d.scope, - type->Symbol->name, - ctx->d.file, - type->Symbol->decl->start.line, - type->Width, - type->Align, - llvm::DINode::DIFlags::FlagZero, - NULL, // DerivedFrom - ctx->d.builder->getOrCreateArray(debugMembers) - ); - } if (type->Symbol) { ty->setName(type->Symbol->name); @@ -1205,11 +1322,23 @@ llvm::StructType *emitExprTypeStruct(Context *ctx, Expr *expr) { userdata = (BackendStructUserdata *) type->Symbol->backendUserdata; ASSERT_MSG(!userdata->debugType, "debugType is only set here, which means this run twice"); } else { - userdata = (BackendStructUserdata *) ArenaAlloc(&ctx->arena, sizeof(BackendStructUserdata)); + userdata = (BackendStructUserdata *) ArenaAlloc(&ctx->arena, sizeof(*userdata)); userdata->type = ty; type->Symbol->backendUserdata = userdata; } + if (FlagDebug) { + llvm::DICompositeType *debugType = ctx->d.builder->createStructType( + ctx->d.scope, + type->Symbol->name, + ctx->d.file, + type->Symbol->decl->start.line, + type->Width, + type->Align, + llvm::DINode::DIFlags::FlagZero, + NULL, // DerivedFrom + ctx->d.builder->getOrCreateArray(debugMembers) + ); userdata->debugType = debugType; } } @@ -1261,6 +1390,11 @@ void emitDeclConstant(Context *ctx, Decl *decl) { break; } + case ExprKind_TypeEnum: { + emitExprTypeEnum(ctx, decl->Constant.values[0]); + break; + } + default: { llvm::Type *type = canonicalize(ctx, symbol->type); @@ -1576,7 +1710,7 @@ void emitStmtFor(Context *ctx, Stmt *stmt) { ctx->b.CreateBr(cond); ctx->b.SetInsertPoint(cond); - llvm::Value *condVal = emitExpr(ctx, fore.cond); + llvm::Value *condVal = emitExpr(ctx, fore.cond, canonicalize(ctx, BoolType)); condVal = ctx->b.CreateTruncOrBitCast(condVal, llvm::IntegerType::get(ctx->m->getContext(), 1)); ctx->b.CreateCondBr(condVal, body, post); } else { @@ -1816,11 +1950,10 @@ void setupTargetInfo() { static b32 init = false; if (init) return; - // TODO: Initialize only for the targets we are outputting. LLVMInitializeX86Target(); LLVMInitializeX86TargetMC(); - LLVMInitializeX86AsmParser(); LLVMInitializeX86TargetInfo(); + LLVMInitializeX86AsmParser(); LLVMInitializeX86AsmPrinter(); init = true; @@ -2026,4 +2159,31 @@ void printIR(llvm::Type *value) { puts("\n"); } +// MARK: Hacks for LLVM and libcurses. Sadly, LLVM uses libncurses to try to see +// if the terminal supports color. We're going to stub all of the ncurses functions +// and tell LLVM that color isn't supported +extern "C" { + int setupterm(char *term, int filedes, int *errret) { + return 1; // Tell LLVM that we've failed and it'll disable colors + } + + struct term *set_curterm(struct term *termp) { + ASSERT(false); + return NULL; + } + + int del_curterm(struct term *termp){ + ASSERT(false); + return 1; + } + + int tigetnum(char *capname){ + ASSERT(false); + return 0; + } +} + + + + #pragma clang diagnostic pop diff --git a/src/main.c b/src/main.c index 7b2f86f..524dc21 100644 --- a/src/main.c +++ b/src/main.c @@ -16,7 +16,6 @@ #define VERSION "0.0.0 (prerelease)" - void outputVersionAndBuildInfo() { printf("%s\n\n", VERSION); diff --git a/src/types.c b/src/types.c index 817fc75..ae1d59c 100644 --- a/src/types.c +++ b/src/types.c @@ -115,7 +115,6 @@ b32 TypesIdentical(Type *type, Type *target) { } StructFieldLookupResult StructFieldLookup(Type_Struct type, const char *name) { - u32 index = 0; TypeField *field = NULL; for (u32 i = 0; i < type.numMembers; i++) { @@ -129,6 +128,22 @@ StructFieldLookupResult StructFieldLookup(Type_Struct type, const char *name) { return (StructFieldLookupResult){index, field}; } +EnumFieldLookupResult EnumFieldLookup(Type_Enum type, const char *name) { + u32 index = 0; + EnumField *field = NULL; + For(type.cases) { + EnumField *it = &type.cases[i]; + if (it->name == name) { + index = (u32) i; + field = it; + break; + } + } + + return (EnumFieldLookupResult){index, field}; +} + + #if TEST void test_SmallestIntTypeForValue() { INIT_COMPILER(); @@ -271,6 +286,16 @@ Type *NewTypeFunction(TypeFlag flags, DynamicArray(Type *) params, DynamicArray( return type; } +Type *NewTypeEnum(TypeFlag flags, Type *backingType, DynamicArray(EnumField) items) { + Type *type = AllocType(TypeKind_Enum); + type->Width = backingType->Width; + type->Align = backingType->Align; + type->Flags = flags; + type->Enum.cases = items; + type->Enum.backingType = backingType; + return type; +} + Type *NewTypeTupleFromFunctionResults(TypeFlag flags, Type_Function function) { Type *type = AllocType(TypeKind_Tuple); type->Flags = flags; @@ -441,7 +466,17 @@ const char *DescribeType(Type *type) { return type->Symbol->name; } - return DescribeTypeKind(type->kind); + switch (type->kind) { + case TypeKind_Pointer: { + String desc = NULL; + const char *pointeeType = DescribeType(type->Pointer.pointeeType); + ArrayPrintf(desc, "*%s", pointeeType); + return (char *)desc; + } + + default: + return DescribeTypeKind(type->kind); + } } #if TEST diff --git a/src/types.h b/src/types.h index 64d70f2..6535ced 100644 --- a/src/types.h +++ b/src/types.h @@ -106,6 +106,12 @@ struct TypeField { u32 offset; }; +typedef struct EnumField EnumField; +struct EnumField { + const char *name; + u64 val; +}; + struct Type_Struct { TypeFlag Flags; TypeField *members; @@ -122,6 +128,8 @@ struct Type_Union { struct Type_Enum { TypeFlag Flags; + Type *backingType; + DynamicArray(EnumField) cases; }; struct Type_Tuple { @@ -150,6 +158,7 @@ struct Type { Type_Pointer Pointer; Type_Array Array; Type_Slice Slice; + Type_Enum Enum; Type_Struct Struct; Type_Union Union; Type_Function Function; @@ -163,6 +172,12 @@ struct StructFieldLookupResult { TypeField *field; }; +typedef struct EnumFieldLookupResult EnumFieldLookupResult; +struct EnumFieldLookupResult { + u32 index; + EnumField *field; +}; + #ifdef __cplusplus extern "C" { #endif diff --git a/tools/xcconfigs/LLVM.xcconfig b/tools/xcconfigs/LLVM.xcconfig index e69de29..ffca5e9 100644 --- a/tools/xcconfigs/LLVM.xcconfig +++ b/tools/xcconfigs/LLVM.xcconfig @@ -0,0 +1,4 @@ + +LLVM_CXXFLAGS = -I/usr/local/Cellar/llvm/6.0.0/include -stdlib=libc++ -fPIC -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -std=c++11 -Wall -W -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wcovered-switch-default -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wstring-conversion -DNDEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS + +LLVM_CXXLDFLAGS = -L/usr/local/Cellar/llvm/6.0.0/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVMLTO -lLLVMPasses -lLLVMObjCARCOpts -lLLVMMIRParser -lLLVMSymbolize -lLLVMDebugInfoPDB -lLLVMDebugInfoDWARF -lLLVMCoverage -lLLVMTableGen -lLLVMDlltoolDriver -lLLVMOrcJIT -lLLVMXCoreDisassembler -lLLVMXCoreCodeGen -lLLVMXCoreDesc -lLLVMXCoreInfo -lLLVMXCoreAsmPrinter -lLLVMSystemZDisassembler -lLLVMSystemZCodeGen -lLLVMSystemZAsmParser -lLLVMSystemZDesc -lLLVMSystemZInfo -lLLVMSystemZAsmPrinter -lLLVMSparcDisassembler -lLLVMSparcCodeGen -lLLVMSparcAsmParser -lLLVMSparcDesc -lLLVMSparcInfo -lLLVMSparcAsmPrinter -lLLVMPowerPCDisassembler -lLLVMPowerPCCodeGen -lLLVMPowerPCAsmParser -lLLVMPowerPCDesc -lLLVMPowerPCInfo -lLLVMPowerPCAsmPrinter -lLLVMNVPTXCodeGen -lLLVMNVPTXDesc -lLLVMNVPTXInfo -lLLVMNVPTXAsmPrinter -lLLVMMSP430CodeGen -lLLVMMSP430Desc -lLLVMMSP430Info -lLLVMMSP430AsmPrinter -lLLVMMipsDisassembler -lLLVMMipsCodeGen -lLLVMMipsAsmParser -lLLVMMipsDesc -lLLVMMipsInfo -lLLVMMipsAsmPrinter -lLLVMLanaiDisassembler -lLLVMLanaiCodeGen -lLLVMLanaiAsmParser -lLLVMLanaiDesc -lLLVMLanaiAsmPrinter -lLLVMLanaiInfo -lLLVMHexagonDisassembler -lLLVMHexagonCodeGen -lLLVMHexagonAsmParser -lLLVMHexagonDesc -lLLVMHexagonInfo -lLLVMBPFDisassembler -lLLVMBPFCodeGen -lLLVMBPFAsmParser -lLLVMBPFDesc -lLLVMBPFInfo -lLLVMBPFAsmPrinter -lLLVMARMDisassembler -lLLVMARMCodeGen -lLLVMARMAsmParser -lLLVMARMDesc -lLLVMARMInfo -lLLVMARMAsmPrinter -lLLVMARMUtils -lLLVMAMDGPUDisassembler -lLLVMAMDGPUCodeGen -lLLVMAMDGPUAsmParser -lLLVMAMDGPUDesc -lLLVMAMDGPUInfo -lLLVMAMDGPUAsmPrinter -lLLVMAMDGPUUtils -lLLVMAArch64Disassembler -lLLVMAArch64CodeGen -lLLVMAArch64AsmParser -lLLVMAArch64Desc -lLLVMAArch64Info -lLLVMAArch64AsmPrinter -lLLVMAArch64Utils -lLLVMObjectYAML -lLLVMLibDriver -lLLVMOption -lLLVMWindowsManifest -lLLVMFuzzMutate -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMGlobalISel -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMDebugInfoCodeView -lLLVMDebugInfoMSF -lLLVMX86Desc -lLLVMMCDisassembler -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMLineEditor -lLLVMInterpreter -lLLVMExecutionEngine -lLLVMRuntimeDyld -lLLVMCodeGen -lLLVMTarget -lLLVMCoroutines -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMScalarOpts -lLLVMLinker -lLLVMIRReader -lLLVMAsmParser -lLLVMInstCombine -lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis -lLLVMProfileData -lLLVMObject -lLLVMMCParser -lLLVMMC -lLLVMBitReader -lLLVMCore -lLLVMBinaryFormat -lLLVMSupport -lLLVMDemangle -lz -lcurses -lm