برنامه نویسی

فرآیند گردآوری – گردآوری – جامعه dev

عکس پوشش توسط برنارد هرمان در Unsplash

در آخرین پست وبلاگ ، ما مرحله پیش پردازش را پوشش دادیم. اکنون وقت آن است که وارد مرحله تدوین شوید.

تالیف

تدوین چیست؟

تدوین فرآیند تبدیل کد منبع از پیش پردازش شده (در مورد ما ، کد C یا C ++) به کد مونتاژ است. این مرحله توسط کامپایلر انجام می شود ، که قبل از تولید کد سطح پایین ، چک ها و بهینه سازی های مختلفی را انجام می دهد.

بر خلاف مرحله پیش پردازش ، که صرفاً کد را از نظر متنی اصلاح می کند ، تدوین شامل تجزیه و تحلیل عمیق تر و تحول است.

توجه: برای متوقف کردن فرآیند تدوین بعد از مرحله تدوین ، از پرچم -s استفاده کنید:

gcc/clang -S main.c -o main.s
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

بیایید این را با یک مثال کشف کنیم:

foo.h

int foo(void);
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

دست

#include "foo.h"

int square(int i) { return i * i; }

int main() {
  int a = 5;
  int f = foo();
  return f + square(a);
}

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

مراحل اصلی تدوین

1. تجزیه و تحلیل واژگانی (توکینیزاسیون)

کد از پیش پردازش شده به نشانه ها تقسیم می شود. به عنوان مثال ، خط:

int a = 5;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در: intبا aبا =با 5 وت ;

این مرحله فضای سفید را از بین می برد و نمادهای ناشناخته را تشخیص می دهد. به عنوان مثال:

int    a    = 5  ;
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

هنوز هم با همان نشانه ها به پایان می رسد intبا aبا =با 5 وت ;

با این حال ، این باعث خطایی خواهد شد:
int a = 5 @ 3;

error: expected ';' at end of declaration
    6 |   int a = 5 @3;
      |            ^
      |
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

2. تجزیه و تحلیل نحو (تجزیه)

  • توکن ها بر اساس قوانین دستور زبان برای تشکیل یک درخت نحوی انتزاعی (AST) گروه بندی می شوند.

  • AST نمایانگر ساختار نحوی سلسله مراتبی کد است ، و جزئیات غیر ضروری مانند قسمتهای نیمه یا پرانتز را انتزاع می کند.

  • این مرحله تضمین می کند که ساختار کد از نحو زبان پیروی می کند.
    مثال:
    int a = 5 // Missing the ;

خروجی:

error: expected ';' at end of declaration
    6 |   int a = 5 // Missing the ;
      |            ^
      |
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

3. تجزیه و تحلیل معنایی

این فاز صحت منطقی را بررسی می کند:

  • تضمین می کند که متغیرها قبل از استفاده اعلام می شوند.
