JuliaHubOSS/llvm-cbe

Private constant missing from generated output

Closed this issue · 6 comments

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;
}

<{ [0 x i8] }>

Hmm, that's a zero-length array. I know LLVM-CBE will skip “empty” types like this, and that might be the problem.

(Is that even legal LLVM IR? Aren't the stores to it useless?)

(Is that even legal LLVM IR? Aren't the stores to it useless?)

I'm not an expert on LLVM IR, but it's definitely legal because I can build a library from it. The stores might be useless, but the bug is that the stores to it (search for alloc7) are still included in the generated C.

Yeah, I guess it must be legal if Rust's emitting it.

It is probably a simple change to add a check to skip the store.

I feel like rust is at fault here for specifying nonsense, but LLVM will sensible change it into a 1 byte allocation (to force it to have a unique address). This can do the same and emit static char alloc7;

l_alloc7:
	.byte	0

Since I am also interested in compiling Rust code to C, I am going to try to fix this issue. By the way, there's a related problem for allocas, which do get emitted but with the illegal type void.

One way to implement this could be to add a new pass before the C writer, which would rewrite zero-sized variables' types and insert bitcasts at usage sites. I believe this would be a departure from how the C backend solves similar problems right now (single-pass-ish code emission which checks for a given special case in multiple places), but I am hoping it would be easier to write and maintain.

I am also wondering if some problems the C backend already deals with could be more maintainable if changed to use that approach, but that's maybe a bit off-topic.

Nevermind, I was overthinking things.

Here's a simple and more traditional fix :) #104