Code Monkey home page Code Monkey logo

llvm-cbe's People

Contributors

aguinet avatar apaz-cli avatar bcoppens avatar certik avatar dipietroai avatar dpaoliello avatar ds5678 avatar gregorysimpson13 avatar hikari-no-yume avatar jfmherokiller avatar jimmyw avatar jorickert avatar lyh-kernel-mcw avatar makise-homura avatar martineztorres avatar michaelstorm avatar niansa avatar raffaellod avatar robiwano avatar rtc-draper avatar sapir avatar sdtelectronics avatar spektom avatar stephand avatar tonitick avatar twalters25 avatar viralbshah avatar vtjnash avatar woachk avatar xampprocky avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

llvm-cbe's Issues

c++ support

I am having problems with this tool generating code that won't compile when converting IR code that was generated from c++ sources. In other words C++ code -> IR -> C code result in Code that has undeclared variables.

What type of support does this tool have for this type of conversion? Can it convert any IR back to C? Has any tried this and had any success with it?

Private constant missing from generated output

Hello I was testing out this project, and I ran into a bug where a private constant in the LLVM Ir was referenced but not defined the generated C code.

@alloc7 = private constant <{ [0 x i8] }> zeroinitializer, align 8

Consider the following Rust code:

use std::alloc::System;

#[global_allocator]
static GLOBAL: System = System;

pub fn bazza() {
    println!("Hello World!");
}

This can be compiled using the following.

  1. Install Rust
  2. cargo new --lib cbe-test
  3. Paste the above code into src/lib.rs
  4. cargo rustc --release -- --emit llvm-ir
  5. In your target/release/deps folder there should be an cbe-test.ll or similar file.
  6. llvm-cbe ./cbe-test.ll -o cbe-test.c
  7. clang cbe-test.c

You get the following error.

scratchpad.c:98:10: warning: incompatible redeclaration of library function 'calloc' [-Wincompatible-library-redeclaration]
uint8_t* calloc(uint64_t, uint64_t) __ATTRIBUTELIST__((nothrow));
         ^
scratchpad.c:98:10: note: 'calloc' is a builtin with type 'void *(unsigned long, unsigned long)'
scratchpad.c:99:10: warning: incompatible redeclaration of library function 'malloc' [-Wincompatible-library-redeclaration]
uint8_t* malloc(uint64_t) __ATTRIBUTELIST__((nothrow));
         ^
scratchpad.c:99:10: note: 'malloc' is a builtin with type 'void *(unsigned long)'
scratchpad.c:101:10: warning: incompatible redeclaration of library function 'realloc' [-Wincompatible-library-redeclaration]
uint8_t* realloc(uint8_t*, uint64_t) __ATTRIBUTELIST__((nothrow));
         ^
scratchpad.c:101:10: note: 'realloc' is a builtin with type 'void *(void *, unsigned long)'
scratchpad.c:103:67: warning: declaration of 'struct l_struct_unwind_KD__KD_libunwind_KD__KD__Unwind_Exception' will not be
      visible outside of this function [-Wvisibility]
uint32_t rust_eh_personality(uint32_t, uint32_t, uint64_t, struct l_struct_unwind_KD__KD_libunwind_KD__KD__Unwind_Exce...
                                                                  ^
scratchpad.c:105:10: warning: incompatible redeclaration of library function 'memset' [-Wincompatible-library-redeclaration]
uint8_t* memset(uint8_t*, uint32_t, uint64_t);
         ^
scratchpad.c:105:10: note: 'memset' is a builtin with type 'void *(void *, int, unsigned long)'
scratchpad.c:136:47: error: use of undeclared identifier 'alloc7'
  *((&llvm_cbe__2.field5.field0)) = ((void*)(&alloc7));
                                              ^
scratchpad.c:211:105: error: use of undeclared identifier 'alloc7'
  llvm_cbe_tmp__3 =  /*tail*/ _ZN3std10sys_common5alloc16realloc_fallback17h5648078a40a04803E(((void*)(&alloc7)), llvm...

LLVM IR

LLVM IR src

; ModuleID = 'scratchpad.69buci42-cgu.0'
source_filename = "scratchpad.69buci42-cgu.0"
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.7.0"

%"std::fmt::Arguments" = type { [0 x i64], { [0 x { [0 x i8]*, i64 }]*, i64 }, [0 x i64], { i64*, i64 }, [0 x i64], { [0 x { i8*, i64* }]*, i64 }, [0 x i64] }
%"std::alloc::System" = type {}
%"unwind::libunwind::_Unwind_Exception" = type { [0 x i64], i64, [0 x i64], void (i32, %"unwind::libunwind::_Unwind_Exception"*)*, [0 x i64], [6 x i64], [0 x i64] }
%"unwind::libunwind::_Unwind_Context" = type { [0 x i8] }

@alloc4 = private unnamed_addr constant <{ [13 x i8] }> <{ [13 x i8] c"Hello World!\0A" }>, align 1
@alloc5 = private unnamed_addr constant <{ i8*, [8 x i8] }> <{ i8* getelementptr inbounds (<{ [13 x i8] }>, <{ [13 x i8] }>* @alloc4, i32 0, i32 0, i32 0), [8 x i8] c"\0D\00\00\00\00\00\00\00" }>, align 8
@alloc7 = private constant <{ [0 x i8] }> zeroinitializer, align 8

; scratchpad::bazza
; Function Attrs: uwtable
define void @_ZN10scratchpad5bazza17hd3687861172d5603E() unnamed_addr #0 {
start:
  %_2 = alloca %"std::fmt::Arguments", align 8
  %0 = bitcast %"std::fmt::Arguments"* %_2 to i8*
  call void @llvm.lifetime.start.p0i8(i64 48, i8* nonnull %0)
  %1 = bitcast %"std::fmt::Arguments"* %_2 to [0 x { [0 x i8]*, i64 }]**
  store [0 x { [0 x i8]*, i64 }]* bitcast (<{ i8*, [8 x i8] }>* @alloc5 to [0 x { [0 x i8]*, i64 }]*), [0 x { [0 x i8]*, i64 }]** %1, align 8, !alias.scope !1
  %2 = getelementptr inbounds %"std::fmt::Arguments", %"std::fmt::Arguments"* %_2, i64 0, i32 1, i32 1
  store i64 1, i64* %2, align 8, !alias.scope !1
  %3 = getelementptr inbounds %"std::fmt::Arguments", %"std::fmt::Arguments"* %_2, i64 0, i32 3, i32 0
  store i64* null, i64** %3, align 8, !alias.scope !1
  %4 = getelementptr inbounds %"std::fmt::Arguments", %"std::fmt::Arguments"* %_2, i64 0, i32 5, i32 0
  store [0 x { i8*, i64* }]* bitcast (<{ [0 x i8] }>* @alloc7 to [0 x { i8*, i64* }]*), [0 x { i8*, i64* }]** %4, align 8, !alias.scope !1
  %5 = getelementptr inbounds %"std::fmt::Arguments", %"std::fmt::Arguments"* %_2, i64 0, i32 5, i32 1
  store i64 0, i64* %5, align 8, !alias.scope !1
; call std::io::stdio::_print
  call void @_ZN3std2io5stdio6_print17h2b92ca946b4108adE(%"std::fmt::Arguments"* noalias nocapture nonnull dereferenceable(48) %_2)
  call void @llvm.lifetime.end.p0i8(i64 48, i8* nonnull %0)
  ret void
}

; Function Attrs: nounwind uwtable
define i8* @__rg_alloc(i64 %arg0, i64 %arg1) unnamed_addr #1 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality {
start:
  %out.i.i = alloca i8*, align 8
  %_4.i = icmp ult i64 %arg1, 17
  br i1 %_4.i, label %bb3.i, label %bb8.critedge.i

bb3.i:                                            ; preds = %start
  %_7.not.i = icmp ugt i64 %arg1, %arg0
  br i1 %_7.not.i, label %bb13.i, label %bb9.i

bb8.critedge.i:                                   ; preds = %start
  %_15.i = icmp ugt i64 %arg1, 2147483648
  br i1 %_15.i, label %"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$5alloc17hf14305b38e5bcb60E.exit", label %bb13.i

bb9.i:                                            ; preds = %bb3.i
  %_12.i = tail call i8* @malloc(i64 %arg0) #5
  br label %"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$5alloc17hf14305b38e5bcb60E.exit"

bb13.i:                                           ; preds = %bb8.critedge.i, %bb3.i
  %0 = bitcast i8** %out.i.i to i8*
  call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #5
  store i8* null, i8** %out.i.i, align 8
  %1 = icmp ugt i64 %arg1, 8
  %.0.sroa.speculated.i.i.i.i = select i1 %1, i64 %arg1, i64 8
  %ret.i.i = call i32 @posix_memalign(i8** nonnull %out.i.i, i64 %.0.sroa.speculated.i.i.i.i, i64 %arg0) #5
  %2 = icmp eq i32 %ret.i.i, 0
  %_14.i.i = load i8*, i8** %out.i.i, align 8
  %spec.select.i.i = select i1 %2, i8* %_14.i.i, i8* null
  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #5
  br label %"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$5alloc17hf14305b38e5bcb60E.exit"

"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$5alloc17hf14305b38e5bcb60E.exit": ; preds = %bb8.critedge.i, %bb9.i, %bb13.i
  %.1.i = phi i8* [ %_12.i, %bb9.i ], [ %spec.select.i.i, %bb13.i ], [ null, %bb8.critedge.i ]
  ret i8* %.1.i
}

; Function Attrs: nounwind uwtable
define void @__rg_dealloc(i8* nocapture %arg0, i64 %arg1, i64 %arg2) unnamed_addr #1 {
start:
  tail call void @free(i8* %arg0) #5
  ret void
}

; Function Attrs: uwtable
define i8* @__rg_realloc(i8* %arg0, i64 %arg1, i64 %arg2, i64 %arg3) unnamed_addr #0 {
start:
  %_6.i = icmp ugt i64 %arg2, 16
  %_9.not.i = icmp ugt i64 %arg2, %arg3
  %or.cond.i = or i1 %_6.i, %_9.not.i
  br i1 %or.cond.i, label %bb7.critedge.i, label %bb8.i

bb7.critedge.i:                                   ; preds = %start
; call std::sys_common::alloc::realloc_fallback
  %0 = tail call i8* @_ZN3std10sys_common5alloc16realloc_fallback17h5648078a40a04803E(%"std::alloc::System"* noalias nonnull readonly align 1 bitcast (<{ [0 x i8] }>* @alloc7 to %"std::alloc::System"*), i8* %arg0, i64 %arg1, i64 %arg2, i64 %arg3)
  br label %"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$7realloc17h2c5c3aefe4a815adE.exit"

bb8.i:                                            ; preds = %start
  %_13.i = tail call i8* @realloc(i8* %arg0, i64 %arg3)
  br label %"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$7realloc17h2c5c3aefe4a815adE.exit"

"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$7realloc17h2c5c3aefe4a815adE.exit": ; preds = %bb7.critedge.i, %bb8.i
  %.0.i = phi i8* [ %_13.i, %bb8.i ], [ %0, %bb7.critedge.i ]
  ret i8* %.0.i
}

; Function Attrs: nounwind uwtable
define i8* @__rg_alloc_zeroed(i64 %arg0, i64 %arg1) unnamed_addr #1 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality {
start:
  %out.i.i.i = alloca i8*, align 8
  %_4.i = icmp ult i64 %arg1, 17
  br i1 %_4.i, label %bb3.i, label %bb8.critedge.i.i

bb3.i:                                            ; preds = %start
  %_7.not.i = icmp ugt i64 %arg1, %arg0
  br i1 %_7.not.i, label %bb13.i.i, label %bb9.i

bb8.critedge.i.i:                                 ; preds = %start
  %_15.i.i = icmp ugt i64 %arg1, 2147483648
  br i1 %_15.i.i, label %"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$12alloc_zeroed17h1e7aa0e00521c158E.exit", label %bb13.i.i

bb13.i.i:                                         ; preds = %bb8.critedge.i.i, %bb3.i
  %0 = bitcast i8** %out.i.i.i to i8*
  call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #5
  store i8* null, i8** %out.i.i.i, align 8
  %1 = icmp ugt i64 %arg1, 8
  %.0.sroa.speculated.i.i.i.i.i = select i1 %1, i64 %arg1, i64 8
  %ret.i.i.i = call i32 @posix_memalign(i8** nonnull %out.i.i.i, i64 %.0.sroa.speculated.i.i.i.i.i, i64 %arg0) #5
  %2 = icmp ne i32 %ret.i.i.i, 0
  %_14.i.i.i = load i8*, i8** %out.i.i.i, align 8
  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #5
  %3 = icmp eq i8* %_14.i.i.i, null
  %or.cond.i = or i1 %2, %3
  br i1 %or.cond.i, label %"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$12alloc_zeroed17h1e7aa0e00521c158E.exit", label %bb15.i

bb9.i:                                            ; preds = %bb3.i
  %_12.i = tail call i8* @calloc(i64 %arg0, i64 1) #5
  br label %"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$12alloc_zeroed17h1e7aa0e00521c158E.exit"

bb15.i:                                           ; preds = %bb13.i.i
  call void @llvm.memset.p0i8.i64(i8* nonnull align 1 %_14.i.i.i, i8 0, i64 %arg0, i1 false) #5
  br label %"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$12alloc_zeroed17h1e7aa0e00521c158E.exit"

"_ZN3std3sys4unix5alloc81_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$12alloc_zeroed17h1e7aa0e00521c158E.exit": ; preds = %bb8.critedge.i.i, %bb13.i.i, %bb9.i, %bb15.i
  %.0.i = phi i8* [ %_12.i, %bb9.i ], [ %_14.i.i.i, %bb15.i ], [ null, %bb13.i.i ], [ null, %bb8.critedge.i.i ]
  ret i8* %.0.i
}

; Function Attrs: argmemonly nounwind willreturn
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #2

; Function Attrs: nofree nounwind uwtable
declare i32 @posix_memalign(i8**, i64, i64) unnamed_addr #3

; Function Attrs: argmemonly nounwind willreturn
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #2

; Function Attrs: nofree nounwind uwtable
declare noalias i8* @calloc(i64, i64) unnamed_addr #3

; Function Attrs: nofree nounwind uwtable
declare noalias i8* @malloc(i64) unnamed_addr #3

; Function Attrs: nounwind uwtable
declare void @free(i8* nocapture) unnamed_addr #1

; Function Attrs: nounwind uwtable
declare noalias i8* @realloc(i8* nocapture, i64) unnamed_addr #1

