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
93
94
95
|
#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;
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::String: {
Value *StrVal = emitStringNullGuard(Val);
Fmt = AppendNewline
? PrintfStringFormatStr
: Builder->CreateGlobalString("%s", "fmt_str_inline", 0, TheModule.get());
Args.push_back(Fmt);
Args.push_back(StrVal);
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);
}
|