主頁 > 移動端開發 > clang如何為平方和生成非回圈代碼?

clang如何為平方和生成非回圈代碼?

2022-11-16 02:30:46 移動端開發

我承認這個問題的答案可能是“一些非常特殊的魔法”,但我對我在這里觀察到的情況感到有點震驚。我想知道是否有人了解這些型別的優化是如何作業的。我發現編譯器設計很有趣,我真的無法想象它是如何作業的。我確定答案在 clang 源代碼中的某處,但我什至不知道我會去哪里找。

我是大學班級的助教,最近有人要求我幫忙做一道簡單的家庭作業題。這讓我走上了一條有趣的道路......

問題很簡單:在 x86_64 匯編中,撰寫一個給定(正)整數 n 回傳的函式1^2 2^2 3^2 ... n^2

我決定嘗試一下,在幫助他們用 x86_64 匯編撰寫這個之后,我有一臺 M1 macbook,決定看看我是否可以在 arm64 匯編中創建一個不錯的解決方案。我想出了相對簡單直接的解決方案:

_sum_squares:
    mov x1, x0  ; Do multiplication from x1
    mov x0, xzr ; Clear x0

    Lloop:
        ; x0 <-- (x1 * x1)   x0
        madd x0, x1, x1, x0

        ; Loop until x1 == 0
        subs x1, x1, #1
        bne Lloop

    ret

(我希望在一條指令中有某種很好的方法來做分支--x1 == 0,但我想不出任何)

注意:任何基礎數論課程都有一個簡單的公式,它是[n(n 1)(2n 1)] / 6,但我認為這不符合問題的精神。

然后我想知道 clang 如何為簡單的 C 版本生成程式集。在撰寫簡單的 C 實作時,我發現 clang-Og生成的程式集看起來有點冗長,但通常可以按預期使用回圈和累加器作業(盡管它非常低效):

int sum_squares(int n)
{
    int a = 0;

    while (n--)
        a  = (n * n);

    return a;
}

( clang -Og -S, 注釋了我自己,洗掉了 cfi,重命名了標簽)