; std::sys_common::alloc::realloc_fallback
; Function Attrs: uwtable
declare i8* @_ZN3std10sys_common5alloc16realloc_fallback17h5648078a40a04803E(%"std::alloc::System"* noalias nonnull readonly align 1, i8*, i64, i64, i64) unnamed_addr #0

; Function Attrs: argmemonly nounwind willreturn writeonly
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #4

; Function Attrs: nounwind uwtable
declare i32 @rust_eh_personality(i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*) unnamed_addr #1

; std::io::stdio::_print
; Function Attrs: uwtable
declare void @_ZN3std2io5stdio6_print17h2b92ca946b4108adE(%"std::fmt::Arguments"* noalias nocapture dereferenceable(48)) unnamed_addr #0

attributes #0 = { uwtable "frame-pointer"="all" "probe-stack"="__rust_probestack" "target-cpu"="core2" }
attributes #1 = { nounwind uwtable "frame-pointer"="all" "probe-stack"="__rust_probestack" "target-cpu"="core2" }
attributes #2 = { argmemonly nounwind willreturn }
attributes #3 = { nofree nounwind uwtable "frame-pointer"="all" "probe-stack"="__rust_probestack" "target-cpu"="core2" }
attributes #4 = { argmemonly nounwind willreturn writeonly }
attributes #5 = { nounwind }

!llvm.module.flags = !{!0}

!0 = !{i32 7, !"PIC Level", i32 2}
!1 = !{!2}
!2 = distinct !{!2, !3, !"_ZN4core3fmt9Arguments6new_v117h9011edc505bf7fa6E: argument 0"}
!3 = distinct !{!3, !"_ZN4core3fmt9Arguments6new_v117h9011edc505bf7fa6E"}

Generated C

C src


/* Provide Declarations */
#include 
#include 
#include 
#include 
#include 
#ifndef __cplusplus
typedef unsigned char bool;
#endif

#ifndef _MSC_VER
#define __forceinline __attribute__((always_inline)) inline
#endif

#if defined(__GNUC__)
#define  __ATTRIBUTELIST__(x) __attribute__(x)
#else
#define  __ATTRIBUTELIST__(x)  
#endif

#ifdef _MSC_VER  /* Can only support "linkonce" vars with GCC */
#define __attribute__(X)
#endif

#ifdef _MSC_VER
#define __MSALIGN__(X) __declspec(align(X))
#else
#define __MSALIGN__(X)
#endif



/* Global Declarations */

/* Types Declarations */
struct l_unnamed_3;
struct l_unnamed_4;
struct l_unnamed_5;
struct l_struct_std_KD__KD_fmt_KD__KD_Arguments;
struct l_unnamed_1;
struct l_unnamed_2;

/* Function definitions */

/* Types Definitions */
struct l_unnamed_3 {
  void* field0;
  uint64_t field1;
};
struct l_unnamed_4 {
  uint64_t* field0;
  uint64_t field1;
};
struct l_unnamed_5 {
  void* field0;
  uint64_t field1;
};
struct l_struct_std_KD__KD_fmt_KD__KD_Arguments {
  /* void field0 */  struct l_unnamed_3 field1;
  /* void field2 */  struct l_unnamed_4 field3;
  /* void field4 */  struct l_unnamed_5 field5;
  /* void field6 */};
struct l_array_13_uint8_t {
  uint8_t array[13];
};
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif
struct l_unnamed_1 {
  struct l_array_13_uint8_t field0;
} __attribute__ ((packed));
#ifdef _MSC_VER
#pragma pack(pop)
#endif
struct l_array_8_uint8_t {
  uint8_t array[8];
};
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif
struct l_unnamed_2 {
  uint8_t* field0;
  struct l_array_8_uint8_t field1;
} __attribute__ ((packed));
#ifdef _MSC_VER
#pragma pack(pop)
#endif

/* External Global Variable Declarations */

/* Function Declarations */
void _ZN10scratchpad5bazza17hd3687861172d5603E(void);
uint8_t* __rg_alloc(uint64_t, uint64_t) __ATTRIBUTELIST__((nothrow));
void __rg_dealloc(uint8_t*, uint64_t, uint64_t) __ATTRIBUTELIST__((nothrow));
uint8_t* __rg_realloc(uint8_t*, uint64_t, uint64_t, uint64_t);
uint8_t* __rg_alloc_zeroed(uint64_t, uint64_t) __ATTRIBUTELIST__((nothrow));
uint32_t posix_memalign(uint8_t**, uint64_t, uint64_t) __ATTRIBUTELIST__((nothrow));
uint8_t* calloc(uint64_t, uint64_t) __ATTRIBUTELIST__((nothrow));
uint8_t* malloc(uint64_t) __ATTRIBUTELIST__((nothrow));
void free(uint8_t*) __ATTRIBUTELIST__((nothrow));
uint8_t* realloc(uint8_t*, uint64_t) __ATTRIBUTELIST__((nothrow));
uint8_t* _ZN3std10sys_common5alloc16realloc_fallback17h5648078a40a04803E(void*, uint8_t*, uint64_t, uint64_t, uint64_t);
uint32_t rust_eh_personality(uint32_t, uint32_t, uint64_t, struct l_struct_unwind_KD__KD_libunwind_KD__KD__Unwind_Exception*, void*) __ATTRIBUTELIST__((nothrow));
void _ZN3std2io5stdio6_print17h2b92ca946b4108adE(struct l_struct_std_KD__KD_fmt_KD__KD_Arguments*);
uint8_t* memset(uint8_t*, uint32_t, uint64_t);


/* Global Variable Definitions and Initialization */
static struct l_unnamed_1 alloc4 = { { { 72u, 101u, 108u, 108u, 111u, 32, 87u, 111u, 114u, 108u, 100u, 33, 10 } } };
static __MSALIGN__(8) struct l_unnamed_2 alloc5 __attribute__((aligned(8))) = { ((&alloc4.field0.array[((int32_t)0)])), { { 13, 0, 0, 0, 0, 0, 0, 0 } } };


/* LLVM Intrinsic Builtin Function Bodies */
static __forceinline uint64_t llvm_select_u64(bool condition, uint64_t iftrue, uint64_t ifnot) {
  uint64_t r;
  r = condition ? iftrue : ifnot;
  return r;
}
static __forceinline uint8_t* llvm_select_pu8(bool condition, uint8_t* iftrue, uint8_t* ifnot) {
  uint8_t* r;
  r = condition ? iftrue : ifnot;
  return r;
}


/* Function Bodies */

void _ZN10scratchpad5bazza17hd3687861172d5603E(void) {
  struct l_struct_std_KD__KD_fmt_KD__KD_Arguments llvm_cbe__2;    /* Address-exposed local */
  uint8_t* llvm_cbe_tmp__1;

  llvm_cbe_tmp__1 = ((uint8_t*)(&llvm_cbe__2));
  *(((void**)(&llvm_cbe__2))) = ((void*)(&alloc5));
  *((&llvm_cbe__2.field1.field1)) = UINT64_C(1);
  *((&llvm_cbe__2.field3.field0)) = ((uint64_t*)/*NULL*/0);
  *((&llvm_cbe__2.field5.field0)) = ((void*)(&alloc7));
  *((&llvm_cbe__2.field5.field1)) = UINT64_C(0);
  _ZN3std2io5stdio6_print17h2b92ca946b4108adE((&llvm_cbe__2));
}


uint8_t* __rg_alloc(uint64_t llvm_cbe_arg0, uint64_t llvm_cbe_arg1) {
  uint8_t* llvm_cbe_out_2e_i_2e_i;    /* Address-exposed local */
  uint8_t* llvm_cbe__12_2e_i;
  uint8_t* llvm_cbe_tmp__2;
  uint32_t llvm_cbe_ret_2e_i_2e_i;
  uint8_t* llvm_cbe__14_2e_i_2e_i;
  uint8_t* llvm_cbe_spec_2e_select_2e_i_2e_i;
  uint8_t* llvm_cbe__2e_1_2e_i;
  uint8_t* llvm_cbe__2e_1_2e_i__PHI_TEMPORARY;

  if ((((((uint64_t)llvm_cbe_arg1) < ((uint64_t)UINT64_C(17)))&1))) {
    goto llvm_cbe_bb3_2e_i;
  } else {
    goto llvm_cbe_bb8_2e_critedge_2e_i;
  }

llvm_cbe_bb3_2e_i:
  if ((((((uint64_t)llvm_cbe_arg1) > ((uint64_t)llvm_cbe_arg0))&1))) {
    goto llvm_cbe_bb13_2e_i;
  } else {
    goto llvm_cbe_bb9_2e_i;
  }

llvm_cbe_bb8_2e_critedge_2e_i:
  if ((((((uint64_t)llvm_cbe_arg1) > ((uint64_t)UINT64_C(2147483648)))&1))) {
    llvm_cbe__2e_1_2e_i__PHI_TEMPORARY = ((uint8_t*)/*NULL*/0);   /* for PHI node */
    goto llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_5alloc17hf14305b38e5bcb60E_2e_exit;
  } else {
    goto llvm_cbe_bb13_2e_i;
  }

llvm_cbe_bb9_2e_i:
  llvm_cbe__12_2e_i =  /*tail*/ malloc(llvm_cbe_arg0);
  llvm_cbe__2e_1_2e_i__PHI_TEMPORARY = llvm_cbe__12_2e_i;   /* for PHI node */
  goto llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_5alloc17hf14305b38e5bcb60E_2e_exit;

llvm_cbe_bb13_2e_i:
  llvm_cbe_tmp__2 = ((uint8_t*)(&llvm_cbe_out_2e_i_2e_i));
  llvm_cbe_out_2e_i_2e_i = ((uint8_t*)/*NULL*/0);
  llvm_cbe_ret_2e_i_2e_i = posix_memalign((&llvm_cbe_out_2e_i_2e_i), (llvm_select_u64((((((uint64_t)llvm_cbe_arg1) > ((uint64_t)UINT64_C(8)))&1)), llvm_cbe_arg1, UINT64_C(8))), llvm_cbe_arg0);
  llvm_cbe__14_2e_i_2e_i = llvm_cbe_out_2e_i_2e_i;
  llvm_cbe_spec_2e_select_2e_i_2e_i = llvm_select_pu8((((llvm_cbe_ret_2e_i_2e_i == 0u)&1)), llvm_cbe__14_2e_i_2e_i, ((uint8_t*)/*NULL*/0));
  llvm_cbe__2e_1_2e_i__PHI_TEMPORARY = llvm_cbe_spec_2e_select_2e_i_2e_i;   /* for PHI node */
  goto llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_5alloc17hf14305b38e5bcb60E_2e_exit;

llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_5alloc17hf14305b38e5bcb60E_2e_exit:
  llvm_cbe__2e_1_2e_i = llvm_cbe__2e_1_2e_i__PHI_TEMPORARY;
  return llvm_cbe__2e_1_2e_i;
}


void __rg_dealloc(uint8_t* llvm_cbe_arg0, uint64_t llvm_cbe_arg1, uint64_t llvm_cbe_arg2) {
   /*tail*/ free(llvm_cbe_arg0);
}


uint8_t* __rg_realloc(uint8_t* llvm_cbe_arg0, uint64_t llvm_cbe_arg1, uint64_t llvm_cbe_arg2, uint64_t llvm_cbe_arg3) {
  uint8_t* llvm_cbe_tmp__3;
  uint8_t* llvm_cbe__13_2e_i;
  uint8_t* llvm_cbe__2e_0_2e_i;
  uint8_t* llvm_cbe__2e_0_2e_i__PHI_TEMPORARY;

  if (((((((((uint64_t)llvm_cbe_arg2) > ((uint64_t)UINT64_C(16)))&1)) | (((((uint64_t)llvm_cbe_arg2) > ((uint64_t)llvm_cbe_arg3))&1)))&1))) {
    goto llvm_cbe_bb7_2e_critedge_2e_i;
  } else {
    goto llvm_cbe_bb8_2e_i;
  }

llvm_cbe_bb7_2e_critedge_2e_i:
  llvm_cbe_tmp__3 =  /*tail*/ _ZN3std10sys_common5alloc16realloc_fallback17h5648078a40a04803E(((void*)(&alloc7)), llvm_cbe_arg0, llvm_cbe_arg1, llvm_cbe_arg2, llvm_cbe_arg3);
  llvm_cbe__2e_0_2e_i__PHI_TEMPORARY = llvm_cbe_tmp__3;   /* for PHI node */
  goto llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_7realloc17h2c5c3aefe4a815adE_2e_exit;

llvm_cbe_bb8_2e_i:
  llvm_cbe__13_2e_i =  /*tail*/ realloc(llvm_cbe_arg0, llvm_cbe_arg3);
  llvm_cbe__2e_0_2e_i__PHI_TEMPORARY = llvm_cbe__13_2e_i;   /* for PHI node */
  goto llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_7realloc17h2c5c3aefe4a815adE_2e_exit;

llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_7realloc17h2c5c3aefe4a815adE_2e_exit:
  llvm_cbe__2e_0_2e_i = llvm_cbe__2e_0_2e_i__PHI_TEMPORARY;
  return llvm_cbe__2e_0_2e_i;
}


