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) {...@@ -324,30 +324,33 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
324 zig_unreachable();324 zig_unreachable();
325}325}
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{
328 assert(node->type == NodeTypeBinOpExpr);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 assert(op1_type == op2_type);333 assert(op1_type == op2_type);
336334
337 switch (node->data.bin_op_expr.bin_op) {335 switch (node->data.bin_op_expr.bin_op) {
338 case BinOpTypeBinOr:336 case BinOpTypeBinOr:
337 case BinOpTypeAssignBitOr:
339 add_debug_source_node(g, node);338 add_debug_source_node(g, node);
340 return LLVMBuildOr(g->builder, val1, val2, "");339 return LLVMBuildOr(g->builder, val1, val2, "");
341 case BinOpTypeBinXor:340 case BinOpTypeBinXor:
341 case BinOpTypeAssignBitXor:
342 add_debug_source_node(g, node);342 add_debug_source_node(g, node);
343 return LLVMBuildXor(g->builder, val1, val2, "");343 return LLVMBuildXor(g->builder, val1, val2, "");
344 case BinOpTypeBinAnd:344 case BinOpTypeBinAnd:
345 case BinOpTypeAssignBitAnd:
345 add_debug_source_node(g, node);346 add_debug_source_node(g, node);
346 return LLVMBuildAnd(g->builder, val1, val2, "");347 return LLVMBuildAnd(g->builder, val1, val2, "");
347 case BinOpTypeBitShiftLeft:348 case BinOpTypeBitShiftLeft:
349 case BinOpTypeAssignBitShiftLeft:
348 add_debug_source_node(g, node);350 add_debug_source_node(g, node);
349 return LLVMBuildShl(g->builder, val1, val2, "");351 return LLVMBuildShl(g->builder, val1, val2, "");
350 case BinOpTypeBitShiftRight:352 case BinOpTypeBitShiftRight:
353 case BinOpTypeAssignBitShiftRight:
351 add_debug_source_node(g, node);354 add_debug_source_node(g, node);
352 if (op1_type->id == TypeTableEntryIdInt) {355 if (op1_type->id == TypeTableEntryIdInt) {
353 return LLVMBuildAShr(g->builder, val1, val2, "");356 return LLVMBuildAShr(g->builder, val1, val2, "");
...@@ -355,6 +358,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -355,6 +358,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
355 return LLVMBuildLShr(g->builder, val1, val2, "");358 return LLVMBuildLShr(g->builder, val1, val2, "");
356 }359 }
357 case BinOpTypeAdd:360 case BinOpTypeAdd:
361 case BinOpTypeAssignPlus:
358 add_debug_source_node(g, node);362 add_debug_source_node(g, node);
359 if (op1_type->id == TypeTableEntryIdFloat) {363 if (op1_type->id == TypeTableEntryIdFloat) {
360 return LLVMBuildFAdd(g->builder, val1, val2, "");364 return LLVMBuildFAdd(g->builder, val1, val2, "");
...@@ -362,6 +366,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -362,6 +366,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
362 return LLVMBuildNSWAdd(g->builder, val1, val2, "");366 return LLVMBuildNSWAdd(g->builder, val1, val2, "");
363 }367 }
364 case BinOpTypeSub:368 case BinOpTypeSub:
369 case BinOpTypeAssignMinus:
365 add_debug_source_node(g, node);370 add_debug_source_node(g, node);
366 if (op1_type->id == TypeTableEntryIdFloat) {371 if (op1_type->id == TypeTableEntryIdFloat) {
367 return LLVMBuildFSub(g->builder, val1, val2, "");372 return LLVMBuildFSub(g->builder, val1, val2, "");
...@@ -369,6 +374,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -369,6 +374,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
369 return LLVMBuildNSWSub(g->builder, val1, val2, "");374 return LLVMBuildNSWSub(g->builder, val1, val2, "");
370 }375 }
371 case BinOpTypeMult:376 case BinOpTypeMult:
377 case BinOpTypeAssignTimes:
372 add_debug_source_node(g, node);378 add_debug_source_node(g, node);
373 if (op1_type->id == TypeTableEntryIdFloat) {379 if (op1_type->id == TypeTableEntryIdFloat) {
374 return LLVMBuildFMul(g->builder, val1, val2, "");380 return LLVMBuildFMul(g->builder, val1, val2, "");
...@@ -376,6 +382,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -376,6 +382,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
376 return LLVMBuildNSWMul(g->builder, val1, val2, "");382 return LLVMBuildNSWMul(g->builder, val1, val2, "");
377 }383 }
378 case BinOpTypeDiv:384 case BinOpTypeDiv:
385 case BinOpTypeAssignDiv:
379 add_debug_source_node(g, node);386 add_debug_source_node(g, node);
380 if (op1_type->id == TypeTableEntryIdFloat) {387 if (op1_type->id == TypeTableEntryIdFloat) {
381 return LLVMBuildFDiv(g->builder, val1, val2, "");388 return LLVMBuildFDiv(g->builder, val1, val2, "");
...@@ -388,6 +395,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -388,6 +395,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
388 }395 }
389 }396 }
390 case BinOpTypeMod:397 case BinOpTypeMod:
398 case BinOpTypeAssignMod:
391 add_debug_source_node(g, node);399 add_debug_source_node(g, node);
392 if (op1_type->id == TypeTableEntryIdFloat) {400 if (op1_type->id == TypeTableEntryIdFloat) {
393 return LLVMBuildFRem(g->builder, val1, val2, "");401 return LLVMBuildFRem(g->builder, val1, val2, "");
...@@ -409,22 +417,23 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -409,22 +417,23 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
409 case BinOpTypeCmpGreaterOrEq:417 case BinOpTypeCmpGreaterOrEq:
410 case BinOpTypeInvalid:418 case BinOpTypeInvalid:
411 case BinOpTypeAssign: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 case BinOpTypeAssignBoolAnd:420 case BinOpTypeAssignBoolAnd:
423 case BinOpTypeAssignBoolOr:421 case BinOpTypeAssignBoolOr:
424 zig_unreachable();422 zig_unreachable();
425 }423 }
426 zig_unreachable();424 zig_unreachable();
427}425}
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
429static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed) {438static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed) {
430 switch (cmp_op) {439 switch (cmp_op) {
...@@ -555,11 +564,8 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {...@@ -555,11 +564,8 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
555564
556 AstNode *lhs_node = node->data.bin_op_expr.op1;565 AstNode *lhs_node = node->data.bin_op_expr.op1;
557566
558 bool is_read_first = node->data.bin_op_expr.bin_op != BinOpTypeAssign;567 LLVMValueRef target_ref;
559 if (is_read_first) {568 TypeTableEntry *op1_type;
560 zig_panic("TODO: implement modify assignment ops");
561 }
562
563 if (lhs_node->type == NodeTypeSymbol) {569 if (lhs_node->type == NodeTypeSymbol) {
564 LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,570 LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
565 &lhs_node->data.symbol);571 &lhs_node->data.symbol);
...@@ -567,33 +573,30 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {...@@ -567,33 +573,30 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
567 // semantic checking ensures no variables are constant573 // semantic checking ensures no variables are constant
568 assert(!var->is_const);574 assert(!var->is_const);
569575
570 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);576 op1_type = var->type;
571577 target_ref = var->value_ref;
572 add_debug_source_node(g, node);
573 return LLVMBuildStore(g->builder, value, var->value_ref);
574 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {578 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
575 LLVMValueRef ptr = gen_array_ptr(g, lhs_node);579 TypeTableEntry *array_type = get_expr_type(lhs_node->data.array_access_expr.array_ref_expr);
576 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);580 assert(array_type->id == TypeTableEntryIdArray);
577 add_debug_source_node(g, node);581 op1_type = array_type->data.array.child_type;
578 return LLVMBuildStore(g->builder, value, ptr);582 target_ref = gen_array_ptr(g, lhs_node);
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, "");
594 } else {583 } else {
595 zig_panic("bad assign target");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}
598601
599static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {602static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
src/tokenizer.cpp+3
...@@ -402,6 +402,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -402,6 +402,7 @@ void tokenize(Buf *buf, Tokenization *out) {
402 t.cur_tok->id = TokenIdBitShiftRightEq;402 t.cur_tok->id = TokenIdBitShiftRightEq;
403 end_token(&t);403 end_token(&t);
404 t.state = TokenizeStateStart;404 t.state = TokenizeStateStart;
405 break;
405 default:406 default:
406 t.pos -= 1;407 t.pos -= 1;
407 end_token(&t);408 end_token(&t);
...@@ -415,6 +416,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -415,6 +416,7 @@ void tokenize(Buf *buf, Tokenization *out) {
415 t.cur_tok->id = TokenIdCmpLessOrEq;416 t.cur_tok->id = TokenIdCmpLessOrEq;
416 end_token(&t);417 end_token(&t);
417 t.state = TokenizeStateStart;418 t.state = TokenizeStateStart;
419 break;
418 case '<':420 case '<':
419 t.cur_tok->id = TokenIdBitShiftLeft;421 t.cur_tok->id = TokenIdBitShiftLeft;
420 t.state = TokenizeStateSawLessThanLessThan;422 t.state = TokenizeStateSawLessThanLessThan;
...@@ -432,6 +434,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -432,6 +434,7 @@ void tokenize(Buf *buf, Tokenization *out) {
432 t.cur_tok->id = TokenIdBitShiftLeftEq;434 t.cur_tok->id = TokenIdBitShiftLeftEq;
433 end_token(&t);435 end_token(&t);
434 t.state = TokenizeStateStart;436 t.state = TokenizeStateStart;
437 break;
435 default:438 default:
436 t.pos -= 1;439 t.pos -= 1;
437 end_token(&t);440 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 {...@@ -454,6 +454,29 @@ export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
454}454}
455 )SOURCE", "OK 1\nOK 2\nOK 3\nOK 4\n");455 )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
457}480}
458481
459static void add_compile_failure_test_cases(void) {482static void add_compile_failure_test_cases(void) {