authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-12-12 19:47:37-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-12-12 19:47:37-07:00
log0f02e29a2b7a975407c7f3b4ed742f886e0c1add
tree30c8555a09b2f88b7f6b446b09a5b45db693a2e1
parent5cb5f5dbf625f5995a2e34b96985dca181222cea

codegen and tests for modify operators. closes #16


3 files changed, 74 insertions(+), 45 deletions(-)

src/codegen.cpp+48-45
......@@ -324,30 +324,33 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
324324 zig_unreachable();
325325}
326326
327static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
327static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
328 LLVMValueRef val1, LLVMValueRef val2,
329 TypeTableEntry *op1_type, TypeTableEntry *op2_type,
330 AstNode *node)
331{
328332 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);
335333 assert(op1_type == op2_type);
336334
337335 switch (node->data.bin_op_expr.bin_op) {
338336 case BinOpTypeBinOr:
337 case BinOpTypeAssignBitOr:
339338 add_debug_source_node(g, node);
340339 return LLVMBuildOr(g->builder, val1, val2, "");
341340 case BinOpTypeBinXor:
341 case BinOpTypeAssignBitXor:
342342 add_debug_source_node(g, node);
343343 return LLVMBuildXor(g->builder, val1, val2, "");
344344 case BinOpTypeBinAnd:
345 case BinOpTypeAssignBitAnd:
345346 add_debug_source_node(g, node);
346347 return LLVMBuildAnd(g->builder, val1, val2, "");
347348 case BinOpTypeBitShiftLeft:
349 case BinOpTypeAssignBitShiftLeft:
348350 add_debug_source_node(g, node);
349351 return LLVMBuildShl(g->builder, val1, val2, "");
350352 case BinOpTypeBitShiftRight:
353 case BinOpTypeAssignBitShiftRight:
351354 add_debug_source_node(g, node);
352355 if (op1_type->id == TypeTableEntryIdInt) {
353356 return LLVMBuildAShr(g->builder, val1, val2, "");
......@@ -355,6 +358,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
355358 return LLVMBuildLShr(g->builder, val1, val2, "");
356359 }
357360 case BinOpTypeAdd:
361 case BinOpTypeAssignPlus:
358362 add_debug_source_node(g, node);
359363 if (op1_type->id == TypeTableEntryIdFloat) {
360364 return LLVMBuildFAdd(g->builder, val1, val2, "");
......@@ -362,6 +366,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
362366 return LLVMBuildNSWAdd(g->builder, val1, val2, "");
363367 }
364368 case BinOpTypeSub:
369 case BinOpTypeAssignMinus:
365370 add_debug_source_node(g, node);
366371 if (op1_type->id == TypeTableEntryIdFloat) {
367372 return LLVMBuildFSub(g->builder, val1, val2, "");
......@@ -369,6 +374,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
369374 return LLVMBuildNSWSub(g->builder, val1, val2, "");
370375 }
371376 case BinOpTypeMult:
377 case BinOpTypeAssignTimes:
372378 add_debug_source_node(g, node);
373379 if (op1_type->id == TypeTableEntryIdFloat) {
374380 return LLVMBuildFMul(g->builder, val1, val2, "");
......@@ -376,6 +382,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
376382 return LLVMBuildNSWMul(g->builder, val1, val2, "");
377383 }
378384 case BinOpTypeDiv:
385 case BinOpTypeAssignDiv:
379386 add_debug_source_node(g, node);
380387 if (op1_type->id == TypeTableEntryIdFloat) {
381388 return LLVMBuildFDiv(g->builder, val1, val2, "");
......@@ -388,6 +395,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
388395 }
389396 }
390397 case BinOpTypeMod:
398 case BinOpTypeAssignMod:
391399 add_debug_source_node(g, node);
392400 if (op1_type->id == TypeTableEntryIdFloat) {
393401 return LLVMBuildFRem(g->builder, val1, val2, "");
......@@ -409,22 +417,23 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
409417 case BinOpTypeCmpGreaterOrEq:
410418 case BinOpTypeInvalid:
411419 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:
422420 case BinOpTypeAssignBoolAnd:
423421 case BinOpTypeAssignBoolOr:
424422 zig_unreachable();
425423 }
426424 zig_unreachable();
427425}
426static 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}
428437
429438static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed) {
430439 switch (cmp_op) {
......@@ -555,11 +564,8 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
555564
556565 AstNode *lhs_node = node->data.bin_op_expr.op1;
557566
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;
563569 if (lhs_node->type == NodeTypeSymbol) {
564570 LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
565571 &lhs_node->data.symbol);
......@@ -567,33 +573,30 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
567573 // semantic checking ensures no variables are constant
568574 assert(!var->is_const);
569575
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;
574578 } 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);
594583 } else {
595584 zig_panic("bad assign target");
596585 }
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);
597600}
598601
599602static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
src/tokenizer.cpp+3
......@@ -402,6 +402,7 @@ void tokenize(Buf *buf, Tokenization *out) {
402402 t.cur_tok->id = TokenIdBitShiftRightEq;
403403 end_token(&t);
404404 t.state = TokenizeStateStart;
405 break;
405406 default:
406407 t.pos -= 1;
407408 end_token(&t);
......@@ -415,6 +416,7 @@ void tokenize(Buf *buf, Tokenization *out) {
415416 t.cur_tok->id = TokenIdCmpLessOrEq;
416417 end_token(&t);
417418 t.state = TokenizeStateStart;
419 break;
418420 case '<':
419421 t.cur_tok->id = TokenIdBitShiftLeft;
420422 t.state = TokenizeStateSawLessThanLessThan;
......@@ -432,6 +434,7 @@ void tokenize(Buf *buf, Tokenization *out) {
432434 t.cur_tok->id = TokenIdBitShiftLeftEq;
433435 end_token(&t);
434436 t.state = TokenizeStateStart;
437 break;
435438 default:
436439 t.pos -= 1;
437440 end_token(&t);
test/run_tests.cpp+23
......@@ -454,6 +454,29 @@ export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
454454}
455455 )SOURCE", "OK 1\nOK 2\nOK 3\nOK 4\n");
456456
457 add_simple_case("modify operators", R"SOURCE(
458use "std.zig";
459
460export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
461 let mut i : i32 = 0;
462 i += 5; if i != 5 { print_str("BAD +=\n" as string); }
463 i -= 2; if i != 3 { print_str("BAD -=\n" as string); }
464 i *= 20; if i != 60 { print_str("BAD *=\n" as string); }
465 i /= 3; if i != 20 { print_str("BAD /=\n" as string); }
466 i %= 11; if i != 9 { print_str("BAD %=\n" as string); }
467 i <<= 1; if i != 18 { print_str("BAD <<=\n" as string); }
468 i >>= 2; if i != 4 { print_str("BAD >>=\n" as string); }
469 i = 6;
470 i &= 5; if i != 4 { print_str("BAD &=\n" as string); }
471 i ^= 6; if i != 2 { print_str("BAD ^=\n" as string); }
472 i = 6;
473 i |= 3; if i != 7 { print_str("BAD |=\n" as string); }
474
475 print_str("OK\n" as string);
476 return 0;
477}
478 )SOURCE", "OK\n");
479
457480}
458481
459482static void add_compile_failure_test_cases(void) {