_sum_squares:
    sub sp, sp, #16         ; create stack space
    str w0, [sp, #12]       ; store n
    str wzr, [sp, #8]       ; store 0
    b   Ldec                ; silly clang, this just falls through...

Ldec:                       ; n-- and return if n == 0
    ldr w8, [sp, #12]       ; load n
    subs    w9, w8, #1      ; w9 = (n - 1)
    str w9, [sp, #12]       ; store (n - 1) over n
    subs    w8, w8, #0      ; w8 = n - 0 (set flags based on n)
    cset    w8, eq          ; set w8 = 1 if n == 0 else w8 = 0
    tbnz    w8, #0, Lret    ; branch to return if n == 0, else fall through
    b   Ladd                ; silly clang, this falls through again...

Ladd:                       ; a  = n^2
    ldr w8, [sp, #12]       ; load n
    ldr w9, [sp, #12]       ; load n
    mul w9, w8, w9          ; w9 = n * n
    ldr w8, [sp, #8]        ; load a
    add w8, w8, w9          ; a  = w9
    str w8, [sp, #8]        ; store a
    b   Ldec                ; go back to start of look

Lret:                       ; return a from top of stack
    ldr w0, [sp, #8]        ; w0 = a
    add sp, sp, #16         ; cleanup temp stack
    ret                     ; back to caller

這對于將 C 代碼直接轉換為 arm64 匯編來說是完全合理的。經過一些優化(O1 使用類似的公式,O2 和 O3 相同),clang 產生了一些魔力。我不知道這段代碼是怎么想出來的,它看起來有點類似于這個求和的基本公式,除了有點魔法。我沒想到編譯器能夠在沒有回圈的情況下為此推匯出一個公式,但看來我錯了。生成的代碼如下(我盡最大努力在評論中,n是輸入w0):

_sum_squares:
        cbz     w0, Lret             ; return if n == 0

        sub     w8, w0, #1           ; w8 = (n - 1)
        mul     w9, w8, w8           ; w9 = (n - 1)^2
        orr     w9, w9, #0x2         ; w9 = ((n - 1)^2) | 2
        sub     w9, w9, w0           ; w9 = [((n - 1)^2) | 2] - n

        mov     w10, #5              ; w10 = 5
        sub     w10, w10, w0, lsl #1 ; w10 = 5 - (n / 2)

        sub     w11, w0, #2          ; w11 = n - 2
        umull   x11, w8, w11         ; w11 = (n - 1)(n - 2)

        lsr     x12, x11, #1         ; x12 = ((n - 1)(n - 2)) / 2
        mul     w10, w10, w12        ; w10 = (5 - (n / 2))(((n - 1)(n - 2)) / 2)

        sub     w12, w0, #3          ; w12 = n - 3
        mul     x11, x11, x12        ; x11 = (n - 1)(n - 2)(n - 3)
        lsr     x11, x11, #1         ; x11 = ((n - 1)(n - 2)(n - 3)) / 2

        mov     w12, #21846          ; w12 = 0x5556
        movk    w12, #21845, lsl #16 ; w12 = 0x55555556

        ; w8 = ((n - 1)([((n - 1)^2) | 2] - n))   (5 - (n / 2))(((n - 1)(n - 2)) / 2)
        madd    w8, w9, w8, w10

        ; let A = w8 (set in last instruction)
        ; w0 = (0x55555556 * (((n - 1)(n - 2)(n - 3)) / 2))   A
        madd    w0, w11, w12, w8
        ; somehow, this is the correct result?
        ; this feels like magic to me...

Lret:
        ret                          ; return. Result already in w0.

我的問題:這究竟是如何運作的?C 編譯器怎么能被賦予這樣的回圈并推匯出一個甚至不涉及回圈的公式?我預計可能會有一些回圈展開,但不是這樣的。有沒有人有涉及這種優化的參考資料?

我特別不明白某些步驟orr w9, w9, #0x2或神奇數字 0x55555556 的作用。任何對這些步驟的深入了解將不勝感激。

uj5u.com熱心網友回復:

TL:DR: 是的,clang 知道整數冪級數和的閉式公式,并且可以檢測到這樣的回圈。 聰明的人已經教會現代編譯器識別某些操作模式并用源代碼中不存在的操作替換它們,例如旋轉甚至 popcount 回圈和 bithacks。特別是對于 clang/LLVM,還有 i^power 總和的封閉形式公式,包括步幅不是 1 的情況。耶數學!因此,您可以獲得 asm 邏輯,而不僅僅是源代碼的展開或矢量化版本。

另請參閱博客文章LLVM 如何優化冪和,其中討論了編譯器如何通過查看變數如何跨回圈迭代更新來找到這些回圈。

Matthieu M. 評論說封閉式公式是由 LLVM 中的標量演化優化匯出的。 代碼中的注釋說它主要用于分析回圈中涉及歸納變數的運算式。并參考了它用于重復鏈的技術的參考資料。


現代 C 編譯器可以在代碼的內部表示中識別某些回圈或短邏輯序列中的模式。人類(編譯器開發人員)已經告訴編譯器要尋找什么,并提供了一個手工制作的替換“公式”。我希望在 GIMPLE (GCC) 或 LLVM-IR 中,在生成 asm 時,不僅僅是像窺孔優化這樣的編譯后期。

所以我猜想 LLVM 優化器內部的邏輯會檢查它找到的每個回圈是否存在以下一種或多種可能性,并使用一些代碼來查找代表該回圈程式邏輯的 LLVM-IR 的某些屬性:

  • 它是否將一個陣列原封不動地復制到另一個陣列?如果是,則替換為__builtin_memcpy,稍后可能會行內擴展或編譯為call memcpy. 如果它有其他副作用,比如讓指標變數遞增,那么在包含回圈的函式的新 LLVM-IR 中也表示它。
  • 它是否將記憶體范圍的每個位元組設定為一個常量位元組值?如果是這樣,memset
  • 它的操作順序是否等同于這個popcnt的順序?如果存在硬體支持,則發出一個popcnt,否則保持回圈策略。(所以它不只是把它當作它__builtin_popcount,而不是用 bithack 或呼叫輔助函式替換回圈。這是有道理的,因為有些策略適用于設定了少量位的數字,程式員可能已經選擇了那個心里。)
  • 回圈變數是用一系列整數的總和(有一定步幅)更新的,還是用整數的總和更新的?然后使用避免固定寬度整數溢位的封閉式公式。(如果起點和步幅不是1,則添加偏移量和/或比例因子。)

檢查可能在考慮由回圈修改的變數方面起作用,該變數在回圈后讀取。所以它知道在查看操作時要考慮什么變數。(沒有使用結果的回圈被洗掉。)

GCC 不會尋找整數序列的總和,但 clang 會。IDK 這實際上加速了多少真實世界的代碼庫;封閉形式的公式相當有名,著名的是它在小時候被高斯重新發現(所以希望很多代碼使用公式而不是回圈)。沒有多少程式需要完全做到這一點,我曾想,除非作為練習。

(封閉形式的平方和公式的存在不太為人所知,但有一個,而且顯然也適用于一般的冪。)


Clang 的公式實作當然必須為每個輸入整數給出準確正確的結果,其中 C 抽象機不會遇到未定義的行為(對于有符號整數溢位),或者匹配無符號乘法的截斷。否則它不會滿足 as-if 規則,或者只能在行內到具有已知有限值范圍的地方時使用。(在實踐中,似乎 clang 沒有使用無符號的封閉形式優化,但也許我只是在我嘗試的版本中犯了一個錯誤。使用 64 位整數可以安全地計算 32 位整數的總和。并且然后截斷可能會產生與源相同的結果。)

n*(n 1)n*(n 1)/2在仍在范圍內的情況下可能會溢位,因此這很重要。對于int64 位機器上的 32 位,LLVM 可以并且確實簡單地使用 64 位乘法和右移。這可能是對使用雙寬度輸出和擴展精度右移的一般情況的窺孔優化,如果產品不適合一個,則跨兩個暫存器。(例如,在 EDX:EAX 中生成 64 位乘積后, x86shrd edx, eax, 1將低位從高位轉移到 EAX 的頂部。)mul r32

它也n * (n-1) / 2 n代替了通常的n * (n 1)/2; 不知道這有什么幫助。它避免了輸入型別的溢位,我猜,以防萬一對于unsigned原始回圈只有包裝而不是 UB 的型別很重要。除了它不對無符號進行此優化。(順便說一句,要么是偶數,n要么n -1是偶數,所以除法(右移)是精確的;這很好,因為整數之和最好是整數。)

在您的平方和 asm 中,您可以看到它umull x, w, w用于進行擴大乘法和 64 位右移,然后再進行除以 3 的 32 位乘法逆運算。


玩弄您的代碼和簡化版本而不是平方,當您倒數或倒數時,它對代碼生成的影響很小。

int sum_ints(int n) {
    int a = 0;
    //for (int i=0 ; i<n ; i  )  a  = i;        // count up, skipping n
    while (n--) a  = n;                      // count down, skipping n
    return a;
}

否定n會與您的版本有 UB,因為回圈會運行到INT_MIN--, 并首先溢位a所以 clang 可能會也可能不會使用它來假設初始n值是非負的。但如果不是,IDK 為什么它會生成更復雜的乘以兩倍的代碼。

// count down version, starting with a  = n-1, so x = n-1 in the usual formulae.
//  clang15 -O3
sum_ints(int):
        cbz     w0, .LBB0_2        // only bail on zero, not negative.
        sub     w8, w0, #1         // n-1
        sub     w9, w0, #2         // n-2
        umull   x10, w8, w9        // (n-1)*(n-2)
        madd    w8, w8, w9, w0     // w8 = (n-1)*(n-2)   n
        lsr     x9, x10, #1        // w9 = (n-1)*(n-2)/2
        mvn     w9, w9             // w9 = ~w9 = -w9 - 1
        add     w0, w8, w9         // (n-1)*(n-2) - (n-1)*(n-2)/2   n - 1 I think?
.LBB0_2:
        ret
// count up version, ending with n-1.  clang15 -O3
sum_ints(int):
        subs    w8, w0, #1       // n-1
        b.lt    .LBB0_2
        sub     w9, w0, #2       // n-2
        umull   x9, w8, w9       // (n-1)*(n-2)
        lsr     x9, x9, #1       // . / 2
        add     w0, w8, w9       // (n-1)*(n-2)/2   (n-1) = (n-1)*(n-2   2)/2
                                 // = the usual               x  * (x 1   )/2 for x=n-1
        ret
.LBB0_2:
        mov     w0, wzr         // separate return path for all negative inputs
        ret


其他型別的回圈模式-識別/替換

GCC 和 clang 對計算設定位的回圈進行模式識別,以及人們將從 SO 復制/粘貼的標準 bithack 。(這很有用,因為 ISO C 無法提供一種可移植的方式來表達大多數現代 CPU 所具有的這種操作。而 ISO C 僅使用<bit>或通過修復了 C 20 中的該缺陷std::bitset<32> .count())。所以一些真正的代碼庫只是在設定位上有一個 bithack 或簡單的回圈而不是__builtin_popcount因為人們更喜歡簡單并且希望將性能留給編譯器。

這些模式識別器僅在某些特定的實作方式上起作用popcount,即x &= x-1; count 試圖證明每個可能回圈的等價性可能會花費太多編譯時間。由此,我們可以非常確定這些通過尋找特定的實作來作業,而不是尋找每個可能的整數的實際結果。

變數當然無關緊要,但對輸入變數的操作順序很重要。我假設在檢查等效性時以給出相同結果的方式重新排序操作有一定的靈活性。在 GCC 的例子中,顯然number_of_iterations_popcount是發現這個的函式的名稱:編譯器通常想知道一個回圈將運行多少次迭代:如果它是一個小常量,他們可能會完全展開它。如果它可以在開始回圈之前從其他變數中計算出來,它就是自動矢量化的候選物件。(GCC/clang 無法自動向量化搜索回圈,或任何其他具有資料依賴 if() 中斷的內容。)

如Count the number of set bits in a 32-bit integer的頂部答案所示,GCC10 和 clang10 ( Godbolt ) 也可以popcount使用 SWAR bithack 識別 a,因此您可以兩全其美:理想情況下是一條指令,但如果不是那么至少是一個好策略。

當預期的設定位數較小時,計算x &= x-1until的迭代次數x == 0是可以的,因此有時也是一個明智的選擇,因為如果硬體 popcount 可用,GCC / clang 可以替代的另一件事。(并且撰寫簡單,不需要屏蔽常量,并且可以編譯成小的機器代碼大小,-Os如果不被單個指令替換的話。)

int popcount_blsr_until_zero(unsigned x){
    int count = 0;
    while (x){
        count  ;  // loop trip-count = popcount, this is what GCC looks for
        x &= x - 1;
    }
    return count;
}

用于 x86-64 的 GCC 和 clang,-O3 -march=nehalem或更高版本,用于此版本和其他一些版本的 Godbolt 。

# gcc12 -O3 -march=znver2
popcount_blsr_until_zero(unsigned int):
        popcnt  eax, edi
        ret
// clang -O3        for AArch64
popcount_blsr_until_zero(unsigned int):
        mov     w8, w0            // this is pointless, GCC doesn't do it.
        fmov    d0, x8
        cnt     v0.8b, v0.8b      // ARM unfortunately only has vector popcnt
        uaddlv  h0, v0.8b         // hsum bytes
        fmov    w0, s0            // copy back to GP-integer
        ret

通過模式識別進行代碼替換的最簡單形式之一是編譯(n<<5) | (n>>(32-5))成 rotate-left by 5。(請參閱此 Q&A以了解運行時變數計數,以及如何安全地撰寫能夠被識別的內容,但即使是計數也能避免 UB 0.)

但這可能會在編譯程序中發生得足夠晚,您將其稱為窺孔優化CISC ISA 往往有更多的窺孔優化,比如 x86 有特殊情況的更短指令來在累加器中簽名(cdqe而不是movzx eax, ax)。x86 xor-將暫存器設定為零的歸零仍然可以稱為窺孔,盡管有時需要重新排列東西,因為它會破壞 FLAGS 而mov eax, 0不會。

-fpeephole2GCC 使用(部分)啟用異或歸零-O2也許把它當作一個窺視孔就是為什么 GCC 有時做得不好并且無法找到重新排序的方法所以xor-zero //cmpsetcc不是cmp/ setcc/ movzx,因為 x86 setcc 根據 FLAGS 條件設定暫存器很糟糕,只寫低 8 位。AArch64 有更好的指令,例如csinc可以與零暫存器一起使用以實作 0/1,或與其他暫存器一起使用以有條件地選擇和遞增。

但是級數和回圈是一種更大規模的替代,而不是我認為的窺孔,特別是因為它不是特定于目標的。

還相關:

  • 是否允許 C 編譯器用另一種演算法替換演算法?- 是的。但通常他們不會這樣做,因為編譯器足夠機械以至于它們并不總是正確的,并且為資料選擇一種有效的演算法是 C 程式員希望編譯器尊重的東西,除非有一條指令顯然總是更快.

  • clang 知道如何__builtin_popcount使用 AVX2 自動矢量化陣列vpshub作為半位元組查找表。它不僅僅是通過相同的操作制作 SIMD 版本,它再次使用了人類編譯器開發人員放在那里供其使用的擴展。

  • 為什么編譯器優化不為 1..N 的整數總和生成回圈?是關于這種優化不會發生的情況,例如一個帶有j <= nfor unsigned 的情況,這是一個潛在的無限回圈。

    那里的評論發現了一些關于何時可以優化 clang 的有趣限制:例如,如果回圈是for (int j=0 ; j < n; j = 3),則行程計數將難以預測/計算,并且會破壞此優化。

uj5u.com熱心網友回復:

至少要開始,這您的“基本數論”公式,盡管形式相當混亂且效率低下。clang 開發人員顯然也參加了該課程。

一些幫助驗證它的提示:

  • 您的sum_squares函式有一個差一錯誤,總和僅為n-1. 因此我們期望得到的公式是n(n-1)(2n-1)/6

  • orr w9, w9, #0x2這種情況下,等同于add w9, w9, #0x2前面的指令,mul w9, w8, w8加載w9了 的平方w8現在唯一的完美平方模 4 是 0 和 1,它們的第 1 位都是清零的,因此第 1 位w9將永遠是清零的。所以w9 | 2相當于w9 2. (不,我不知道為什么 clang 會這樣做。)

  • 正如哈羅德評論的那樣,乘以0x55555556mod 2^32 相當于除以 3 和乘以 2(假設沒有余數)。這種技術有時被稱為“幻數除法”。請參閱為什么 GCC 在實作整數除法時使用乘以一個奇怪的數字?. 因此,在此之前x11 = ((n - 1)(n - 2)(n - 3)) / 2,請注意,您始終是 3 的倍數(除以 2 始終是精確的,因為分子始終是偶數)。因此w11 * w12導致(n-1)(n-2)(n-3)/6.

將所有這些放在一起,您可以檢查代數以驗證最終結果是否等同于n(n-1)(2n-1)/6

我不能說 clang 如何執行此優化。我想我曾經經歷過弄清楚哪個 LLVM 優化程序使它發生的練習,但我不記得它是什么。但是有一些已知的演算法可以自動匯出這種封閉形式的運算式,例如Gosper 演算法所以 clang 可能正在應用類似的東西。我現在在猜測,但也許演算法以未簡化的形式吐出一個公式,也許 clang 只是發出直接對應的代碼,而不是首先嘗試進行代數簡化。

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/533856.html

標籤:部件优化铛LLVMarm64

上一篇:轉換為ASCII時只列印最后2位數字?[x86_32]-NASM

下一篇:Greatestof4NumbersSolidity匯編代碼

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more