int main() {
  // int a = 5;
  int f = foo();
  return f + square(a);
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

 error: use of undeclared identifier 'a'
    8 |   return f + square(a);
      |                     ^
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

  • سازگاری نوع را تضمین می کند (به عنوان مثال ، هیچ رشته ای به یک عدد صحیح اختصاص نمی دهد).
int a = "hello";
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

خطا:

error: incompatible pointer to integer conversion initializing 'int' with an expression of type 'char[6]' [-Wint-conversion]
    6 |   int a = "hello";
      |       ^   ~~~~~~~
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

4. IR – نمایندگی متوسط

  • کامپایلر AST را به یک بازنمایی میانی (IR) تبدیل می کند که مستقل از سکوی است.

  • IR به عنوان پلی بین کد منبع سطح بالا و کد دستگاه سطح پایین عمل می کند و بهینه سازی را امکان پذیر می کند.

در پست های آینده ، ما این موضوع را به طور عمیق و همراه با بهینه سازی های مختلف پوشش خواهیم داد. در حال حاضر ، بیایید ببینیم که چگونه به کامپایلر دستور می دهیم این فرم را منتشر کند.

برای تولید LLVM IR با استفاده از clang:

clang main.c -S -emit-llvm -o main.ll`
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

نسخه بهینه شده:

; ModuleID = 'main.c'
source_filename = "main.c"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "arm64-apple-macosx14.0.0"

; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
define i32 @square(i32 noundef %0) #0 {
  %2 = alloca i32, align 4
  store i32 %0, ptr %2, align 4
  %3 = load i32, ptr %2, align 4
  %4 = load i32, ptr %2, align 4
  %5 = mul nsw i32 %3, %4
  ret i32 %5
}

; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
define i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  store i32 0, ptr %1, align 4
  store i32 5, ptr %2, align 4
  %4 = call i32 @foo()
  store i32 %4, ptr %3, align 4
  %5 = load i32, ptr %3, align 4
  %6 = load i32, ptr %2, align 4
  %7 = call i32 @square(i32 noundef %6)
  %8 = add nsw i32 %5, %7
  ret i32 %8
}

declare i32 @foo() #1

attributes #0 = {...}
attributes #1 = {...}
...
...
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

بهینه سازی کامپایلر

کامپایلر قبل از تولید کد مونتاژ IR را بهینه می کند. بهینه سازی های مشترک شامل موارد زیر است:

  • عملکردی
  • حذف کد مرده
  • حلقه دور زدن
  • حرکت کد ثابت حلقه
  • توابع ادغام
  • و غیره …

ما این موارد را در پست های آینده کشف خواهیم کرد.

نتیجه نهایی ، مونتاژ ARM64

لینوکس

    .text
    .file   "main.c"
    .globl  square                          // -- Begin function square
    .p2align    2
    .type   square,@function
square:                                 // @square
    .cfi_startproc
// %bb.0:
    sub sp, sp, #16
    .cfi_def_cfa_offset 16
    str w0, [sp, #12]
    ldr w8, [sp, #12]
    ldr w9, [sp, #12]
    mul w0, w8, w9
    add sp, sp, #16
    .cfi_def_cfa_offset 0
    ret
.Lfunc_end0:
    .size   square, .Lfunc_end0-square
    .cfi_endproc
                                        // -- End function
    .globl  main                            // -- Begin function main
    .p2align    2
    .type   main,@function
main:                                   // @main
    .cfi_startproc
// %bb.0:
    sub sp, sp, #32
    .cfi_def_cfa_offset 32
    stp x29, x30, [sp, #16]             // 16-byte Folded Spill
    add x29, sp, #16
    .cfi_def_cfa w29, 16
    .cfi_offset w30, -8
    .cfi_offset w29, -16
    stur    wzr, [x29, #-4]
    mov w8, #5                          // =0x5
    str w8, [sp, #8]
    bl  foo
    str w0, [sp, #4]
    ldr w8, [sp, #4]
    str w8, [sp]                        // 4-byte Folded Spill
    ldr w0, [sp, #8]
    bl  square
    ldr w8, [sp]                        // 4-byte Folded Reload
    add w0, w8, w0
    .cfi_def_cfa wsp, 32
    ldp x29, x30, [sp, #16]             // 16-byte Folded Reload
    add sp, sp, #32
    .cfi_def_cfa_offset 0
    .cfi_restore w30
    .cfi_restore w29
    ret
.Lfunc_end1:
    .size   main, .Lfunc_end1-main
    .cfi_endproc
                                        // -- End function
    .ident  "Ubuntu clang version 18.1.3 (1ubuntu1)"
    .section    ".note.GNU-stack","",@progbits
    .addrsig
    .addrsig_sym square
    .addrsig_sym foo
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

MACOS:

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 14, 0 sdk_version 14, 4
    .globl  _square                         ; -- Begin function square
    .p2align    2
_square:                                ; @square
    .cfi_startproc
; %bb.0:
    sub sp, sp, #16
    .cfi_def_cfa_offset 16
    str w0, [sp, #12]
    ldr w8, [sp, #12]
    ldr w9, [sp, #12]
    mul w0, w8, w9
    add sp, sp, #16
    ret
    .cfi_endproc
                                        ; -- End function
    .globl  _main                           ; -- Begin function main
    .p2align    2
_main:                                  ; @main
    .cfi_startproc
; %bb.0:
    sub sp, sp, #32
    stp x29, x30, [sp, #16]             ; 16-byte Folded Spill
    add x29, sp, #16
    .cfi_def_cfa w29, 16
    .cfi_offset w30, -8
    .cfi_offset w29, -16
    stur    wzr, [x29, #-4]
    mov w8, #5                          ; =0x5
    str w8, [sp, #8]
    bl  _foo
    str w0, [sp, #4]
    ldr w8, [sp, #4]
    str w8, [sp]                        ; 4-byte Folded Spill
    ldr w0, [sp, #8]
    bl  _square
    ldr w8, [sp]                        ; 4-byte Folded Reload
    add w0, w8, w0
    ldp x29, x30, [sp, #16]             ; 16-byte Folded Reload
    add sp, sp, #32
    ret
    .cfi_endproc
                                        ; -- End function
.subsections_via_symbols

حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این برای این پست است! در مورد بعدی ، ما آن را پوشش خواهیم داد مونتاژ کننده فاز

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا