JuliaHubOSS / llvm-cbe

resurrected LLVM "C Backend", with improvements
Other
832 stars 141 forks source link

Add option to declare locals at first assignment (C99) #94

Closed hikari-no-yume closed 3 years ago

hikari-no-yume commented 3 years ago

I think it reduces verbosity and improves readability. I've made it an option because it might not be to everyone's taste, and also this breaks pure C89 support, though I suspect this is available as an extension in many non-C99 compilers.

Example output without the change:

static uint32_t factorial(uint32_t llvm_cbe_tmp__8) {
  uint32_t llvm_cbe_tmp__9;
  uint32_t llvm_cbe_tmp__10;
  uint32_t llvm_cbe_tmp__11;
  uint32_t llvm_cbe_tmp__11__PHI_TEMPORARY;

  if ((((((int32_t)llvm_cbe_tmp__8) > ((int32_t)1u))&1))) {
    goto llvm_cbe_tmp__12;
  } else {
    llvm_cbe_tmp__11__PHI_TEMPORARY = llvm_cbe_tmp__8;   /* for PHI node */
    goto llvm_cbe_tmp__13;
  }

llvm_cbe_tmp__12:
  llvm_cbe_tmp__9 = factorial((llvm_add_u32(llvm_cbe_tmp__8, -1)));
  llvm_cbe_tmp__10 = llvm_mul_u32(llvm_cbe_tmp__9, llvm_cbe_tmp__8);
  llvm_cbe_tmp__11__PHI_TEMPORARY = llvm_cbe_tmp__10;   /* for PHI node */
  goto llvm_cbe_tmp__13;

llvm_cbe_tmp__13:
  llvm_cbe_tmp__11 = llvm_cbe_tmp__11__PHI_TEMPORARY;
  return llvm_cbe_tmp__11;
}

Example with the change:

static uint32_t factorial(uint32_t llvm_cbe_tmp__8) {
  uint32_t llvm_cbe_tmp__9__PHI_TEMPORARY;

  if ((((((int32_t)llvm_cbe_tmp__8) > ((int32_t)1u))&1))) {
    goto llvm_cbe_tmp__10;
  } else {
    llvm_cbe_tmp__9__PHI_TEMPORARY = llvm_cbe_tmp__8;   /* for PHI node */
    goto llvm_cbe_tmp__11;
  }

llvm_cbe_tmp__10:;
  uint32_t llvm_cbe_tmp__12 = factorial((llvm_add_u32(llvm_cbe_tmp__8, -1)));
  uint32_t llvm_cbe_tmp__13 = llvm_mul_u32(llvm_cbe_tmp__12, llvm_cbe_tmp__8);
  llvm_cbe_tmp__9__PHI_TEMPORARY = llvm_cbe_tmp__13;   /* for PHI node */
  goto llvm_cbe_tmp__11;

llvm_cbe_tmp__11:;
  uint32_t llvm_cbe_tmp__9 = llvm_cbe_tmp__9__PHI_TEMPORARY;
  return llvm_cbe_tmp__9;
}

It looks even better with https://github.com/JuliaComputing/llvm-cbe/pull/95:

static uint32_t factorial(uint32_t _8) {
  uint32_t _9__PHI_TEMPORARY;

  if ((((((int32_t)_8) > ((int32_t)1u))&1))) {
    goto _10;
  } else {
    _9__PHI_TEMPORARY = _8;   /* for PHI node */
    goto _11;
  }

_10:;
  uint32_t _12 = factorial((llvm_add_u32(_8, -1)));
  uint32_t _13 = llvm_mul_u32(_12, _8);
  _9__PHI_TEMPORARY = _13;   /* for PHI node */
  goto _11;

_11:;
  uint32_t _9 = _9__PHI_TEMPORARY;
  return _9;
}

Of course, this is quite simple code. (I chose it as an example because it's reasonably short.) In practice, the benefit is of course particularly pronounced for large functions with many instructions.