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 }