Understanding how memory allocation (LLVM) works

I am advancing on a toy compiler (first time) and trying to figure out how to distribute / build an LLVM structure type. The Kaleidoscope tutorial does not include or mention this, and I don’t know what I am looking for in the LLVM source / tests to find possible examples.

So, I just wrote an example in C ++, dropped IR with clang, trying to figure out what it produces, but honestly, I am not following all this. Things that are obvious to me are function definitions / declarations and some function calls and a call memset, so I get chunks, but that's not all for me. (PS My interpretation of the allocationa instruction documents is that everything created from this is freed upon return, so I can’t use this right, essentially, only for local variables?)

What I've done:

alloc.cpp

struct Alloc {
  int age;
};

//Alloc allocCpy() {
//  return *new Alloc();
//}

Alloc *allocPtr() {
  return new Alloc();
}

int main() {
  Alloc *ptr = allocPtr();
//  ptr->name = "Courtney";
//  Alloc cpy = allocCpy();
//  cpy.name = "Robinson";
//  std::cout << ptr->name << std::endl;
//  std::cout << cpy.name << std::endl;
  return 0;
}

Then run clang -S -emit-llvm alloc.cppto createalloc.ll

; ModuleID = 'alloc.cpp'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.11.0"

%struct.Alloc = type { i32 }

; Function Attrs: ssp uwtable
define %struct.Alloc* @_Z8allocPtrv() #0 {
entry:
  %call = call noalias i8* @_Znwm(i64 4) #3
  %0 = bitcast i8* %call to %struct.Alloc*
  %1 = bitcast %struct.Alloc* %0 to i8*
  call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 4, i32 4, i1 false)
  ret %struct.Alloc* %0
}

; Function Attrs: nobuiltin
declare noalias i8* @_Znwm(i64) #1

; Function Attrs: nounwind
declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) #2

; Function Attrs: ssp uwtable
define i32 @main() #0 {
entry:
  %retval = alloca i32, align 4
  %ptr = alloca %struct.Alloc*, align 8
  store i32 0, i32* %retval
  %call = call %struct.Alloc* @_Z8allocPtrv()
  store %struct.Alloc* %call, %struct.Alloc** %ptr, align 8
  ret i32 0
}

attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nobuiltin "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind }
attributes #3 = { builtin }

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

!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"clang version 3.7.0 (tags/RELEASE_370/final)"}

- , IR ++? , / LLVM StructType, , ( , ).

, , , , , IR ...

+4
2

alloca , - , , , , ?

. , LLVM IR , , alloca , , - . , alloca , .

- . LLVM . new T(), operator new, , T . . , , ++ - ABI, LLVM. void* p = malloc(size); new(p) T();. T p .

.

, / LLVM

LLVM . .

LLVM, , . , , , . , .

, , , , , w.r.t. .

Clang LLVM IR. , batshit , , , ++, . #llvm IRC , .

+5

- Clang - . -O1 - -O1 , ( , ):

%struct.Alloc = type { i32 }                   ; Define the Alloc type.

define noalias %struct.Alloc* @_Z8allocPtrv() #0 {
  %1 = tail call noalias i8* @_Znwj(i32 4) #2  ; Call _Znwj(4). This retuns i8*.
  %3 = bitcast i8* %1 to i32*                  ; Cast the returned value to i32* (int*)...
  store i32 0, i32* %3, align 4                ; ...and zero its content.
  %2 = bitcast i8* %1 to %struct.Alloc*        ; Cast the returned value to Alloc*...
  ret %struct.Alloc* %2                        ; ...and return it.
}

; Declare the _Znwj function. This doesn't need to be defined since it already defined
; in libstdc++: this is 'operator new'. You can see this by passing this string through a
; C++ demangler, for example the one at http://demangler.com/.
declare noalias i8* @_Znwj(i32) #1

define i32 @main() #0 {
  %1 = tail call %struct.Alloc* @_Z8allocPtrv()  ; Call _Z8allocPtrv (Defined above).
  ret i32 0
}

new, , @_Z8allocPtrv . LLVM IR alloca, new.

, new, , malloc, , , .

+2

Source: https://habr.com/ru/post/1614518/


All Articles