aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/OutputGen.cc
blob: c1ea4b6bdbedb6aa13269d90c6e7cbd5889050fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

#include "cps/CodeGen.h"

using namespace llvm;
using namespace cps;

Value *CodeGen::emitStringNullGuard(Value *StrVal) {
    if (!StrVal || !StrVal->getType()->isPointerTy()) return StrVal;
    Value *IsNull = Builder->CreateICmpEQ(StrVal,
                                          ConstantPointerNull::get(cast<PointerType>(StrVal->getType())),
                                          "str_is_null");
    return Builder->CreateSelect(IsNull, EmptyStringStr, StrVal, "safe_str");
}

void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewline) {
    if (!Val || !Info) return;
    if (Info->isString()) {
        Value *Text = emitStringCString(Val);
        if (Text) Builder->CreateCall(PrintfFunc, {
            AppendNewline ? PrintfStringFormatStr
                : Builder->CreateGlobalString("%s", "fmt_str_inline", 0, TheModule.get()), Text});
        return;
    }

    std::vector<Value*> Args;
    Value *Fmt = nullptr;

    // Exhaustive over TypeKind (no default): the compiler warns when a new
    // kind is added without deciding its OUTPUT story.
    switch (Info->Kind) {
    case TypeKind::Real:
        Fmt = AppendNewline
            ? PrintfFloatFormatStr
            : Builder->CreateGlobalString("%f", "fmt_flt_inline", 0, TheModule.get());
        Args.push_back(Fmt);
        Args.push_back(Val);
        break;

    case TypeKind::Boolean: {
        Value *BoolVal = coerceValueToType(Val, resolveType("BOOLEAN"));
        Fmt = AppendNewline
            ? PrintfStringFormatStr
            : Builder->CreateGlobalString("%s", "fmt_str_inline", 0, TheModule.get());
        Args.push_back(Fmt);
        Args.push_back(Builder->CreateSelect(BoolVal, TrueStr, FalseStr));
        break;
    }

    case TypeKind::Char: {
        Value *CharVal = coerceValueToType(Val, resolveType("CHAR"));
        Value *Promoted = Builder->CreateZExt(CharVal, Type::getInt32Ty(*TheContext), "char_for_printf");
        Fmt = AppendNewline
            ? PrintfCharFormatStr
            : Builder->CreateGlobalString("%c", "fmt_chr_inline", 0, TheModule.get());
        Args.push_back(Fmt);
        Args.push_back(Promoted);
        break;
    }

    case TypeKind::Integer:
    case TypeKind::Enum: { // an enum prints its ordinal (user decision)
        Value *IntVal = Info->isEnum() ? Val : coerceValueToType(Val, resolveType("INTEGER"));
        Fmt = AppendNewline
            ? PrintfFormatStr
            : Builder->CreateGlobalString("%lld", "fmt_int_inline", 0, TheModule.get());
        Args.push_back(Fmt);
        Args.push_back(IntVal);
        break;
    }

    case TypeKind::Record:
        reportError("Cannot OUTPUT a value of record type %s; output its fields individually",
                    Info->Name.c_str());
        return;

    case TypeKind::Pointer:
        reportError("Cannot OUTPUT a value of pointer type %s", Info->Name.c_str());
        return;

    case TypeKind::CScalar:
        emitCOutput(Val, Info, AppendNewline);
        return;
    case TypeKind::CPointer:
        reportError("OUTPUT is not supported for type %s", Info->Name.c_str());
        return;

    case TypeKind::Void:
        reportError("Cannot OUTPUT a VOID value");
        return;
    }

    Builder->CreateCall(PrintfFunc, Args);
}