| ... | ... | @@ -324,30 +324,33 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 324 | 324 | zig_unreachable(); |
| 325 | 325 | } |
| 326 | 326 | |
| 327 | | static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 327 | static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, |
| 328 | LLVMValueRef val1, LLVMValueRef val2, |
| 329 | TypeTableEntry *op1_type, TypeTableEntry *op2_type, |
| 330 | AstNode *node) |
| 331 | { |
| 328 | 332 | assert(node->type == NodeTypeBinOpExpr); |
| 329 | | |
| 330 | | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); |
| 331 | | LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); |
| 332 | | |
| 333 | | TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1); |
| 334 | | TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2); |
| 335 | 333 | assert(op1_type == op2_type); |
| 336 | 334 | |
| 337 | 335 | switch (node->data.bin_op_expr.bin_op) { |
| 338 | 336 | case BinOpTypeBinOr: |
| 337 | case BinOpTypeAssignBitOr: |
| 339 | 338 | add_debug_source_node(g, node); |
| 340 | 339 | return LLVMBuildOr(g->builder, val1, val2, ""); |
| 341 | 340 | case BinOpTypeBinXor: |
| 341 | case BinOpTypeAssignBitXor: |
| 342 | 342 | add_debug_source_node(g, node); |
| 343 | 343 | return LLVMBuildXor(g->builder, val1, val2, ""); |
| 344 | 344 | case BinOpTypeBinAnd: |
| 345 | case BinOpTypeAssignBitAnd: |
| 345 | 346 | add_debug_source_node(g, node); |
| 346 | 347 | return LLVMBuildAnd(g->builder, val1, val2, ""); |
| 347 | 348 | case BinOpTypeBitShiftLeft: |
| 349 | case BinOpTypeAssignBitShiftLeft: |
| 348 | 350 | add_debug_source_node(g, node); |
| 349 | 351 | return LLVMBuildShl(g->builder, val1, val2, ""); |
| 350 | 352 | case BinOpTypeBitShiftRight: |
| 353 | case BinOpTypeAssignBitShiftRight: |
| 351 | 354 | add_debug_source_node(g, node); |
| 352 | 355 | if (op1_type->id == TypeTableEntryIdInt) { |
| 353 | 356 | return LLVMBuildAShr(g->builder, val1, val2, ""); |
| ... | ... | @@ -355,6 +358,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 355 | 358 | return LLVMBuildLShr(g->builder, val1, val2, ""); |
| 356 | 359 | } |
| 357 | 360 | case BinOpTypeAdd: |
| 361 | case BinOpTypeAssignPlus: |
| 358 | 362 | add_debug_source_node(g, node); |
| 359 | 363 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 360 | 364 | return LLVMBuildFAdd(g->builder, val1, val2, ""); |
| ... | ... | @@ -362,6 +366,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 362 | 366 | return LLVMBuildNSWAdd(g->builder, val1, val2, ""); |
| 363 | 367 | } |
| 364 | 368 | case BinOpTypeSub: |
| 369 | case BinOpTypeAssignMinus: |
| 365 | 370 | add_debug_source_node(g, node); |
| 366 | 371 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 367 | 372 | return LLVMBuildFSub(g->builder, val1, val2, ""); |
| ... | ... | @@ -369,6 +374,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 369 | 374 | return LLVMBuildNSWSub(g->builder, val1, val2, ""); |
| 370 | 375 | } |
| 371 | 376 | case BinOpTypeMult: |
| 377 | case BinOpTypeAssignTimes: |
| 372 | 378 | add_debug_source_node(g, node); |
| 373 | 379 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 374 | 380 | return LLVMBuildFMul(g->builder, val1, val2, ""); |
| ... | ... | @@ -376,6 +382,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 376 | 382 | return LLVMBuildNSWMul(g->builder, val1, val2, ""); |
| 377 | 383 | } |
| 378 | 384 | case BinOpTypeDiv: |
| 385 | case BinOpTypeAssignDiv: |
| 379 | 386 | add_debug_source_node(g, node); |
| 380 | 387 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 381 | 388 | return LLVMBuildFDiv(g->builder, val1, val2, ""); |
| ... | ... | @@ -388,6 +395,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 388 | 395 | } |
| 389 | 396 | } |
| 390 | 397 | case BinOpTypeMod: |
| 398 | case BinOpTypeAssignMod: |
| 391 | 399 | add_debug_source_node(g, node); |
| 392 | 400 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 393 | 401 | return LLVMBuildFRem(g->builder, val1, val2, ""); |
| ... | ... | @@ -409,22 +417,23 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 409 | 417 | case BinOpTypeCmpGreaterOrEq: |
| 410 | 418 | case BinOpTypeInvalid: |
| 411 | 419 | case BinOpTypeAssign: |
| 412 | | case BinOpTypeAssignTimes: |
| 413 | | case BinOpTypeAssignDiv: |
| 414 | | case BinOpTypeAssignMod: |
| 415 | | case BinOpTypeAssignPlus: |
| 416 | | case BinOpTypeAssignMinus: |
| 417 | | case BinOpTypeAssignBitShiftLeft: |
| 418 | | case BinOpTypeAssignBitShiftRight: |
| 419 | | case BinOpTypeAssignBitAnd: |
| 420 | | case BinOpTypeAssignBitXor: |
| 421 | | case BinOpTypeAssignBitOr: |
| 422 | 420 | case BinOpTypeAssignBoolAnd: |
| 423 | 421 | case BinOpTypeAssignBoolOr: |
| 424 | 422 | zig_unreachable(); |
| 425 | 423 | } |
| 426 | 424 | zig_unreachable(); |
| 427 | 425 | } |
| 426 | static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 427 | assert(node->type == NodeTypeBinOpExpr); |
| 428 | |
| 429 | LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); |
| 430 | LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); |
| 431 | |
| 432 | TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1); |
| 433 | TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2); |
| 434 | return gen_arithmetic_bin_op(g, val1, val2, op1_type, op2_type, node); |
| 435 | |
| 436 | } |
| 428 | 437 | |
| 429 | 438 | static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed) { |
| 430 | 439 | switch (cmp_op) { |
| ... | ... | @@ -555,11 +564,8 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { |
| 555 | 564 | |
| 556 | 565 | AstNode *lhs_node = node->data.bin_op_expr.op1; |
| 557 | 566 | |
| 558 | | bool is_read_first = node->data.bin_op_expr.bin_op != BinOpTypeAssign; |
| 559 | | if (is_read_first) { |
| 560 | | zig_panic("TODO: implement modify assignment ops"); |
| 561 | | } |
| 562 | | |
| 567 | LLVMValueRef target_ref; |
| 568 | TypeTableEntry *op1_type; |
| 563 | 569 | if (lhs_node->type == NodeTypeSymbol) { |
| 564 | 570 | LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context, |
| 565 | 571 | &lhs_node->data.symbol); |
| ... | ... | @@ -567,33 +573,30 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { |
| 567 | 573 | // semantic checking ensures no variables are constant |
| 568 | 574 | assert(!var->is_const); |
| 569 | 575 | |
| 570 | | LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2); |
| 571 | | |
| 572 | | add_debug_source_node(g, node); |
| 573 | | return LLVMBuildStore(g->builder, value, var->value_ref); |
| 576 | op1_type = var->type; |
| 577 | target_ref = var->value_ref; |
| 574 | 578 | } else if (lhs_node->type == NodeTypeArrayAccessExpr) { |
| 575 | | LLVMValueRef ptr = gen_array_ptr(g, lhs_node); |
| 576 | | LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2); |
| 577 | | add_debug_source_node(g, node); |
| 578 | | return LLVMBuildStore(g->builder, value, ptr); |
| 579 | | } else if (lhs_node->type == NodeTypeFieldAccessExpr) { |
| 580 | | /* |
| 581 | | LLVMValueRef ptr = gen_field_ptr(g, lhs_node); |
| 582 | | LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2); |
| 583 | | add_debug_source_node(g, node); |
| 584 | | return LLVMBuildStore(g->builder, value, ptr); |
| 585 | | */ |
| 586 | | LLVMValueRef struct_val = gen_expr(g, lhs_node->data.field_access_expr.struct_expr); |
| 587 | | assert(struct_val); |
| 588 | | FieldAccessNode *codegen_field_access = &lhs_node->codegen_node->data.field_access_node; |
| 589 | | assert(codegen_field_access->field_index >= 0); |
| 590 | | |
| 591 | | LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2); |
| 592 | | add_debug_source_node(g, node); |
| 593 | | return LLVMBuildInsertValue(g->builder, struct_val, value, codegen_field_access->field_index, ""); |
| 579 | TypeTableEntry *array_type = get_expr_type(lhs_node->data.array_access_expr.array_ref_expr); |
| 580 | assert(array_type->id == TypeTableEntryIdArray); |
| 581 | op1_type = array_type->data.array.child_type; |
| 582 | target_ref = gen_array_ptr(g, lhs_node); |
| 594 | 583 | } else { |
| 595 | 584 | zig_panic("bad assign target"); |
| 596 | 585 | } |
| 586 | LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2); |
| 587 | |
| 588 | if (node->data.bin_op_expr.bin_op == BinOpTypeAssign) { |
| 589 | // value is ready as is |
| 590 | } else { |
| 591 | add_debug_source_node(g, node->data.bin_op_expr.op1); |
| 592 | LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, ""); |
| 593 | |
| 594 | TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2); |
| 595 | value = gen_arithmetic_bin_op(g, left_value, value, op1_type, op2_type, node); |
| 596 | } |
| 597 | |
| 598 | add_debug_source_node(g, node); |
| 599 | return LLVMBuildStore(g->builder, value, target_ref); |
| 597 | 600 | } |
| 598 | 601 | |
| 599 | 602 | static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) { |