[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-7-gaseffiziente-schleifen-verzweigungen-yul":3},{"article":4,"author":58},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":7,"meta_description":16,"focus_keyword":17,"og_image":18,"canonical_url":18,"robots_meta":19,"created_at":15,"updated_at":15,"tags":20,"category_name":38,"related_articles":39},"d7000000-0000-0000-0000-000000000107","a0000000-0000-0000-0000-000000000072","Deep EVM #7: Gaseffiziente Schleifen und Verzweigungen in Yul","deep-evm-7-gaseffiziente-schleifen-verzweigungen-yul","Hochoptimierte Schleifen- und Verzweigungsmuster in Yul implementieren: Loop-Unrolling, Lookup-Tabellen, Batch-Verarbeitung und das Vermeiden teurer Vergleiche.","## Schleifen in der EVM sind teuer\n\nJede Iteration einer Schleife in der EVM kostet Gas fuer JUMPI (10 Gas), den Vergleich (3 Gas), die Inkrementierung (3+3 Gas fuer ADD+MSTORE\u002FDUP) und die eigentliche Arbeit. Bei Tausenden von Iterationen summiert sich das schnell.\n\nIn Solidity generiert der Compiler relativ effizienten Schleifencode, aber er kann die Semantik Ihrer Schleife nicht aendern. In Yul haben Sie die volle Kontrolle.\n\n## Grundlegende Schleifenoptimierung\n\n### Rueckwaerts zaehlen statt vorwaerts\n```yul\n\u002F\u002F Vorwaerts (standard):\nfor { let i := 0 } lt(i, n) { i := add(i, 1) } {\n    \u002F\u002F LT-Vergleich: 3 Gas pro Iteration\n}\n\n\u002F\u002F Rueckwaerts (optimiert):\nfor { let i := n } i { i := sub(i, 1) } {\n    \u002F\u002F ISZERO implizit im Bedingungstest: spart 1 Opcode\n}\n```\n\nWarum ist Rueckwaertszaehlen schneller? Der Bedingungstest `i` ist aequivalent zu `iszero(iszero(i))`, was der EVM-Compiler zu einem einfachen Nulltest optimiert. `lt(i, n)` erfordert einen expliziten LT-Opcode.\n\n### Loop-Unrolling\n```yul\n\u002F\u002F Statt 4 Iterationen:\nfor { let i := 0 } lt(i, 4) { i := add(i, 1) } {\n    sstore(add(baseSlot, i), 0)\n}\n\n\u002F\u002F Entrollt (spart JUMP\u002FJUMPI-Overhead):\nsstore(baseSlot, 0)\nsstore(add(baseSlot, 1), 0)\nsstore(add(baseSlot, 2), 0)\nsstore(add(baseSlot, 3), 0)\n```\n\nBei kleinen, bekannten Iterationszahlen spart Unrolling die JUMP\u002FJUMPI-Kosten (10 Gas pro Iteration) und den Schleifenoverhead.\n\n## Verzweigungen optimieren\n\n### Switch statt if-else-Ketten\n```yul\n\u002F\u002F Schlecht: if-else-Kette (O(n) Vergleiche)\nif eq(selector, 0xa9059cbb) { \u002F* transfer *\u002F }\nif eq(selector, 0x70a08231) { \u002F* balanceOf *\u002F }\nif eq(selector, 0x095ea7b3) { \u002F* approve *\u002F }\n\n\u002F\u002F Besser: switch-Anweisung\nswitch selector\ncase 0xa9059cbb { \u002F* transfer *\u002F }\ncase 0x70a08231 { \u002F* balanceOf *\u002F }\ncase 0x095ea7b3 { \u002F* approve *\u002F }\ndefault { revert(0, 0) }\n```\n\nDer Yul-Compiler optimiert switch-Anweisungen besser als verschachtelte if-Anweisungen, obwohl auf EVM-Ebene beides zu Vergleichen und JUMPIs kompiliert.\n\n## Batch-Verarbeitung\n\n### Mehrere Storage-Writes buendeln\n```yul\n\u002F\u002F Statt einzelner Schreibvorgaenge:\nfunction batchWrite(slot, values_ptr, count) {\n    for { let i := 0 } lt(i, count) { i := add(i, 1) } {\n        let value := mload(add(values_ptr, mul(i, 32)))\n        sstore(add(slot, i), value)\n    }\n}\n```\n\n### Parallele Vergleiche mit Bitmasks\n```yul\n\u002F\u002F Pruefe mehrere Bedingungen gleichzeitig:\nlet flags := or(\n    mul(eq(a, target_a), 1),   \u002F\u002F Bit 0\n    mul(eq(b, target_b), 2)    \u002F\u002F Bit 1\n)\nif eq(flags, 3) {\n    \u002F\u002F Beide Bedingungen erfuellt\n}\n```\n\n## Gasvergleich: Solidity vs. Yul\n\nEin konkretes Beispiel — Summierung eines Arrays:\n\n```solidity\n\u002F\u002F Solidity: ~250 Gas fuer 10 Elemente\nfunction sumSolidity(uint256[] calldata arr) external pure returns (uint256 total) {\n    for (uint256 i = 0; i \u003C arr.length; i++) {\n        total += arr[i];\n    }\n}\n```\n\n```yul\n\u002F\u002F Yul: ~180 Gas fuer 10 Elemente\nfunction sumYul(uint256[] calldata arr) external pure returns (uint256 total) {\n    assembly {\n        let len := arr.length\n        let ptr := arr.offset\n        for { let i := 0 } lt(i, len) { i := add(i, 1) } {\n            total := add(total, calldataload(add(ptr, mul(i, 32))))\n        }\n    }\n}\n```\n\nDie Yul-Version spart ~30% Gas, hauptsaechlich durch Vermeidung von Soliditys Bounds-Checking und Stack-Management-Overhead.\n\n## Fortgeschrittene Techniken\n\n### Branchless Minimum\u002FMaximum\n```yul\n\u002F\u002F Minimum ohne Verzweigung (spart JUMPI):\n\u002F\u002F min(a, b) = b ^ ((a ^ b) & -(a \u003C b))\nfunction branchlessMin(a, b) -> result {\n    let diff := xor(a, b)\n    let mask := sub(0, lt(a, b))  \u002F\u002F 0xfff...fff wenn a \u003C b, sonst 0\n    result := xor(b, and(diff, mask))\n}\n```\n\n### Effiziente Modulo-Operationen fuer Zweierpotenzen\n```yul\n\u002F\u002F x % 8 (teuer):\nlet r := mod(x, 8)  \u002F\u002F 5 Gas\n\n\u002F\u002F x & 7 (guenstig):\nlet r := and(x, 7)  \u002F\u002F 3 Gas\n```\n\n## Fazit\n\nGaseffiziente Schleifen und Verzweigungen in Yul erfordern ein Verstaendnis der zugrunde liegenden Opcode-Kosten. Rueckwaerts zaehlen, Loop-Unrolling, Batch-Verarbeitung und Branchless-Techniken koennen den Gasverbrauch erheblich reduzieren. Im naechsten und letzten Artikel dieser Serie werden wir einen vollstaendigen Token-Swap in reinem Yul implementieren und alle bisher gelernten Techniken anwenden.","\u003Ch2 id=\"schleifen-in-der-evm-sind-teuer\">Schleifen in der EVM sind teuer\u003C\u002Fh2>\n\u003Cp>Jede Iteration einer Schleife in der EVM kostet Gas fuer JUMPI (10 Gas), den Vergleich (3 Gas), die Inkrementierung (3+3 Gas fuer ADD+MSTORE\u002FDUP) und die eigentliche Arbeit. Bei Tausenden von Iterationen summiert sich das schnell.\u003C\u002Fp>\n\u003Cp>In Solidity generiert der Compiler relativ effizienten Schleifencode, aber er kann die Semantik Ihrer Schleife nicht aendern. In Yul haben Sie die volle Kontrolle.\u003C\u002Fp>\n\u003Ch2 id=\"grundlegende-schleifenoptimierung\">Grundlegende Schleifenoptimierung\u003C\u002Fh2>\n\u003Ch3>Rueckwaerts zaehlen statt vorwaerts\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-yul\">\u002F\u002F Vorwaerts (standard):\nfor { let i := 0 } lt(i, n) { i := add(i, 1) } {\n    \u002F\u002F LT-Vergleich: 3 Gas pro Iteration\n}\n\n\u002F\u002F Rueckwaerts (optimiert):\nfor { let i := n } i { i := sub(i, 1) } {\n    \u002F\u002F ISZERO implizit im Bedingungstest: spart 1 Opcode\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Warum ist Rueckwaertszaehlen schneller? Der Bedingungstest \u003Ccode>i\u003C\u002Fcode> ist aequivalent zu \u003Ccode>iszero(iszero(i))\u003C\u002Fcode>, was der EVM-Compiler zu einem einfachen Nulltest optimiert. \u003Ccode>lt(i, n)\u003C\u002Fcode> erfordert einen expliziten LT-Opcode.\u003C\u002Fp>\n\u003Ch3>Loop-Unrolling\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-yul\">\u002F\u002F Statt 4 Iterationen:\nfor { let i := 0 } lt(i, 4) { i := add(i, 1) } {\n    sstore(add(baseSlot, i), 0)\n}\n\n\u002F\u002F Entrollt (spart JUMP\u002FJUMPI-Overhead):\nsstore(baseSlot, 0)\nsstore(add(baseSlot, 1), 0)\nsstore(add(baseSlot, 2), 0)\nsstore(add(baseSlot, 3), 0)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Bei kleinen, bekannten Iterationszahlen spart Unrolling die JUMP\u002FJUMPI-Kosten (10 Gas pro Iteration) und den Schleifenoverhead.\u003C\u002Fp>\n\u003Ch2 id=\"verzweigungen-optimieren\">Verzweigungen optimieren\u003C\u002Fh2>\n\u003Ch3>Switch statt if-else-Ketten\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-yul\">\u002F\u002F Schlecht: if-else-Kette (O(n) Vergleiche)\nif eq(selector, 0xa9059cbb) { \u002F* transfer *\u002F }\nif eq(selector, 0x70a08231) { \u002F* balanceOf *\u002F }\nif eq(selector, 0x095ea7b3) { \u002F* approve *\u002F }\n\n\u002F\u002F Besser: switch-Anweisung\nswitch selector\ncase 0xa9059cbb { \u002F* transfer *\u002F }\ncase 0x70a08231 { \u002F* balanceOf *\u002F }\ncase 0x095ea7b3 { \u002F* approve *\u002F }\ndefault { revert(0, 0) }\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Der Yul-Compiler optimiert switch-Anweisungen besser als verschachtelte if-Anweisungen, obwohl auf EVM-Ebene beides zu Vergleichen und JUMPIs kompiliert.\u003C\u002Fp>\n\u003Ch2 id=\"batch-verarbeitung\">Batch-Verarbeitung\u003C\u002Fh2>\n\u003Ch3>Mehrere Storage-Writes buendeln\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-yul\">\u002F\u002F Statt einzelner Schreibvorgaenge:\nfunction batchWrite(slot, values_ptr, count) {\n    for { let i := 0 } lt(i, count) { i := add(i, 1) } {\n        let value := mload(add(values_ptr, mul(i, 32)))\n        sstore(add(slot, i), value)\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Parallele Vergleiche mit Bitmasks\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-yul\">\u002F\u002F Pruefe mehrere Bedingungen gleichzeitig:\nlet flags := or(\n    mul(eq(a, target_a), 1),   \u002F\u002F Bit 0\n    mul(eq(b, target_b), 2)    \u002F\u002F Bit 1\n)\nif eq(flags, 3) {\n    \u002F\u002F Beide Bedingungen erfuellt\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"gasvergleich-solidity-vs-yul\">Gasvergleich: Solidity vs. Yul\u003C\u002Fh2>\n\u003Cp>Ein konkretes Beispiel — Summierung eines Arrays:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F Solidity: ~250 Gas fuer 10 Elemente\nfunction sumSolidity(uint256[] calldata arr) external pure returns (uint256 total) {\n    for (uint256 i = 0; i &lt; arr.length; i++) {\n        total += arr[i];\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode class=\"language-yul\">\u002F\u002F Yul: ~180 Gas fuer 10 Elemente\nfunction sumYul(uint256[] calldata arr) external pure returns (uint256 total) {\n    assembly {\n        let len := arr.length\n        let ptr := arr.offset\n        for { let i := 0 } lt(i, len) { i := add(i, 1) } {\n            total := add(total, calldataload(add(ptr, mul(i, 32))))\n        }\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Die Yul-Version spart ~30% Gas, hauptsaechlich durch Vermeidung von Soliditys Bounds-Checking und Stack-Management-Overhead.\u003C\u002Fp>\n\u003Ch2 id=\"fortgeschrittene-techniken\">Fortgeschrittene Techniken\u003C\u002Fh2>\n\u003Ch3>Branchless Minimum\u002FMaximum\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-yul\">\u002F\u002F Minimum ohne Verzweigung (spart JUMPI):\n\u002F\u002F min(a, b) = b ^ ((a ^ b) &amp; -(a &lt; b))\nfunction branchlessMin(a, b) -&gt; result {\n    let diff := xor(a, b)\n    let mask := sub(0, lt(a, b))  \u002F\u002F 0xfff...fff wenn a &lt; b, sonst 0\n    result := xor(b, and(diff, mask))\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Effiziente Modulo-Operationen fuer Zweierpotenzen\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-yul\">\u002F\u002F x % 8 (teuer):\nlet r := mod(x, 8)  \u002F\u002F 5 Gas\n\n\u002F\u002F x &amp; 7 (guenstig):\nlet r := and(x, 7)  \u002F\u002F 3 Gas\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"fazit\">Fazit\u003C\u002Fh2>\n\u003Cp>Gaseffiziente Schleifen und Verzweigungen in Yul erfordern ein Verstaendnis der zugrunde liegenden Opcode-Kosten. Rueckwaerts zaehlen, Loop-Unrolling, Batch-Verarbeitung und Branchless-Techniken koennen den Gasverbrauch erheblich reduzieren. Im naechsten und letzten Artikel dieser Serie werden wir einen vollstaendigen Token-Swap in reinem Yul implementieren und alle bisher gelernten Techniken anwenden.\u003C\u002Fp>\n","de","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:29.939038Z","Hochoptimierte Schleifen- und Verzweigungsmuster in Yul: Loop-Unrolling, Batch-Verarbeitung, Branchless-Techniken und Gasvergleiche.","Yul gaseffiziente Schleifen",null,"index, follow",[21,26,30,34],{"id":22,"name":23,"slug":24,"created_at":25},"c0000000-0000-0000-0000-000000000016","EVM","evm","2026-03-28T10:44:21.513630Z",{"id":27,"name":28,"slug":29,"created_at":25},"c0000000-0000-0000-0000-000000000020","Gas Optimization","gas-optimization",{"id":31,"name":32,"slug":33,"created_at":25},"c0000000-0000-0000-0000-000000000014","Solidity","solidity",{"id":35,"name":36,"slug":37,"created_at":25},"c0000000-0000-0000-0000-000000000018","Yul","yul","Blockchain",[40,46,52],{"id":41,"title":42,"slug":43,"excerpt":44,"locale":12,"category_name":38,"published_at":45},"d0000000-0000-0000-0000-000000000611","Die Ethereum-Interoperabilitaetsschicht: Wie 55+ L2s zu einer Chain werden","ethereum-interoperabilitaetsschicht-55-l2s-eine-chain","Ethereum hat 55+ Layer-2-Rollups, die Liquiditaet und Nutzererfahrung fragmentieren. Die Ethereum-Interoperabilitaetsschicht — bestehend aus Cross-Rollup-Messaging, Shared Sequencern und Based Rollups — zielt darauf ab, sie zu einem einzigen komponierbaren Netzwerk zu vereinen.","2026-03-28T10:44:45.264352Z",{"id":47,"title":48,"slug":49,"excerpt":50,"locale":12,"category_name":38,"published_at":51},"d0000000-0000-0000-0000-000000000610","ZK-Beweise jenseits von Rollups: Verifizierbare KI-Inferenz auf Ethereum","zk-beweise-jenseits-von-rollups-verifizierbare-ki-inferenz-ethereum","Zero-Knowledge-Beweise sind nicht mehr nur ein Skalierungswerkzeug. Im Jahr 2026 ermoeglicht zkML verifizierbare KI-Inferenz on-chain, ZK-Coprozessoren verlagern schwere Berechnungen off-chain mit On-Chain-Verifizierung, und neue Beweissysteme wie SP1 und Jolt machen es praktikabel.","2026-03-28T10:44:45.257775Z",{"id":53,"title":54,"slug":55,"excerpt":56,"locale":12,"category_name":38,"published_at":57},"d0000000-0000-0000-0000-000000000587","EIP-7702 in der Praxis: Smart-Account-Flows nach Pectra erstellen","eip-7702-in-der-praxis-smart-account-flows-nach-pectra-erstellen","EIP-7702 ermoeglicht jedem Ethereum-EOA, innerhalb einer einzelnen Transaktion voruebergehend als Smart Contract zu agieren. So implementieren Sie Batch-Transaktionen, Gas-Sponsoring und Social Recovery mit dem neuen Account-Abstraction-Primitiv.","2026-03-28T10:44:43.781201Z",{"id":13,"name":59,"slug":60,"bio":61,"photo_url":18,"linkedin":18,"role":62,"created_at":63,"updated_at":63},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]