1 /// Copyright: Copyright (c) 2017-2019 Andrey Penechko.
2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
3 /// Authors: Andrey Penechko.
4 module vox.fe.ast.expr.type_conv;
5 
6 import vox.all;
7 
8 
9 @(AstType.expr_type_conv)
10 struct TypeConvExprNode {
11 	mixin ExpressionNodeData!(AstType.expr_type_conv);
12 	AstIndex expr;
13 	TypeConvResKind convKind() { return cast(TypeConvResKind)subType; }
14 }
15 
16 void print_type_conv(TypeConvExprNode* node, ref AstPrintState state)
17 {
18 	state.print("CAST to ", node.type.printer(state.context));
19 	print_ast(node.expr, state);
20 }
21 
22 void post_clone_type_conv(TypeConvExprNode* node, ref CloneState state)
23 {
24 	state.fixAstIndex(node.type);
25 	state.fixAstIndex(node.expr);
26 }
27 
28 void name_register_nested_type_conv(TypeConvExprNode* node, ref NameRegisterState state) {
29 	node.state = AstNodeState.name_register_nested;
30 	require_name_register(node.expr, state);
31 	node.state = AstNodeState.name_register_nested_done;
32 }
33 
34 void name_resolve_type_conv(TypeConvExprNode* node, ref NameResolveState state) {
35 	node.state = AstNodeState.name_resolve;
36 	require_name_resolve(node.type, state);
37 	require_name_resolve(node.expr, state);
38 	node.state = AstNodeState.name_resolve_done;
39 }
40 
41 // Checks cast() parsed from code
42 // Casts inserted by the compiler skip this step
43 void type_check_type_conv(TypeConvExprNode* node, ref TypeCheckState state)
44 {
45 	CompilationContext* c = state.context;
46 	node.state = AstNodeState.type_check;
47 	require_type_check(node.expr, state);
48 	TypeConvResKind kind = checkTypeConversion(node.expr.get_expr_type(c), node.type, node.expr, c);
49 	if (!kind.successful)
50 	{
51 		c.error(node.loc,
52 			"Cannot convert expression of type `%s` to `%s`",
53 			node.expr.get_expr_type(c).printer(c),
54 			node.type.printer(c));
55 	}
56 	node.subType = kind;
57 	// TODO: handling is different for user inserted casts and for implicit casts.
58 	// because implicit casts can be omitted/replaced with other nodes.
59 	node.state = AstNodeState.type_check_done;
60 }
61 
62 ExprValue ir_gen_expr_type_conv(ref IrGenState gen, IrIndex currentBlock, ref IrLabel nextStmt, TypeConvExprNode* t)
63 {
64 	CompilationContext* c = gen.context;
65 
66 	if (t.type == CommonAstNodes.type_alias || t.type == CommonAstNodes.type_type) {
67 		AstIndex aliasedNode = get_effective_node(t.expr, c);
68 		if (t.type == CommonAstNodes.type_type)
69 			if (!aliasedNode.isType(c))
70 				c.error(t.loc,
71 					"Cannot convert expression of type `%s` to `%s`",
72 					t.expr.get_expr_type(c).printer(c),
73 					t.type.printer(c));
74 		IrIndex result = c.constants.add(makeIrType(IrBasicType.i32), aliasedNode.storageIndex);
75 		gen.builder.addJumpToLabel(currentBlock, nextStmt);
76 		return ExprValue(result);
77 	}
78 
79 	IrLabel afterExpr = IrLabel(currentBlock);
80 	ExprValue lval = ir_gen_expr(gen, t.expr, currentBlock, afterExpr);
81 	currentBlock = afterExpr.blockIndex;
82 	IrIndex rval = lval.rvalue(gen, t.loc, currentBlock);
83 
84 	ExpressionNode* childExpr = t.expr.get_expr(c);
85 	TypeNode* sourceType = childExpr.type.get_type(c);
86 	TypeNode* targetType = t.type.get_type(c);
87 
88 	// fold the alias in the form of enum type
89 	if (sourceType.astType == AstType.decl_enum) {
90 		sourceType = sourceType.as_enum.memberType.get_type(c);
91 	}
92 	if (targetType.astType == AstType.decl_enum) {
93 		targetType = targetType.as_enum.memberType.get_type(c);
94 	}
95 
96 	IrIndex typeFrom = sourceType.gen_ir_type(c);
97 	IrIndex typeTo = targetType.gen_ir_type(c);
98 	uint typeSizeFrom = c.types.typeSize(typeFrom);
99 	uint typeSizeTo = c.types.typeSize(typeTo);
100 	//writefln("cast %s %s -> %s", t.convKind, IrTypeDump(typeFrom, *c), IrTypeDump(typeTo, *c));
101 
102 	IrIndex result;
103 
104 	if (rval.isSimpleConstant) {
105 		//writefln("%s", FmtSrcLoc(t.loc, c));
106 		result = eval_type_conv(t, rval, c);
107 	}
108 	else final switch (t.convKind) with(TypeConvResKind) {
109 		case fail: c.internal_error(t.loc, "IR gen of failed cast");
110 		case no_e, no_i: result = rval; break;
111 		case ii_e, ii_i, override_expr_type_e, override_expr_type_i:
112 			if (targetType.isBool) {
113 				ExtraInstrArgs extra = { type : typeTo, cond : IrUnaryCondition.not_zero };
114 				result = gen.builder.emitInstr!(IrOpcode.set_unary_cond)(currentBlock, extra, rval).result;
115 			} else {
116 				ExtraInstrArgs extra = { type : typeTo, argSize : sizeToIrArgSize(typeSizeTo, c) };
117 				if (typeSizeFrom == typeSizeTo) {
118 					// bitcast
119 					// needed in case of ptr conversion. Later we may need to look into pointed type
120 					result = gen.builder.emitInstr!(IrOpcode.conv)(currentBlock, extra, rval).result;
121 				} else if (typeSizeTo < typeSizeFrom) {
122 					// trunc
123 					result = gen.builder.emitInstr!(IrOpcode.trunc)(currentBlock, extra, rval).result;
124 				} else {
125 					// sext/zext
126 					if (sourceType.isSigned && targetType.isSigned)
127 						result = gen.builder.emitInstr!(IrOpcode.sext)(currentBlock, extra, rval).result;
128 					else
129 						result = gen.builder.emitInstr!(IrOpcode.zext)(currentBlock, extra, rval).result;
130 				}
131 			}
132 			break;
133 		case if_e, if_i:
134 			ExtraInstrArgs extra = { type : typeTo, argSize : sizeToIrArgSize(typeSizeTo, c) };
135 			assert(sourceType.as_basic);
136 			if (sourceType.as_basic.isSigned)
137 				result = gen.builder.emitInstr!(IrOpcode.sitofp)(currentBlock, extra, rval).result;
138 			else
139 				result = gen.builder.emitInstr!(IrOpcode.uitofp)(currentBlock, extra, rval).result;
140 			break;
141 
142 		case ff_e, ff_i:
143 			ExtraInstrArgs extra = { type : typeTo, argSize : sizeToIrArgSize(typeSizeTo, c) };
144 			if (typeSizeFrom == typeSizeTo)
145 				result = rval;
146 			else if (typeSizeTo < typeSizeFrom)
147 				result = gen.builder.emitInstr!(IrOpcode.fptrunc)(currentBlock, extra, rval).result;
148 			else
149 				result = gen.builder.emitInstr!(IrOpcode.fpext)(currentBlock, extra, rval).result;
150 			break;
151 
152 		case fi_e, fi_i:
153 			ExtraInstrArgs extra = { type : typeTo, argSize : sizeToIrArgSize(typeSizeTo, c) };
154 			assert(sourceType.as_basic);
155 			if (targetType.as_basic.isSigned)
156 				result = gen.builder.emitInstr!(IrOpcode.fptosi)(currentBlock, extra, rval).result;
157 			else
158 				result = gen.builder.emitInstr!(IrOpcode.fptoui)(currentBlock, extra, rval).result;
159 			break;
160 
161 		case string_literal_to_u8_ptr:
162 			result = c.constants.getAggregateMember(rval, c.constants.add(makeIrType(IrBasicType.i32), 1), c);
163 			break;
164 		case array_literal_to_slice:
165 			assert(false, to!string(t.convKind));
166 	}
167 	gen.builder.addJumpToLabel(currentBlock, nextStmt);
168 	return ExprValue(result);
169 }
170 
171 IrIndex eval_type_conv(TypeConvExprNode* node, IrIndex rval, CompilationContext* c)
172 {
173 	c.assertf(rval.isSomeConstant, node.loc, "%s must be a constant", rval);
174 
175 	TypeNode* sourceType = node.expr.get_expr(c).type.get_type(c);
176 	if (sourceType.astType == AstType.decl_enum) {
177 		sourceType = sourceType.as_enum.memberType.get_type(c);
178 	}
179 	TypeNode* targetType = node.type.get_type(c);
180 	if (targetType.astType == AstType.decl_enum) {
181 		targetType = targetType.as_enum.memberType.get_type(c);
182 	}
183 	IrIndex typeFrom = sourceType.gen_ir_type(c);
184 	IrIndex typeTo = targetType.gen_ir_type(c);
185 	uint typeSizeTo = c.types.typeSize(typeTo);
186 
187 	final switch (node.convKind) with(TypeConvResKind) {
188 		case fail: c.internal_error(node.loc, "eval of failed cast");
189 		case no_e, no_i: return rval;
190 		case ii_e, ii_i, override_expr_type_e, override_expr_type_i:
191 			if (rval.isConstantZero) {
192 				return typeTo.zeroConstantOfType;
193 			}
194 			auto con = c.constants.get(rval);
195 			if (sourceType.isSigned && targetType.isSigned) {
196 				if (typeTo.isTypeBasic) {
197 					IrBasicType basicType = typeTo.basicType(c);
198 					switch(basicType) with(IrBasicType) {
199 						case i8:  return c.constants.add(typeTo, con.i8);
200 						case i16: return c.constants.add(typeTo, con.i16);
201 						case i32: return c.constants.add(typeTo, con.i32);
202 						case i64: return c.constants.add(typeTo, con.i64);
203 						default: c.internal_error("Invalid constant type %s", basicType);
204 					}
205 				}
206 			} else {
207 				ulong original = con.u64; // if ptr
208 				if (typeFrom.isTypeBasic) {
209 					IrBasicType basicType = typeFrom.basicType(c);
210 					switch(basicType) with(IrBasicType) {
211 						case i8:  original = con.u8;  break;
212 						case i16: original = con.u16; break;
213 						case i32: original = con.u32; break;
214 						case i64: original = con.u64; break;
215 						default: c.internal_error("Invalid constant type %s", basicType);
216 					}
217 				}
218 				if (typeTo.isTypeBasic) {
219 					IrBasicType basicType = typeTo.basicType(c);
220 					switch(basicType) with(IrBasicType) {
221 						case i8:  return c.constants.add(typeTo, original);
222 						case i16: return c.constants.add(typeTo, original);
223 						case i32: return c.constants.add(typeTo, original);
224 						case i64: return c.constants.add(typeTo, original);
225 						default: c.internal_error("Invalid constant type %s", basicType);
226 					}
227 				}
228 			}
229 			return c.constants.add(typeTo, con.i64); // ptr (unsigned)
230 
231 		case if_e, if_i:
232 			c.assertf(typeFrom.isTypeInteger, "from %s", typeFrom);
233 			c.assertf(typeTo.isTypeFloat, "from %s", typeTo);
234 			auto con = c.constants.get(rval);
235 			if (sourceType.as_basic.isSigned) {
236 				IrBasicType basicTypeFrom = typeFrom.basicType(c);
237 				long val;
238 				switch(basicTypeFrom) with(IrBasicType) {
239 					case i8:  val = con.i8;  break;
240 					case i16: val = con.i16; break;
241 					case i32: val = con.i32; break;
242 					case i64: val = con.i64; break;
243 					default: c.internal_error("Invalid constant type %s", basicTypeFrom);
244 				}
245 				IrBasicType basicTypeTo = typeTo.basicType(c);
246 				switch(basicTypeTo) {
247 					case IrBasicType.f32: return c.constants.add(cast(float)val);
248 					case IrBasicType.f64: return c.constants.add(cast(double)val);
249 					default: c.internal_error("Invalid target type %s", basicTypeTo);
250 				}
251 			} else {
252 				IrBasicType basicTypeFrom = typeFrom.basicType(c);
253 				ulong val;
254 				switch(basicTypeFrom) with(IrBasicType) {
255 					case i8:  val = con.u8;  break;
256 					case i16: val = con.u16; break;
257 					case i32: val = con.u32; break;
258 					case i64: val = con.u64; break;
259 					default: c.internal_error("Invalid constant type %s", basicTypeFrom);
260 				}
261 				IrBasicType basicTypeTo = typeTo.basicType(c);
262 				switch(basicTypeTo) {
263 					case IrBasicType.f32: return c.constants.add(cast(float)val);
264 					case IrBasicType.f64: return c.constants.add(cast(double)val);
265 					default: c.internal_error("Invalid target type %s", basicTypeTo);
266 				}
267 			}
268 
269 		case ff_e, ff_i:
270 			c.assertf(typeFrom.isTypeFloat, "from %s", typeFrom);
271 			c.assertf(typeTo.isTypeFloat, "from %s", typeTo);
272 			switch(typeFrom.basicType(c)) {
273 				case IrBasicType.f32:
274 					c.assertf(typeTo.basicType(c) == IrBasicType.f64, "from f32 to %s", typeTo);
275 					double f64 = cast(double)c.constants.get(rval).f32;
276 					return c.constants.add(f64);
277 				case IrBasicType.f64:
278 					c.assertf(typeTo.basicType(c) == IrBasicType.f32, "from f64 to %s", typeTo);
279 					float f32 = cast(float)c.constants.get(rval).f64;
280 					return c.constants.add(f32);
281 				default: c.unreachable;
282 			}
283 
284 		case fi_e, fi_i:
285 			c.assertf(typeFrom.isTypeFloat, "from %s", typeFrom);
286 			c.assertf(typeTo.isTypeInteger, "from %s", typeTo);
287 			auto con = c.constants.get(rval);
288 			IrBasicType basicTypeFrom = typeFrom.basicType(c);
289 			double val;
290 			switch(basicTypeFrom) {
291 				case IrBasicType.f32: val = con.f32; break;
292 				case IrBasicType.f64: val = con.f64; break;
293 				default: c.internal_error("Invalid target type %s", basicTypeFrom);
294 			}
295 			if (targetType.as_basic.isSigned) {
296 				IrBasicType basicTypeTo = typeTo.basicType(c);
297 				switch(basicTypeTo) with(IrBasicType) {
298 					case i8:  return c.constants.add(typeTo, cast(byte)val);
299 					case i16: return c.constants.add(typeTo, cast(short)val);
300 					case i32: return c.constants.add(typeTo, cast(int)val);
301 					case i64: return c.constants.add(typeTo, cast(long)val);
302 					default: c.internal_error("Invalid constant type %s", basicTypeTo);
303 				}
304 			} else {
305 				IrBasicType basicTypeTo = typeTo.basicType(c);
306 				switch(basicTypeTo) with(IrBasicType) {
307 					case i8:  return c.constants.add(typeTo, cast(ubyte)val);
308 					case i16: return c.constants.add(typeTo, cast(ushort)val);
309 					case i32: return c.constants.add(typeTo, cast(uint)val);
310 					case i64: return c.constants.add(typeTo, cast(ulong)val);
311 					default: c.internal_error("Invalid constant type %s", basicTypeTo);
312 				}
313 			}
314 
315 		case string_literal_to_u8_ptr:
316 			IrIndex ONE = c.constants.add(makeIrType(IrBasicType.i32), 1);
317 			return c.constants.getAggregateMember(rval, ONE, c);
318 
319 		case array_literal_to_slice:
320 			c.internal_error("TODO %s", node.convKind);
321 	}
322 }
323 
324 void ir_gen_branch_type_conv(ref IrGenState gen, IrIndex currentBlock, ref IrLabel trueExit, ref IrLabel falseExit, TypeConvExprNode* t)
325 {
326 	CompilationContext* c = gen.context;
327 	IrLabel afterExpr = IrLabel(currentBlock);
328 	ExprValue lval = ir_gen_expr(gen, t.expr, currentBlock, afterExpr);
329 	currentBlock = afterExpr.blockIndex;
330 	IrIndex rval = lval.rvalue(gen, t.loc, currentBlock);
331 
332 	ExpressionNode* childExpr = t.expr.get_expr(c);
333 	IrIndex from = childExpr.type.gen_ir_type(c);
334 
335 	if (rval.isSimpleConstant ||
336 		from == makeIrType(IrBasicType.i8) ||
337 		from == makeIrType(IrBasicType.i16) ||
338 		from == makeIrType(IrBasicType.i32) ||
339 		from == makeIrType(IrBasicType.i64) ||
340 		from.isTypePointer)
341 	{
342 		addUnaryBranch(gen, rval, currentBlock, trueExit, falseExit);
343 		return;
344 	}
345 	else
346 	{
347 		//result = builder.emitInstr1(IrOpcode.o_conv, to, rval);
348 		c.internal_error(t.loc, "%s to %s", childExpr.type.printer(c), t.type.printer(c));
349 	}
350 }