uint8_t* __rg_alloc_zeroed(uint64_t llvm_cbe_arg0, uint64_t llvm_cbe_arg1) {
  uint8_t* llvm_cbe_out_2e_i_2e_i_2e_i;    /* Address-exposed local */
  uint8_t* llvm_cbe_tmp__4;
  uint32_t llvm_cbe_ret_2e_i_2e_i_2e_i;
  uint8_t* llvm_cbe__14_2e_i_2e_i_2e_i;
  uint8_t* llvm_cbe__12_2e_i;
  uint8_t* llvm_cbe_tmp__5;
  uint8_t* llvm_cbe__2e_0_2e_i;
  uint8_t* llvm_cbe__2e_0_2e_i__PHI_TEMPORARY;

  if ((((((uint64_t)llvm_cbe_arg1) < ((uint64_t)UINT64_C(17)))&1))) {
    goto llvm_cbe_bb3_2e_i;
  } else {
    goto llvm_cbe_bb8_2e_critedge_2e_i_2e_i;
  }

llvm_cbe_bb3_2e_i:
  if ((((((uint64_t)llvm_cbe_arg1) > ((uint64_t)llvm_cbe_arg0))&1))) {
    goto llvm_cbe_bb13_2e_i_2e_i;
  } else {
    goto llvm_cbe_bb9_2e_i;
  }

llvm_cbe_bb8_2e_critedge_2e_i_2e_i:
  if ((((((uint64_t)llvm_cbe_arg1) > ((uint64_t)UINT64_C(2147483648)))&1))) {
    llvm_cbe__2e_0_2e_i__PHI_TEMPORARY = ((uint8_t*)/*NULL*/0);   /* for PHI node */
    goto llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_12alloc_zeroed17h1e7aa0e00521c158E_2e_exit;
  } else {
    goto llvm_cbe_bb13_2e_i_2e_i;
  }

llvm_cbe_bb13_2e_i_2e_i:
  llvm_cbe_tmp__4 = ((uint8_t*)(&llvm_cbe_out_2e_i_2e_i_2e_i));
  llvm_cbe_out_2e_i_2e_i_2e_i = ((uint8_t*)/*NULL*/0);
  llvm_cbe_ret_2e_i_2e_i_2e_i = posix_memalign((&llvm_cbe_out_2e_i_2e_i_2e_i), (llvm_select_u64((((((uint64_t)llvm_cbe_arg1) > ((uint64_t)UINT64_C(8)))&1)), llvm_cbe_arg1, UINT64_C(8))), llvm_cbe_arg0);
  llvm_cbe__14_2e_i_2e_i_2e_i = llvm_cbe_out_2e_i_2e_i_2e_i;
  if (((((((llvm_cbe_ret_2e_i_2e_i_2e_i != 0u)&1)) | (((llvm_cbe__14_2e_i_2e_i_2e_i == ((uint8_t*)/*NULL*/0))&1)))&1))) {
    llvm_cbe__2e_0_2e_i__PHI_TEMPORARY = ((uint8_t*)/*NULL*/0);   /* for PHI node */
    goto llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_12alloc_zeroed17h1e7aa0e00521c158E_2e_exit;
  } else {
    goto llvm_cbe_bb15_2e_i;
  }

llvm_cbe_bb9_2e_i:
  llvm_cbe__12_2e_i =  /*tail*/ calloc(llvm_cbe_arg0, UINT64_C(1));
  llvm_cbe__2e_0_2e_i__PHI_TEMPORARY = llvm_cbe__12_2e_i;   /* for PHI node */
  goto llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_12alloc_zeroed17h1e7aa0e00521c158E_2e_exit;

llvm_cbe_bb15_2e_i:
  llvm_cbe_tmp__5 = memset(llvm_cbe__14_2e_i_2e_i_2e_i, 0, llvm_cbe_arg0);
  llvm_cbe__2e_0_2e_i__PHI_TEMPORARY = llvm_cbe__14_2e_i_2e_i_2e_i;   /* for PHI node */
  goto llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_12alloc_zeroed17h1e7aa0e00521c158E_2e_exit;

llvm_cbe__ZN3std3sys4unix5alloc81__24_LT_24_impl_24_u20_24_core_2e__2e_alloc_2e__2e_global_2e__2e_GlobalAlloc_24_u20_24_for_24_u20_24_std_2e__2e_alloc_2e__2e_System_24_GT_24_12alloc_zeroed17h1e7aa0e00521c158E_2e_exit:
  llvm_cbe__2e_0_2e_i = llvm_cbe__2e_0_2e_i__PHI_TEMPORARY;
  return llvm_cbe__2e_0_2e_i;
}

error: invalid field 'variables'

llvm-cbe compiles, but both when building and testing llvm-cbe on Step 3: Usage Examples or when I try to use it for any of my generated IR I get the same error: error: invalid field 'variables'
Is it some version incompatibility, wrong compilers, or my mistake? I think 'variables' fields should be supported somehow

Installation Instructions, Step 1 (in-tree llvm build) does not work

The installation instructions say:

The first step is to compile LLVM on your machine (this assumes an in-tree build, but out-of-tree will also work):

 cd $HOME
 git clone https://github.com/llvm-mirror/llvm
 cd llvm
 git checkout release_37
 ./configure
 make

./configure results in:
configure: error: In-source builds are not allowed. Please configure from a separate build directory!

Please update instructions.

Readme update

We should update the readme to show the latest status of the repository:

9666d8b is merged which makes it possible to skip the compiling of LLVM (which is impossible or very hard for most of the people), however, there is no section describing how to do it. I got in this trap of building LLVM and my computer was involved for a few days.

Once #65 and #73 are merged:

https://github.com/woachk/llvm-cbe/blob/fix-llvm9/README.md#L24

- llvm-cbe works with the LLVM 8.0 release version and autotools.
+ llvm-cbe works with the LLVM 10.0 release version and autotools.

https://github.com/woachk/llvm-cbe/blob/fix-llvm9/README.md#L10

- This version of the LLVM-CBE library works with LLVM 8.0. You will have
+ This version of the LLVM-CBE library works with LLVM 10.0. You will have

https://github.com/woachk/llvm-cbe/blob/fix-llvm9/README.md#L34

- git checkout release/8.x
+ git checkout release/10.x

https://github.com/JuliaComputing/llvm-cbe/blob/master/README.md#L68
It should changed to:

- $ $(HOME)/llvm/build/bin/llvm-cbe main.ll
+ $ $HOME/llvm-project/llvm/build/bin/llvm-cbe main.ll

https://github.com/woachk/llvm-cbe/blob/fix-llvm9/README.md#L75

- $ gcc -o main.cbe main.cbe.c
+ $ clang -o main.cbe main.cbe.c

The README has outdated build instructions

The README file contains info about checking out release 3.7; since the project now targets LLVM 6/7, it needs to be updated to git checkout RELEASE_70, and the rest of the build instructions should be changed accordingly to use cmake instead.

Unable to build llvm-cbe

After pretty much following Step 1 mentioned in README, in Step 2 when I try to do

make llvm-cbe

I get the following:

[100%] Linking CXX executable ../../../../bin/llvm-cbe
collect2: error: ld returned 1 exit status
projects/llvm-cbe/tools/llvm-cbe/CMakeFiles/llvm-cbe.dir/build.make:255: recipe for target 'bin/llvm-cbe' failed
make[3]: *** [bin/llvm-cbe] Error 1
CMakeFiles/Makefile2:20783: recipe for target 'projects/llvm-cbe/tools/llvm-cbe/CMakeFiles/llvm-cbe.dir/all' failed
make[2]: *** [projects/llvm-cbe/tools/llvm-cbe/CMakeFiles/llvm-cbe.dir/all] Error 2
CMakeFiles/Makefile2:20795: recipe for target 'projects/llvm-cbe/tools/llvm-cbe/CMakeFiles/llvm-cbe.dir/rule' failed
make[1]: *** [projects/llvm-cbe/tools/llvm-cbe/CMakeFiles/llvm-cbe.dir/rule] Error 2
Makefile:6465: recipe for target 'llvm-cbe' failed
make: *** [llvm-cbe] Error 2

This is on an Ubuntu 16.04 virtual machine running on Virtual Box in Mac.

Unsupported "fence" instruction

Hi

It seems llvm-cbe doesn't support "fence" instruction. My .ll file has "fence" and the whole stack is as following. I used the latest code and tested tonight.

unsupported LLVM instruction in:   fence syncscope("singlethread") seq_cst, !dbg !8312 @ locks.jl:124
unsupported LLVM instruction
UNREACHABLE executed at /llvm/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp:5131!
#0 0x0000000003472aa5 llvm::sys::PrintStackTrace(llvm::raw_ostream&) /llvm/lib/Support/Unix/Signals.inc:398:0
#1 0x0000000003472b38 PrintStackTraceSignalHandler(void*) /llvm/lib/Support/Unix/Signals.inc:462:0
#2 0x0000000003470d21 llvm::sys::RunSignalHandlers() /llvm/lib/Support/Signals.cpp:49:0
#3 0x000000000347231a SignalHandler(int) /llvm/lib/Support/Unix/Signals.inc:252:0
#4 0x00007f52435a9390 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x11390)
#5 0x00007f524231c428 gsignal /build/glibc-t3gR2i/glibc-2.23/signal/../sysdeps/unix/sysv/linux/raise.c:54:0
#6 0x00007f524231e02a abort /build/glibc-t3gR2i/glibc-2.23/stdlib/abort.c:91:0
#7 0x00000000033e65d1 bindingsErrorHandler(void*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) /llvm/lib/Support/ErrorHandling.cpp:198:0
#8 0x00000000028d51f1 __static_initialization_and_destruction_0(int, int) /llvm/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp:5134:0
#9 0x00000000028d5e18 llvm_cbe::CWriter::outputLValue(llvm::Instruction*) /llvm/projects/llvm-cbe/lib/Target/CBackend/CBackend.h:262:0
#10 0x00000000028ddaa7 llvm::InstVisitor<llvm_cbe::CWriter, void>::visitFenceInst(llvm::FenceInst&) /llvm/include/llvm/IR/InstVisitor.h:185:0
#11 0x00000000028dac43 llvm::InstVisitor<llvm_cbe::CWriter, void>::visitFence(llvm::FenceInst&) /llvm/include/llvm/IR/Instruction.def:156:0
#12 0x00000000028d7cff llvm::InstVisitor<llvm_cbe::CWriter, void>::visit(llvm::Instruction&) /llvm/include/llvm/IR/Instruction.def:156:0
#13 0x00000000028d6fd9 llvm::InstVisitor<llvm_cbe::CWriter, void>::visit(llvm::Instruction*) /llvm/include/llvm/IR/InstVisitor.h:114:0
#14 0x00000000028c2d01 llvm_cbe::CWriter::writeInstComputationInline(llvm::Instruction&) /llvm/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp:1517:0
#15 0x00000000028cd124 llvm_cbe::CWriter::printBasicBlock(llvm::BasicBlock*) /llvm/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp:3389:0
#16 0x00000000028cce10 llvm_cbe::CWriter::printLoop(llvm::Loop*) /llvm/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp:3356:0
#17 0x00000000028ccc7a llvm_cbe::CWriter::printFunction(llvm::Function&) /llvm/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp:3340:0
#18 0x00000000028bc251 llvm_cbe::CWriter::runOnFunction(llvm::Function&) /llvm/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp:167:0
#19 0x0000000002ec22e2 llvm::FPPassManager::runOnFunction(llvm::Function&) /llvm/lib/IR/LegacyPassManager.cpp:1520:0
#20 0x0000000002ec247b llvm::FPPassManager::runOnModule(llvm::Module&) /llvm/lib/IR/LegacyPassManager.cpp:1541:0
#21 0x0000000002ec27f6 (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&) /llvm/lib/IR/LegacyPassManager.cpp:1597:0
#22 0x0000000002ec2f0b llvm::legacy::PassManagerImpl::run(llvm::Module&) /llvm/lib/IR/LegacyPassManager.cpp:1700:0
#23 0x0000000002ec3117 llvm::legacy::PassManager::run(llvm::Module&) /llvm/lib/IR/LegacyPassManager.cpp:1732:0
#24 0x000000000136ffb2 compileModule(char**, llvm::LLVMContext&) /llvm/projects/llvm-cbe/tools/llvm-cbe/llvm-cbe.cpp:353:0
#25 0x000000000136f35d main /llvm/projects/llvm-cbe/tools/llvm-cbe/llvm-cbe.cpp:203:0
#26 0x00007f5242307830 __libc_start_main /build/glibc-t3gR2i/glibc-2.23/csu/../csu/libc-start.c:325:0
#27 0x000000000136dba9 _start (../bin/llvm-cbe+0x136dba9)

`goto` Removal Algorithm

LLVM C back-end now generates a lot of gotos in the C code. These gotos can be removed by using certain transformations on the code. This can significantly improve the readability of the code.

In the following, I discuss a practical summary of the algorithm that was introduced in Taming Control Flow: A Structured Approach to Eliminating Goto Statements, and in the end, an implementation by @mbergin is given.

goto Removal Algorithm

It has 5 steps (keep reading if it has unknown words. Most of these are discussed later):

  • Collect a list of all goto and Target statements.
  • "Introduce one logical variable for each Target, initialize it to false, and insert another reinitialization to false at the point of the Target. These are required to make sure that the value of the logical variable is false on all paths except the path coming from the point at which the appropriate conditional test evaluated to true."
  • Convert unconditional gotos to conditional gotos: if (true) goto Target;
  • Eliminate Each goto one at a time: do movement transformations if needed to bring Target and goto to the same level (make them sibling). Then applying elimination transformation.
  • Remove unused labels

There are two main types of transformation that need to be applied:

Elimination Transformations:

when goto and Target are in the same level (siblings):

goto before target:

// ...

if (goto_condition) {
	goto Target;
}
statement_1;
Target: target_statement

    can be replaced with:

// ...

if (!goto_condition) {
	statement_1;
}
Target: target_statement

goto after target:

// ...

Target: target_statement;

if (goto_condition) {
	goto Target;
}

    can be replaced with:

// ...

do {
	Target: target_statement;
} while(goto_condition)

Movement Transformations:

when goto and Target are in different levels:

We should apply these transformations to bring the gotos to the same level of their Target. Then, we can use elimination transformations to remove them.

Each of these transformations moves goto up a level. So, it should be repeated until goto and its target are at the same level.

Outward-movement:

It doesn't matter if Target is before or after goto.

Move goto out of loop:

All types of loops are similar:

for (expression) {
    // ...
	if (goto_condition) {
		goto Target;
	}
    // ...
}
// ...
Target: target_statement;

    can be replaced with:

for (expression) {
    // ...
    goto_condition_var = goto_condition;
	if (goto_condition_var) {
		break;
	}
    // ...
}
if (goto_condition_var) {
    goto Target;
}
// ...
Target: target_statement;

Move goto out of if:

if (expression) {
    // ...

    if (goto_condition) {
        goto Target;
    }
    statement_1;
}
// ...
Target: target_statement;

    can be replaced with:

if (expression) {
    // ...

    goto_condition_var = goto_condition;
    if (!goto_condition_var) {
        statement_1;
    }
}
if (goto_condition_var) {
    goto Target;
}
// ...
Target: target_statement;

Move goto out of switch:

switch(i): {
	case 1:
        // ...

    	if (goto_condition) {
    		goto Target;
    	}

        // ...
    	break;

	case 2:
        // ...

    default:
        // ...
}
// ...
Target: target_statement;

    can be replaced with:

switch(i): {
	case 1:
        // ...

        goto_condition_var = goto_condition;
    	if (goto_condition_var) {
    		break;
    	}

        // ...
    	break;

    case 2:
        // ...

    default:
        // ...
}
if (goto_condition_var) {
    goto Target;
}
// ...
Target: target_statement;

Inward-movement:

We here assume that goto is before Target. If not, you should do go-lifting transformation before this step to bring goto before.

Move goto into a while-loop:

if (goto_condition) {
    goto Target;
}
statement_1;
while (loop_expression) {
    // ...
    Target: target_statement;
    // ...
}

    can be replaced with:

goto_condition_var = goto_condition;
if (!goto_condition_var) {
    statement_1;
}
while (goto_condition_var || loop_expression) {
    if (goto_condition_var) {
        goto Target;
    }
    // ...
    Target:
        goto_condition_var = false;
        target_statement;
    // ...
}

Move goto into a for-loop:

We convert for to an equivalent while and then transform it similar to the previous transformation:

if (goto_condition) {
    goto Target;
}
statement_1;
for (loop_expression) {
    // ...
    Target: target_statement;
    // ...
}

    can be replaced with:

goto_condition_var = goto_condition;
if (!goto_condition_var) {
    statement_1;
}
i = 0;
while (goto_condition_var || equivilant_loop_expression) {
    if (goto_condition_var) {
        goto Target;
    }
    // ...
    Target:
        goto_condition_var = false;
        target_statement;
    // ...

    i++; // loop counter
}

Move goto into a do-while-loop:

if (goto_condition) {
    goto Target;
}
statement_1;
do {
    // ...
    Target: target_statement;
    // ...
} while(loop_expression)

    can be replaced with:

goto_condition_var = goto_condition;
if (!goto_condition_var) {
    statement_1;
}
do {
    if (goto_condition_var) {
        goto Target;
    }
    // ...
    Target:
        goto_condition_var = false;
        target_statement;
    // ...
} while(loop_expression)

Move goto into a if:

  • Target is in the then part:
if (goto_condition) {
    goto Target;
}
statement_1;
if (if_expression) {
    // ...
    Target: target_statement;
    // ...
}

    can be replaced with:

goto_condition_var = goto_condition;
if (!goto_condition_var) {
    statement_1;
}
if (goto_condition_var || if_expression) {
    if (goto_condition_var) {
        goto Target;
    }
    // ...
    Target: target_statement;
    // ...
}
  • Target is in the else part:
if (goto_condition) {
    goto Target;
}
statement_1;
if (if_expression) {
	// ...

} else {
	if (goto_condition_var) {
			goto Target;
	}
	// ...
	Target: target_statement;
	// ...
}

    can be replaced with:

goto_condition_var = goto_condition;
if (!goto_condition_var) {
    statement_1;
}
if (!goto_condition_var && if_expression) {
    // ...

 else {
	 // ...
	 Target: target_statement;
	 // ...
}

Move goto into a switch:

if (goto_condition) {
    goto Target;
}
statement_1;
switch(i): {
	case 1:
        // ...
        Target: target_statement;
        // ...
    	break;

	case 2:
        // ...

    default:
        // ...
}

    can be replaced with:

goto_condition_var = goto_condition;
if (!goto_condition) {
    statement_1;
    t_switch = i;  // `i` is the original switch value
} else {
    t_switch = 1;  // `1` is the case that contains `Target`
}
switch(t_switch): {
	case 1:
        if (goto_condition_var) {
            goto Target;
        }
        // ...
        Target: target_statement;
        // ...
    	break;

	case 2:
        // ...

    default:
        // ...
}

Goto-lifting:

Inward movements require the goto to be before Target. In cases where Target is before goto, we can do goto-lifting transformation first and then apply inward movement.

The transformation is as follows:

// ...
// ...
Target: target_statement;
// ...
if (goto_condition) {
    goto Target;
}
// ...

    can be replaced with (we move the statement that contains Target):

int goto_condition_var = false;
// ...
do {
    if (goto_condition_var) {
        goto Target;
    }
    // ...
    Target: target_statement;
    // ...
    goto_condition_var = goto_condition;
} while (goto_condition_var);
// ...

Conflict of do-loop with outer break/continue:

There is a possibility that a do loop that we introduce has a break or continue that belongs to an outer loop or switch statement. To solve these cases, we use an extra check. For example:

while(true) {   // outer loop
    Target: target_statement;
    // ...
    if (outer_loop_break_condition) {
        break;
    }
    // ...
    if (goto_condition) {
        goto Target;
    }
    // ...
}

    should be replaced with the following for introducing do-while-loop instead of what we discussed before:

int do_break = 0;
while(true) {   // outer loop
    do {
        Target: target_statement;
        // ...
        if (outer_loop_break_condition) {
            do_break = 1;
            break;
        }
        // ...
        goto_condition_var = goto_condition;
    } while( goto_condition_var);
    if (do_break) {
        do_break = 0;
        break;
    }
    // ...
}

Optimizations

The cases that we can simplify our transformations:

  • goto next to Target:
// ...
if (goto_condition) {
    goto Target;
}
Target: target_statement;

    is reduced to:

// ...
Target: target_statement;
  • goto at the end of an if:
if (expression) {
	// ...
	if (goto_condition) {
   	 goto Target;
	}
}
// ...
Target: target_statement;

    is replaced with:

if (expression) {
	// ...
	goto_condition_var = goto_condition;
}
if (goto_condition_var) {
	 goto Target;
}
// ...
Target: target_statement;
  • goto right before a loop:
if (goto_condition) {
	 goto Target;
}
while (loop_expression) {
	//...
	Target: target_statement;
	//...
}

   
    is replaced with:

goto_condition_var = goto_condition;
while (goto_condition || loop_expression) {
	if (goto_condition_var) {
		 goto Target;
	}
	//...
	Target: target_statement;
	//...
}
  • goto right before switch
if (goto_condition) {
	 goto Target;
}
switch (i) {
	case 1:
		//...
		Target: target_statement;
		//...
	case 2:
		//...
	default:
		//...
}

    is replaced with:

goto_condition_var = goto_condition;
if (goto_condition_var) {
	i = 1; // `1` contains `Target`
}
switch (i) {
	case 1:
		if (goto_condition_var){
			goto Target;
		}
		//...
		Target: target_statement;
		//...
	case 2:
		//...
	default:
		//...
}
  • More than one goto associated with a Target inside the same while, if, switch or loop statement:

It would be preferable to insert only one conditional check per label. We can first check to see if the appropriate conditional has already been inserted, and avoid duplicating the code.

For example:

switch (i) {
	case 1:
		//...
	case 2:
		//...
		goto Target;
		break;
	case 3:
		//...
		goto Target;
}
Target: target_statement;

    can be replaced with:

switch (i) {
	case 1:
		//...
	case 2:
		//...
		goto_condition_var = true;
		break;
	case 3:
		//...
		goto_condition_var = true;
		break;
}
if (goto_condition_var){
	goto Target;
}
Target: target_statement;

Implementation:

This algorithm is implemented by @mbergin in https://github.com/mbergin/controlflow. The important functions of this program are:

  • ElimGotos/elimGotos : main function that removes any goto statements from stmts by rewriting them as conditionals and loops. It has a switch case and applies these functions:
    • movement functions:

    • IfStmt -> moveGotosOutOfIf: before: if body contains only gotos that refer to an outer label. after: if body contains no gotos

    • ForStmt -> moveGotosOutOfFor

    • RangeStmt -> moveGotosOutOfRange

    • SwitchStmt -> moveGotosOutOfSwitch

    • removal functions

      • BlockStmt -> elimSiblings: Eliminate conditional gotos from this block -> removeLabels: Remove the (now unused) labels
      • BranchStmt: Unconditional goto. Wrap in "if true { goto L }"

Here is the summary of the algorithm from the original paper:

References:

Related: #6

use memcpy instead of union casts?

Currently, the code uses cast-through-union to implement type-punning reinterpret (llvm BitCast). This was suggested by the C99 standard, but is no longer recommended or compliant with strict tbaa rules. The replacement now is to use memcpy (using a helper function, perhaps, similar to how we emit i128 and print intrinsic definitions).

Wrong declaration order in generated C (some types get used before their declaration)

The backend can generate wrong C code for some correct LLVM inputs:
(the initial bitcode was generated by the LDC frontend ; I reduced the testcase).

; issue #1
@C = external constant %MyStruct ; [#uses = 1]

%MyStruct = type
{
  %NestedStruct*,
  { i64, %MyStruct* }
}

%NestedStruct = type
{
  i64 (%Info*)*
}

%Info = type
{
  %ObjectTypeInfoVtable*,
  i8*
}

%ObjectTypeInfoVtable = type
{
  %MyStruct*,
  i1 (%Info*, i8*, i8*)*,
  i64 (%Info*)*
}

; issue #2
$A = comdat any
@A = linkonce_odr global [6 x i8]* @MyStringLiteral
@MyStringLiteral = private unnamed_addr constant [6 x i8] c"HELLO\00" ; [#uses = 1]

llvm-cbe processes it without error, although it creates an output file which implicitely forward-references some types:

$ llvm-cbe yo.ll -o=yo.c && gcc -w -c yo.c
yo.c:166:3: error: unknown type name ‘l_fptr_2’
   l_fptr_2* field2;
   ^
yo.c:215:57: error: ‘MyStringLiteral’ undeclared here (not in a function)
 struct l_array_6_uint8_t* A __attribute__((common)) = (&MyStringLiteral);
                                                         ^

Here's the problematic part from the generated C code (with some instrumentation traces):

/* Types Declarations */
// Contained types for:
 //%MyStruct = type { %NestedStruct*, { i64, %MyStruct* } }
// OK
// printFunctionDeclaration:
//i1 (%Info*, i8*, i8*)
typedef bool l_fptr_1(struct l_struct_Info*, uint8_t*, uint8_t*);
struct l_struct_ObjectTypeInfoVtable {
  struct l_struct_MyStruct* field0;
  l_fptr_1* field1;
  l_fptr_2* field2; // <---- compile error here, the type is defined below
};
struct l_struct_Info {
  struct l_struct_ObjectTypeInfoVtable* field0;
  uint8_t* field1;
};
// printFunctionDeclaration:
//i64 (%Info*)
typedef uint64_t l_fptr_2(struct l_struct_Info*);
struct l_struct_NestedStruct {
  l_fptr_2* field0;
};
struct l_unnamed_1 {
  uint64_t field0;
  struct l_struct_MyStruct* field1;
};
struct l_struct_MyStruct {
  struct l_struct_NestedStruct* field0;
  struct l_unnamed_1 field1;
};

Binaries?

Compiling llvm and then llvm-cbe takes a long time. Evan cloning the git project takes significant time. It would be nice to use Github Actions or something else to provide binaries.

I ran a GitHub action that uses the docker file:
https://github.com/aminya/llvm-cbe/actions
Let's see if this is successful.

Edit: the build failed.

process limits when building cbe?

I'm unable to build this project (which I'm hoping to use to improve the back-end code generated by a static binary translator for 8-bit arcade games - z80, 6502, 6809 etc):

...
[ 83%] Built target LLVMX86CodeGen
[ 84%] Built target LLVMX86AsmParser
[ 84%] Built target LLVMX86Disassembler
[ 84%] Built target LLVMX86AsmPrinter
...
[ 88%] Built target yaml-bench
[ 88%] Built target LTO_exports
[ 88%] Linking CXX shared library ../../lib/libLTO.so
/lib/i386-linux-gnu/libpthread.so.0: error adding symbols: Memory exhausted
collect2: error: ld returned 1 exit status
tools/lto/CMakeFiles/LTO.dir/build.make:278: recipe for target 'lib/libLTO.so.8' failed
make[2]: *** [lib/libLTO.so.8] Error 1
CMakeFiles/Makefile2:20744: recipe for target 'tools/lto/CMakeFiles/LTO.dir/all' failed
make[1]: *** [tools/lto/CMakeFiles/LTO.dir/all] Error 2
Makefile:151: recipe for target 'all' failed
make: *** [all] Error 2

I have a reasonable amount of RAM on this machine:

top - 18:03:41 up 8 days, 18:50,  4 users,  load average: 0.17, 0.31, 0.24
Tasks: 251 total,   1 running, 201 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3.3 us,  3.6 sy,  0.0 ni, 92.8 id,  0.3 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  5671944 total,  3404616 free,   705636 used,  1561692 buff/cache
KiB Swap:  5743612 total,  5743612 free,        0 used.  4452396 avail Mem

Do you think that the failure to build is from a lack of physical memory or do you think there is some process limit that I could tweak that would allow this to build, even if it takes a bit longer?

gtoal@linux:~/src/llvm-project/llvm/build$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 43906
max locked memory       (kbytes, -l) 16384
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 43906
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Alias shouldn't be compiled as a new C variable.

Take the following code as an example, the LLVM bitcode
@jl_tls_offset = alias i64, i64* @jl_tls_offset.real
is now generated as
uint64_t *jl_tls_offset = (&jl_tls_offset_OC_real);,
which is not appropriate.

jl_tls_offset should be the alias of jl_tls_offset_OC_real, which means they have the same address. But in the generated C code, jl_tls_offset has its own address.

As a result, after we compile the generated C code into a Julia system image, and load it during Julia initialization, in jl_load_sysimg_so(void) function
jl_dlsym(jl_sysimg_handle, "jl_tls_offset", (void **)&tls_offset_idx, 1);,
tls_offset_idx wrongly stores the address of jl_tls_offset, but it actually should store the address of jl_tls_offset_OC_real.

So the alias should be compiled to something like:
extern uint64_t jl_tls_offset __attribute__((alias ("jl_tls_offset_OC_real")));

Can llvm-cbe output optimized arithmetic expressions?

I'm asking this question because I don't have LLVM 8.0 built (I have 7.0.0 and I'm planning to either move to 9.0.1 or 10.0.0)... building LLVM takes time and effort (I have done it several times, and I'm getting ready for the next one), so let me ask this question even if I'm not able to build llvm-cbe at this time:

Can I get the C source code after the optimization of arithmetic expressions takes place? I suppose llvm-cbe converts from IR, but what I don't know is when are arithmetic expressions optimized within the LLVM pipeline: are they optimized before llvm-cbe comes into play, or after?

For example, if LLVM decides to use the shift operator instead of multiplications by powers of 2... would that be seen in the C source generated by llvm-cbe?

I'm fearing that arithmetic optimization might take place when the scheduler comes into place (and that task belongs to the backend...).

The reason for my fear is: how does the optimizer know if for example additions are faster than multiplications, or multiplications faster than divisions, or shifts faster than multiplications? That depends on the CPU...

I'm trying to optimize C++ code written with custom integer types and custom float types (with operators implemented in software). But I'm not finding any solution for doing this, and I was thinking that source-to-source transformations would be a solution, thus I thought in llvm-cbe

LLVM 10 build errors

Build with system llvm 10.0:
/tmp/.private/lav/RPM/BUILD/llvm-cbe-0.0.1/lib/Target/CBackend/TargetInfo/../CTargetMachine.h:38:20: error: no matching function for call to ‘llvm::TargetSubtargetInfo::TargetSubtargetInfo(const llvm::Triple&, llvm::StringRef&, llvm::StringRef&, llvm::ArrayRefllvm::SubtargetFeatureKV, llvm::ArrayRefllvm::SubtargetFeatureKV, std::nullptr_t, std::nullptr_t, std::nullptr_t, std::nullptr_t, std::nullptr_t, std::nullptr_t, std::nullptr_t)’
38 | Lowering(TM) {}

Calling Conventions

Currently llvm-cbe only supports standard C Calls, X86_StdCall, X86_FastCall, X86_ThisCall.
This prevents even the compilation of simple programs, because clang likes to generate calls with the "fast" calling convention. (This is different from X86_FastCall).
The other problem is that it seems to be impossible to implement some llvm supported calling conventions in C code.
Personally i would emit all unknown calling conventions as standard C call and emit a warning. (Only in Debug builds or always?)

http://llvm.org/doxygen/namespacellvm_1_1CallingConv.html
http://llvm.org/docs/LangRef.html#calling-conventions

Build/test Instruction

First: This is great and I appreciate the instructions

But: I had two problems

Following the build instructions on raspbian:
**cd ../build **fails because there is no such directory
I mkdir'd build inside llvm-cbe and cd'd to it and the rest worked as written

Following the test instructions:
$ $(HOME)/llvm/build/bin/llvm-cbe main.ll fails because there is no build/bin directory.
I found the binary in ~/llvm-project/llvm/projects/llvm-cbe/build/tools/llvm-cbe/ and it works fine

perhaps the second problem is related to the first and both are caused by my ignorance. Anyway, thanks again, looking forward to playing with it.

fneg instruction unsupported

When I tried to decompile the bitcode generated by following source code:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
	float state = -12345.12345;
	state = -state;
}

I have the unsupported instruction error as followed, which should correspond to "state = -state":

unsupported LLVM instruction in:   %7 = fneg float %6 @ 
unsupported LLVM instruction
UNREACHABLE executed at /home/muqi/decompile_tool/llvm-cbe/lib/Target/CBackend/CBackend.cpp:5351!
/usr/lib/llvm-10/lib/libLLVM-10.so.1(_ZN4llvm3sys15PrintStackTraceERNS_11raw_ostreamE+0x1f)[0x7f21b35b8c3f]
/usr/lib/llvm-10/lib/libLLVM-10.so.1(_ZN4llvm3sys17RunSignalHandlersEv+0x22)[0x7f21b35b6ed2]
/usr/lib/llvm-10/lib/libLLVM-10.so.1(+0x978205)[0x7f21b35b9205]
/lib/x86_64-linux-gnu/libc.so.6(+0x3f040)[0x7f21b22ee040]
/lib/x86_64-linux-gnu/libc.so.6(gsignal+0xc7)[0x7f21b22edfb7]
/lib/x86_64-linux-gnu/libc.so.6(abort+0x141)[0x7f21b22ef921]
/usr/lib/llvm-10/lib/libLLVM-10.so.1(+0x8d6231)[0x7f21b3517231]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x5aef9)[0x556040017ef9]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x661a2)[0x5560400231a2]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x7f95d)[0x55604003c95d]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x79345)[0x556040036345]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x72c5b)[0x55604002fc5b]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x6bfab)[0x556040028fab]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x6a66d)[0x55604002766d]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x48f49)[0x556040005f49]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x49031)[0x556040006031]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x49158)[0x556040006158]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x59e17)[0x556040016e17]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x72f79)[0x55604002ff79]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x6c1a3)[0x5560400291a3]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x6a66d)[0x55604002766d]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x48f49)[0x556040005f49]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x52cdb)[0x55604000fcdb]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x52737)[0x55604000f737]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x420d1)[0x55603ffff0d1]
/usr/lib/llvm-10/lib/libLLVM-10.so.1(_ZN4llvm13FPPassManager13runOnFunctionERNS_8FunctionE+0x466)[0x7f21b36bf866]
/usr/lib/llvm-10/lib/libLLVM-10.so.1(_ZN4llvm13FPPassManager11runOnModuleERNS_6ModuleE+0x33)[0x7f21b36bfae3]
/usr/lib/llvm-10/lib/libLLVM-10.so.1(_ZN4llvm6legacy15PassManagerImpl3runERNS_6ModuleE+0x3c0)[0x7f21b36bff90]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x190e1)[0x55603ffd60e1]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x18545)[0x55603ffd5545]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7)[0x7f21b22d0bf7]
/home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe(+0x169ea)[0x55603ffd39ea]
Stack dump:
0.	Program arguments: /home/muqi/decompile_tool/llvm-cbe/build/tools/llvm-cbe/llvm-cbe ./test_muqi/generatedll/test.ll --o ./test_muqi/generatedc/test.c 
1.	Running pass 'Function Pass Manager' on module './test_muqi/generatedll/test.ll'.
2.	Running pass 'C backend' on function '@main'
Aborted (core dumped)
Traceback (most recent call last):
  File "generate_symbolic.py", line 145, in <module>
    main()
  File "generate_symbolic.py", line 115, in main
    modify_main(filepath_generatedc)
  File "generate_symbolic.py", line 40, in modify_main
    fin = open(filepath,'r')
