|
1 | 1 | // Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
|
2 | 2 | use super::{
|
3 |
| - expression_generator::{to_i1, ExpressionCodeGenerator}, |
| 3 | + expression_generator::{to_i1, ExpressionCodeGenerator, ExpressionValue}, |
4 | 4 | llvm::Llvm,
|
5 | 5 | };
|
6 | 6 | use crate::{
|
7 |
| - codegen::debug::Debug, |
8 |
| - codegen::{debug::DebugBuilderEnum, LlvmTypedIndex}, |
| 7 | + codegen::{ |
| 8 | + debug::{Debug, DebugBuilderEnum}, |
| 9 | + llvm_typesystem::cast_if_needed, |
| 10 | + LlvmTypedIndex, |
| 11 | + }, |
9 | 12 | index::{ImplementationIndexEntry, Index},
|
10 | 13 | resolver::{AnnotationMap, AstAnnotations, StatementAnnotation},
|
11 |
| - typesystem::DataTypeInformation, |
| 14 | + typesystem::{get_bigger_type, DataTypeInformation, DINT_TYPE}, |
12 | 15 | };
|
13 | 16 | use inkwell::{
|
14 | 17 | basic_block::BasicBlock,
|
15 | 18 | builder::Builder,
|
16 | 19 | context::Context,
|
17 |
| - values::{BasicValueEnum, FunctionValue, PointerValue}, |
| 20 | + values::{FunctionValue, PointerValue}, |
18 | 21 | };
|
19 | 22 | use plc_ast::{
|
20 | 23 | ast::{
|
@@ -325,117 +328,107 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> {
|
325 | 328 | body: &[AstNode],
|
326 | 329 | ) -> Result<(), Diagnostic> {
|
327 | 330 | let (builder, current_function, context) = self.get_llvm_deps();
|
328 |
| - self.generate_assignment_statement(counter, start)?; |
329 |
| - let condition_check = context.append_basic_block(current_function, "condition_check"); |
330 |
| - let for_body = context.append_basic_block(current_function, "for_body"); |
331 |
| - let increment_block = context.append_basic_block(current_function, "increment"); |
332 |
| - let continue_block = context.append_basic_block(current_function, "continue"); |
333 |
| - |
334 |
| - //Generate an initial jump to the for condition |
335 |
| - builder.build_unconditional_branch(condition_check); |
336 |
| - |
337 |
| - //Check loop condition |
338 |
| - builder.position_at_end(condition_check); |
339 | 331 | let exp_gen = self.create_expr_generator();
|
340 |
| - let counter_statement = exp_gen.generate_expression(counter)?; |
341 | 332 |
|
342 |
| - //. / and_2 \ |
343 |
| - //. / and 1 \ |
344 |
| - //. (counter_end_le && counter_start_ge) || (counter_end_ge && counter_start_le) |
345 |
| - let or_eval = self.generate_compare_expression(counter, end, start, &exp_gen)?; |
| 333 | + let end_ty = self.annotations.get_type_or_void(end, self.index); |
| 334 | + let counter_ty = self.annotations.get_type_or_void(counter, self.index); |
| 335 | + let cast_target_ty = get_bigger_type(self.index.get_type_or_panic(DINT_TYPE), counter_ty, self.index); |
| 336 | + let cast_target_llty = self.llvm_index.find_associated_type(cast_target_ty.get_name()).unwrap(); |
| 337 | + |
| 338 | + let step_ty = by_step.as_ref().map(|it| { |
| 339 | + self.register_debug_location(it); |
| 340 | + self.annotations.get_type_or_void(it, self.index) |
| 341 | + }); |
| 342 | + |
| 343 | + let eval_step = || { |
| 344 | + step_ty.map_or_else( |
| 345 | + || self.llvm.create_const_numeric(&cast_target_llty, "1", SourceLocation::undefined()), |
| 346 | + |step_ty| { |
| 347 | + let step = exp_gen.generate_expression(by_step.as_ref().unwrap())?; |
| 348 | + Ok(cast_if_needed!(exp_gen, cast_target_ty, step_ty, step, None)) |
| 349 | + }, |
| 350 | + ) |
| 351 | + }; |
346 | 352 |
|
347 |
| - builder.build_conditional_branch(to_i1(or_eval.into_int_value(), builder), for_body, continue_block); |
| 353 | + let predicate_incrementing = context.append_basic_block(current_function, "predicate_sle"); |
| 354 | + let predicate_decrementing = context.append_basic_block(current_function, "predicate_sge"); |
| 355 | + let loop_body = context.append_basic_block(current_function, "loop"); |
| 356 | + let increment = context.append_basic_block(current_function, "increment"); |
| 357 | + let afterloop = context.append_basic_block(current_function, "continue"); |
348 | 358 |
|
349 |
| - //Enter the for loop |
350 |
| - builder.position_at_end(for_body); |
351 |
| - let body_generator = StatementCodeGenerator { |
352 |
| - current_loop_exit: Some(continue_block), |
353 |
| - current_loop_continue: Some(increment_block), |
| 359 | + self.generate_assignment_statement(counter, start)?; |
| 360 | + let counter = exp_gen.generate_lvalue(counter)?; |
| 361 | + |
| 362 | + // generate loop predicate selector. since `STEP` can be a reference, this needs to be a runtime eval |
| 363 | + // XXX(mhasel): IR could possibly be improved by generating phi instructions. |
| 364 | + // Candidate for frontend optimization for builds without optimization when `STEP` |
| 365 | + // is a compile-time constant |
| 366 | + let is_incrementing = builder.build_int_compare( |
| 367 | + inkwell::IntPredicate::SGT, |
| 368 | + eval_step()?.into_int_value(), |
| 369 | + self.llvm |
| 370 | + .create_const_numeric(&cast_target_llty, "0", SourceLocation::undefined())? |
| 371 | + .into_int_value(), |
| 372 | + "is_incrementing", |
| 373 | + ); |
| 374 | + builder.build_conditional_branch(is_incrementing, predicate_incrementing, predicate_decrementing); |
| 375 | + // generate predicates for incrementing and decrementing counters |
| 376 | + let generate_predicate = |predicate| { |
| 377 | + builder.position_at_end(match predicate { |
| 378 | + inkwell::IntPredicate::SLE => predicate_incrementing, |
| 379 | + inkwell::IntPredicate::SGE => predicate_decrementing, |
| 380 | + _ => unreachable!(), |
| 381 | + }); |
| 382 | + |
| 383 | + let end = exp_gen.generate_expression_value(end).unwrap(); |
| 384 | + let end_value = match end { |
| 385 | + ExpressionValue::LValue(ptr) => builder.build_load(ptr, ""), |
| 386 | + ExpressionValue::RValue(val) => val, |
| 387 | + }; |
| 388 | + let counter_value = builder.build_load(counter, ""); |
| 389 | + let cmp = builder.build_int_compare( |
| 390 | + predicate, |
| 391 | + cast_if_needed!(exp_gen, cast_target_ty, counter_ty, counter_value, None).into_int_value(), |
| 392 | + cast_if_needed!(exp_gen, cast_target_ty, end_ty, end_value, None).into_int_value(), |
| 393 | + "condition", |
| 394 | + ); |
| 395 | + builder.build_conditional_branch(cmp, loop_body, afterloop); |
| 396 | + }; |
| 397 | + generate_predicate(inkwell::IntPredicate::SLE); |
| 398 | + generate_predicate(inkwell::IntPredicate::SGE); |
| 399 | + |
| 400 | + // generate loop body |
| 401 | + builder.position_at_end(loop_body); |
| 402 | + let body_builder = StatementCodeGenerator { |
| 403 | + current_loop_continue: Some(increment), |
| 404 | + current_loop_exit: Some(afterloop), |
354 | 405 | load_prefix: self.load_prefix.clone(),
|
355 | 406 | load_suffix: self.load_suffix.clone(),
|
356 | 407 | ..*self
|
357 | 408 | };
|
358 |
| - body_generator.generate_body(body)?; |
359 |
| - builder.build_unconditional_branch(increment_block); |
360 |
| - |
361 |
| - //Increment |
362 |
| - builder.position_at_end(increment_block); |
363 |
| - let expression_generator = self.create_expr_generator(); |
364 |
| - let step_by_value = by_step.as_ref().map_or_else( |
365 |
| - || { |
366 |
| - self.llvm.create_const_numeric( |
367 |
| - &counter_statement.get_type(), |
368 |
| - "1", |
369 |
| - SourceLocation::undefined(), |
370 |
| - ) |
371 |
| - }, |
372 |
| - |step| { |
373 |
| - self.register_debug_location(step); |
374 |
| - expression_generator.generate_expression(step) |
375 |
| - }, |
376 |
| - )?; |
377 |
| - |
378 |
| - let next = builder.build_int_add( |
379 |
| - counter_statement.into_int_value(), |
380 |
| - step_by_value.into_int_value(), |
381 |
| - "tmpVar", |
| 409 | + body_builder.generate_body(body)?; |
| 410 | + |
| 411 | + // increment counter |
| 412 | + builder.build_unconditional_branch(increment); |
| 413 | + builder.position_at_end(increment); |
| 414 | + let counter_value = builder.build_load(counter, ""); |
| 415 | + let inc = inkwell::values::BasicValue::as_basic_value_enum(&builder.build_int_add( |
| 416 | + eval_step()?.into_int_value(), |
| 417 | + cast_if_needed!(exp_gen, cast_target_ty, counter_ty, counter_value, None).into_int_value(), |
| 418 | + "next", |
| 419 | + )); |
| 420 | + builder.build_store( |
| 421 | + counter, |
| 422 | + cast_if_needed!(exp_gen, counter_ty, cast_target_ty, inc, None).into_int_value(), |
382 | 423 | );
|
383 | 424 |
|
384 |
| - let ptr = expression_generator.generate_lvalue(counter)?; |
385 |
| - builder.build_store(ptr, next); |
386 |
| - |
387 |
| - //Loop back |
388 |
| - builder.build_unconditional_branch(condition_check); |
389 |
| - |
390 |
| - //Continue |
391 |
| - builder.position_at_end(continue_block); |
392 |
| - |
| 425 | + // check condition |
| 426 | + builder.build_conditional_branch(is_incrementing, predicate_incrementing, predicate_decrementing); |
| 427 | + // continue |
| 428 | + builder.position_at_end(afterloop); |
393 | 429 | Ok(())
|
394 | 430 | }
|
395 | 431 |
|
396 |
| - fn generate_compare_expression( |
397 |
| - &'a self, |
398 |
| - counter: &AstNode, |
399 |
| - end: &AstNode, |
400 |
| - start: &AstNode, |
401 |
| - exp_gen: &'a ExpressionCodeGenerator, |
402 |
| - ) -> Result<BasicValueEnum<'a>, Diagnostic> { |
403 |
| - let bool_id = self.annotations.get_bool_id(); |
404 |
| - let counter_end_ge = AstFactory::create_binary_expression( |
405 |
| - counter.clone(), |
406 |
| - Operator::GreaterOrEqual, |
407 |
| - end.clone(), |
408 |
| - bool_id, |
409 |
| - ); |
410 |
| - let counter_start_ge = AstFactory::create_binary_expression( |
411 |
| - counter.clone(), |
412 |
| - Operator::GreaterOrEqual, |
413 |
| - start.clone(), |
414 |
| - bool_id, |
415 |
| - ); |
416 |
| - let counter_end_le = AstFactory::create_binary_expression( |
417 |
| - counter.clone(), |
418 |
| - Operator::LessOrEqual, |
419 |
| - end.clone(), |
420 |
| - bool_id, |
421 |
| - ); |
422 |
| - let counter_start_le = AstFactory::create_binary_expression( |
423 |
| - counter.clone(), |
424 |
| - Operator::LessOrEqual, |
425 |
| - start.clone(), |
426 |
| - bool_id, |
427 |
| - ); |
428 |
| - let and_1 = |
429 |
| - AstFactory::create_binary_expression(counter_end_le, Operator::And, counter_start_ge, bool_id); |
430 |
| - let and_2 = |
431 |
| - AstFactory::create_binary_expression(counter_end_ge, Operator::And, counter_start_le, bool_id); |
432 |
| - let or = AstFactory::create_binary_expression(and_1, Operator::Or, and_2, bool_id); |
433 |
| - |
434 |
| - self.register_debug_location(&or); |
435 |
| - let or_eval = exp_gen.generate_expression(&or)?; |
436 |
| - Ok(or_eval) |
437 |
| - } |
438 |
| - |
439 | 432 | /// genertes a case statement
|
440 | 433 | ///
|
441 | 434 | /// CASE selector OF
|
|
0 commit comments