FileNotFoundError: [Errno 2] No such file or directory: './test_muqi/generatedc/test.c'

The bitcode is generated by: clang-10 -emit-llvm -c -O0
And assembly language is by: llvm-dis-10
My llvm-cbe version is:

LLVM (http://llvm.org/):
  LLVM version 10.0.0
  
  Optimized build.
  Default target: x86_64-pc-linux-gnu
  Host CPU: skylake

  Registered Targets:
    aarch64    - AArch64 (little endian)
    aarch64_32 - AArch64 (little endian ILP32)
    aarch64_be - AArch64 (big endian)
    amdgcn     - AMD GCN GPUs
    arm        - ARM
    arm64      - ARM64 (little endian)
    arm64_32   - ARM64 (little endian ILP32)
    armeb      - ARM (big endian)
    avr        - Atmel AVR Microcontroller
    bpf        - BPF (host endian)
    bpfeb      - BPF (big endian)
    bpfel      - BPF (little endian)
    c          - C backend
    hexagon    - Hexagon
    lanai      - Lanai
    mips       - MIPS (32-bit big endian)
    mips64     - MIPS (64-bit big endian)
    mips64el   - MIPS (64-bit little endian)
    mipsel     - MIPS (32-bit little endian)
    msp430     - MSP430 [experimental]
    nvptx      - NVIDIA PTX 32-bit
    nvptx64    - NVIDIA PTX 64-bit
    ppc32      - PowerPC 32
    ppc64      - PowerPC 64
    ppc64le    - PowerPC 64 LE
    r600       - AMD GPUs HD2XXX-HD6XXX
    riscv32    - 32-bit RISC-V
    riscv64    - 64-bit RISC-V
    sparc      - Sparc
    sparcel    - Sparc LE
    sparcv9    - Sparc V9
    systemz    - SystemZ
    thumb      - Thumb
    thumbeb    - Thumb (big endian)
    wasm32     - WebAssembly 32-bit
    wasm64     - WebAssembly 64-bit
    x86        - 32-bit X86: Pentium-Pro and above
    x86-64     - 64-bit X86: EM64T and AMD64
    xcore      - XCore

Floating point constants get truncated (or messed up)

The simple C program below:

#include <stdio.h>
#include <stdint.h>

static float my_constant = -1.86673462f;
static uint64_t my_ref_const_int = 0xBFFDDE2520000000; // Value from LLVM IR

int main(void) {
  float my_ref_const = (float)(*((double*)&my_ref_const_int));
  printf("my_constant = %.10f (ref = %.10f, diff = %.10f)\n", my_constant, my_ref_const, my_constant - my_ref_const);
  return 0;
}

Yields result 1:

> clang-10 -o test_c main.c
> ./test_c
my_constant = -1.8667346239 (ref = -1.8667346239, diff = 0.0000000000)

and result 2 (llvm-cbe):

> clang-10 -S -emit-llvm -o main.ll main.c && llvm-cbe -o main_cbe.c main.ll && clang-10 -o test_cbe main_cbe.c
> ./test_cbe
my_constant = -1.8667349815 (ref = -1.8667346239, diff = -0.0000003576)

Step 2 not working

It says to make in llvm directory but when I do, I get this error
Makefile:44: Makefile.config: No such file or directory
Makefile:151: /Makefile.rules: No such file or directory
make: *** No rule to make target '/Makefile.rules'. Stop.

RFC: LLVM version support policy

Please don't break prior LLVM versions in the process (talking about that second commit, perhaps using an #ifdef there?).

Originally posted by @woachk in #55 (comment)

My unannounced personal policy (and thus effectively the de facto repo policy as primary maintainer) has been to only support the latest released version of LLVM on head of repo here. My rationale is that supporting multiple versions is additional work for the rare contributor to a repository that already sees little enough activity, and usually just drive-by PRs (in my impression). Additionally, since there's very few changes other than maintaining version compatibility, anyone using an older version can just checkout the last commit to work on that branch and be pretty well content. If someone had a strong interest in maintaining one version for longer, I'd happily create a branch for them—this has not come up yet in practice however (or, to be more accurate, I haven't received communication of such an interest).

I am proposing here making this an official documented policy (with mention on the README page), but first wanted to leave this open for RFC for an extended comment period, as it's not solely my decision—the ad hoc community should ultimately decide. But even as an ultra-low-activity repo, I think it's important to be up-front about expectations.

Compact name for tmp variables

Instead of using llvm_cbe_tmp__34 we could just use v__34.

This makes the code nicer to look at. Especially when there are many of these tmp variables.

Related to #6

Fails for simple program with destructor

Fails for simple program with destructor, attached with txt exention. To reproduce:
clang++ -emit-llvm -S main2.cpp
llvm-cbe main2.ll
->
UNREACHABLE executed at CBackend.cpp:380!
0 llvm-cbe 0x0000000001d211fe llvm::sys::PrintStackTrace(_IO_FILE*) + 53
1 llvm-cbe 0x0000000001d2148e
2 llvm-cbe 0x0000000001d20d67
3 libpthread.so.0 0x00007f7becc57390
4 libc.so.6 0x00007f7bebe0c428 gsignal + 56
5 libc.so.6 0x00007f7bebe0e02a abort + 362
6 llvm-cbe 0x0000000001d0673d
7 llvm-cbe 0x0000000000aae7c2
8 llvm-cbe 0x0000000000ac2171
9 llvm-cbe 0x0000000000ac1ae5
10 llvm-cbe 0x0000000000ac0fcf
11 llvm-cbe 0x0000000000ab3b42
12 llvm-cbe 0x0000000000abac24
13 llvm-cbe 0x0000000000ab97f2
14 llvm-cbe 0x0000000000aae1fd
15 llvm-cbe 0x0000000001c07c9c llvm::FPPassManager::runOnFunction(llvm::Function&) + 330
16 llvm-cbe 0x0000000001c07e12 llvm::FPPassManager::runOnModule(llvm::Module&) + 120
17 llvm-cbe 0x0000000001c08112
18 llvm-cbe 0x0000000001c08796 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 262
19 llvm-cbe 0x0000000001c08983 llvm::legacy::PassManager::run(llvm::Module&) + 39
20 llvm-cbe 0x0000000000a9854d
21 llvm-cbe 0x0000000000a9762b main + 271
22 libc.so.6 0x00007f7bebdf7830 __libc_start_main + 240
23 llvm-cbe 0x0000000000a96ee9 _start + 41
Stack dump:
0. Program arguments: llvm-cbe main2.ll

  1. Running pass 'Function Pass Manager' on module 'main2.ll'.
  2. Running pass 'C backend' on function '@main'
    Aborted (core dumped)

main2.txt

Only the old LLVM license is used

LLVM moved to a new license a while ago. This backend is still using the old one.

For new contributions, would it make sense to dual-license them for easier reuse in other LLVM code?

For the existing code, I assume it can't just be marked as using the new license, since it's based on upstream LLVM code that got deleted and thus wouldn't have been relicensed, right?

return type of 'main' is not 'int'

With even the simplest code:

#include <stdio.h>
int main()
{
  printf("Hello World!\n");
  return 0;
}

I get the following warning:

src/CMakeFiles/llvm_cbe_poc.dir/main.c:802:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
uint32_t main(void) __ATTRIBUTELIST__((noinline));
^

but the LLVM file clearly states:

; Function Attrs: noinline norecurse optnone uwtable
define dso_local i32 @main() #0 { 
...
}

How is the i32 converted to uint32_t ?

Problem using CNL C++

I have a problem using CNL (https://github.com/johnmcfarlane/cnl) where the result is different between:

  1. C++ -O3 -> LLVM -> C (via llvm-cbe) -> Binary (errors)
  2. C++ -O3 -> LLVM -> ASM (via llc) -> Binary (works)

Running without -O3 makes both approaches above work.

If you'd like, I can setup a unit test for this repo to show the problem?

Edit: Ok, this poses a problem as I have no idea how to get unittest binaries. Added LLVM_INCLUDE_TESTS=ON when configuring, but that doesn't help.

BUG: wrong compilation

Hi,
I had bug after translating code. my C code. File "test.c":

struct A{
	int arr[1];
};
void test_fn(struct A * p){
	p->arr[0] = ((struct A *)9)->arr[0];
}

It is translated by LLVM-CBE:

struct l_array_1_uint32_t {
  uint32_t array[1];
};
struct l_struct_struct_OC_A {
  struct l_array_1_uint32_t field0;
};
void test_fn(struct l_struct_struct_OC_A* llvm_cbe_tmp__1) {
  struct l_struct_struct_OC_A* llvm_cbe_tmp__2;    /* Address-exposed local */
  uint32_t llvm_cbe_tmp__3;
  struct l_struct_struct_OC_A* llvm_cbe_tmp__4;

  llvm_cbe_tmp__2 = llvm_cbe_tmp__1;
  llvm_cbe_tmp__3 = *((&((struct l_struct_struct_OC_A*)(uintptr_t)UINT64_C(9))->field0[((int64_t)UINT64_C(0))]));
  llvm_cbe_tmp__4 = llvm_cbe_tmp__2;
  *((&(*((&llvm_cbe_tmp__4->field0))).array[((int64_t)UINT64_C(0))])) = llvm_cbe_tmp__3;
}

`
And Then compile error:

$ clang -S -emit-llvm test.c && llvm-cbe test.ll && clang -c test.cbe.c
test.cbe.c:53:87: error: subscripted value is not an array, pointer, or vector
var_name_tmp__3 = ((&((struct l_struct_struct_OC_A)(uintptr_t)UINT64_C(9))->field0[((int64_t)UINT64_C(0))]));

I think that generating code should be :
var_name_tmp__3 = *((&((struct l_struct_struct_OC_A*)(uintptr_t)UINT64_C(9))->field0.array[((int64_t)UINT64_C(0))]));

And this code has tested. It's ok.
I guess LLVM-CBE misses the operation ".array" for the test case

Fix indentation by running a code beautifier on the generated c file

The current generated c file has wrong indentations. Running a code beautifier easily solves this issue, reveals the logic of the code, and makes the code nicer overall.

Related to #6

Here is an example:

using https://codebeautify.org/c-formatter-beautifier and by replacing llvm_cbe_tmp with v
After:

/* Provide Declarations */ #include <stdarg.h>

#include <setjmp.h>

#include <limits.h>

#include <stdint.h>

#include <math.h>

#ifndef __cplusplus
typedef unsigned char bool;
#endif

#ifndef _MSC_VER
#define __forceinline __attribute__((always_inline)) inline
#endif

#if defined(__GNUC__)
#define __ATTRIBUTELIST__(x) __attribute__(x)
#else
#define __ATTRIBUTELIST__(x)
#endif

#ifdef _MSC_VER /* Can only support "linkonce" vars with GCC */
#define __attribute__(X)
#endif

#ifdef _MSC_VER
#define __MSALIGN__(X) __declspec(align(X))
#else
#define __MSALIGN__(X)
#endif

/* Global Declarations */

/* Types Declarations */

/* Function definitions */

/* Types Definitions */
struct l_array_26_uint8_t {
  uint8_t array[26];
};
struct l_array_3_uint8_t {
  uint8_t array[3];
};
struct l_array_19_uint8_t {
  uint8_t array[19];
};
struct l_array_33_uint8_t {
  uint8_t array[33];
};
struct l_array_4_uint8_t {
  uint8_t array[4];
};
struct l_array_100_uint32_t {
  uint32_t array[100];
};

/* External Global Variable Declarations */

/* Function Declarations */
uint32_t main(void) __ATTRIBUTELIST__((noinline, nothrow));
uint32_t printf(uint8_t * , ...);
uint32_t __isoc99_scanf(uint8_t * , ...);

/* Global Variable Definitions and Initialization */
static struct l_array_26_uint8_t _OC_str = {
  "Enter number of elements\n"
};
static struct l_array_3_uint8_t _OC_str_OC_1 = {
  "%d"
};
static struct l_array_19_uint8_t _OC_str_OC_2 = {
  "Enter %d integers\n"
};
static struct l_array_33_uint8_t _OC_str_OC_3 = {
  "Sorted list in ascending order:\n"
};
static struct l_array_4_uint8_t _OC_str_OC_4 = {
  "%d\n"
};

/* LLVM Intrinsic Builtin Function Bodies */
static __forceinline uint32_t llvm_add_u32(uint32_t a, uint32_t b) {
  uint32_t r = a + b;
  return r;
}
static __forceinline uint32_t llvm_sub_u32(uint32_t a, uint32_t b) {
  uint32_t r = a - b;
  return r;
}

/* Function Bodies */

uint32_t main(void) {
  uint32_t llvm_cbe_tmp__1; /* Address-exposed local */
  __MSALIGN__(16) struct l_array_100_uint32_t llvm_cbe_tmp__2 __attribute__((aligned(16))); /* Address-exposed local */
  uint32_t llvm_cbe_tmp__3; /* Address-exposed local */
  uint32_t llvm_cbe_tmp__4; /* Address-exposed local */
  uint32_t llvm_cbe_tmp__5; /* Address-exposed local */
  uint32_t llvm_cbe_tmp__6; /* Address-exposed local */
  uint32_t llvm_cbe_tmp__7; /* Address-exposed local */
  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__12;
  uint32_t llvm_cbe_tmp__13;
  uint32_t llvm_cbe_tmp__14;
  uint32_t llvm_cbe_tmp__15;
  uint32_t llvm_cbe_tmp__16;
  uint32_t llvm_cbe_tmp__17;
  uint32_t llvm_cbe_tmp__18;
  uint32_t llvm_cbe_tmp__19;
  uint32_t llvm_cbe_tmp__20;
  uint32_t llvm_cbe_tmp__21;
  uint32_t llvm_cbe_tmp__22;
  uint32_t llvm_cbe_tmp__23;
  uint32_t llvm_cbe_tmp__24;
  uint32_t llvm_cbe_tmp__25;
  uint32_t llvm_cbe_tmp__26;
  uint32_t llvm_cbe_tmp__27;
  uint32_t llvm_cbe_tmp__28;
  uint32_t llvm_cbe_tmp__29;
  uint32_t llvm_cbe_tmp__30;
  uint32_t llvm_cbe_tmp__31;
  uint32_t llvm_cbe_tmp__32;
  uint32_t llvm_cbe_tmp__33;
  uint32_t llvm_cbe_tmp__34;
  uint32_t llvm_cbe_tmp__35;
  uint32_t llvm_cbe_tmp__36;
  uint32_t llvm_cbe_tmp__37;
  uint32_t llvm_cbe_tmp__38;
  uint32_t llvm_cbe_tmp__39;
  uint32_t llvm_cbe_tmp__40;
  uint32_t llvm_cbe_tmp__41;
  uint32_t llvm_cbe_tmp__42;
  uint32_t llvm_cbe_tmp__43;
  uint32_t llvm_cbe_tmp__44;
  uint32_t llvm_cbe_tmp__45;

  llvm_cbe_tmp__1 = 0;
  #line 4 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c";;;;;;
  #line 6 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__8 = printf((( & _OC_str.array[((int64_t) UINT64_C(0))])));
  #line 7 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__9 = __isoc99_scanf((( & _OC_str_OC_1.array[((int64_t) UINT64_C(0))])), ( & llvm_cbe_tmp__3));
  #line 9 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__10 = llvm_cbe_tmp__3;
  llvm_cbe_tmp__11 = printf((( & _OC_str_OC_2.array[((int64_t) UINT64_C(0))])), llvm_cbe_tmp__10);
  #line 11 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__4 = 0;
  goto llvm_cbe_tmp__46;

  do {
    /* Syntactic loop '' to make GCC happy */
    llvm_cbe_tmp__46: llvm_cbe_tmp__12 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__13 = llvm_cbe_tmp__3;
    if ((((((int32_t) llvm_cbe_tmp__12) < ((int32_t) llvm_cbe_tmp__13)) & 1))) {
      goto llvm_cbe_tmp__47;
    } else {
      goto llvm_cbe_tmp__48;
    }

    llvm_cbe_tmp__47: #line 12 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__14 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__15 = __isoc99_scanf((( & _OC_str_OC_1.array[((int64_t) UINT64_C(0))])), (( & llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t) llvm_cbe_tmp__14)))])));
    goto llvm_cbe_tmp__49;

    llvm_cbe_tmp__49: #line 11 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__16 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__4 = (llvm_add_u32(llvm_cbe_tmp__16, 1));
    goto llvm_cbe_tmp__46;

  } while (1); /* end of syntactic loop '' */
  llvm_cbe_tmp__48:
    #line 14 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__4 = 0;
  goto llvm_cbe_tmp__50;

  do {
    /* Syntactic loop '' to make GCC happy */
    llvm_cbe_tmp__50: llvm_cbe_tmp__17 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__18 = llvm_cbe_tmp__3;
    if ((((((int32_t) llvm_cbe_tmp__17) < ((int32_t)(llvm_sub_u32(llvm_cbe_tmp__18, 1)))) & 1))) {
      goto llvm_cbe_tmp__51;
    } else {
      goto llvm_cbe_tmp__52;
    }

    llvm_cbe_tmp__51: #line 15 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__19 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__6 = llvm_cbe_tmp__19;
    #line 17 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__20 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__5 = (llvm_add_u32(llvm_cbe_tmp__20, 1));
    goto llvm_cbe_tmp__53;

    do {
      /* Syntactic loop '' to make GCC happy */
      llvm_cbe_tmp__53: llvm_cbe_tmp__21 = llvm_cbe_tmp__5;
      llvm_cbe_tmp__22 = llvm_cbe_tmp__3;
      if ((((((int32_t) llvm_cbe_tmp__21) < ((int32_t) llvm_cbe_tmp__22)) & 1))) {
        goto llvm_cbe_tmp__54;
      } else {
        goto llvm_cbe_tmp__55;
      }

      llvm_cbe_tmp__54: #line 18 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
      llvm_cbe_tmp__23 = llvm_cbe_tmp__6;
      llvm_cbe_tmp__24 = * (( & llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t) llvm_cbe_tmp__23)))]));
      llvm_cbe_tmp__25 = llvm_cbe_tmp__5;
      llvm_cbe_tmp__26 = * (( & llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t) llvm_cbe_tmp__25)))]));
      if ((((((int32_t) llvm_cbe_tmp__24) > ((int32_t) llvm_cbe_tmp__26)) & 1))) {
        goto llvm_cbe_tmp__56;
      } else {
        goto llvm_cbe_tmp__57;
      }

      llvm_cbe_tmp__56: #line 19 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
      llvm_cbe_tmp__27 = llvm_cbe_tmp__5;
      llvm_cbe_tmp__6 = llvm_cbe_tmp__27;
      goto llvm_cbe_tmp__57;

      llvm_cbe_tmp__57: goto llvm_cbe_tmp__58;

      llvm_cbe_tmp__58: #line 17 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
      llvm_cbe_tmp__28 = llvm_cbe_tmp__5;
      llvm_cbe_tmp__5 = (llvm_add_u32(llvm_cbe_tmp__28, 1));
      goto llvm_cbe_tmp__53;

    } while (1); /* end of syntactic loop '' */
    llvm_cbe_tmp__55: #line 21 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__29 = llvm_cbe_tmp__6;
    llvm_cbe_tmp__30 = llvm_cbe_tmp__4;
    if ((((llvm_cbe_tmp__29 != llvm_cbe_tmp__30) & 1))) {
      goto llvm_cbe_tmp__59;
    } else {
      goto llvm_cbe_tmp__60;
    }

    llvm_cbe_tmp__59: #line 22 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__31 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__32 = * (( & llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t) llvm_cbe_tmp__31)))]));
    llvm_cbe_tmp__7 = llvm_cbe_tmp__32;
    #line 23 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__33 = llvm_cbe_tmp__6;
    llvm_cbe_tmp__34 = * (( & llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t) llvm_cbe_tmp__33)))]));
    llvm_cbe_tmp__35 = llvm_cbe_tmp__4;
    *(( & llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t) llvm_cbe_tmp__35)))])) = llvm_cbe_tmp__34;
    #line 24 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__36 = llvm_cbe_tmp__7;
    llvm_cbe_tmp__37 = llvm_cbe_tmp__6;
    *(( & llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t) llvm_cbe_tmp__37)))])) = llvm_cbe_tmp__36;
    goto llvm_cbe_tmp__60;

    llvm_cbe_tmp__60: goto llvm_cbe_tmp__61;

    llvm_cbe_tmp__61: #line 14 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__38 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__4 = (llvm_add_u32(llvm_cbe_tmp__38, 1));
    goto llvm_cbe_tmp__50;

  } while (1); /* end of syntactic loop '' */
  llvm_cbe_tmp__52:
    #line 28 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__39 = printf((( & _OC_str_OC_3.array[((int64_t) UINT64_C(0))])));
  #line 30 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__4 = 0;
  goto llvm_cbe_tmp__62;

  do {
    /* Syntactic loop '' to make GCC happy */
    llvm_cbe_tmp__62: llvm_cbe_tmp__40 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__41 = llvm_cbe_tmp__3;
    if ((((((int32_t) llvm_cbe_tmp__40) < ((int32_t) llvm_cbe_tmp__41)) & 1))) {
      goto llvm_cbe_tmp__63;
    } else {
      goto llvm_cbe_tmp__64;
    }

    llvm_cbe_tmp__63: #line 31 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__42 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__43 = * (( & llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t) llvm_cbe_tmp__42)))]));
    llvm_cbe_tmp__44 = printf((( & _OC_str_OC_4.array[((int64_t) UINT64_C(0))])), llvm_cbe_tmp__43);
    goto llvm_cbe_tmp__65;

    llvm_cbe_tmp__65: #line 30 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
    llvm_cbe_tmp__45 = llvm_cbe_tmp__4;
    llvm_cbe_tmp__4 = (llvm_add_u32(llvm_cbe_tmp__45, 1));
    goto llvm_cbe_tmp__62;

  } while (1); /* end of syntactic loop '' */
  llvm_cbe_tmp__64:
    return 0;
}

Before:

/* Provide Declarations */
#include <stdarg.h>
#include <setjmp.h>
#include <limits.h>
#include <stdint.h>
#include <math.h>
#ifndef __cplusplus
typedef unsigned char bool;
#endif

#ifndef _MSC_VER
#define __forceinline __attribute__((always_inline)) inline
#endif

#if defined(__GNUC__)
#define  __ATTRIBUTELIST__(x) __attribute__(x)
#else
#define  __ATTRIBUTELIST__(x)  
#endif

#ifdef _MSC_VER  /* Can only support "linkonce" vars with GCC */
#define __attribute__(X)
#endif

#ifdef _MSC_VER
#define __MSALIGN__(X) __declspec(align(X))
#else
#define __MSALIGN__(X)
#endif



/* Global Declarations */

/* Types Declarations */

/* Function definitions */

/* Types Definitions */
struct l_array_26_uint8_t {
  uint8_t array[26];
};
struct l_array_3_uint8_t {
  uint8_t array[3];
};
struct l_array_19_uint8_t {
  uint8_t array[19];
};
struct l_array_33_uint8_t {
  uint8_t array[33];
};
struct l_array_4_uint8_t {
  uint8_t array[4];
};
struct l_array_100_uint32_t {
  uint32_t array[100];
};

/* External Global Variable Declarations */

/* Function Declarations */
uint32_t main(void) __ATTRIBUTELIST__((noinline, nothrow));
uint32_t printf(uint8_t*, ...);
uint32_t __isoc99_scanf(uint8_t*, ...);


/* Global Variable Definitions and Initialization */
static struct l_array_26_uint8_t _OC_str = { "Enter number of elements\n" };
static struct l_array_3_uint8_t _OC_str_OC_1 = { "%d" };
static struct l_array_19_uint8_t _OC_str_OC_2 = { "Enter %d integers\n" };
static struct l_array_33_uint8_t _OC_str_OC_3 = { "Sorted list in ascending order:\n" };
static struct l_array_4_uint8_t _OC_str_OC_4 = { "%d\n" };


/* LLVM Intrinsic Builtin Function Bodies */
static __forceinline uint32_t llvm_add_u32(uint32_t a, uint32_t b) {
  uint32_t r = a + b;
  return r;
}
static __forceinline uint32_t llvm_sub_u32(uint32_t a, uint32_t b) {
  uint32_t r = a - b;
  return r;
}


/* Function Bodies */

uint32_t main(void) {
  uint32_t llvm_cbe_tmp__1;    /* Address-exposed local */
  __MSALIGN__(16) struct l_array_100_uint32_t llvm_cbe_tmp__2 __attribute__((aligned(16)));    /* Address-exposed local */
  uint32_t llvm_cbe_tmp__3;    /* Address-exposed local */
  uint32_t llvm_cbe_tmp__4;    /* Address-exposed local */
  uint32_t llvm_cbe_tmp__5;    /* Address-exposed local */
  uint32_t llvm_cbe_tmp__6;    /* Address-exposed local */
  uint32_t llvm_cbe_tmp__7;    /* Address-exposed local */
  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__12;
  uint32_t llvm_cbe_tmp__13;
  uint32_t llvm_cbe_tmp__14;
  uint32_t llvm_cbe_tmp__15;
  uint32_t llvm_cbe_tmp__16;
  uint32_t llvm_cbe_tmp__17;
  uint32_t llvm_cbe_tmp__18;
  uint32_t llvm_cbe_tmp__19;
  uint32_t llvm_cbe_tmp__20;
  uint32_t llvm_cbe_tmp__21;
  uint32_t llvm_cbe_tmp__22;
  uint32_t llvm_cbe_tmp__23;
  uint32_t llvm_cbe_tmp__24;
  uint32_t llvm_cbe_tmp__25;
  uint32_t llvm_cbe_tmp__26;
  uint32_t llvm_cbe_tmp__27;
  uint32_t llvm_cbe_tmp__28;
  uint32_t llvm_cbe_tmp__29;
  uint32_t llvm_cbe_tmp__30;
  uint32_t llvm_cbe_tmp__31;
  uint32_t llvm_cbe_tmp__32;
  uint32_t llvm_cbe_tmp__33;
  uint32_t llvm_cbe_tmp__34;
  uint32_t llvm_cbe_tmp__35;
  uint32_t llvm_cbe_tmp__36;
  uint32_t llvm_cbe_tmp__37;
  uint32_t llvm_cbe_tmp__38;
  uint32_t llvm_cbe_tmp__39;
  uint32_t llvm_cbe_tmp__40;
  uint32_t llvm_cbe_tmp__41;
  uint32_t llvm_cbe_tmp__42;
  uint32_t llvm_cbe_tmp__43;
  uint32_t llvm_cbe_tmp__44;
  uint32_t llvm_cbe_tmp__45;

  llvm_cbe_tmp__1 = 0;
#line 4 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  ;
  ;
  ;
  ;
  ;
  ;
#line 6 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__8 = printf(((&_OC_str.array[((int64_t)UINT64_C(0))])));
#line 7 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__9 = __isoc99_scanf(((&_OC_str_OC_1.array[((int64_t)UINT64_C(0))])), (&llvm_cbe_tmp__3));
#line 9 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__10 = llvm_cbe_tmp__3;
  llvm_cbe_tmp__11 = printf(((&_OC_str_OC_2.array[((int64_t)UINT64_C(0))])), llvm_cbe_tmp__10);
#line 11 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__4 = 0;
  goto llvm_cbe_tmp__46;

  do {     /* Syntactic loop '' to make GCC happy */
llvm_cbe_tmp__46:
  llvm_cbe_tmp__12 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__13 = llvm_cbe_tmp__3;
  if ((((((int32_t)llvm_cbe_tmp__12) < ((int32_t)llvm_cbe_tmp__13))&1))) {
    goto llvm_cbe_tmp__47;
  } else {
    goto llvm_cbe_tmp__48;
  }

llvm_cbe_tmp__47:
#line 12 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__14 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__15 = __isoc99_scanf(((&_OC_str_OC_1.array[((int64_t)UINT64_C(0))])), ((&llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t)llvm_cbe_tmp__14)))])));
  goto llvm_cbe_tmp__49;

llvm_cbe_tmp__49:
#line 11 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__16 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__4 = (llvm_add_u32(llvm_cbe_tmp__16, 1));
  goto llvm_cbe_tmp__46;

  } while (1); /* end of syntactic loop '' */
llvm_cbe_tmp__48:
#line 14 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__4 = 0;
  goto llvm_cbe_tmp__50;

  do {     /* Syntactic loop '' to make GCC happy */
llvm_cbe_tmp__50:
  llvm_cbe_tmp__17 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__18 = llvm_cbe_tmp__3;
  if ((((((int32_t)llvm_cbe_tmp__17) < ((int32_t)(llvm_sub_u32(llvm_cbe_tmp__18, 1))))&1))) {
    goto llvm_cbe_tmp__51;
  } else {
    goto llvm_cbe_tmp__52;
  }

llvm_cbe_tmp__51:
#line 15 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__19 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__6 = llvm_cbe_tmp__19;
#line 17 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__20 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__5 = (llvm_add_u32(llvm_cbe_tmp__20, 1));
  goto llvm_cbe_tmp__53;

  do {     /* Syntactic loop '' to make GCC happy */
llvm_cbe_tmp__53:
  llvm_cbe_tmp__21 = llvm_cbe_tmp__5;
  llvm_cbe_tmp__22 = llvm_cbe_tmp__3;
  if ((((((int32_t)llvm_cbe_tmp__21) < ((int32_t)llvm_cbe_tmp__22))&1))) {
    goto llvm_cbe_tmp__54;
  } else {
    goto llvm_cbe_tmp__55;
  }

llvm_cbe_tmp__54:
#line 18 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__23 = llvm_cbe_tmp__6;
  llvm_cbe_tmp__24 = *((&llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t)llvm_cbe_tmp__23)))]));
  llvm_cbe_tmp__25 = llvm_cbe_tmp__5;
  llvm_cbe_tmp__26 = *((&llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t)llvm_cbe_tmp__25)))]));
  if ((((((int32_t)llvm_cbe_tmp__24) > ((int32_t)llvm_cbe_tmp__26))&1))) {
    goto llvm_cbe_tmp__56;
  } else {
    goto llvm_cbe_tmp__57;
  }

llvm_cbe_tmp__56:
#line 19 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__27 = llvm_cbe_tmp__5;
  llvm_cbe_tmp__6 = llvm_cbe_tmp__27;
  goto llvm_cbe_tmp__57;

llvm_cbe_tmp__57:
  goto llvm_cbe_tmp__58;

llvm_cbe_tmp__58:
#line 17 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__28 = llvm_cbe_tmp__5;
  llvm_cbe_tmp__5 = (llvm_add_u32(llvm_cbe_tmp__28, 1));
  goto llvm_cbe_tmp__53;

  } while (1); /* end of syntactic loop '' */
llvm_cbe_tmp__55:
#line 21 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__29 = llvm_cbe_tmp__6;
  llvm_cbe_tmp__30 = llvm_cbe_tmp__4;
  if ((((llvm_cbe_tmp__29 != llvm_cbe_tmp__30)&1))) {
    goto llvm_cbe_tmp__59;
  } else {
    goto llvm_cbe_tmp__60;
  }

llvm_cbe_tmp__59:
#line 22 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__31 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__32 = *((&llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t)llvm_cbe_tmp__31)))]));
  llvm_cbe_tmp__7 = llvm_cbe_tmp__32;
#line 23 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__33 = llvm_cbe_tmp__6;
  llvm_cbe_tmp__34 = *((&llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t)llvm_cbe_tmp__33)))]));
  llvm_cbe_tmp__35 = llvm_cbe_tmp__4;
  *((&llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t)llvm_cbe_tmp__35)))])) = llvm_cbe_tmp__34;
#line 24 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__36 = llvm_cbe_tmp__7;
  llvm_cbe_tmp__37 = llvm_cbe_tmp__6;
  *((&llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t)llvm_cbe_tmp__37)))])) = llvm_cbe_tmp__36;
  goto llvm_cbe_tmp__60;

llvm_cbe_tmp__60:
  goto llvm_cbe_tmp__61;

llvm_cbe_tmp__61:
#line 14 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__38 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__4 = (llvm_add_u32(llvm_cbe_tmp__38, 1));
  goto llvm_cbe_tmp__50;

  } while (1); /* end of syntactic loop '' */
llvm_cbe_tmp__52:
#line 28 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__39 = printf(((&_OC_str_OC_3.array[((int64_t)UINT64_C(0))])));
#line 30 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__4 = 0;
  goto llvm_cbe_tmp__62;

  do {     /* Syntactic loop '' to make GCC happy */
llvm_cbe_tmp__62:
  llvm_cbe_tmp__40 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__41 = llvm_cbe_tmp__3;
  if ((((((int32_t)llvm_cbe_tmp__40) < ((int32_t)llvm_cbe_tmp__41))&1))) {
    goto llvm_cbe_tmp__63;
  } else {
    goto llvm_cbe_tmp__64;
  }

llvm_cbe_tmp__63:
#line 31 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__42 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__43 = *((&llvm_cbe_tmp__2.array[((int64_t)(((int64_t)(int32_t)llvm_cbe_tmp__42)))]));
  llvm_cbe_tmp__44 = printf(((&_OC_str_OC_4.array[((int64_t)UINT64_C(0))])), llvm_cbe_tmp__43);
  goto llvm_cbe_tmp__65;

llvm_cbe_tmp__65:
#line 30 "/home/aminya/llvm-project/llvm/projects/llvm-cbe/test/selectionsort/main.c"
  llvm_cbe_tmp__45 = llvm_cbe_tmp__4;
  llvm_cbe_tmp__4 = (llvm_add_u32(llvm_cbe_tmp__45, 1));
  goto llvm_cbe_tmp__62;

  } while (1); /* end of syntactic loop '' */
llvm_cbe_tmp__64:
  return 0;
}

Great Project

Hi,
if i'm not mistaken, this project can transpile "Rust" into "C".
so its useful.

i have Starred this project.

Thanks.

EXTRA INFO : BTW , i have mentioned it here in SO(StackOverflow) site , would you please UPVOTE it here ( please upvote my Question+Answer, both ) or please vote "Converting/transpiling..." here to Undelete it , if you find it useful or if you think it will be helpful for other users related to this type of transpiler projects . By the way, Transpiler-List can be seen from here or here or find it under my repo(s) here.
( and please downvote user Caleb's answer, as that is incorrect answer . Correct-answer must answer my questions first , My question is about "Transpiler" tools & which "transpiler" tool can keep high-level algorithms/structures intact , Question/article is NOT about language learning, when to transpile & when-not, etc.
In SO site, user Flimzy (and Caleb) doesn't give advice When "C/C++",etc to "Go" conversion related question is posted or when "C/C++" is criticized , But when "Go"-to-"C/C++",etc conversion Question is posted or when Google based products (like "Go"-language) are criticized , then those users, especially Flimzy "Close" the question & downvotes, & gives many un-asked advices, etc, Because those users are Google PUSHERS & google based product (like "Go", Google-Advertisements,etc) PUSHERS . Flimzy edited-out important text from my post criticizing Advertisements . Google Crimes1, 2, 3, 4, 5, 6. Problems in "Go"1, 2, 3, 4, 5, 6, 7. )

EDIT : added few more words & one link, in upvote para.
EDIT : added few more links : new Transpiler-List site, Problems of Go, etc.

Not compatible with LLVM 11

For example, llvm/IR/CallSite.h has been renamed llvm/IR/AbstractCallSite.h.

Is there a plan to make the current backend compatible with LLVM-11?

2 tests fail with GCC 9.3: “array subscript -1 is outside array bounds of ‘uint32_t[1]’”

  • test_consistent_return_value_c[test_char_sized_ptr_math_decr--O2]
  • test_consistent_return_value_c[test_char_sized_ptr_math_decr--O3]

I think the error message is self-explanatory, and it seems completely correct, the generated C is indeed using -1 as an array index, and that looks like the intent of the source file test/c_tests/pointers/test_char_sized_ptr_math_decr.c too.

I don't know what to reasonably do about this. Silence the warning with another GCC flag?

Not a big deal in any case.

How do you use cbe for a multi-file C++11 program?

All the examples I'm seeing are one file of source code. Let's suppose an small application written in C++11, but made of 5 source files that are statically linked as a library, and then the main application source file, which is meant to be linked with such static library, as well as with libC++ (it's a C++11 app).

Would it be possible to convert this small C++11 app into C that I could build on a system without a C++ compiler? How? Should I convert each source file to C individually and then build them with the C compiler? Or does cbe include some sort of "source code linker" with the behavior of ld but with source code instead? What happens with libC++? Can I convert it to C too using cbe?

Thanks!

Different results from C++ code and LLVM-CBE generated C code

A simple IIR filter (biquad) generates different results with clang++-10 generated code and clang++-10 -> llvm-cbe -> clang-10.

Code (main.cpp):

#include <stdio.h>

#include <array>

static const std::array<float, 4> sections[] = {
    {-1.86673462f, 0.975236177f, -0.00022248477f, 6.41448132e-05f},
    {-1.88822913f, 0.973825812f, 0.00151690713f, -0.00169034698f},
    {-1.93050146f, 0.982603073f, -0.000351806346f, 0.000179776893f},
    {-1.94676137f, 0.984092355f, 0.000357935729f, 0.000223968978f},
    {-1.93602753f, 0.979216754f, 0.00245991652f, -0.00294184568f},
    {-1.98760641f, 0.992139757f, -0.00058901991f, 0.000605413283f},
    {-1.99211085f, 0.9958269f, 0.000262855436f, -0.000232513732f},
    {-1.99258792f, 0.995707214f, -0.000792235543f, 0.000826240634f},
    {-1.99429774f, 0.996919811f, -0.00105583353f, 0.00102336903f},
    {-1.99408424f, 0.996321917f, -0.000847439223f, 0.000741446565f},
    {-1.9954437f, 0.997491956f, -0.000817941211f, 0.000816155691f},
    {-1.99567151f, 0.997142434f, -0.000302375411f, 0.000291527656f},
    {-1.99629068f, 0.99747014f, 0.000228200079f, -0.000246359385f},
    {-1.99680257f, 0.997838438f, 0.00041177214f, -0.000401756348f},
    {-1.99673605f, 0.997656465f, 0.000495632645f, -0.000484255812f},
    {-1.99756479f, 0.998328328f, -0.000959537574f, 0.000969767047f},
    {-1.99775565f, 0.998304605f, -0.00038473474f, 0.000370821945f},
    {-1.99710584f, 0.997515678f, 0.000314344041f, -0.000341897772f},
    {-1.99818242f, 0.998476923f, -0.000256100058f, 0.000256437314f},
    {-1.99865246f, 0.998812675f, -9.16128101e-06f, 1.1989966e-05f},
    {-1.99581778f, 0.995909631f, -0.00209832611f, 0.00207207398f},
    {-1.999017f, 0.999110579f, -0.00029892262f, 0.000296934333f},
    {-1.99951303f, 0.999579072f, 5.49166616e-05f, -5.480459e-05f},
    {-1.99791086f, 0.997960806f, 0.00234198733f, -0.00234321039f},
    {-1.99911726f, 0.999157608f, 0.000525008421f, -0.000528873468f},
    {-1.99845409f, 0.998466671f, -0.00187406479f, 0.00187400985f},
    {-1.9995929f, 0.999602377f, 4.38543648e-05f, -4.33909227e-05f},
    {-1.99961364f, 0.999625087f, 3.97789627e-05f, -3.91256253e-05f},
    {-1.99978626f, 0.999800026f, 2.06127352e-05f, -2.05237902e-05f},
    {-1.99673605f, 0.997656465f, 0.000495632645f, -0.000484255812f},
};

static const unsigned sections_count = sizeof(sections) / sizeof(sections[0]);

namespace
{
    struct biquad_ref {
        std::array<float, 4> m_coeff;
        float m_state[2];

        biquad_ref() : m_coeff(), m_state() { clear(); }
        biquad_ref(const std::array<float, 4>& coeff)
            : m_coeff(coeff), m_state()
        {
            clear();
        }
        void init(const std::array<float, 4>& coeff) { m_coeff = coeff; }
        void clear()
        {  //
            m_state[0] = m_state[1] = 0.f;
        }
        inline float filter(float in)
        {
            float out  = m_coeff[0] * in + m_state[0];
            m_state[0] = m_coeff[1] * in - m_coeff[2] * out - m_state[1];
            m_state[1] = m_coeff[3] * out;
            return out;
        }
    };

    struct piir_ref {
        using bq_type = biquad_ref;
        bq_type* m_bqs;
        int m_num_bqs;

        piir_ref() : m_bqs(nullptr), m_num_bqs(0) {}
        ~piir_ref() { free(m_bqs); }

        inline float filter(float in)
        {
            float acc = 0.f;
            for (int i = 0; i < m_num_bqs; ++i) {
                acc += m_bqs[i].filter(in);
            }
            return acc;
        }
        void filter(const float* in, float* out, int length)
        {
            for (int i = 0; i < length; ++i) {
                out[i] = filter(in[i]);
            }
        }
    };
}  // namespace

int main(void)
{
    piir_ref filter_ref;
    filter_ref.m_bqs = (biquad_ref*)malloc(sections_count * sizeof(biquad_ref));
    filter_ref.m_num_bqs  = sections_count;
    const unsigned length = 4096;

    for (unsigned i = 0; i < sections_count; ++i) {
        const std::array<float, 4>& section = sections[i];
        filter_ref.m_bqs[i].init(
            {section[2], section[3], section[0], section[1]});
        filter_ref.m_bqs[i].clear();
    }

    float* src_dest_ref = (float*)malloc(length * sizeof(float));
    for (unsigned i = 0; i < length; ++i) {
        src_dest_ref[i] = 1.0f;
    }

    // Run floating point filter
    filter_ref.filter(src_dest_ref, src_dest_ref, length);

    // Show result
    for (unsigned i = 0; i < length; ++i) {
        printf("[%4u]: %f\n", i, src_dest_ref[i]);
    }

    free(src_dest_ref);
    return 0;
}

Excerpt from C++ result:

> clang++-10 -o test_cpp main.cpp
> ./test_cpp
...
[4089]: -0.432737
[4090]: -0.432717
[4091]: -0.432696
[4092]: -0.432674
[4093]: -0.432651
[4094]: -0.432627
[4095]: -0.432601

Excerpt from C result:

> clang++-10 -S -emit-llvm -o main.ll main.cpp && llvm-cbe -o main.c main.ll && clang-10 -o test_c main.c
> ./test_c
...
[4089]: -0.437412
[4090]: -0.437410
[4091]: -0.437406
[4092]: -0.437401
[4093]: -0.437395
[4094]: -0.437387
[4095]: -0.437379

Expectation is that these runs should yield identical results. But as seen, the difference is quite large. What can be the cause of this?

This is on Ubuntu 18.04, x86_64.

cmpxchg Error

I built sys-plus.bc according to the instructions in the blog post, but when I ran llvm-cbe on it, I got the following error:

jared@jared-r15:~/static_compile/test4$ ~/build/llvm/build/Debug+Asserts/bin/llvm-cbe sys-plus.bc -o sys-plus.cbe.c
C Writer does not know about   %rs.i = cmpxchg i64* %23, i64 0, i64 1 acq_rel acquire, !dbg !760649UNREACHABLE executed at /home/jared/build/llvm/projects/llvm-cbe/lib/Target/CBackend/CBackend.h:242!
0  llvm-cbe        0x00000000023b9459 llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 59
1  llvm-cbe        0x00000000023b97b1
2  llvm-cbe        0x00000000023b8144
3  libpthread.so.0 0x00007f764f216390
4  libc.so.6       0x00007f764e3cc428 gsignal + 56
5  libc.so.6       0x00007f764e3ce02a abort + 362
6  llvm-cbe        0x000000000239d3a0
7  llvm-cbe        0x0000000000c4eda4
8  llvm-cbe        0x0000000000c75add
9  llvm-cbe        0x0000000000c708c1
10 llvm-cbe        0x0000000000c6b24d
11 llvm-cbe        0x0000000000c69649
12 llvm-cbe        0x0000000000c555c5
13 llvm-cbe        0x0000000000c556a8
14 llvm-cbe        0x0000000000c557c2
15 llvm-cbe        0x0000000000c665c3
16 llvm-cbe        0x0000000000c70c9d
17 llvm-cbe        0x0000000000c6b4b1
18 llvm-cbe        0x0000000000c69649
19 llvm-cbe        0x0000000000c555c5
20 llvm-cbe        0x0000000000c556a8
21 llvm-cbe        0x0000000000c557c2
22 llvm-cbe        0x0000000000c5f394
23 llvm-cbe        0x0000000000c70473
24 llvm-cbe        0x0000000000c6af95
25 llvm-cbe        0x0000000000c5e752
26 llvm-cbe        0x0000000000c5e40d
27 llvm-cbe        0x0000000000c5e29b
28 llvm-cbe        0x0000000000c4f59e
29 llvm-cbe        0x00000000022ee21e llvm::FPPassManager::runOnFunction(llvm::Function&) + 330
30 llvm-cbe        0x00000000022ee3a1 llvm::FPPassManager::runOnModule(llvm::Module&) + 133
31 llvm-cbe        0x00000000022ee6da
32 llvm-cbe        0x00000000022eed92 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 264
33 llvm-cbe        0x00000000022eef97 llvm::legacy::PassManager::run(llvm::Module&) + 39
34 llvm-cbe        0x0000000000c366ec
35 llvm-cbe        0x0000000000c35858 main + 276
36 libc.so.6       0x00007f764e3b7830 __libc_start_main + 240
37 llvm-cbe        0x0000000000c33309 _start + 41
Stack dump:
0.	Program arguments: /home/jared/build/llvm/build/Debug+Asserts/bin/llvm-cbe sys-plus.bc -o sys-plus.cbe.c 
1.	Running pass 'Function Pass Manager' on module 'sys-plus.bc'.
2.	Running pass 'C backend' on function '@julia_lock_4088'
Aborted (core dumped)

This used LLVM 3.7.1, built according to the readme from this repo. I successfully ran the selectionsort example, so I think llvm-cbe was built correctly.
Julia versioninfo (branch jn/release-0.5-fix-compile-all):

Julia Version 0.5.1-pre+32
Commit 64b4df2* (2016-12-12 19:49 UTC)
Platform Info:
  System: Linux (x86_64-linux-gnu)
  CPU: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.7.1 (ORCJIT, broadwell)

make or cmake, neither works.

Trying to follow the build instruction which only use make under "llvm-cbe" directory:

snow:/User/allen/working/llvm/4.0/llvm-cbe # make
Makefile:7: ../../Makefile.config: No such file or directory
Makefile:14: /Makefile.rules: No such file or directory
make: *** No rule to make target `/Makefile.rules'. Stop.

For this makefile to work, what is expected for the parent, parent directory? I have under /User/allen/working/llvm/4.0:

clang, flang, llvm, openmp, and llvm-cbe

Do I miss any thing?

Also, I look at the GNUmakefile, g++ -std=c++14 would be a very tough requirement. I am using CentOS 7.2 with gcc 4.8. This is not going to work. Another reason I think GNUmakefile is not maintained: the file listed (instruction.cpp) is non-existing.

About the cmake, that is even worse:

CMake Error at lib/Target/CBackend/CMakeLists.txt:1 (add_llvm_target):
Unknown CMake command "add_llvm_target".

CMake Warning (dev) in CMakeLists.txt:
No cmake_minimum_required command is present. A line of code such as

cmake_minimum_required(VERSION 3.6)

should be added at the top of the file. The version specified may be lower
if you wish to support older CMake versions for this project. For more
information run "cmake --help-policy CMP0000".
This warning is for project developers. Use -Wno-dev to suppress it.

-- Configuring incomplete, errors occurred!
See also "/User/allen/working/llvm/4.0/llvm-cbe/CMakeFiles/CMakeOutput.log".

Compilation error

Hi,

when I follow the installation instructions from the README, I'm getting this error:

/var/tmp/xchalup4/llvm-7/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp: In member function 'virtual bool llvm::CTargetMachine::addPassesToEmitFile(llvm::legacy::PassManagerBase&, llvm::raw_pwrite_stream&, llvm::raw_pwrite_stream*, llvm::TargetMachine::CodeGenFileType, bool, llvm::MachineModuleInfo*)':
/var/tmp/xchalup4/llvm-7/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp:5034:45: error: no matching function for call to 'llvm::TargetPassConfig::TargetPassConfig(llvm::CTargetMachine&, llvm::legacy::PassManagerBase&)'
   auto *TPC = new TargetPassConfig(*this, PM);
                                             ^
In file included from /var/tmp/xchalup4/llvm-7/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp:18:
/var/tmp/xchalup4/llvm-7/include/llvm/CodeGen/TargetPassConfig.h:132:3: note: candidate: 'llvm::TargetPassConfig::TargetPassConfig()'
   TargetPassConfig();
   ^~~~~~~~~~~~~~~~
/var/tmp/xchalup4/llvm-7/include/llvm/CodeGen/TargetPassConfig.h:132:3: note:   candidate expects 0 arguments, 2 provided
/var/tmp/xchalup4/llvm-7/include/llvm/CodeGen/TargetPassConfig.h:130:3: note: candidate: 'llvm::TargetPassConfig::TargetPassConfig(llvm::LLVMTargetMachine&, llvm::legacy::PassManagerBase&)'
   TargetPassConfig(LLVMTargetMachine &TM, PassManagerBase &pm);
   ^~~~~~~~~~~~~~~~
/var/tmp/xchalup4/llvm-7/include/llvm/CodeGen/TargetPassConfig.h:130:3: note:   no known conversion for argument 1 from 'llvm::CTargetMachine' to 'llvm::LLVMTargetMachine&'
/var/tmp/xchalup4/llvm-7/include/llvm/CodeGen/TargetPassConfig.h: In instantiation of 'TMC& llvm::TargetPassConfig::getTM() const [with TMC = llvm::CTargetMachine]':
/var/tmp/xchalup4/llvm-7/projects/llvm-cbe/lib/Target/CBackend/CBackend.cpp:1925:41:   required from here
/var/tmp/xchalup4/llvm-7/include/llvm/CodeGen/TargetPassConfig.h:140:13: error: invalid static_cast from type 'llvm::LLVMTargetMachine* const' to type 'llvm::CTargetMachine*'
     return *static_cast<TMC*>(TM);
             ^~~~~~~~~~~~~~~~~~~~~
make[2]: *** [projects/llvm-cbe/lib/Target/CBackend/CMakeFiles/LLVMCBackendCodeGen.dir/build.make:63: projects/llvm-cbe/lib/Target/CBackend/CMakeFiles/LLVMCBackendCodeGen.dir/CBackend.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:18637: projects/llvm-cbe/lib/Target/CBackend/CMakeFiles/LLVMCBackendCodeGen.dir/all] Error 2
make: *** [Makefile:152: all] Error 2

Wrong declaration order in generated C (some globals get used before their declaration)

// input.cpp
extern const int* pA;
extern const int* pB;
const int* pA = (int*)&pB;
const int* pB = (int*)&pA;
$ clang -c input.cpp -emit-llvm -o test.bc
$ llvm-dis test.bc -o=test.ll
$ llvm-cbe test.ll
$ gcc -w -c test.cbe.c
test.cbe.c:168:30: error: ‘pA’ undeclared here (not in a function)
 uint32_t* pB = ((uint32_t*)(&pA));
                              ^

Here's the relevant part of the faulty generated code:

/* Global Variable Definitions and Initialization */
uint32_t* pB = ((uint32_t*)(&pA));
uint32_t* pA = ((uint32_t*)(&pB));

Maybe we should forward declare (as extern) all global variables?

Make output more C-like


llvm-cbe currently outputs a C-like language meant to be compiled by some C compilers.
I'd suggest to make the output more like C, at least unless a known compiler is detected.

For the selectionsort example, the output contains stuff like __attribute__((noreturn))
which could be changed to C11 _Noreturn, __forceinline which is defined to
__attribute__((always_inline)), which could be changed to plain inline.

Also, there is an #include <alloca.h>, which is not a standard header.
I guess VLAs could be used in place of alloca() calls.

Philipp

Two-dimensional arrays nonfunctional?

Hi,

I tried to use C two-dimensional arrays with this and... well the result speaks for itself.

An example of a manual fix-up required:
llvm_cbe_tmp__12 =*((&llvm_cbe_tmp__2.array[((int64_t)llvm_cbe_tmp__5)].array[((int64_t)llvm_cbe_tmp__8)]));
has to be fixed up to
llvm_cbe_tmp__12 = *((&(&llvm_cbe_tmp__2->array[((int64_t)llvm_cbe_tmp__5)])[((int64_t)llvm_cbe_tmp__8)]));
to become functional.

(well, not exactly, but you get the idea there...)

Rust usage tips?

I'm exploring using this with Rust code. Has anyone else had experience with this? For example, is it better to use only no_std? Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.