authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-11 20:26:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-11 20:26:53-07:00
logab3ac291ac08435f7aba1fc8a53fe0a0290cc1e1
tree5f6dd2a4a7dc97a72e3652fff09399ed1cba8b83
parent37cdb5dbf90acd61584bae4a6661d0a6f9b54295
parentc97d64b677eb891144fb356e1f4b9011c60cc0e2

Merge remote-tracking branch 'origin/master' into llvm15


51 files changed, 2502 insertions(+), 1721 deletions(-)

lib/docs/main.js+231-64
......@@ -203,7 +203,7 @@ var zigAnalysis;
203203 if (!("type" in resolvedExpr)) {
204204 return null;
205205 }
206 let type = zigAnalysis.types[resolvedExpr.type];
206 let type = getType(resolvedExpr.type);
207207
208208 outer: for (let i = 0; i < 10000; i += 1) {
209209 switch (type.kind) {
......@@ -212,7 +212,7 @@ var zigAnalysis;
212212 let child = type.child;
213213 let resolvedChild = resolveValue(child);
214214 if ("type" in resolvedChild) {
215 type = zigAnalysis.types[resolvedChild.type];
215 type = getType(resolvedChild.type);
216216 continue;
217217 } else {
218218 return null;
......@@ -276,7 +276,7 @@ var zigAnalysis;
276276 }
277277
278278 if ("declRef" in value.expr) {
279 value = zigAnalysis.decls[value.expr.declRef].value;
279 value = getDecl(value.expr.declRef).value;
280280 continue;
281281 }
282282
......@@ -430,7 +430,7 @@ var zigAnalysis;
430430 curNav.pkgObjs.push(pkg);
431431 }
432432
433 let currentType = zigAnalysis.types[pkg.main];
433 let currentType = getType(pkg.main);
434434 curNav.declObjs = [currentType];
435435 for (let i = 0; i < curNav.declNames.length; i += 1) {
436436 let childDecl = findSubDecl(currentType, curNav.declNames[i]);
......@@ -440,7 +440,7 @@ var zigAnalysis;
440440
441441 let childDeclValue = resolveValue(childDecl.value).expr;
442442 if ("type" in childDeclValue) {
443 const t = zigAnalysis.types[childDeclValue.type];
443 const t = getType(childDeclValue.type);
444444 if (t.kind != typeKinds.Fn) {
445445 childDecl = t;
446446 }
......@@ -478,19 +478,21 @@ var zigAnalysis;
478478 }
479479
480480 if (lastIsDecl && last.kind === "const") {
481 let typeObj = zigAnalysis.types[resolveValue(last.value).expr.type];
482 if (typeObj && typeObj.kind === typeKinds.Fn) {
483 return renderFn(last);
481 const value = resolveValue(last.value);
482 if ("type" in value.expr) {
483 let typeObj = getType(value.expr.type);
484 if (typeObj.kind === typeKinds.Fn) {
485 return renderFn(last);
486 }
484487 }
485
486488 return renderValue(last);
487489 }
488490
489491 }
490492
491493 function renderDocTest(decl) {
492 if (!("decltest" in decl)) return;
493 const astNode = zigAnalysis.astNodes[decl.decltest];
494 if (!decl.decltest) return;
495 const astNode = getAstNode(decl.decltest);
494496 domSectDocTests.classList.remove("hidden");
495497 domDocTestsCode.innerHTML = astNode.code;
496498 }
......@@ -498,7 +500,7 @@ var zigAnalysis;
498500 function renderUnknownDecl(decl) {
499501 domDeclNoRef.classList.remove("hidden");
500502
501 let docs = zigAnalysis.astNodes[decl.src].docs;
503 let docs = getAstNode(decl.src).docs;
502504 if (docs != null) {
503505 domTldDocs.innerHTML = markdown(docs);
504506 } else {
......@@ -509,18 +511,18 @@ var zigAnalysis;
509511 }
510512
511513 function typeIsErrSet(typeIndex) {
512 let typeObj = zigAnalysis.types[typeIndex];
514 let typeObj = getType(typeIndex);
513515 return typeObj.kind === typeKinds.ErrorSet;
514516 }
515517
516518 function typeIsStructWithNoFields(typeIndex) {
517 let typeObj = zigAnalysis.types[typeIndex];
519 let typeObj = getType(typeIndex);
518520 if (typeObj.kind !== typeKinds.Struct) return false;
519521 return typeObj.fields.length == 0;
520522 }
521523
522524 function typeIsGenericFn(typeIndex) {
523 let typeObj = zigAnalysis.types[typeIndex];
525 let typeObj = getType(typeIndex);
524526 if (typeObj.kind !== typeKinds.Fn) {
525527 return false;
526528 }
......@@ -532,12 +534,12 @@ var zigAnalysis;
532534 let last = fnDecl.value.expr.refPath.length - 1;
533535 let lastExpr = fnDecl.value.expr.refPath[last];
534536 console.assert("declRef" in lastExpr);
535 fnDecl = zigAnalysis.decls[lastExpr.declRef];
537 fnDecl = getDecl(lastExpr.declRef);
536538 }
537539
538540 let value = resolveValue(fnDecl.value);
539541 console.assert("type" in value.expr);
540 let typeObj = zigAnalysis.types[value.expr.type];
542 let typeObj = getType(value.expr.type);
541543
542544 domFnProtoCode.innerHTML = exprName(value.expr, {
543545 wantHtml: true,
......@@ -546,7 +548,7 @@ var zigAnalysis;
546548 });
547549
548550 let docsSource = null;
549 let srcNode = zigAnalysis.astNodes[fnDecl.src];
551 let srcNode = getAstNode(fnDecl.src);
550552 if (srcNode.docs != null) {
551553 docsSource = srcNode.docs;
552554 }
......@@ -557,14 +559,14 @@ var zigAnalysis;
557559 if ("type" in retExpr) {
558560 let retIndex = retExpr.type;
559561 let errSetTypeIndex = null;
560 let retType = zigAnalysis.types[retIndex];
562 let retType = getType(retIndex);
561563 if (retType.kind === typeKinds.ErrorSet) {
562564 errSetTypeIndex = retIndex;
563565 } else if (retType.kind === typeKinds.ErrorUnion) {
564566 errSetTypeIndex = retType.err.type;
565567 }
566568 if (errSetTypeIndex != null) {
567 let errSetType = zigAnalysis.types[errSetTypeIndex];
569 let errSetType = getType(errSetTypeIndex);
568570 renderErrorSet(errSetType);
569571 }
570572 }
......@@ -578,7 +580,7 @@ var zigAnalysis;
578580 let call = zigAnalysis.calls[resolvedGenericRet.expr.call];
579581 let resolvedFunc = resolveValue({ expr: call.func });
580582 if (!("type" in resolvedFunc.expr)) return;
581 let callee = zigAnalysis.types[resolvedFunc.expr.type];
583 let callee = getType(resolvedFunc.expr.type);
582584 if (!callee.generic_ret) return;
583585 resolvedGenericRet = resolveValue({ expr: callee.generic_ret });
584586 }
......@@ -591,7 +593,7 @@ var zigAnalysis;
591593 }
592594
593595 if (!("type" in resolvedGenericRet.expr)) return;
594 const genericType = zigAnalysis.types[resolvedGenericRet.expr.type];
596 const genericType = getType(resolvedGenericRet.expr.type);
595597 if (isContainerType(genericType)) {
596598 renderContainer(genericType);
597599 }
......@@ -621,7 +623,7 @@ var zigAnalysis;
621623 domFnNoExamples.classList.add("hidden");
622624 }
623625
624 let protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];
626 let protoSrcNode = getAstNode(protoSrcIndex);
625627 if (
626628 docsSource == null &&
627629 protoSrcNode != null &&
......@@ -639,13 +641,13 @@ var zigAnalysis;
639641 function renderFnParamDocs(fnDecl, typeObj) {
640642 let docCount = 0;
641643
642 let fnNode = zigAnalysis.astNodes[fnDecl.src];
644 let fnNode = getAstNode(fnDecl.src);
643645 let fields = fnNode.fields;
644646 let isVarArgs = fnNode.varArgs;
645647
646648 for (let i = 0; i < fields.length; i += 1) {
647649 let field = fields[i];
648 let fieldNode = zigAnalysis.astNodes[field];
650 let fieldNode = getAstNode(field);
649651 if (fieldNode.docs != null) {
650652 docCount += 1;
651653 }
......@@ -659,7 +661,7 @@ var zigAnalysis;
659661
660662 for (let i = 0; i < fields.length; i += 1) {
661663 let field = fields[i];
662 let fieldNode = zigAnalysis.astNodes[field];
664 let fieldNode = getAstNode(field);
663665 let docs = fieldNode.docs;
664666 if (fieldNode.docs == null) {
665667 continue;
......@@ -967,17 +969,17 @@ var zigAnalysis;
967969 }
968970 case "switchOp": {
969971 let condExpr = zigAnalysis.exprs[expr.switchOp.cond_index];
970 let ast = zigAnalysis.astNodes[expr.switchOp.ast];
972 let ast = getAstNode(expr.switchOp.src);
971973 let file_name = expr.switchOp.file_name;
972974 let outer_decl_index = expr.switchOp.outer_decl;
973 let outer_decl = zigAnalysis.types[outer_decl_index];
975 let outer_decl = getType(outer_decl_index);
974976 let line = 0;
975977 // console.log(expr.switchOp)
976978 // console.log(outer_decl)
977979 while (outer_decl_index !== 0 && outer_decl.line_number > 0) {
978980 line += outer_decl.line_number;
979981 outer_decl_index = outer_decl.outer_decl;
980 outer_decl = zigAnalysis.types[outer_decl_index];
982 outer_decl = getType(outer_decl_index);
981983 // console.log(outer_decl)
982984 }
983985 line += ast.line + 1;
......@@ -1028,8 +1030,8 @@ var zigAnalysis;
10281030 case "fieldRef": {
10291031 const enumObj = exprName({ type: expr.fieldRef.type }, opts);
10301032 const field =
1031 zigAnalysis.astNodes[enumObj.ast].fields[expr.fieldRef.index];
1032 const name = zigAnalysis.astNodes[field].name;
1033 getAstNode(enumObj.src).fields[expr.fieldRef.index];
1034 const name = getAstNode(field).name;
10331035 return name;
10341036 }
10351037 case "enumToInt": {
......@@ -1452,13 +1454,13 @@ var zigAnalysis;
14521454 return print_lhs + " " + operator + " " + print_rhs;
14531455 }
14541456 case "errorSets": {
1455 const errUnionObj = zigAnalysis.types[expr.errorSets];
1457 const errUnionObj = getType(expr.errorSets);
14561458 let lhs = exprName(errUnionObj.lhs, opts);
14571459 let rhs = exprName(errUnionObj.rhs, opts);
14581460 return lhs + " || " + rhs;
14591461 }
14601462 case "errorUnion": {
1461 const errUnionObj = zigAnalysis.types[expr.errorUnion];
1463 const errUnionObj = getType(expr.errorUnion);
14621464 let lhs = exprName(errUnionObj.lhs, opts);
14631465 let rhs = exprName(errUnionObj.rhs, opts);
14641466 return lhs + "!" + rhs;
......@@ -1574,7 +1576,7 @@ var zigAnalysis;
15741576 return exprName(exprArg, opts);
15751577 }
15761578 case "declRef": {
1577 return zigAnalysis.decls[expr.declRef].name;
1579 return getDecl(expr.declRef).name;
15781580 }
15791581 case "refPath": {
15801582 return expr.refPath.map((x) => exprName(x, opts)).join(".");
......@@ -1611,7 +1613,7 @@ var zigAnalysis;
16111613 let name = "";
16121614
16131615 let typeObj = expr.type;
1614 if (typeof typeObj === "number") typeObj = zigAnalysis.types[typeObj];
1616 if (typeof typeObj === "number") typeObj = getType(typeObj);
16151617 switch (typeObj.kind) {
16161618 default:
16171619 throw "TODO";
......@@ -1865,7 +1867,7 @@ var zigAnalysis;
18651867 if (fnObj.params) {
18661868 let fields = null;
18671869 let isVarArgs = false;
1868 let fnNode = zigAnalysis.astNodes[fnObj.src];
1870 let fnNode = getAstNode(fnObj.src);
18691871 fields = fnNode.fields;
18701872 isVarArgs = fnNode.varArgs;
18711873
......@@ -1880,7 +1882,7 @@ var zigAnalysis;
18801882 let paramValue = resolveValue({ expr: value });
18811883
18821884 if (fields != null) {
1883 let paramNode = zigAnalysis.astNodes[fields[i]];
1885 let paramNode = getAstNode(fields[i]);
18841886
18851887 if (paramNode.varArgs) {
18861888 payloadHtml += "...";
......@@ -2046,7 +2048,7 @@ var zigAnalysis;
20462048 function shouldSkipParamName(typeRef, paramName) {
20472049 let resolvedTypeRef = resolveValue({ expr: typeRef });
20482050 if ("type" in resolvedTypeRef) {
2049 let typeObj = zigAnalysis.types[resolvedTypeRef.type];
2051 let typeObj = getType(resolvedTypeRef.type);
20502052 if (typeObj.kind === typeKinds.Pointer) {
20512053 let ptrObj = typeObj;
20522054 if (getPtrSize(ptrObj) === pointerSizeEnum.One) {
......@@ -2067,7 +2069,7 @@ var zigAnalysis;
20672069 if (
20682070 rootIsStd &&
20692071 typeObj ===
2070 zigAnalysis.types[zigAnalysis.packages[zigAnalysis.rootPkg].main]
2072 getType(zigAnalysis.packages[zigAnalysis.rootPkg].main)
20712073 ) {
20722074 name = "std";
20732075 } else {
......@@ -2189,7 +2191,7 @@ var zigAnalysis;
21892191
21902192 if (resolvedValue.expr.fieldRef) {
21912193 const declRef = decl.value.expr.refPath[0].declRef;
2192 const type = zigAnalysis.decls[declRef];
2194 const type = getDecl(declRef);
21932195 domFnProtoCode.innerHTML =
21942196 '<span class="tok-kw">const</span> ' +
21952197 escapeHtml(decl.name) +
......@@ -2229,7 +2231,7 @@ var zigAnalysis;
22292231 ";";
22302232 }
22312233
2232 let docs = zigAnalysis.astNodes[decl.src].docs;
2234 let docs = getAstNode(decl.src).docs;
22332235 if (docs != null) {
22342236 domTldDocs.innerHTML = markdown(docs);
22352237 domTldDocs.classList.remove("hidden");
......@@ -2246,7 +2248,7 @@ var zigAnalysis;
22462248 ": " +
22472249 typeValueName(declTypeRef, true, true);
22482250
2249 let docs = zigAnalysis.astNodes[decl.src].docs;
2251 let docs = getAstNode(decl.src).docs;
22502252 if (docs != null) {
22512253 domTldDocs.innerHTML = markdown(docs);
22522254 domTldDocs.classList.remove("hidden");
......@@ -2266,7 +2268,7 @@ var zigAnalysis;
22662268 testsList
22672269 ) {
22682270 for (let i = 0; i < decls.length; i += 1) {
2269 let decl = zigAnalysis.decls[decls[i]];
2271 let decl = getDecl(decls[i]);
22702272 let declValue = resolveValue(decl.value);
22712273
22722274 if (decl.isTest) {
......@@ -2282,7 +2284,7 @@ var zigAnalysis;
22822284 if (decl.kind === "const") {
22832285 if ("type" in declValue.expr) {
22842286 // We have the actual type expression at hand.
2285 const typeExpr = zigAnalysis.types[declValue.expr.type];
2287 const typeExpr = getType(declValue.expr.type);
22862288 if (typeExpr.kind == typeKinds.Fn) {
22872289 const funcRetExpr = resolveValue({
22882290 expr: typeExpr.ret,
......@@ -2310,7 +2312,7 @@ var zigAnalysis;
23102312 typesList.push(decl);
23112313 }
23122314 }
2313 } else if ("typeRef" in declValue) {
2315 } else if (declValue.typeRef) {
23142316 if ("type" in declValue.typeRef && declValue.typeRef == typeTypeId) {
23152317 // We don't know what the type expression is, but we know it's a type.
23162318 typesList.push(decl);
......@@ -2324,7 +2326,7 @@ var zigAnalysis;
23242326 }
23252327 }
23262328 function renderSourceFileLink(decl) {
2327 let srcNode = zigAnalysis.astNodes[decl.src];
2329 let srcNode = getAstNode(decl.src);
23282330
23292331 return "<a style=\"float: right;\" href=\"" +
23302332 sourceFileUrlTemplate.replace("{{file}}",
......@@ -2377,7 +2379,7 @@ var zigAnalysis;
23772379 testsList.sort(byNameProperty);
23782380
23792381 if (container.src != null) {
2380 let docs = zigAnalysis.astNodes[container.src].docs;
2382 let docs = getAstNode(container.src).docs;
23812383 if (docs != null) {
23822384 domTldDocs.innerHTML = markdown(docs);
23832385 domTldDocs.classList.remove("hidden");
......@@ -2457,7 +2459,7 @@ var zigAnalysis;
24572459 });
24582460 tdFnSrc.innerHTML = renderSourceFileLink(decl);
24592461
2460 let docs = zigAnalysis.astNodes[decl.src].docs;
2462 let docs = getAstNode(decl.src).docs;
24612463 if (docs != null) {
24622464 tdDesc.innerHTML = shortDescMarkdown(docs);
24632465 } else {
......@@ -2467,12 +2469,12 @@ var zigAnalysis;
24672469 domSectFns.classList.remove("hidden");
24682470 }
24692471
2470 let containerNode = zigAnalysis.astNodes[container.src];
2472 let containerNode = getAstNode(container.src);
24712473 if (containerNode.fields && containerNode.fields.length > 0) {
24722474 resizeDomList(domListFields, containerNode.fields.length, "<div></div>");
24732475
24742476 for (let i = 0; i < containerNode.fields.length; i += 1) {
2475 let fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
2477 let fieldNode = getAstNode(containerNode.fields[i]);
24762478 let divDom = domListFields.children[i];
24772479 let fieldName = fieldNode.name;
24782480 let docs = fieldNode.docs;
......@@ -2528,7 +2530,7 @@ var zigAnalysis;
25282530
25292531 tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
25302532
2531 let docs = zigAnalysis.astNodes[decl.src].docs;
2533 let docs = getAstNode(decl.src).docs;
25322534 if (docs != null) {
25332535 tdDesc.innerHTML = shortDescMarkdown(docs);
25342536 } else {
......@@ -2561,7 +2563,7 @@ var zigAnalysis;
25612563 wantLink: true,
25622564 });
25632565
2564 let docs = zigAnalysis.astNodes[decl.src].docs;
2566 let docs = getAstNode(decl.src).docs;
25652567 if (docs != null) {
25662568 tdDesc.innerHTML = shortDescMarkdown(docs);
25672569 } else {
......@@ -2594,7 +2596,7 @@ var zigAnalysis;
25942596 wantLink: true,
25952597 });
25962598
2597 let docs = zigAnalysis.astNodes[decl.src].docs;
2599 let docs = getAstNode(decl.src).docs;
25982600 if (docs != null) {
25992601 tdDesc.innerHTML = shortDescMarkdown(docs);
26002602 } else {
......@@ -2668,7 +2670,7 @@ var zigAnalysis;
26682670
26692671 function findTypeTypeId() {
26702672 for (let i = 0; i < zigAnalysis.types.length; i += 1) {
2671 if (zigAnalysis.types[i].kind == typeKinds.Type) {
2673 if (getType(i).kind == typeKinds.Type) {
26722674 return i;
26732675 }
26742676 }
......@@ -2732,11 +2734,11 @@ var zigAnalysis;
27322734 if ("value" in parentType) {
27332735 const rv = resolveValue(parentType.value);
27342736 if ("type" in rv.expr) {
2735 const t = zigAnalysis.types[rv.expr.type];
2737 const t = getType(rv.expr.type);
27362738 if (t.kind == typeKinds.Fn && t.generic_ret != null) {
27372739 const rgr = resolveValue({ expr: t.generic_ret });
27382740 if ("type" in rgr.expr) {
2739 parentType = zigAnalysis.types[rgr.expr.type];
2741 parentType = getType(rgr.expr.type);
27402742 }
27412743 }
27422744 }
......@@ -2746,7 +2748,7 @@ var zigAnalysis;
27462748 if (!parentType.pubDecls) return null;
27472749 for (let i = 0; i < parentType.pubDecls.length; i += 1) {
27482750 let declIndex = parentType.pubDecls[i];
2749 let childDecl = zigAnalysis.decls[declIndex];
2751 let childDecl = getDecl(declIndex);
27502752 if (childDecl.name === childName) {
27512753 return childDecl;
27522754 }
......@@ -2754,7 +2756,7 @@ var zigAnalysis;
27542756 if (!parentType.privDecls) return null;
27552757 for (let i = 0; i < parentType.privDecls.length; i += 1) {
27562758 let declIndex = parentType.privDecls[i];
2757 let childDecl = zigAnalysis.decls[declIndex];
2759 let childDecl = getDecl(declIndex);
27582760 if (childDecl.name === childName) {
27592761 return childDecl;
27602762 }
......@@ -2805,7 +2807,7 @@ var zigAnalysis;
28052807 let stack = [
28062808 {
28072809 declNames: [],
2808 type: zigAnalysis.types[pkg.main],
2810 type: getType(pkg.main),
28092811 },
28102812 ];
28112813 while (stack.length !== 0) {
......@@ -2819,7 +2821,7 @@ var zigAnalysis;
28192821 let mainDeclIndex = t.pubDecls[declI];
28202822 if (list[mainDeclIndex] != null) continue;
28212823
2822 let decl = zigAnalysis.decls[mainDeclIndex];
2824 let decl = getDecl(mainDeclIndex);
28232825 let declVal = resolveValue(decl.value);
28242826 let declNames = item.declNames.concat([decl.name]);
28252827 list[mainDeclIndex] = {
......@@ -2827,7 +2829,7 @@ var zigAnalysis;
28272829 declNames: declNames,
28282830 };
28292831 if ("type" in declVal.expr) {
2830 let value = zigAnalysis.types[declVal.expr.type];
2832 let value = getType(declVal.expr.type);
28312833 if (declCanRepresentTypeKind(value.kind)) {
28322834 canonTypeDecls[declVal.type] = mainDeclIndex;
28332835 }
......@@ -2843,7 +2845,7 @@ var zigAnalysis;
28432845 if (value.kind == typeKinds.Fn && value.generic_ret != null) {
28442846 let resolvedVal = resolveValue({ expr: value.generic_ret });
28452847 if ("type" in resolvedVal.expr) {
2846 let generic_type = zigAnalysis.types[resolvedVal.expr.type];
2848 let generic_type = getType(resolvedVal.expr.type);
28472849 if (isContainerType(generic_type)) {
28482850 stack.push({
28492851 declNames: declNames,
......@@ -3394,11 +3396,11 @@ var zigAnalysis;
33943396 let canonPath = getCanonDeclPath(declIndex);
33953397 if (canonPath == null) continue;
33963398
3397 let decl = zigAnalysis.decls[declIndex];
3399 let decl = getDecl(declIndex);
33983400 let lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];
33993401 let fullPathSearchText =
34003402 lastPkgName + "." + canonPath.declNames.join(".");
3401 let astNode = zigAnalysis.astNodes[decl.src];
3403 let astNode = getAstNode(decl.src);
34023404 let fileAndDocs = ""; //zigAnalysis.files[astNode.file];
34033405 // TODO: understand what this piece of code is trying to achieve
34043406 // also right now `files` are expressed as a hashmap.
......@@ -3513,4 +3515,169 @@ var zigAnalysis;
35133515 function byNameProperty(a, b) {
35143516 return operatorCompare(a.name, b.name);
35153517 }
3518
3519
3520 function getDecl(idx) {
3521 const decl = zigAnalysis.decls[idx];
3522 return {
3523 name: decl[0],
3524 kind: decl[1],
3525 isTest: decl[2],
3526 src: decl[3],
3527 value: decl[4],
3528 decltest: decl[5],
3529 };
3530 }
3531
3532 function getAstNode(idx) {
3533 const ast = zigAnalysis.astNodes[idx];
3534 return {
3535 file: ast[0],
3536 line: ast[1],
3537 col: ast[2],
3538 name: ast[3],
3539 code: ast[4],
3540 docs: ast[5],
3541 fields: ast[6],
3542 comptime: ast[7],
3543 };
3544 }
3545
3546 function getType(idx){
3547 const ty = zigAnalysis.types[idx];
3548 switch(ty[0]) {
3549 default:
3550 throw "unhandled type kind!";
3551 case 0: // Unanalyzed
3552 throw "unanalyzed type!";
3553 case 1: // Type
3554 case 2: // Void
3555 case 3: // Bool
3556 case 4: // NoReturn
3557 case 5: // Int
3558 case 6: // Float
3559 return { kind: ty[0], name: ty[1]};
3560 case 7: // Pointer
3561 return {
3562 kind: ty[0],
3563 size: ty[1],
3564 child: ty[2],
3565 sentinel: ty[3],
3566 align: ty[4],
3567 address_space: ty[5],
3568 bit_start: ty[6],
3569 host_size: ty[7],
3570 is_ref: ty[8],
3571 is_allowzero: ty[9],
3572 is_mutable: ty[10],
3573 is_volatile: ty[11],
3574 has_sentinel: ty[12],
3575 has_align: ty[13],
3576 has_addrspace: ty[14],
3577 has_bit_range: ty[15],
3578 };
3579 case 8: // Array
3580 return {
3581 kind: ty[0],
3582 len: ty[1],
3583 child: ty[2],
3584 sentinel: ty[3],
3585 };
3586 case 9: // Struct
3587 return {
3588 kind: ty[0],
3589 name: ty[1],
3590 src: ty[2],
3591 privDecls: ty[3],
3592 pubDecls: ty[4],
3593 fields: ty[5],
3594 line_number: ty[6],
3595 outer_decl: ty[7],
3596 };
3597 case 10: // ComptimeExpr
3598 case 11: // ComptimeFloat
3599 case 12: // ComptimeInt
3600 case 13: // Undefined
3601 case 14: // Null
3602 return { kind: ty[0], name: ty[1] };
3603 case 15: // Optional
3604 return {
3605 kind: ty[0],
3606 name: ty[1],
3607 child: ty[2],
3608 };
3609 case 16: // ErrorUnion
3610 return {
3611 kind: ty[0],
3612 lhs: ty[1],
3613 rhs: ty[2],
3614 };
3615 case 17: // InferredErrorUnion
3616 return {
3617 kind: ty[0],
3618 payload: ty[1],
3619 };
3620 case 18: // ErrorSet
3621 return {
3622 kind: ty[0],
3623 name: ty[1],
3624 fields: ty[2],
3625 };
3626 case 19: // Enum
3627 return {
3628 kind: ty[0],
3629 name: ty[1],
3630 src: ty[2],
3631 privDecls: ty[3],
3632 pubDecls: ty[4],
3633 };
3634 case 20: // Union
3635 return {
3636 kind: ty[0],
3637 name: ty[1],
3638 src: ty[2],
3639 privDecls: ty[3],
3640 pubDecls: ty[4],
3641 fields: ty[5],
3642 };
3643 case 21: // Fn
3644 return {
3645 kind: ty[0],
3646 name: ty[1],
3647 src: ty[2],
3648 ret: ty[3],
3649 generic_ret: ty[4],
3650 params: ty[5],
3651 lib_name: ty[6],
3652 is_var_args: ty[7],
3653 is_inferred_error: ty[8],
3654 has_lib_name: ty[9],
3655 has_cc: ty[10],
3656 cc: ty[11],
3657 align: ty[12],
3658 has_align: ty[13],
3659 is_test: ty[14],
3660 is_extern: ty[15],
3661 };
3662 case 22: // BoundFn
3663 return { kind: ty[0], name: ty[1] };
3664 case 23: // Opaque
3665 return {
3666 kind: ty[0],
3667 name: ty[1],
3668 src: ty[2],
3669 privDecls: ty[3],
3670 pubDecls: ty[4],
3671 };
3672 case 24: // Frame
3673 case 25: // AnyFrame
3674 case 26: // Vector
3675 case 27: // EnumLiteral
3676 return { kind: ty[0], name: ty[1] };
3677 }
3678 }
3679
35163680})();
3681
3682
3683
lib/std/child_process.zig+1-1
......@@ -508,7 +508,7 @@ pub const ChildProcess = struct {
508508 // it, that's the error code returned by the child process.
509509 _ = std.os.poll(&fd, 0) catch unreachable;
510510
511 // According to eventfd(2) the descriptro is readable if the counter
511 // According to eventfd(2) the descriptor is readable if the counter
512512 // has a value greater than 0
513513 if ((fd[0].revents & std.os.POLL.IN) != 0) {
514514 const err_int = try readIntFd(err_pipe[0]);
lib/std/linked_list.zig-2
......@@ -2,8 +2,6 @@ const std = @import("std.zig");
22const debug = std.debug;
33const assert = debug.assert;
44const testing = std.testing;
5const mem = std.mem;
6const Allocator = mem.Allocator;
75
86/// A singly-linked list is headed by a single forward pointer. The elements
97/// are singly linked for minimum space and pointer manipulation overhead at
src/Autodoc.zig+83-19
......@@ -280,8 +280,8 @@ pub fn generateZirData(self: *Autodoc) !void {
280280 try std.json.stringify(
281281 data,
282282 .{
283 .whitespace = .{ .indent = if (builtin.mode == .Debug) .{ .Space = 4 } else .None },
284 .emit_null_optional_fields = false,
283 .whitespace = .{ .indent = .None, .separator = false },
284 .emit_null_optional_fields = true,
285285 },
286286 out,
287287 );
......@@ -404,6 +404,7 @@ const DocData = struct {
404404 w: anytype,
405405 ) !void {
406406 var jsw = std.json.writeStream(w, 15);
407 if (opts.whitespace) |ws| jsw.whitespace = ws;
407408 try jsw.beginObject();
408409 inline for (comptime std.meta.tags(std.meta.FieldEnum(DocData))) |f| {
409410 const f_name = @tagName(f);
......@@ -449,6 +450,8 @@ const DocData = struct {
449450 w: anytype,
450451 ) !void {
451452 var jsw = std.json.writeStream(w, 15);
453 if (opts.whitespace) |ws| jsw.whitespace = ws;
454
452455 try jsw.beginObject();
453456 inline for (comptime std.meta.tags(std.meta.FieldEnum(DocPackage))) |f| {
454457 const f_name = @tagName(f);
......@@ -474,6 +477,22 @@ const DocData = struct {
474477 // The index in astNodes of the `test declname { }` node
475478 decltest: ?usize = null,
476479 _analyzed: bool, // omitted in json data
480
481 pub fn jsonStringify(
482 self: Decl,
483 opts: std.json.StringifyOptions,
484 w: anytype,
485 ) !void {
486 var jsw = std.json.writeStream(w, 15);
487 if (opts.whitespace) |ws| jsw.whitespace = ws;
488 try jsw.beginArray();
489 inline for (comptime std.meta.fields(Decl)) |f| {
490 try jsw.arrayElem();
491 try std.json.stringify(@field(self, f.name), opts, w);
492 jsw.state_index -= 1;
493 }
494 try jsw.endArray();
495 }
477496 };
478497
479498 const AstNode = struct {
......@@ -485,6 +504,22 @@ const DocData = struct {
485504 docs: ?[]const u8 = null,
486505 fields: ?[]usize = null, // index into astNodes
487506 @"comptime": bool = false,
507
508 pub fn jsonStringify(
509 self: AstNode,
510 opts: std.json.StringifyOptions,
511 w: anytype,
512 ) !void {
513 var jsw = std.json.writeStream(w, 15);
514 if (opts.whitespace) |ws| jsw.whitespace = ws;
515 try jsw.beginArray();
516 inline for (comptime std.meta.fields(AstNode)) |f| {
517 try jsw.arrayElem();
518 try std.json.stringify(@field(self, f.name), opts, w);
519 jsw.state_index -= 1;
520 }
521 try jsw.endArray();
522 }
488523 };
489524
490525 const Type = union(enum) {
......@@ -525,7 +560,6 @@ const DocData = struct {
525560 fields: ?[]Expr = null, // (use src->fields to find names)
526561 line_number: usize,
527562 outer_decl: usize,
528 ast: usize,
529563 },
530564 ComptimeExpr: struct { name: []const u8 },
531565 ComptimeFloat: struct { name: []const u8 },
......@@ -548,7 +582,6 @@ const DocData = struct {
548582 src: usize, // index into astNodes
549583 privDecls: []usize = &.{}, // index into decls
550584 pubDecls: []usize = &.{}, // index into decls
551 ast: usize,
552585 // (use src->fields to find field names)
553586 },
554587 Union: struct {
......@@ -557,7 +590,6 @@ const DocData = struct {
557590 privDecls: []usize = &.{}, // index into decls
558591 pubDecls: []usize = &.{}, // index into decls
559592 fields: []Expr = &.{}, // (use src->fields to find names)
560 ast: usize,
561593 },
562594 Fn: struct {
563595 name: []const u8,
......@@ -582,7 +614,6 @@ const DocData = struct {
582614 src: usize, // index into astNodes
583615 privDecls: []usize = &.{}, // index into decls
584616 pubDecls: []usize = &.{}, // index into decls
585 ast: usize,
586617 },
587618 Frame: struct { name: []const u8 },
588619 AnyFrame: struct { name: []const u8 },
......@@ -601,14 +632,15 @@ const DocData = struct {
601632 ) !void {
602633 const active_tag = std.meta.activeTag(self);
603634 var jsw = std.json.writeStream(w, 15);
604 try jsw.beginObject();
605 try jsw.objectField("kind");
635 if (opts.whitespace) |ws| jsw.whitespace = ws;
636 try jsw.beginArray();
637 try jsw.arrayElem();
606638 try jsw.emitNumber(@enumToInt(active_tag));
607639 inline for (comptime std.meta.fields(Type)) |case| {
608640 if (@field(Type, case.name) == active_tag) {
609641 const current_value = @field(self, case.name);
610642 inline for (comptime std.meta.fields(case.field_type)) |f| {
611 try jsw.objectField(f.name);
643 try jsw.arrayElem();
612644 if (f.field_type == std.builtin.TypeInfo.Pointer.Size) {
613645 try jsw.emitNumber(@enumToInt(@field(current_value, f.name)));
614646 } else {
......@@ -618,7 +650,7 @@ const DocData = struct {
618650 }
619651 }
620652 }
621 try jsw.endObject();
653 try jsw.endArray();
622654 }
623655 };
624656
......@@ -686,7 +718,7 @@ const DocData = struct {
686718 const SwitchOp = struct {
687719 cond_index: usize,
688720 file_name: []const u8,
689 ast: usize,
721 src: usize,
690722 outer_decl: usize, // index in `types`
691723 };
692724 const BuiltinBin = struct {
......@@ -704,7 +736,15 @@ const DocData = struct {
704736 end: ?usize = null,
705737 sentinel: ?usize = null, // index in `exprs`
706738 };
707 const Cmpxchg = struct { name: []const u8, type: usize, ptr: usize, expected_value: usize, new_value: usize, success_order: usize, failure_order: usize };
739 const Cmpxchg = struct {
740 name: []const u8,
741 type: usize,
742 ptr: usize,
743 expected_value: usize,
744 new_value: usize,
745 success_order: usize,
746 failure_order: usize,
747 };
708748 const As = struct {
709749 typeRefArg: ?usize, // index in `exprs`
710750 exprArg: usize, // index in `exprs`
......@@ -721,11 +761,12 @@ const DocData = struct {
721761
722762 pub fn jsonStringify(
723763 self: Expr,
724 opt: std.json.StringifyOptions,
764 opts: std.json.StringifyOptions,
725765 w: anytype,
726766 ) !void {
727767 const active_tag = std.meta.activeTag(self);
728768 var jsw = std.json.writeStream(w, 15);
769 if (opts.whitespace) |ws| jsw.whitespace = ws;
729770 try jsw.beginObject();
730771 try jsw.objectField(@tagName(active_tag));
731772 switch (self) {
......@@ -742,7 +783,7 @@ const DocData = struct {
742783 if (comptime std.mem.eql(u8, case.name, "builtinField"))
743784 continue;
744785 if (@field(Expr, case.name) == active_tag) {
745 try std.json.stringify(@field(self, case.name), opt, w);
786 try std.json.stringify(@field(self, case.name), opts, w);
746787 jsw.state_index -= 1;
747788 // TODO: we should not reach into the state of the
748789 // json writer, but alas, this is what's
......@@ -1874,7 +1915,12 @@ fn walkInstruction(
18741915 // log.debug("{s}", .{sep});
18751916
18761917 const switch_index = self.exprs.items.len;
1877 try self.exprs.append(self.arena, .{ .switchOp = .{ .cond_index = cond_index, .file_name = file.sub_file_path, .ast = ast_index, .outer_decl = type_index } });
1918 try self.exprs.append(self.arena, .{ .switchOp = .{
1919 .cond_index = cond_index,
1920 .file_name = file.sub_file_path,
1921 .src = ast_index,
1922 .outer_decl = type_index,
1923 } });
18781924
18791925 return DocData.WalkResult{
18801926 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
......@@ -2505,7 +2551,6 @@ fn walkInstruction(
25052551 .src = self_ast_node_index,
25062552 .privDecls = priv_decl_indexes.items,
25072553 .pubDecls = decl_indexes.items,
2508 .ast = self_ast_node_index,
25092554 },
25102555 };
25112556 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
......@@ -2644,7 +2689,13 @@ fn walkInstruction(
26442689 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
26452690
26462691 self.types.items[type_slot_index] = .{
2647 .Union = .{ .name = "todo_name", .src = self_ast_node_index, .privDecls = priv_decl_indexes.items, .pubDecls = decl_indexes.items, .fields = field_type_refs.items, .ast = self_ast_node_index },
2692 .Union = .{
2693 .name = "todo_name",
2694 .src = self_ast_node_index,
2695 .privDecls = priv_decl_indexes.items,
2696 .pubDecls = decl_indexes.items,
2697 .fields = field_type_refs.items,
2698 },
26482699 };
26492700
26502701 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
......@@ -2796,7 +2847,12 @@ fn walkInstruction(
27962847 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
27972848
27982849 self.types.items[type_slot_index] = .{
2799 .Enum = .{ .name = "todo_name", .src = self_ast_node_index, .privDecls = priv_decl_indexes.items, .pubDecls = decl_indexes.items, .ast = self_ast_node_index },
2850 .Enum = .{
2851 .name = "todo_name",
2852 .src = self_ast_node_index,
2853 .privDecls = priv_decl_indexes.items,
2854 .pubDecls = decl_indexes.items,
2855 },
28002856 };
28012857 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
28022858 for (paths.items) |resume_info| {
......@@ -2910,7 +2966,15 @@ fn walkInstruction(
29102966 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
29112967
29122968 self.types.items[type_slot_index] = .{
2913 .Struct = .{ .name = "todo_name", .src = self_ast_node_index, .privDecls = priv_decl_indexes.items, .pubDecls = decl_indexes.items, .fields = field_type_refs.items, .line_number = self.ast_nodes.items[self_ast_node_index].line, .outer_decl = type_slot_index - 1, .ast = self_ast_node_index },
2969 .Struct = .{
2970 .name = "todo_name",
2971 .src = self_ast_node_index,
2972 .privDecls = priv_decl_indexes.items,
2973 .pubDecls = decl_indexes.items,
2974 .fields = field_type_refs.items,
2975 .line_number = self.ast_nodes.items[self_ast_node_index].line,
2976 .outer_decl = type_slot_index - 1,
2977 },
29142978 };
29152979 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
29162980 for (paths.items) |resume_info| {
src/Compilation.zig+87-65
......@@ -1238,7 +1238,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
12381238 options.target,
12391239 options.is_native_abi,
12401240 link_libc,
1241 options.system_lib_names.len != 0 or options.frameworks.count() != 0,
12421241 options.libc_installation,
12431242 options.native_darwin_sdk != null,
12441243 );
......@@ -4522,7 +4521,6 @@ fn detectLibCIncludeDirs(
45224521 target: Target,
45234522 is_native_abi: bool,
45244523 link_libc: bool,
4525 link_system_libs: bool,
45264524 libc_installation: ?*const LibCInstallation,
45274525 has_macos_sdk: bool,
45284526) !LibCDirs {
......@@ -4539,7 +4537,7 @@ fn detectLibCIncludeDirs(
45394537
45404538 // If linking system libraries and targeting the native abi, default to
45414539 // using the system libc installation.
4542 if (link_system_libs and is_native_abi and !target.isMinGW()) {
4540 if (is_native_abi and !target.isMinGW()) {
45434541 if (target.isDarwin()) {
45444542 return if (has_macos_sdk)
45454543 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.
......@@ -4551,74 +4549,29 @@ fn detectLibCIncludeDirs(
45514549 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target);
45524550 }
45534551 const libc = try arena.create(LibCInstallation);
4554 libc.* = try LibCInstallation.findNative(.{ .allocator = arena, .verbose = true });
4552 libc.* = LibCInstallation.findNative(.{ .allocator = arena }) catch |err| switch (err) {
4553 error.CCompilerExitCode,
4554 error.CCompilerCrashed,
4555 error.CCompilerCannotFindHeaders,
4556 error.UnableToSpawnCCompiler,
4557 => |e| {
4558 // We tried to integrate with the native system C compiler,
4559 // however, it is not installed. So we must rely on our bundled
4560 // libc files.
4561 if (target_util.canBuildLibC(target)) {
4562 return detectLibCFromBuilding(arena, zig_lib_dir, target, has_macos_sdk);
4563 }
4564 return e;
4565 },
4566 else => |e| return e,
4567 };
45554568 return detectLibCFromLibCInstallation(arena, target, libc);
45564569 }
45574570
45584571 // If not linking system libraries, build and provide our own libc by
45594572 // default if possible.
45604573 if (target_util.canBuildLibC(target)) {
4561 switch (target.os.tag) {
4562 .macos => return if (has_macos_sdk)
4563 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.
4564 LibCDirs{
4565 .libc_include_dir_list = &[0][]u8{},
4566 .libc_installation = null,
4567 }
4568 else
4569 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target),
4570 else => {
4571 const generic_name = target_util.libCGenericName(target);
4572 // Some architectures are handled by the same set of headers.
4573 const arch_name = if (target.abi.isMusl())
4574 musl.archName(target.cpu.arch)
4575 else if (target.cpu.arch.isThumb())
4576 // ARM headers are valid for Thumb too.
4577 switch (target.cpu.arch) {
4578 .thumb => "arm",
4579 .thumbeb => "armeb",
4580 else => unreachable,
4581 }
4582 else
4583 @tagName(target.cpu.arch);
4584 const os_name = @tagName(target.os.tag);
4585 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.
4586 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);
4587 const s = std.fs.path.sep_str;
4588 const arch_include_dir = try std.fmt.allocPrint(
4589 arena,
4590 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}",
4591 .{ zig_lib_dir, arch_name, os_name, abi_name },
4592 );
4593 const generic_include_dir = try std.fmt.allocPrint(
4594 arena,
4595 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}",
4596 .{ zig_lib_dir, generic_name },
4597 );
4598 const generic_arch_name = target_util.osArchName(target);
4599 const arch_os_include_dir = try std.fmt.allocPrint(
4600 arena,
4601 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any",
4602 .{ zig_lib_dir, generic_arch_name, os_name },
4603 );
4604 const generic_os_include_dir = try std.fmt.allocPrint(
4605 arena,
4606 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any",
4607 .{ zig_lib_dir, os_name },
4608 );
4609
4610 const list = try arena.alloc([]const u8, 4);
4611 list[0] = arch_include_dir;
4612 list[1] = generic_include_dir;
4613 list[2] = arch_os_include_dir;
4614 list[3] = generic_os_include_dir;
4615
4616 return LibCDirs{
4617 .libc_include_dir_list = list,
4618 .libc_installation = null,
4619 };
4620 },
4621 }
4574 return detectLibCFromBuilding(arena, zig_lib_dir, target, has_macos_sdk);
46224575 }
46234576
46244577 // If zig can't build the libc for the target and we are targeting the
......@@ -4677,6 +4630,75 @@ fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const
46774630 };
46784631}
46794632
4633fn detectLibCFromBuilding(
4634 arena: Allocator,
4635 zig_lib_dir: []const u8,
4636 target: std.Target,
4637 has_macos_sdk: bool,
4638) !LibCDirs {
4639 switch (target.os.tag) {
4640 .macos => return if (has_macos_sdk)
4641 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.
4642 LibCDirs{
4643 .libc_include_dir_list = &[0][]u8{},
4644 .libc_installation = null,
4645 }
4646 else
4647 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target),
4648 else => {
4649 const generic_name = target_util.libCGenericName(target);
4650 // Some architectures are handled by the same set of headers.
4651 const arch_name = if (target.abi.isMusl())
4652 musl.archName(target.cpu.arch)
4653 else if (target.cpu.arch.isThumb())
4654 // ARM headers are valid for Thumb too.
4655 switch (target.cpu.arch) {
4656 .thumb => "arm",
4657 .thumbeb => "armeb",
4658 else => unreachable,
4659 }
4660 else
4661 @tagName(target.cpu.arch);
4662 const os_name = @tagName(target.os.tag);
4663 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.
4664 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);
4665 const s = std.fs.path.sep_str;
4666 const arch_include_dir = try std.fmt.allocPrint(
4667 arena,
4668 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}",
4669 .{ zig_lib_dir, arch_name, os_name, abi_name },
4670 );
4671 const generic_include_dir = try std.fmt.allocPrint(
4672 arena,
4673 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}",
4674 .{ zig_lib_dir, generic_name },
4675 );
4676 const generic_arch_name = target_util.osArchName(target);
4677 const arch_os_include_dir = try std.fmt.allocPrint(
4678 arena,
4679 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any",
4680 .{ zig_lib_dir, generic_arch_name, os_name },
4681 );
4682 const generic_os_include_dir = try std.fmt.allocPrint(
4683 arena,
4684 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any",
4685 .{ zig_lib_dir, os_name },
4686 );
4687
4688 const list = try arena.alloc([]const u8, 4);
4689 list[0] = arch_include_dir;
4690 list[1] = generic_include_dir;
4691 list[2] = arch_os_include_dir;
4692 list[3] = generic_os_include_dir;
4693
4694 return LibCDirs{
4695 .libc_include_dir_list = list,
4696 .libc_installation = null,
4697 };
4698 },
4699 }
4700}
4701
46804702pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
46814703 if (comp.wantBuildGLibCFromSource() or
46824704 comp.wantBuildMuslFromSource() or
src/arch/aarch64/CodeGen.zig+35-50
......@@ -139,21 +139,10 @@ const MCValue = union(enum) {
139139 /// If the type is a pointer, it means the pointer address is at
140140 /// this memory location.
141141 memory: u64,
142 /// The value is in memory referenced indirectly via a GOT entry
143 /// index.
144 ///
145 /// If the type is a pointer, it means the pointer is referenced
146 /// indirectly via GOT. When lowered, linker will emit
147 /// relocations of type ARM64_RELOC_GOT_LOAD_PAGE21 and
148 /// ARM64_RELOC_GOT_LOAD_PAGEOFF12.
149 got_load: u32,
150 /// The value is in memory referenced directly via symbol index.
151 ///
152 /// If the type is a pointer, it means the pointer is referenced
153 /// directly via symbol index. When lowered, linker will emit a
154 /// relocation of type ARM64_RELOC_PAGE21 and
155 /// ARM64_RELOC_PAGEOFF12.
156 direct_load: u32,
142 /// The value is in memory but requires a linker relocation fixup:
143 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
144 /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
145 linker_load: struct { @"type": enum { got, direct }, sym_index: u32 },
157146 /// The value is one of the stack variables.
158147 ///
159148 /// If the type is a pointer, it means the pointer address is in
......@@ -2959,8 +2948,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
29592948 .memory,
29602949 .stack_offset,
29612950 .stack_argument_offset,
2962 .got_load,
2963 .direct_load,
2951 .linker_load,
29642952 => {
29652953 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr);
29662954 try self.load(dst_mcv, .{ .register = addr_reg }, ptr_ty);
......@@ -3197,8 +3185,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
31973185 .memory,
31983186 .stack_offset,
31993187 .stack_argument_offset,
3200 .got_load,
3201 .direct_load,
3188 .linker_load,
32023189 => {
32033190 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr);
32043191 try self.store(.{ .register = addr_reg }, value, ptr_ty, value_ty);
......@@ -3493,7 +3480,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
34933480 const func = func_payload.data;
34943481 const fn_owner_decl = mod.declPtr(func.owner_decl);
34953482 try self.genSetReg(Type.initTag(.u64), .x30, .{
3496 .got_load = fn_owner_decl.link.macho.sym_index,
3483 .linker_load = .{
3484 .@"type" = .got,
3485 .sym_index = fn_owner_decl.link.macho.sym_index,
3486 },
34973487 });
34983488 // blr x30
34993489 _ = try self.addInst(.{
......@@ -4427,8 +4417,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
44274417 .register = cond_reg,
44284418 });
44294419 },
4430 .got_load,
4431 .direct_load,
4420 .linker_load,
44324421 .memory,
44334422 .stack_argument_offset,
44344423 .stack_offset,
......@@ -4479,13 +4468,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
44794468 });
44804469 },
44814470 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),
4482 .got_load,
4483 .direct_load,
4484 => |sym_index| {
4485 const tag: Mir.Inst.Tag = switch (mcv) {
4486 .got_load => .load_memory_ptr_got,
4487 .direct_load => .load_memory_ptr_direct,
4488 else => unreachable,
4471 .linker_load => |load_struct| {
4472 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
4473 .got => .load_memory_ptr_got,
4474 .direct => .load_memory_ptr_direct,
44894475 };
44904476 const mod = self.bin_file.options.module.?;
44914477 _ = try self.addInst(.{
......@@ -4494,7 +4480,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
44944480 .payload = try self.addExtra(Mir.LoadMemoryPie{
44954481 .register = @enumToInt(src_reg),
44964482 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,
4497 .sym_index = sym_index,
4483 .sym_index = load_struct.sym_index,
44984484 }),
44994485 },
45004486 });
......@@ -4594,13 +4580,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
45944580 });
45954581 },
45964582 .register_with_overflow => unreachable, // doesn't fit into a register
4597 .got_load,
4598 .direct_load,
4599 => |sym_index| {
4600 const tag: Mir.Inst.Tag = switch (mcv) {
4601 .got_load => .load_memory_got,
4602 .direct_load => .load_memory_direct,
4603 else => unreachable,
4583 .linker_load => |load_struct| {
4584 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
4585 .got => .load_memory_got,
4586 .direct => .load_memory_direct,
46044587 };
46054588 const mod = self.bin_file.options.module.?;
46064589 _ = try self.addInst(.{
......@@ -4609,7 +4592,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
46094592 .payload = try self.addExtra(Mir.LoadMemoryPie{
46104593 .register = @enumToInt(reg),
46114594 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,
4612 .sym_index = sym_index,
4595 .sym_index = load_struct.sym_index,
46134596 }),
46144597 },
46154598 });
......@@ -4741,8 +4724,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
47414724 .register_with_overflow => {
47424725 return self.fail("TODO implement genSetStackArgument {}", .{mcv});
47434726 },
4744 .got_load,
4745 .direct_load,
4727 .linker_load,
47464728 .memory,
47474729 .stack_argument_offset,
47484730 .stack_offset,
......@@ -4785,13 +4767,10 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
47854767 });
47864768 },
47874769 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
4788 .got_load,
4789 .direct_load,
4790 => |sym_index| {
4791 const tag: Mir.Inst.Tag = switch (mcv) {
4792 .got_load => .load_memory_ptr_got,
4793 .direct_load => .load_memory_ptr_direct,
4794 else => unreachable,
4770 .linker_load => |load_struct| {
4771 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
4772 .got => .load_memory_ptr_got,
4773 .direct => .load_memory_ptr_direct,
47954774 };
47964775 const mod = self.bin_file.options.module.?;
47974776 _ = try self.addInst(.{
......@@ -4800,7 +4779,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
48004779 .payload = try self.addExtra(Mir.LoadMemoryPie{
48014780 .register = @enumToInt(src_reg),
48024781 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,
4803 .sym_index = sym_index,
4782 .sym_index = load_struct.sym_index,
48044783 }),
48054784 },
48064785 });
......@@ -5107,7 +5086,10 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
51075086 // Because MachO is PIE-always-on, we defer memory address resolution until
51085087 // the linker has enough info to perform relocations.
51095088 assert(decl.link.macho.sym_index != 0);
5110 return MCValue{ .got_load = decl.link.macho.sym_index };
5089 return MCValue{ .linker_load = .{
5090 .@"type" = .got,
5091 .sym_index = decl.link.macho.sym_index,
5092 } };
51115093 } else if (self.bin_file.cast(link.File.Coff)) |_| {
51125094 return self.fail("TODO codegen COFF const Decl pointer", .{});
51135095 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
......@@ -5129,7 +5111,10 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
51295111 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
51305112 return MCValue{ .memory = vaddr };
51315113 } else if (self.bin_file.cast(link.File.MachO)) |_| {
5132 return MCValue{ .direct_load = local_sym_index };
5114 return MCValue{ .linker_load = .{
5115 .@"type" = .direct,
5116 .sym_index = local_sym_index,
5117 } };
51335118 } else if (self.bin_file.cast(link.File.Coff)) |_| {
51345119 return self.fail("TODO lower unnamed const in COFF", .{});
51355120 } else if (self.bin_file.cast(link.File.Plan9)) |_| {
src/arch/aarch64/Emit.zig+2-4
......@@ -681,12 +681,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
681681 };
682682 // Add relocation to the decl.
683683 const atom = macho_file.atom_by_index_table.get(relocation.atom_index).?;
684 const target = macho_file.getGlobalByIndex(relocation.sym_index);
684685 try atom.relocs.append(emit.bin_file.allocator, .{
685686 .offset = offset,
686 .target = .{
687 .sym_index = relocation.sym_index,
688 .file = null,
689 },
687 .target = target,
690688 .addend = 0,
691689 .subtractor = null,
692690 .pcrel = true,
src/arch/arm/CodeGen.zig+1558-1057
......@@ -438,9 +438,8 @@ fn gen(self: *Self) !void {
438438 // mov fp, sp
439439 _ = try self.addInst(.{
440440 .tag = .mov,
441 .data = .{ .rr_op = .{
441 .data = .{ .r_op_mov = .{
442442 .rd = .fp,
443 .rn = .r0,
444443 .op = Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none),
445444 } },
446445 });
......@@ -452,9 +451,7 @@ fn gen(self: *Self) !void {
452451 // The address of where to store the return value is in
453452 // r0. As this register might get overwritten along the
454453 // way, save the address to the stack.
455 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, 4) + 4;
456 self.next_stack_offset = stack_offset;
457 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
454 const stack_offset = try self.allocMem(4, 4, null);
458455
459456 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 });
460457 self.ret_mcv = MCValue{ .stack_offset = stack_offset };
......@@ -491,14 +488,10 @@ fn gen(self: *Self) !void {
491488 const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);
492489 const stack_size = aligned_total_stack_end - self.saved_regs_stack_space;
493490 self.max_end_stack = stack_size;
494 if (Instruction.Operand.fromU32(stack_size)) |op| {
495 self.mir_instructions.set(sub_reloc, .{
496 .tag = .sub,
497 .data = .{ .rr_op = .{ .rd = .sp, .rn = .sp, .op = op } },
498 });
499 } else {
500 return self.failSymbol("TODO ARM: allow larger stacks", .{});
501 }
491 self.mir_instructions.set(sub_reloc, .{
492 .tag = .sub_sp_scratch_r0,
493 .data = .{ .imm32 = stack_size },
494 });
502495
503496 _ = try self.addInst(.{
504497 .tag = .dbg_epilogue_begin,
......@@ -531,9 +524,8 @@ fn gen(self: *Self) !void {
531524 // mov sp, fp
532525 _ = try self.addInst(.{
533526 .tag = .mov,
534 .data = .{ .rr_op = .{
527 .data = .{ .r_op_mov = .{
535528 .rd = .sp,
536 .rn = .r0,
537529 .op = Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none),
538530 } },
539531 });
......@@ -895,17 +887,30 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
895887 try table.ensureUnusedCapacity(self.gpa, additional_count);
896888}
897889
898fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
890fn allocMem(
891 self: *Self,
892 abi_size: u32,
893 abi_align: u32,
894 maybe_inst: ?Air.Inst.Index,
895) !u32 {
896 assert(abi_size > 0);
897 assert(abi_align > 0);
898
899899 if (abi_align > self.stack_align)
900900 self.stack_align = abi_align;
901
901902 // TODO find a free slot instead of always appending
902903 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
903904 self.next_stack_offset = offset;
904905 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
905 try self.stack.putNoClobber(self.gpa, offset, .{
906 .inst = inst,
907 .size = abi_size,
908 });
906
907 if (maybe_inst) |inst| {
908 try self.stack.putNoClobber(self.gpa, offset, .{
909 .inst = inst,
910 .size = abi_size,
911 });
912 }
913
909914 return offset;
910915}
911916
......@@ -927,35 +932,34 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
927932 };
928933 // TODO swap this for inst.ty.ptrAlign
929934 const abi_align = elem_ty.abiAlignment(self.target.*);
930 return self.allocMem(inst, abi_size, abi_align);
935
936 return self.allocMem(abi_size, abi_align, inst);
931937}
932938
933fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
934 const elem_ty = self.air.typeOfIndex(inst);
939fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue {
935940 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {
936941 const mod = self.bin_file.options.module.?;
937942 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
938943 };
939944 const abi_align = elem_ty.abiAlignment(self.target.*);
940 if (abi_align > self.stack_align)
941 self.stack_align = abi_align;
942945
943946 if (reg_ok) {
944947 // Make sure the type can fit in a register before we try to allocate one.
945948 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
946949 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
947950 if (abi_size <= ptr_bytes) {
948 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
951 if (self.register_manager.tryAllocReg(maybe_inst, gp)) |reg| {
949952 return MCValue{ .register = reg };
950953 }
951954 }
952955 }
953 const stack_offset = try self.allocMem(inst, abi_size, abi_align);
956
957 const stack_offset = try self.allocMem(abi_size, abi_align, maybe_inst);
954958 return MCValue{ .stack_offset = stack_offset };
955959}
956960
957961pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
958 const stack_mcv = try self.allocRegOrMem(inst, false);
962 const stack_mcv = try self.allocRegOrMem(self.air.typeOfIndex(inst), false, inst);
959963 log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv });
960964
961965 const reg_mcv = self.getResolvedInstValue(inst);
......@@ -976,12 +980,13 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
976980/// occupied
977981fn spillCompareFlagsIfOccupied(self: *Self) !void {
978982 if (self.cpsr_flags_inst) |inst_to_save| {
983 const ty = self.air.typeOfIndex(inst_to_save);
979984 const mcv = self.getResolvedInstValue(inst_to_save);
980985 const new_mcv = switch (mcv) {
981 .cpsr_flags => try self.allocRegOrMem(inst_to_save, true),
986 .cpsr_flags => try self.allocRegOrMem(ty, true, inst_to_save),
982987 .register_c_flag,
983988 .register_v_flag,
984 => try self.allocRegOrMem(inst_to_save, false),
989 => try self.allocRegOrMem(ty, false, inst_to_save),
985990 else => unreachable, // mcv doesn't occupy the compare flags
986991 };
987992
......@@ -1112,10 +1117,11 @@ fn truncRegister(
11121117 });
11131118}
11141119
1120/// Asserts that both operand_ty and dest_ty are integer types
11151121fn trunc(
11161122 self: *Self,
11171123 maybe_inst: ?Air.Inst.Index,
1118 operand: MCValue,
1124 operand_bind: ReadArg.Bind,
11191125 operand_ty: Type,
11201126 dest_ty: Type,
11211127) !MCValue {
......@@ -1123,39 +1129,38 @@ fn trunc(
11231129 const info_b = dest_ty.intInfo(self.target.*);
11241130
11251131 if (info_b.bits <= 32) {
1126 const operand_reg = switch (operand) {
1127 .register => |r| r,
1128 else => operand_reg: {
1129 if (info_a.bits <= 32) {
1130 break :operand_reg try self.copyToTmpRegister(operand_ty, operand);
1131 } else {
1132 return self.fail("TODO load least significant word into register", .{});
1133 }
1134 },
1135 };
1136 const operand_reg_lock = self.register_manager.lockReg(operand_reg);
1137 defer if (operand_reg_lock) |reg| self.register_manager.unlockReg(reg);
1132 if (info_a.bits > 32) {
1133 return self.fail("TODO load least significant word into register", .{});
1134 }
11381135
1139 const dest_reg = if (maybe_inst) |inst| blk: {
1140 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1136 var operand_reg: Register = undefined;
1137 var dest_reg: Register = undefined;
11411138
1142 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1143 break :blk operand_reg;
1144 } else {
1145 break :blk try self.register_manager.allocReg(inst, gp);
1146 }
1147 } else try self.register_manager.allocReg(null, gp);
1139 const read_args = [_]ReadArg{
1140 .{ .ty = operand_ty, .bind = operand_bind, .class = gp, .reg = &operand_reg },
1141 };
1142 const write_args = [_]WriteArg{
1143 .{ .ty = dest_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1144 };
1145 try self.allocRegs(
1146 &read_args,
1147 &write_args,
1148 if (maybe_inst) |inst| .{
1149 .corresponding_inst = inst,
1150 .operand_mapping = &.{0},
1151 } else null,
1152 );
11481153
11491154 switch (info_b.bits) {
11501155 32 => {
11511156 try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg });
1152 return MCValue{ .register = dest_reg };
11531157 },
11541158 else => {
11551159 try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);
1156 return MCValue{ .register = dest_reg };
11571160 },
11581161 }
1162
1163 return MCValue{ .register = dest_reg };
11591164 } else {
11601165 return self.fail("TODO: truncate to ints > 32 bits", .{});
11611166 }
......@@ -1163,12 +1168,12 @@ fn trunc(
11631168
11641169fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
11651170 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1166 const operand = try self.resolveInst(ty_op.operand);
1171 const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand };
11671172 const operand_ty = self.air.typeOf(ty_op.operand);
11681173 const dest_ty = self.air.typeOfIndex(inst);
11691174
11701175 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
1171 break :blk try self.trunc(inst, operand, operand_ty, dest_ty);
1176 break :blk try self.trunc(inst, operand_bind, operand_ty, dest_ty);
11721177 };
11731178
11741179 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -1184,29 +1189,32 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
11841189fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11851190 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
11861191 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1187 const operand = try self.resolveInst(ty_op.operand);
1192 const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand };
11881193 const operand_ty = self.air.typeOf(ty_op.operand);
1189 switch (operand) {
1194 switch (try operand_bind.resolveToMcv(self)) {
11901195 .dead => unreachable,
11911196 .unreach => unreachable,
11921197 .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() },
11931198 else => {
11941199 switch (operand_ty.zigTypeTag()) {
11951200 .Bool => {
1196 const op_reg = switch (operand) {
1197 .register => |r| r,
1198 else => try self.copyToTmpRegister(operand_ty, operand),
1199 };
1200 const op_reg_lock = self.register_manager.lockRegAssumeUnused(op_reg);
1201 defer self.register_manager.unlockReg(op_reg_lock);
1201 var op_reg: Register = undefined;
1202 var dest_reg: Register = undefined;
12021203
1203 const dest_reg = blk: {
1204 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1205 break :blk op_reg;
1206 }
1207
1208 break :blk try self.register_manager.allocReg(null, gp);
1204 const read_args = [_]ReadArg{
1205 .{ .ty = operand_ty, .bind = operand_bind, .class = gp, .reg = &op_reg },
12091206 };
1207 const write_args = [_]WriteArg{
1208 .{ .ty = operand_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1209 };
1210 try self.allocRegs(
1211 &read_args,
1212 &write_args,
1213 ReuseMetadata{
1214 .corresponding_inst = inst,
1215 .operand_mapping = &.{0},
1216 },
1217 );
12101218
12111219 _ = try self.addInst(.{
12121220 .tag = .eor,
......@@ -1223,26 +1231,28 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
12231231 .Int => {
12241232 const int_info = operand_ty.intInfo(self.target.*);
12251233 if (int_info.bits <= 32) {
1226 const op_reg = switch (operand) {
1227 .register => |r| r,
1228 else => try self.copyToTmpRegister(operand_ty, operand),
1229 };
1230 const op_reg_lock = self.register_manager.lockRegAssumeUnused(op_reg);
1231 defer self.register_manager.unlockReg(op_reg_lock);
1232
1233 const dest_reg = blk: {
1234 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1235 break :blk op_reg;
1236 }
1234 var op_reg: Register = undefined;
1235 var dest_reg: Register = undefined;
12371236
1238 break :blk try self.register_manager.allocReg(null, gp);
1237 const read_args = [_]ReadArg{
1238 .{ .ty = operand_ty, .bind = operand_bind, .class = gp, .reg = &op_reg },
12391239 };
1240 const write_args = [_]WriteArg{
1241 .{ .ty = operand_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1242 };
1243 try self.allocRegs(
1244 &read_args,
1245 &write_args,
1246 ReuseMetadata{
1247 .corresponding_inst = inst,
1248 .operand_mapping = &.{0},
1249 },
1250 );
12401251
12411252 _ = try self.addInst(.{
12421253 .tag = .mvn,
1243 .data = .{ .rr_op = .{
1254 .data = .{ .r_op_mov = .{
12441255 .rd = dest_reg,
1245 .rn = undefined,
12461256 .op = Instruction.Operand.reg(op_reg, Instruction.Operand.Shift.none),
12471257 } },
12481258 });
......@@ -1267,11 +1277,11 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
12671277fn minMax(
12681278 self: *Self,
12691279 tag: Air.Inst.Tag,
1270 maybe_inst: ?Air.Inst.Index,
1271 lhs: MCValue,
1272 rhs: MCValue,
1280 lhs_bind: ReadArg.Bind,
1281 rhs_bind: ReadArg.Bind,
12731282 lhs_ty: Type,
12741283 rhs_ty: Type,
1284 maybe_inst: ?Air.Inst.Index,
12751285) !MCValue {
12761286 switch (lhs_ty.zigTypeTag()) {
12771287 .Float => return self.fail("TODO ARM min/max on floats", .{}),
......@@ -1281,34 +1291,25 @@ fn minMax(
12811291 assert(lhs_ty.eql(rhs_ty, mod));
12821292 const int_info = lhs_ty.intInfo(self.target.*);
12831293 if (int_info.bits <= 32) {
1284 const lhs_is_register = lhs == .register;
1285 const rhs_is_register = rhs == .register;
1294 var lhs_reg: Register = undefined;
1295 var rhs_reg: Register = undefined;
1296 var dest_reg: Register = undefined;
12861297
1287 const lhs_reg = switch (lhs) {
1288 .register => |r| r,
1289 else => try self.copyToTmpRegister(lhs_ty, lhs),
1298 const read_args = [_]ReadArg{
1299 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
1300 .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
12901301 };
1291 const lhs_reg_lock = self.register_manager.lockReg(lhs_reg);
1292 defer if (lhs_reg_lock) |reg| self.register_manager.unlockReg(reg);
1293
1294 const rhs_reg = switch (rhs) {
1295 .register => |r| r,
1296 else => try self.copyToTmpRegister(rhs_ty, rhs),
1302 const write_args = [_]WriteArg{
1303 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
12971304 };
1298 const rhs_reg_lock = self.register_manager.lockReg(rhs_reg);
1299 defer if (rhs_reg_lock) |reg| self.register_manager.unlockReg(reg);
1300
1301 const dest_reg = if (maybe_inst) |inst| blk: {
1302 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1303
1304 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1305 break :blk lhs_reg;
1306 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
1307 break :blk rhs_reg;
1308 } else {
1309 break :blk try self.register_manager.allocReg(inst, gp);
1310 }
1311 } else try self.register_manager.allocReg(null, gp);
1305 try self.allocRegs(
1306 &read_args,
1307 &write_args,
1308 if (maybe_inst) |inst| .{
1309 .corresponding_inst = inst,
1310 .operand_mapping = &.{ 0, 1 },
1311 } else null,
1312 );
13121313
13131314 // lhs == reg should have been checked by airMinMax
13141315 //
......@@ -1318,7 +1319,13 @@ fn minMax(
13181319 // register.
13191320 assert(lhs_reg != rhs_reg); // see note above
13201321
1321 _ = try self.binOpRegister(.cmp, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty, null);
1322 _ = try self.addInst(.{
1323 .tag = .cmp,
1324 .data = .{ .r_op_cmp = .{
1325 .rn = lhs_reg,
1326 .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
1327 } },
1328 });
13221329
13231330 const cond_choose_lhs: Condition = switch (tag) {
13241331 .max => switch (int_info.signedness) {
......@@ -1337,9 +1344,8 @@ fn minMax(
13371344 _ = try self.addInst(.{
13381345 .tag = .mov,
13391346 .cond = cond_choose_lhs,
1340 .data = .{ .rr_op = .{
1347 .data = .{ .r_op_mov = .{
13411348 .rd = dest_reg,
1342 .rn = .r0,
13431349 .op = Instruction.Operand.reg(lhs_reg, Instruction.Operand.Shift.none),
13441350 } },
13451351 });
......@@ -1348,9 +1354,8 @@ fn minMax(
13481354 _ = try self.addInst(.{
13491355 .tag = .mov,
13501356 .cond = cond_choose_rhs,
1351 .data = .{ .rr_op = .{
1357 .data = .{ .r_op_mov = .{
13521358 .rd = dest_reg,
1353 .rn = .r0,
13541359 .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
13551360 } },
13561361 });
......@@ -1368,15 +1373,17 @@ fn minMax(
13681373fn airMinMax(self: *Self, inst: Air.Inst.Index) !void {
13691374 const tag = self.air.instructions.items(.tag)[inst];
13701375 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1371 const lhs = try self.resolveInst(bin_op.lhs);
1372 const rhs = try self.resolveInst(bin_op.rhs);
13731376 const lhs_ty = self.air.typeOf(bin_op.lhs);
13741377 const rhs_ty = self.air.typeOf(bin_op.rhs);
13751378
13761379 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1380 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
1381 const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
1382
1383 const lhs = try self.resolveInst(bin_op.lhs);
13771384 if (bin_op.lhs == bin_op.rhs) break :result lhs;
13781385
1379 break :result try self.minMax(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
1386 break :result try self.minMax(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst);
13801387 };
13811388 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
13821389}
......@@ -1390,7 +1397,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
13901397 const len = try self.resolveInst(bin_op.rhs);
13911398 const len_ty = self.air.typeOf(bin_op.rhs);
13921399
1393 const stack_offset = try self.allocMem(inst, 8, 4);
1400 const stack_offset = try self.allocMem(8, 4, inst);
13941401 try self.genSetStack(ptr_ty, stack_offset, ptr);
13951402 try self.genSetStack(len_ty, stack_offset - 4, len);
13961403 break :result MCValue{ .stack_offset = stack_offset };
......@@ -1400,38 +1407,65 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
14001407
14011408fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
14021409 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1403 const lhs = try self.resolveInst(bin_op.lhs);
1404 const rhs = try self.resolveInst(bin_op.rhs);
14051410 const lhs_ty = self.air.typeOf(bin_op.lhs);
14061411 const rhs_ty = self.air.typeOf(bin_op.rhs);
14071412
1408 const result: MCValue = if (self.liveness.isUnused(inst))
1409 .dead
1410 else
1411 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
1412 .lhs = bin_op.lhs,
1413 .rhs = bin_op.rhs,
1414 .inst = inst,
1415 });
1413 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1414 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
1415 const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
1416
1417 break :result switch (tag) {
1418 .add => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1419 .sub => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1420
1421 .mul => try self.mul(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1422
1423 .div_float => try self.divFloat(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1424
1425 .div_trunc => try self.div(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1426 .div_floor => try self.div(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1427
1428 .div_exact => try self.divExact(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1429
1430 .rem => try self.rem(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1431
1432 .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1433
1434 .addwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1435 .subwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1436 .mulwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1437
1438 .bit_and => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1439 .bit_or => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1440 .xor => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1441
1442 .shl_exact => try self.shiftExact(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1443 .shr_exact => try self.shiftExact(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1444
1445 .shl => try self.shiftNormal(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1446 .shr => try self.shiftNormal(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1447
1448 .bool_and => try self.booleanOp(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1449 .bool_or => try self.booleanOp(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1450
1451 else => unreachable,
1452 };
1453 };
14161454 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
14171455}
14181456
14191457fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
14201458 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
14211459 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1422 const lhs = try self.resolveInst(bin_op.lhs);
1423 const rhs = try self.resolveInst(bin_op.rhs);
14241460 const lhs_ty = self.air.typeOf(bin_op.lhs);
14251461 const rhs_ty = self.air.typeOf(bin_op.rhs);
14261462
1427 const result: MCValue = if (self.liveness.isUnused(inst))
1428 .dead
1429 else
1430 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
1431 .lhs = bin_op.lhs,
1432 .rhs = bin_op.rhs,
1433 .inst = inst,
1434 });
1463 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1464 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
1465 const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
1466
1467 break :result try self.ptrArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst);
1468 };
14351469 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
14361470}
14371471
......@@ -1458,8 +1492,8 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
14581492 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
14591493 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
14601494 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1461 const lhs = try self.resolveInst(extra.lhs);
1462 const rhs = try self.resolveInst(extra.rhs);
1495 const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
1496 const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
14631497 const lhs_ty = self.air.typeOf(extra.lhs);
14641498 const rhs_ty = self.air.typeOf(extra.rhs);
14651499
......@@ -1475,17 +1509,16 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
14751509 assert(lhs_ty.eql(rhs_ty, mod));
14761510 const int_info = lhs_ty.intInfo(self.target.*);
14771511 if (int_info.bits < 32) {
1478 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
1512 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
14791513
14801514 try self.spillCompareFlagsIfOccupied();
1481 self.cpsr_flags_inst = null;
14821515
14831516 const base_tag: Air.Inst.Tag = switch (tag) {
14841517 .add_with_overflow => .add,
14851518 .sub_with_overflow => .sub,
14861519 else => unreachable,
14871520 };
1488 const dest = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1521 const dest = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null);
14891522 const dest_reg = dest.register;
14901523 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
14911524 defer self.register_manager.unlockReg(dest_reg_lock);
......@@ -1498,25 +1531,34 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
14981531 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
14991532
15001533 // cmp dest, truncated
1501 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
1534 _ = try self.addInst(.{
1535 .tag = .cmp,
1536 .data = .{ .r_op_cmp = .{
1537 .rn = dest_reg,
1538 .op = Instruction.Operand.reg(truncated_reg, Instruction.Operand.Shift.none),
1539 } },
1540 });
15021541
15031542 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
15041543 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });
15051544
15061545 break :result MCValue{ .stack_offset = stack_offset };
15071546 } else if (int_info.bits == 32) {
1547 const lhs_immediate = try lhs_bind.resolveToImmediate(self);
1548 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
1549
15081550 // Only say yes if the operation is
15091551 // commutative, i.e. we can swap both of the
15101552 // operands
15111553 const lhs_immediate_ok = switch (tag) {
1512 .add_with_overflow => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null,
1554 .add_with_overflow => if (lhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false,
15131555 .sub_with_overflow => false,
15141556 else => unreachable,
15151557 };
15161558 const rhs_immediate_ok = switch (tag) {
15171559 .add_with_overflow,
15181560 .sub_with_overflow,
1519 => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null,
1561 => if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false,
15201562 else => unreachable,
15211563 };
15221564
......@@ -1531,12 +1573,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
15311573
15321574 const dest = blk: {
15331575 if (rhs_immediate_ok) {
1534 break :blk try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, null);
1576 break :blk try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, null);
15351577 } else if (lhs_immediate_ok) {
15361578 // swap lhs and rhs
1537 break :blk try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, null);
1579 break :blk try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, null);
15381580 } else {
1539 break :blk try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1581 break :blk try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null);
15401582 }
15411583 };
15421584
......@@ -1563,8 +1605,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15631605 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
15641606 if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
15651607 const result: MCValue = result: {
1566 const lhs = try self.resolveInst(extra.lhs);
1567 const rhs = try self.resolveInst(extra.rhs);
1608 const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
1609 const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
15681610 const lhs_ty = self.air.typeOf(extra.lhs);
15691611 const rhs_ty = self.air.typeOf(extra.rhs);
15701612
......@@ -1580,17 +1622,16 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15801622 assert(lhs_ty.eql(rhs_ty, mod));
15811623 const int_info = lhs_ty.intInfo(self.target.*);
15821624 if (int_info.bits <= 16) {
1583 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
1625 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
15841626
15851627 try self.spillCompareFlagsIfOccupied();
1586 self.cpsr_flags_inst = null;
15871628
15881629 const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {
15891630 .signed => .smulbb,
15901631 .unsigned => .mul,
15911632 };
15921633
1593 const dest = try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1634 const dest = try self.binOpRegisterNew(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null);
15941635 const dest_reg = dest.register;
15951636 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
15961637 defer self.register_manager.unlockReg(dest_reg_lock);
......@@ -1603,62 +1644,48 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
16031644 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
16041645
16051646 // cmp dest, truncated
1606 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
1647 _ = try self.addInst(.{
1648 .tag = .cmp,
1649 .data = .{ .r_op_cmp = .{
1650 .rn = dest_reg,
1651 .op = Instruction.Operand.reg(truncated_reg, Instruction.Operand.Shift.none),
1652 } },
1653 });
16071654
16081655 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
16091656 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });
16101657
16111658 break :result MCValue{ .stack_offset = stack_offset };
16121659 } else if (int_info.bits <= 32) {
1613 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
1660 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
16141661
16151662 try self.spillCompareFlagsIfOccupied();
1616 self.cpsr_flags_inst = null;
16171663
16181664 const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {
16191665 .signed => .smull,
16201666 .unsigned => .umull,
16211667 };
16221668
1623 // TODO extract umull etc. to binOpTwoRegister
1624 // once MCValue.rr is implemented
1625 const lhs_is_register = lhs == .register;
1626 const rhs_is_register = rhs == .register;
1627
1628 const lhs_lock: ?RegisterLock = if (lhs_is_register)
1629 self.register_manager.lockReg(lhs.register)
1630 else
1631 null;
1632 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
1633
1634 const lhs_reg = if (lhs_is_register)
1635 lhs.register
1636 else
1637 try self.register_manager.allocReg(null, gp);
1638 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
1639 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
1640
1641 const rhs_reg = if (rhs_is_register)
1642 rhs.register
1643 else
1644 try self.register_manager.allocReg(null, gp);
1645 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
1646 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
1647
1648 const dest_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
1649 const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
1650 defer for (dest_regs_locks) |reg| {
1651 self.register_manager.unlockReg(reg);
1652 };
1653 const rdlo = dest_regs[0];
1654 const rdhi = dest_regs[1];
1655
1656 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1657 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
1669 var lhs_reg: Register = undefined;
1670 var rhs_reg: Register = undefined;
1671 var rdhi: Register = undefined;
1672 var rdlo: Register = undefined;
1673 var truncated_reg: Register = undefined;
16581674
1659 const truncated_reg = try self.register_manager.allocReg(null, gp);
1660 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
1661 defer self.register_manager.unlockReg(truncated_reg_lock);
1675 const read_args = [_]ReadArg{
1676 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
1677 .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
1678 };
1679 const write_args = [_]WriteArg{
1680 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &rdhi },
1681 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &rdlo },
1682 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &truncated_reg },
1683 };
1684 try self.allocRegs(
1685 &read_args,
1686 &write_args,
1687 null,
1688 );
16621689
16631690 _ = try self.addInst(.{
16641691 .tag = base_tag,
......@@ -1677,14 +1704,19 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
16771704 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
16781705
16791706 // cmp truncated, rdlo
1680 _ = try self.binOp(.cmp_eq, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize, null);
1707 _ = try self.addInst(.{
1708 .tag = .cmp,
1709 .data = .{ .r_op_cmp = .{
1710 .rn = truncated_reg,
1711 .op = Instruction.Operand.reg(rdlo, Instruction.Operand.Shift.none),
1712 } },
1713 });
16811714
16821715 // mov rdlo, #0
16831716 _ = try self.addInst(.{
16841717 .tag = .mov,
1685 .data = .{ .rr_op = .{
1718 .data = .{ .r_op_mov = .{
16861719 .rd = rdlo,
1687 .rn = .r0,
16881720 .op = Instruction.Operand.fromU32(0).?,
16891721 } },
16901722 });
......@@ -1693,23 +1725,27 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
16931725 _ = try self.addInst(.{
16941726 .tag = .mov,
16951727 .cond = .ne,
1696 .data = .{ .rr_op = .{
1728 .data = .{ .r_op_mov = .{
16971729 .rd = rdlo,
1698 .rn = .r0,
16991730 .op = Instruction.Operand.fromU32(1).?,
17001731 } },
17011732 });
17021733
17031734 // cmp rdhi, #0
1704 _ = try self.binOp(.cmp_eq, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize, null);
1735 _ = try self.addInst(.{
1736 .tag = .cmp,
1737 .data = .{ .r_op_cmp = .{
1738 .rn = rdhi,
1739 .op = Instruction.Operand.fromU32(0).?,
1740 } },
1741 });
17051742
17061743 // movne rdlo, #1
17071744 _ = try self.addInst(.{
17081745 .tag = .mov,
17091746 .cond = .ne,
1710 .data = .{ .rr_op = .{
1747 .data = .{ .r_op_mov = .{
17111748 .rd = rdlo,
1712 .rn = .r0,
17131749 .op = Instruction.Operand.fromU32(1).?,
17141750 } },
17151751 });
......@@ -1733,8 +1769,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
17331769 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
17341770 if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
17351771 const result: MCValue = result: {
1736 const lhs = try self.resolveInst(extra.lhs);
1737 const rhs = try self.resolveInst(extra.rhs);
17381772 const lhs_ty = self.air.typeOf(extra.lhs);
17391773 const rhs_ty = self.air.typeOf(extra.rhs);
17401774
......@@ -1748,30 +1782,109 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
17481782 .Int => {
17491783 const int_info = lhs_ty.intInfo(self.target.*);
17501784 if (int_info.bits <= 32) {
1751 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
1752
1753 const lhs_lock: ?RegisterLock = if (lhs == .register)
1754 self.register_manager.lockRegAssumeUnused(lhs.register)
1755 else
1756 null;
1757 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
1785 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
17581786
17591787 try self.spillCompareFlagsIfOccupied();
1760 self.cpsr_flags_inst = null;
17611788
1762 // lsl dest, lhs, rhs
1763 const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null);
1764 const dest_reg = dest.register;
1765 const dest_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1766 defer self.register_manager.unlockReg(dest_lock);
1789 const shr_mir_tag: Mir.Inst.Tag = switch (int_info.signedness) {
1790 .signed => Mir.Inst.Tag.asr,
1791 .unsigned => Mir.Inst.Tag.lsr,
1792 };
1793
1794 var lhs_reg: Register = undefined;
1795 var rhs_reg: Register = undefined;
1796 var dest_reg: Register = undefined;
1797 var reconstructed_reg: Register = undefined;
1798
1799 const rhs_mcv = try self.resolveInst(extra.rhs);
1800 const rhs_immediate_ok = rhs_mcv == .immediate and Instruction.Operand.fromU32(rhs_mcv.immediate) != null;
1801
1802 const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
1803 const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
1804
1805 if (rhs_immediate_ok) {
1806 const read_args = [_]ReadArg{
1807 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
1808 };
1809 const write_args = [_]WriteArg{
1810 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1811 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &reconstructed_reg },
1812 };
1813 try self.allocRegs(
1814 &read_args,
1815 &write_args,
1816 null,
1817 );
1818
1819 // lsl dest, lhs, rhs
1820 _ = try self.addInst(.{
1821 .tag = .lsl,
1822 .data = .{ .rr_shift = .{
1823 .rd = dest_reg,
1824 .rm = lhs_reg,
1825 .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs_mcv.immediate)),
1826 } },
1827 });
1828
1829 try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits);
1830
1831 // asr/lsr reconstructed, dest, rhs
1832 _ = try self.addInst(.{
1833 .tag = shr_mir_tag,
1834 .data = .{ .rr_shift = .{
1835 .rd = reconstructed_reg,
1836 .rm = dest_reg,
1837 .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs_mcv.immediate)),
1838 } },
1839 });
1840 } else {
1841 const read_args = [_]ReadArg{
1842 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
1843 .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
1844 };
1845 const write_args = [_]WriteArg{
1846 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1847 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &reconstructed_reg },
1848 };
1849 try self.allocRegs(
1850 &read_args,
1851 &write_args,
1852 null,
1853 );
1854
1855 // lsl dest, lhs, rhs
1856 _ = try self.addInst(.{
1857 .tag = .lsl,
1858 .data = .{ .rr_shift = .{
1859 .rd = dest_reg,
1860 .rm = lhs_reg,
1861 .shift_amount = Instruction.ShiftAmount.reg(rhs_reg),
1862 } },
1863 });
1864
1865 try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits);
17671866
1768 // asr/lsr reconstructed, dest, rhs
1769 const reconstructed = try self.binOp(.shr, dest, rhs, lhs_ty, rhs_ty, null);
1867 // asr/lsr reconstructed, dest, rhs
1868 _ = try self.addInst(.{
1869 .tag = shr_mir_tag,
1870 .data = .{ .rr_shift = .{
1871 .rd = reconstructed_reg,
1872 .rm = dest_reg,
1873 .shift_amount = Instruction.ShiftAmount.reg(rhs_reg),
1874 } },
1875 });
1876 }
17701877
17711878 // cmp lhs, reconstructed
1772 _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null);
1879 _ = try self.addInst(.{
1880 .tag = .cmp,
1881 .data = .{ .r_op_cmp = .{
1882 .rn = lhs_reg,
1883 .op = Instruction.Operand.reg(reconstructed_reg, Instruction.Operand.Shift.none),
1884 } },
1885 });
17731886
1774 try self.genSetStack(lhs_ty, stack_offset, dest);
1887 try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg });
17751888 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });
17761889
17771890 break :result MCValue{ .stack_offset = stack_offset };
......@@ -1826,19 +1939,57 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
18261939}
18271940
18281941/// Given an error union, returns the error
1829fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
1942fn errUnionErr(
1943 self: *Self,
1944 error_union_bind: ReadArg.Bind,
1945 error_union_ty: Type,
1946 maybe_inst: ?Air.Inst.Index,
1947) !MCValue {
18301948 const err_ty = error_union_ty.errorUnionSet();
18311949 const payload_ty = error_union_ty.errorUnionPayload();
18321950 if (err_ty.errorSetIsEmpty()) {
18331951 return MCValue{ .immediate = 0 };
18341952 }
18351953 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1836 return error_union_mcv;
1954 return try error_union_bind.resolveToMcv(self);
18371955 }
18381956
18391957 const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));
1840 switch (error_union_mcv) {
1841 .register => return self.fail("TODO errUnionErr for registers", .{}),
1958 switch (try error_union_bind.resolveToMcv(self)) {
1959 .register => {
1960 var operand_reg: Register = undefined;
1961 var dest_reg: Register = undefined;
1962
1963 const read_args = [_]ReadArg{
1964 .{ .ty = error_union_ty, .bind = error_union_bind, .class = gp, .reg = &operand_reg },
1965 };
1966 const write_args = [_]WriteArg{
1967 .{ .ty = err_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1968 };
1969 try self.allocRegs(
1970 &read_args,
1971 &write_args,
1972 if (maybe_inst) |inst| .{
1973 .corresponding_inst = inst,
1974 .operand_mapping = &.{0},
1975 } else null,
1976 );
1977
1978 const err_bit_offset = err_offset * 8;
1979 const err_bit_size = @intCast(u32, err_ty.abiSize(self.target.*)) * 8;
1980
1981 _ = try self.addInst(.{
1982 .tag = .ubfx, // errors are unsigned integers
1983 .data = .{ .rr_lsb_width = .{
1984 .rd = dest_reg,
1985 .rn = operand_reg,
1986 .lsb = @intCast(u5, err_bit_offset),
1987 .width = @intCast(u6, err_bit_size),
1988 } },
1989 });
1990
1991 return MCValue{ .register = dest_reg };
1992 },
18421993 .stack_argument_offset => |off| {
18431994 return MCValue{ .stack_argument_offset = off + err_offset };
18441995 },
......@@ -1855,27 +2006,66 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV
18552006fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
18562007 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
18572008 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2009 const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand };
18582010 const error_union_ty = self.air.typeOf(ty_op.operand);
1859 const mcv = try self.resolveInst(ty_op.operand);
1860 break :result try self.errUnionErr(mcv, error_union_ty);
2011
2012 break :result try self.errUnionErr(error_union_bind, error_union_ty, inst);
18612013 };
18622014 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
18632015}
18642016
18652017/// Given an error union, returns the payload
1866fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
2018fn errUnionPayload(
2019 self: *Self,
2020 error_union_bind: ReadArg.Bind,
2021 error_union_ty: Type,
2022 maybe_inst: ?Air.Inst.Index,
2023) !MCValue {
18672024 const err_ty = error_union_ty.errorUnionSet();
18682025 const payload_ty = error_union_ty.errorUnionPayload();
18692026 if (err_ty.errorSetIsEmpty()) {
1870 return error_union_mcv;
2027 return try error_union_bind.resolveToMcv(self);
18712028 }
18722029 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
18732030 return MCValue.none;
18742031 }
18752032
18762033 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));
1877 switch (error_union_mcv) {
1878 .register => return self.fail("TODO errUnionPayload for registers", .{}),
2034 switch (try error_union_bind.resolveToMcv(self)) {
2035 .register => {
2036 var operand_reg: Register = undefined;
2037 var dest_reg: Register = undefined;
2038
2039 const read_args = [_]ReadArg{
2040 .{ .ty = error_union_ty, .bind = error_union_bind, .class = gp, .reg = &operand_reg },
2041 };
2042 const write_args = [_]WriteArg{
2043 .{ .ty = err_ty, .bind = .none, .class = gp, .reg = &dest_reg },
2044 };
2045 try self.allocRegs(
2046 &read_args,
2047 &write_args,
2048 if (maybe_inst) |inst| .{
2049 .corresponding_inst = inst,
2050 .operand_mapping = &.{0},
2051 } else null,
2052 );
2053
2054 const payload_bit_offset = payload_offset * 8;
2055 const payload_bit_size = @intCast(u32, payload_ty.abiSize(self.target.*)) * 8;
2056
2057 _ = try self.addInst(.{
2058 .tag = if (payload_ty.isSignedInt()) Mir.Inst.Tag.sbfx else .ubfx,
2059 .data = .{ .rr_lsb_width = .{
2060 .rd = dest_reg,
2061 .rn = operand_reg,
2062 .lsb = @intCast(u5, payload_bit_offset),
2063 .width = @intCast(u6, payload_bit_size),
2064 } },
2065 });
2066
2067 return MCValue{ .register = dest_reg };
2068 },
18792069 .stack_argument_offset => |off| {
18802070 return MCValue{ .stack_argument_offset = off + payload_offset };
18812071 },
......@@ -1892,9 +2082,10 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
18922082fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
18932083 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
18942084 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2085 const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand };
18952086 const error_union_ty = self.air.typeOf(ty_op.operand);
1896 const error_union = try self.resolveInst(ty_op.operand);
1897 break :result try self.errUnionPayload(error_union, error_union_ty);
2087
2088 break :result try self.errUnionPayload(error_union_bind, error_union_ty, inst);
18982089 };
18992090 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
19002091}
......@@ -1938,17 +2129,18 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
19382129 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
19392130 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
19402131 const error_union_ty = self.air.getRefType(ty_op.ty);
2132 const error_ty = error_union_ty.errorUnionSet();
19412133 const payload_ty = error_union_ty.errorUnionPayload();
19422134 const operand = try self.resolveInst(ty_op.operand);
19432135 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand;
19442136
19452137 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
19462138 const abi_align = error_union_ty.abiAlignment(self.target.*);
1947 const stack_offset = @intCast(u32, try self.allocMem(inst, abi_size, abi_align));
2139 const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst));
19482140 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
19492141 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
19502142 try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand);
1951 try self.genSetStack(Type.anyerror, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 });
2143 try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 });
19522144
19532145 break :result MCValue{ .stack_offset = stack_offset };
19542146 };
......@@ -1960,16 +2152,17 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
19602152 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
19612153 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
19622154 const error_union_ty = self.air.getRefType(ty_op.ty);
2155 const error_ty = error_union_ty.errorUnionSet();
19632156 const payload_ty = error_union_ty.errorUnionPayload();
19642157 const operand = try self.resolveInst(ty_op.operand);
19652158 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand;
19662159
19672160 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
19682161 const abi_align = error_union_ty.abiAlignment(self.target.*);
1969 const stack_offset = @intCast(u32, try self.allocMem(inst, abi_size, abi_align));
2162 const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst));
19702163 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
19712164 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
1972 try self.genSetStack(Type.anyerror, stack_offset - @intCast(u32, err_off), operand);
2165 try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), operand);
19732166 try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef);
19742167
19752168 break :result MCValue{ .stack_offset = stack_offset };
......@@ -2008,7 +2201,6 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
20082201 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
20092202 const mcv = try self.resolveInst(ty_op.operand);
20102203 switch (mcv) {
2011 .dead, .unreach => unreachable,
20122204 .register => unreachable, // a slice doesn't fit in one register
20132205 .stack_argument_offset => |off| {
20142206 break :result MCValue{ .stack_argument_offset = off + 4 };
......@@ -2019,7 +2211,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
20192211 .memory => |addr| {
20202212 break :result MCValue{ .memory = addr + 4 };
20212213 },
2022 else => return self.fail("TODO implement slice_len for {}", .{mcv}),
2214 else => unreachable, // invalid MCValue for a slice
20232215 }
20242216 };
20252217 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -2034,7 +2226,12 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
20342226 .ptr_stack_offset => |off| {
20352227 break :result MCValue{ .ptr_stack_offset = off - 4 };
20362228 },
2037 else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}),
2229 else => {
2230 const lhs_bind: ReadArg.Bind = .{ .mcv = mcv };
2231 const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 4 } };
2232
2233 break :result try self.addSub(.add, lhs_bind, rhs_bind, Type.usize, Type.usize, null);
2234 },
20382235 }
20392236 };
20402237 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -2049,91 +2246,96 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
20492246 .ptr_stack_offset => |off| {
20502247 break :result MCValue{ .ptr_stack_offset = off };
20512248 },
2052 else => return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{mcv}),
2249 else => {
2250 if (self.reuseOperand(inst, ty_op.operand, 0, mcv)) {
2251 break :result mcv;
2252 } else {
2253 break :result MCValue{ .register = try self.copyToTmpRegister(Type.usize, mcv) };
2254 }
2255 },
20532256 }
20542257 };
20552258 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
20562259}
20572260
2058fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2059 const is_volatile = false; // TODO
2060 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2061
2062 if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
2063 const result: MCValue = result: {
2064 const slice_mcv = try self.resolveInst(bin_op.lhs);
2065
2066 // TODO optimize for the case where the index is a constant,
2067 // i.e. index_mcv == .immediate
2068 const index_mcv = try self.resolveInst(bin_op.rhs);
2069 const index_is_register = index_mcv == .register;
2070
2071 const slice_ty = self.air.typeOf(bin_op.lhs);
2072 const elem_ty = slice_ty.childType();
2073 const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
2074
2075 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
2076 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
2261fn ptrElemVal(
2262 self: *Self,
2263 ptr_bind: ReadArg.Bind,
2264 index_bind: ReadArg.Bind,
2265 ptr_ty: Type,
2266 maybe_inst: ?Air.Inst.Index,
2267) !MCValue {
2268 const elem_ty = ptr_ty.childType();
2269 const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
20772270
2078 const index_lock: ?RegisterLock = if (index_is_register)
2079 self.register_manager.lockRegAssumeUnused(index_mcv.register)
2080 else
2081 null;
2082 defer if (index_lock) |reg| self.register_manager.unlockReg(reg);
2271 switch (elem_size) {
2272 1, 4 => {
2273 var base_reg: Register = undefined;
2274 var index_reg: Register = undefined;
2275 var dest_reg: Register = undefined;
20832276
2084 const base_mcv = slicePtr(slice_mcv);
2277 const read_args = [_]ReadArg{
2278 .{ .ty = ptr_ty, .bind = ptr_bind, .class = gp, .reg = &base_reg },
2279 .{ .ty = Type.usize, .bind = index_bind, .class = gp, .reg = &index_reg },
2280 };
2281 const write_args = [_]WriteArg{
2282 .{ .ty = elem_ty, .bind = .none, .class = gp, .reg = &dest_reg },
2283 };
2284 try self.allocRegs(
2285 &read_args,
2286 &write_args,
2287 if (maybe_inst) |inst| .{
2288 .corresponding_inst = inst,
2289 .operand_mapping = &.{ 0, 1 },
2290 } else null,
2291 );
2292
2293 const tag: Mir.Inst.Tag = switch (elem_size) {
2294 1 => .ldrb,
2295 4 => .ldr,
2296 else => unreachable,
2297 };
2298 const shift: u5 = switch (elem_size) {
2299 1 => 0,
2300 4 => 2,
2301 else => unreachable,
2302 };
20852303
2086 switch (elem_size) {
2087 1, 4 => {
2088 const base_reg = switch (base_mcv) {
2089 .register => |r| r,
2090 else => try self.copyToTmpRegister(slice_ptr_field_type, base_mcv),
2091 };
2092 const base_reg_lock = self.register_manager.lockRegAssumeUnused(base_reg);
2093 defer self.register_manager.unlockReg(base_reg_lock);
2304 _ = try self.addInst(.{
2305 .tag = tag,
2306 .data = .{ .rr_offset = .{
2307 .rt = dest_reg,
2308 .rn = base_reg,
2309 .offset = .{ .offset = Instruction.Offset.reg(index_reg, .{ .lsl = shift }) },
2310 } },
2311 });
20942312
2095 const dst_reg = try self.register_manager.allocReg(inst, gp);
2096 const dst_mcv = MCValue{ .register = dst_reg };
2097 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
2098 defer self.register_manager.unlockReg(dst_reg_lock);
2313 return MCValue{ .register = dest_reg };
2314 },
2315 else => {
2316 const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, Type.usize, null);
20992317
2100 const index_reg: Register = switch (index_mcv) {
2101 .register => |reg| reg,
2102 else => try self.copyToTmpRegister(Type.usize, index_mcv),
2103 };
2104 const index_reg_lock = self.register_manager.lockReg(index_reg);
2105 defer if (index_reg_lock) |lock| self.register_manager.unlockReg(lock);
2318 const dest = try self.allocRegOrMem(elem_ty, true, maybe_inst);
2319 try self.load(dest, addr, ptr_ty);
2320 return dest;
2321 },
2322 }
2323}
21062324
2107 const tag: Mir.Inst.Tag = switch (elem_size) {
2108 1 => .ldrb,
2109 4 => .ldr,
2110 else => unreachable,
2111 };
2112 const shift: u5 = switch (elem_size) {
2113 1 => 0,
2114 4 => 2,
2115 else => unreachable,
2116 };
2325fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2326 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2327 const slice_ty = self.air.typeOf(bin_op.lhs);
2328 const result: MCValue = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
2329 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
2330 const ptr_ty = slice_ty.slicePtrFieldType(&buf);
21172331
2118 _ = try self.addInst(.{
2119 .tag = tag,
2120 .data = .{ .rr_offset = .{
2121 .rt = dst_reg,
2122 .rn = base_reg,
2123 .offset = .{ .offset = Instruction.Offset.reg(index_reg, .{ .lsl = shift }) },
2124 } },
2125 });
2332 const slice_mcv = try self.resolveInst(bin_op.lhs);
2333 const base_mcv = slicePtr(slice_mcv);
21262334
2127 break :result dst_mcv;
2128 },
2129 else => {
2130 const dest = try self.allocRegOrMem(inst, true);
2131 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
2132 try self.load(dest, addr, slice_ptr_field_type);
2335 const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };
2336 const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
21332337
2134 break :result dest;
2135 },
2136 }
2338 break :result try self.ptrElemVal(base_bind, index_bind, ptr_ty, inst);
21372339 };
21382340 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
21392341}
......@@ -2143,40 +2345,108 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
21432345 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
21442346 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
21452347 const slice_mcv = try self.resolveInst(extra.lhs);
2146 const index_mcv = try self.resolveInst(extra.rhs);
21472348 const base_mcv = slicePtr(slice_mcv);
21482349
2350 const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };
2351 const index_bind: ReadArg.Bind = .{ .inst = extra.rhs };
2352
21492353 const slice_ty = self.air.typeOf(extra.lhs);
2354 const index_ty = self.air.typeOf(extra.rhs);
21502355
2151 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ty, Type.usize, null);
2356 const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ty, index_ty, null);
21522357 break :result addr;
21532358 };
21542359 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
21552360}
21562361
2157fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2158 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2159 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch});
2160 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2161}
2162
2163fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
2164 const is_volatile = false; // TODO
2165 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2166 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_elem_val for {}", .{self.target.cpu.arch});
2167 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2168}
2362fn arrayElemVal(
2363 self: *Self,
2364 array_bind: ReadArg.Bind,
2365 index_bind: ReadArg.Bind,
2366 array_ty: Type,
2367 maybe_inst: ?Air.Inst.Index,
2368) InnerError!MCValue {
2369 const elem_ty = array_ty.childType();
21692370
2170fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2171 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2172 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2173 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2174 const ptr_mcv = try self.resolveInst(extra.lhs);
2175 const index_mcv = try self.resolveInst(extra.rhs);
2371 const mcv = try array_bind.resolveToMcv(self);
2372 switch (mcv) {
2373 .stack_offset,
2374 .memory,
2375 .stack_argument_offset,
2376 => {
2377 const ptr_to_mcv = switch (mcv) {
2378 .stack_offset => |off| MCValue{ .ptr_stack_offset = off },
2379 .memory => |addr| MCValue{ .immediate = @intCast(u32, addr) },
2380 .stack_argument_offset => |off| blk: {
2381 const reg = try self.register_manager.allocReg(null, gp);
21762382
2177 const ptr_ty = self.air.typeOf(extra.lhs);
2383 _ = try self.addInst(.{
2384 .tag = .ldr_ptr_stack_argument,
2385 .data = .{ .r_stack_offset = .{
2386 .rt = reg,
2387 .stack_offset = off,
2388 } },
2389 });
2390
2391 break :blk MCValue{ .register = reg };
2392 },
2393 else => unreachable,
2394 };
2395 const ptr_to_mcv_lock: ?RegisterLock = switch (ptr_to_mcv) {
2396 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2397 else => null,
2398 };
2399 defer if (ptr_to_mcv_lock) |lock| self.register_manager.unlockReg(lock);
2400
2401 const base_bind: ReadArg.Bind = .{ .mcv = ptr_to_mcv };
2402
2403 var ptr_ty_payload: Type.Payload.ElemType = .{
2404 .base = .{ .tag = .single_mut_pointer },
2405 .data = elem_ty,
2406 };
2407 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
2408
2409 return try self.ptrElemVal(base_bind, index_bind, ptr_ty, maybe_inst);
2410 },
2411 else => return self.fail("TODO implement array_elem_val for {}", .{mcv}),
2412 }
2413}
2414
2415fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2416 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2417 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2418 const array_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
2419 const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
2420 const array_ty = self.air.typeOf(bin_op.lhs);
21782421
2179 const addr = try self.binOp(.ptr_add, ptr_mcv, index_mcv, ptr_ty, Type.usize, null);
2422 break :result try self.arrayElemVal(array_bind, index_bind, array_ty, inst);
2423 };
2424 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2425}
2426
2427fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
2428 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2429 const ptr_ty = self.air.typeOf(bin_op.lhs);
2430 const result: MCValue = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
2431 const base_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
2432 const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
2433
2434 break :result try self.ptrElemVal(base_bind, index_bind, ptr_ty, inst);
2435 };
2436 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2437}
2438
2439fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2440 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2441 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2442 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2443 const ptr_bind: ReadArg.Bind = .{ .inst = extra.lhs };
2444 const index_bind: ReadArg.Bind = .{ .inst = extra.rhs };
2445
2446 const ptr_ty = self.air.typeOf(extra.lhs);
2447 const index_ty = self.air.typeOf(extra.rhs);
2448
2449 const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, index_ty, null);
21802450 break :result addr;
21812451 };
21822452 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
......@@ -2240,7 +2510,13 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
22402510 return self.finishAir(inst, result, .{ un_op, .none, .none });
22412511}
22422512
2243fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_index: Liveness.OperandInt, mcv: MCValue) bool {
2513fn reuseOperand(
2514 self: *Self,
2515 inst: Air.Inst.Index,
2516 operand: Air.Inst.Ref,
2517 op_index: Liveness.OperandInt,
2518 mcv: MCValue,
2519) bool {
22442520 if (!self.liveness.operandDies(inst, op_index))
22452521 return false;
22462522
......@@ -2362,16 +2638,18 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
23622638 if (self.liveness.isUnused(inst) and !is_volatile)
23632639 break :result MCValue.dead;
23642640
2365 const dst_mcv: MCValue = blk: {
2366 if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
2641 const dest_mcv: MCValue = blk: {
2642 const ptr_fits_dest = elem_ty.abiSize(self.target.*) <= 4;
2643 if (ptr_fits_dest and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
23672644 // The MCValue that holds the pointer can be re-used as the value.
23682645 break :blk ptr;
23692646 } else {
2370 break :blk try self.allocRegOrMem(inst, true);
2647 break :blk try self.allocRegOrMem(elem_ty, true, inst);
23712648 }
23722649 };
2373 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));
2374 break :result dst_mcv;
2650 try self.load(dest_mcv, ptr, self.air.typeOf(ty_op.operand));
2651
2652 break :result dest_mcv;
23752653 };
23762654 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
23772655}
......@@ -2498,26 +2776,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
24982776 break :result MCValue{ .ptr_stack_offset = off - struct_field_offset };
24992777 },
25002778 else => {
2501 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
2502 .immediate = struct_field_offset,
2503 });
2504 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2505 defer self.register_manager.unlockReg(offset_reg_lock);
2506
2507 const addr_reg = try self.copyToTmpRegister(ptr_ty, mcv);
2508 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
2509 defer self.register_manager.unlockReg(addr_reg_lock);
2510
2511 const dest = try self.binOp(
2512 .add,
2513 .{ .register = addr_reg },
2514 .{ .register = offset_reg },
2515 Type.usize,
2516 Type.usize,
2517 null,
2518 );
2779 const lhs_bind: ReadArg.Bind = .{ .mcv = mcv };
2780 const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = struct_field_offset } };
25192781
2520 break :result dest;
2782 break :result try self.addSub(.add, lhs_bind, rhs_bind, Type.usize, Type.usize, null);
25212783 },
25222784 }
25232785 };
......@@ -2532,6 +2794,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
25322794 const mcv = try self.resolveInst(operand);
25332795 const struct_ty = self.air.typeOf(operand);
25342796 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
2797 const struct_field_ty = struct_ty.structFieldType(index);
25352798
25362799 switch (mcv) {
25372800 .dead, .unreach => unreachable,
......@@ -2569,11 +2832,45 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
25692832 } else {
25702833 // Copy to new register
25712834 const dest_reg = try self.register_manager.allocReg(null, gp);
2572 try self.genSetReg(struct_ty.structFieldType(index), dest_reg, field);
2835 try self.genSetReg(struct_field_ty, dest_reg, field);
25732836
25742837 break :result MCValue{ .register = dest_reg };
25752838 }
25762839 },
2840 .register => {
2841 var operand_reg: Register = undefined;
2842 var dest_reg: Register = undefined;
2843
2844 const read_args = [_]ReadArg{
2845 .{ .ty = struct_ty, .bind = .{ .mcv = mcv }, .class = gp, .reg = &operand_reg },
2846 };
2847 const write_args = [_]WriteArg{
2848 .{ .ty = struct_field_ty, .bind = .none, .class = gp, .reg = &dest_reg },
2849 };
2850 try self.allocRegs(
2851 &read_args,
2852 &write_args,
2853 ReuseMetadata{
2854 .corresponding_inst = inst,
2855 .operand_mapping = &.{0},
2856 },
2857 );
2858
2859 const field_bit_offset = struct_field_offset * 8;
2860 const field_bit_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)) * 8;
2861
2862 _ = try self.addInst(.{
2863 .tag = if (struct_field_ty.isSignedInt()) Mir.Inst.Tag.sbfx else .ubfx,
2864 .data = .{ .rr_lsb_width = .{
2865 .rd = dest_reg,
2866 .rn = operand_reg,
2867 .lsb = @intCast(u5, field_bit_offset),
2868 .width = @intCast(u6, field_bit_size),
2869 } },
2870 });
2871
2872 break :result MCValue{ .register = dest_reg };
2873 },
25772874 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
25782875 }
25792876 };
......@@ -2583,114 +2880,285 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
25832880
25842881fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
25852882 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2586 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2587 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFieldParentPtr", .{});
2588 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2883 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
2884 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2885 const field_ptr = try self.resolveInst(extra.field_ptr);
2886 const struct_ty = self.air.getRefType(ty_pl.ty).childType();
2887 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(extra.field_index, self.target.*));
2888 switch (field_ptr) {
2889 .ptr_stack_offset => |off| {
2890 break :result MCValue{ .ptr_stack_offset = off + struct_field_offset };
2891 },
2892 else => {
2893 const lhs_bind: ReadArg.Bind = .{ .mcv = field_ptr };
2894 const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = struct_field_offset } };
2895
2896 break :result try self.addSub(.sub, lhs_bind, rhs_bind, Type.usize, Type.usize, null);
2897 },
2898 }
2899 };
2900 return self.finishAir(inst, result, .{ extra.field_ptr, .none, .none });
25892901}
25902902
2591/// Allocates a new register. If Inst in non-null, additionally tracks
2592/// this register and the corresponding int and removes all previous
2593/// tracking. Does not do the actual moving (that is handled by
2594/// genSetReg).
2595fn prepareNewRegForMoving(
2596 self: *Self,
2597 track_inst: ?Air.Inst.Index,
2598 register_class: RegisterManager.RegisterBitSet,
2599 mcv: MCValue,
2600) !Register {
2601 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
2602 const reg = try self.register_manager.allocReg(track_inst, register_class);
2903/// An argument to a Mir instruction which is read (and possibly also
2904/// written to) by the respective instruction
2905const ReadArg = struct {
2906 ty: Type,
2907 bind: Bind,
2908 class: RegisterManager.RegisterBitSet,
2909 reg: *Register,
26032910
2604 if (track_inst) |inst| {
2605 // Overwrite the MCValue associated with this inst
2606 branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
2911 const Bind = union(enum) {
2912 inst: Air.Inst.Ref,
2913 mcv: MCValue,
26072914
2608 // If the previous MCValue occupied some space we track, we
2609 // need to make sure it is marked as free now.
2610 switch (mcv) {
2611 .cpsr_flags => {
2612 assert(self.cpsr_flags_inst.? == inst);
2613 self.cpsr_flags_inst = null;
2614 },
2615 .register => |prev_reg| {
2616 assert(!self.register_manager.isRegFree(prev_reg));
2617 self.register_manager.freeReg(prev_reg);
2618 },
2619 else => {},
2915 fn resolveToMcv(bind: Bind, function: *Self) InnerError!MCValue {
2916 return switch (bind) {
2917 .inst => |inst| try function.resolveInst(inst),
2918 .mcv => |mcv| mcv,
2919 };
26202920 }
2621 }
26222921
2623 return reg;
2624}
2922 fn resolveToImmediate(bind: Bind, function: *Self) InnerError!?u32 {
2923 switch (bind) {
2924 .inst => |inst| {
2925 // TODO resolve independently of inst_table
2926 const mcv = try function.resolveInst(inst);
2927 switch (mcv) {
2928 .immediate => |imm| return imm,
2929 else => return null,
2930 }
2931 },
2932 .mcv => |mcv| {
2933 switch (mcv) {
2934 .immediate => |imm| return imm,
2935 else => return null,
2936 }
2937 },
2938 }
2939 }
2940 };
2941};
2942
2943/// An argument to a Mir instruction which is written to (but not read
2944/// from) by the respective instruction
2945const WriteArg = struct {
2946 ty: Type,
2947 bind: Bind,
2948 class: RegisterManager.RegisterBitSet,
2949 reg: *Register,
2950
2951 const Bind = union(enum) {
2952 reg: Register,
2953 none: void,
2954 };
2955};
2956
2957/// Holds all data necessary for enabling the potential reuse of
2958/// operand registers as destinations
2959const ReuseMetadata = struct {
2960 corresponding_inst: Air.Inst.Index,
2961
2962 /// Maps every element index of read_args to the corresponding
2963 /// index in the Air instruction
2964 ///
2965 /// When the order of read_args corresponds exactly to the order
2966 /// of the inputs of the Air instruction, this would be e.g.
2967 /// &.{ 0, 1 }. However, when the order is not the same or some
2968 /// inputs to the Air instruction are omitted (e.g. when they can
2969 /// be represented as immediates to the Mir instruction),
2970 /// operand_mapping should reflect that fact.
2971 operand_mapping: []const Liveness.OperandInt,
2972};
26252973
2626/// Don't call this function directly. Use binOp instead.
2974/// Allocate a set of registers for use as arguments for a Mir
2975/// instruction
26272976///
2628/// Calling this function signals an intention to generate a Mir
2629/// instruction of the form
2977/// If the Mir instruction these registers are allocated for
2978/// corresponds exactly to a single Air instruction, populate
2979/// reuse_metadata in order to enable potential reuse of an operand as
2980/// the destination (provided that that operand dies in this
2981/// instruction).
26302982///
2631/// op dest, lhs, rhs
2983/// Reusing an operand register as destination is the only time two
2984/// arguments may share the same register. In all other cases,
2985/// allocRegs guarantees that a register will never be allocated to
2986/// more than one argument.
26322987///
2633/// Asserts that generating an instruction of that form is possible.
2634fn binOpRegister(
2988/// Furthermore, allocReg guarantees that all arguments which are
2989/// already bound to registers before calling allocRegs will not
2990/// change their register binding. This is done by locking these
2991/// registers.
2992fn allocRegs(
26352993 self: *Self,
2636 mir_tag: Mir.Inst.Tag,
2637 lhs: MCValue,
2638 rhs: MCValue,
2639 lhs_ty: Type,
2640 rhs_ty: Type,
2641 metadata: ?BinOpMetadata,
2642) !MCValue {
2643 const lhs_is_register = lhs == .register;
2644 const rhs_is_register = rhs == .register;
2994 read_args: []const ReadArg,
2995 write_args: []const WriteArg,
2996 reuse_metadata: ?ReuseMetadata,
2997) InnerError!void {
2998 // Air instructions have exactly one output
2999 assert(!(reuse_metadata != null and write_args.len != 1)); // see note above
3000
3001 // The operand mapping is a 1:1 mapping of read args to their
3002 // corresponding operand index in the Air instruction
3003 assert(!(reuse_metadata != null and reuse_metadata.?.operand_mapping.len != read_args.len)); // see note above
3004
3005 const locks = try self.gpa.alloc(?RegisterLock, read_args.len + write_args.len);
3006 defer self.gpa.free(locks);
3007 const read_locks = locks[0..read_args.len];
3008 const write_locks = locks[read_args.len..];
3009
3010 std.mem.set(?RegisterLock, locks, null);
3011 defer for (locks) |lock| {
3012 if (lock) |locked_reg| self.register_manager.unlockReg(locked_reg);
3013 };
26453014
2646 const lhs_lock: ?RegisterLock = if (lhs_is_register)
2647 self.register_manager.lockReg(lhs.register)
2648 else
2649 null;
2650 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
3015 // When we reuse a read_arg as a destination, the corresponding
3016 // MCValue of the read_arg will be set to .dead. In that case, we
3017 // skip allocating this read_arg.
3018 var reused_read_arg: ?usize = null;
26513019
2652 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
2653 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2654 break :inst Air.refToIndex(md.lhs).?;
2655 } else null;
3020 // Lock all args which are already allocated to registers
3021 for (read_args) |arg, i| {
3022 const mcv = try arg.bind.resolveToMcv(self);
3023 if (mcv == .register) {
3024 read_locks[i] = self.register_manager.lockReg(mcv.register);
3025 }
3026 }
26563027
2657 break :blk try self.prepareNewRegForMoving(track_inst, gp, lhs);
2658 };
2659 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
2660 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
3028 for (write_args) |arg, i| {
3029 if (arg.bind == .reg) {
3030 write_locks[i] = self.register_manager.lockReg(arg.bind.reg);
3031 }
3032 }
26613033
2662 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
2663 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2664 break :inst Air.refToIndex(md.rhs).?;
2665 } else null;
3034 // Allocate registers for all args which aren't allocated to
3035 // registers yet
3036 for (read_args) |arg, i| {
3037 const mcv = try arg.bind.resolveToMcv(self);
3038 if (mcv == .register) {
3039 arg.reg.* = mcv.register;
3040 } else {
3041 const track_inst: ?Air.Inst.Index = switch (arg.bind) {
3042 .inst => |inst| Air.refToIndex(inst).?,
3043 else => null,
3044 };
3045 arg.reg.* = try self.register_manager.allocReg(track_inst, arg.class);
3046 read_locks[i] = self.register_manager.lockReg(arg.reg.*);
3047 }
3048 }
26663049
2667 break :blk try self.prepareNewRegForMoving(track_inst, gp, rhs);
2668 };
2669 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
2670 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
2671
2672 const dest_reg = switch (mir_tag) {
2673 .cmp => .r0, // cmp has no destination regardless
2674 else => if (metadata) |md| blk: {
2675 if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) {
2676 break :blk lhs_reg;
2677 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
2678 break :blk rhs_reg;
3050 if (reuse_metadata != null) {
3051 const inst = reuse_metadata.?.corresponding_inst;
3052 const operand_mapping = reuse_metadata.?.operand_mapping;
3053 const arg = write_args[0];
3054 if (arg.bind == .reg) {
3055 arg.reg.* = arg.bind.reg;
3056 } else {
3057 reuse_operand: for (read_args) |read_arg, i| {
3058 if (read_arg.bind == .inst) {
3059 const operand = read_arg.bind.inst;
3060 const mcv = try self.resolveInst(operand);
3061 if (mcv == .register and
3062 std.meta.eql(arg.class, read_arg.class) and
3063 self.reuseOperand(inst, operand, operand_mapping[i], mcv))
3064 {
3065 arg.reg.* = mcv.register;
3066 write_locks[0] = null;
3067 reused_read_arg = i;
3068 break :reuse_operand;
3069 }
3070 }
26793071 } else {
2680 break :blk try self.register_manager.allocReg(md.inst, gp);
3072 arg.reg.* = try self.register_manager.allocReg(inst, arg.class);
3073 write_locks[0] = self.register_manager.lockReg(arg.reg.*);
26813074 }
2682 } else try self.register_manager.allocReg(null, gp),
2683 };
3075 }
3076 } else {
3077 for (write_args) |arg, i| {
3078 if (arg.bind == .reg) {
3079 arg.reg.* = arg.bind.reg;
3080 } else {
3081 arg.reg.* = try self.register_manager.allocReg(null, arg.class);
3082 write_locks[i] = self.register_manager.lockReg(arg.reg.*);
3083 }
3084 }
3085 }
3086
3087 // For all read_args which need to be moved from non-register to
3088 // register, perform the move
3089 for (read_args) |arg, i| {
3090 if (reused_read_arg) |j| {
3091 // Check whether this read_arg was reused
3092 if (i == j) continue;
3093 }
3094
3095 const mcv = try arg.bind.resolveToMcv(self);
3096 if (mcv != .register) {
3097 if (arg.bind == .inst) {
3098 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
3099 const inst = Air.refToIndex(arg.bind.inst).?;
3100
3101 // Overwrite the MCValue associated with this inst
3102 branch.inst_table.putAssumeCapacity(inst, .{ .register = arg.reg.* });
3103
3104 // If the previous MCValue occupied some space we track, we
3105 // need to make sure it is marked as free now.
3106 switch (mcv) {
3107 .cpsr_flags => {
3108 assert(self.cpsr_flags_inst.? == inst);
3109 self.cpsr_flags_inst = null;
3110 },
3111 .register => |prev_reg| {
3112 assert(!self.register_manager.isRegFree(prev_reg));
3113 self.register_manager.freeReg(prev_reg);
3114 },
3115 else => {},
3116 }
3117 }
3118
3119 try self.genSetReg(arg.ty, arg.reg.*, mcv);
3120 }
3121 }
3122}
26843123
2685 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
2686 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
3124/// Wrapper around allocRegs and addInst tailored for specific Mir
3125/// instructions which are binary operations acting on two registers
3126///
3127/// Returns the destination register
3128fn binOpRegisterNew(
3129 self: *Self,
3130 mir_tag: Mir.Inst.Tag,
3131 lhs_bind: ReadArg.Bind,
3132 rhs_bind: ReadArg.Bind,
3133 lhs_ty: Type,
3134 rhs_ty: Type,
3135 maybe_inst: ?Air.Inst.Index,
3136) !MCValue {
3137 var lhs_reg: Register = undefined;
3138 var rhs_reg: Register = undefined;
3139 var dest_reg: Register = undefined;
3140
3141 const read_args = [_]ReadArg{
3142 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
3143 .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
3144 };
3145 const write_args = [_]WriteArg{
3146 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
3147 };
3148 try self.allocRegs(
3149 &read_args,
3150 &write_args,
3151 if (maybe_inst) |inst| .{
3152 .corresponding_inst = inst,
3153 .operand_mapping = &.{ 0, 1 },
3154 } else null,
3155 );
26873156
26883157 const mir_data: Mir.Inst.Data = switch (mir_tag) {
26893158 .add,
26903159 .adds,
26913160 .sub,
26923161 .subs,
2693 .cmp,
26943162 .@"and",
26953163 .orr,
26963164 .eor,
......@@ -2725,78 +3193,51 @@ fn binOpRegister(
27253193 return MCValue{ .register = dest_reg };
27263194}
27273195
2728/// Don't call this function directly. Use binOp instead.
2729///
2730/// Calling this function signals an intention to generate a Mir
2731/// instruction of the form
2732///
2733/// op dest, lhs, #rhs_imm
3196/// Wrapper around allocRegs and addInst tailored for specific Mir
3197/// instructions which are binary operations acting on a register and
3198/// an immediate
27343199///
2735/// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to
2736/// rhs and vice versa. This parameter is only used when maybe_inst !=
2737/// null.
2738///
2739/// Asserts that generating an instruction of that form is possible.
2740fn binOpImmediate(
3200/// Returns the destination register
3201fn binOpImmediateNew(
27413202 self: *Self,
27423203 mir_tag: Mir.Inst.Tag,
2743 lhs: MCValue,
2744 rhs: MCValue,
3204 lhs_bind: ReadArg.Bind,
3205 rhs_immediate: u32,
27453206 lhs_ty: Type,
27463207 lhs_and_rhs_swapped: bool,
2747 metadata: ?BinOpMetadata,
3208 maybe_inst: ?Air.Inst.Index,
27483209) !MCValue {
2749 const lhs_is_register = lhs == .register;
2750
2751 const lhs_lock: ?RegisterLock = if (lhs_is_register)
2752 self.register_manager.lockReg(lhs.register)
2753 else
2754 null;
2755 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
2756
2757 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
2758 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2759 break :inst Air.refToIndex(
2760 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
2761 ).?;
2762 } else null;
3210 var lhs_reg: Register = undefined;
3211 var dest_reg: Register = undefined;
27633212
2764 break :blk try self.prepareNewRegForMoving(track_inst, gp, lhs);
3213 const read_args = [_]ReadArg{
3214 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
27653215 };
2766 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
2767 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
2768
2769 const dest_reg = switch (mir_tag) {
2770 .cmp => .r0, // cmp has no destination reg
2771 else => if (metadata) |md| blk: {
2772 if (lhs_is_register and self.reuseOperand(
2773 md.inst,
2774 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
2775 if (lhs_and_rhs_swapped) 1 else 0,
2776 lhs,
2777 )) {
2778 break :blk lhs_reg;
2779 } else {
2780 break :blk try self.register_manager.allocReg(md.inst, gp);
2781 }
2782 } else try self.register_manager.allocReg(null, gp),
3216 const write_args = [_]WriteArg{
3217 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
27833218 };
2784
2785 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
3219 const operand_mapping: []const Liveness.OperandInt = if (lhs_and_rhs_swapped) &.{1} else &.{0};
3220 try self.allocRegs(
3221 &read_args,
3222 &write_args,
3223 if (maybe_inst) |inst| .{
3224 .corresponding_inst = inst,
3225 .operand_mapping = operand_mapping,
3226 } else null,
3227 );
27863228
27873229 const mir_data: Mir.Inst.Data = switch (mir_tag) {
27883230 .add,
27893231 .adds,
27903232 .sub,
27913233 .subs,
2792 .cmp,
27933234 .@"and",
27943235 .orr,
27953236 .eor,
27963237 => .{ .rr_op = .{
27973238 .rd = dest_reg,
27983239 .rn = lhs_reg,
2799 .op = Instruction.Operand.fromU32(rhs.immediate).?,
3240 .op = Instruction.Operand.fromU32(rhs_immediate).?,
28003241 } },
28013242 .lsl,
28023243 .asr,
......@@ -2804,7 +3245,7 @@ fn binOpImmediate(
28043245 => .{ .rr_shift = .{
28053246 .rd = dest_reg,
28063247 .rm = lhs_reg,
2807 .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs.immediate)),
3248 .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs_immediate)),
28083249 } },
28093250 else => unreachable,
28103251 };
......@@ -2817,417 +3258,502 @@ fn binOpImmediate(
28173258 return MCValue{ .register = dest_reg };
28183259}
28193260
2820const BinOpMetadata = struct {
2821 inst: Air.Inst.Index,
2822 lhs: Air.Inst.Ref,
2823 rhs: Air.Inst.Ref,
2824};
2825
2826/// For all your binary operation needs, this function will generate
2827/// the corresponding Mir instruction(s). Returns the location of the
2828/// result.
2829///
2830/// If the binary operation itself happens to be an Air instruction,
2831/// pass the corresponding index in the inst parameter. That helps
2832/// this function do stuff like reusing operands.
2833///
2834/// This function does not do any lowering to Mir itself, but instead
2835/// looks at the lhs and rhs and determines which kind of lowering
2836/// would be best suitable and then delegates the lowering to other
2837/// functions.
2838fn binOp(
3261fn addSub(
28393262 self: *Self,
28403263 tag: Air.Inst.Tag,
2841 lhs: MCValue,
2842 rhs: MCValue,
3264 lhs_bind: ReadArg.Bind,
3265 rhs_bind: ReadArg.Bind,
28433266 lhs_ty: Type,
28443267 rhs_ty: Type,
2845 metadata: ?BinOpMetadata,
3268 maybe_inst: ?Air.Inst.Index,
28463269) InnerError!MCValue {
2847 switch (tag) {
2848 .add,
2849 .sub,
2850 .cmp_eq,
2851 => {
2852 switch (lhs_ty.zigTypeTag()) {
2853 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
2854 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
2855 .Int => {
2856 const mod = self.bin_file.options.module.?;
2857 assert(lhs_ty.eql(rhs_ty, mod));
2858 const int_info = lhs_ty.intInfo(self.target.*);
2859 if (int_info.bits <= 32) {
2860 // Only say yes if the operation is
2861 // commutative, i.e. we can swap both of the
2862 // operands
2863 const lhs_immediate_ok = switch (tag) {
2864 .add => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null,
2865 .sub,
2866 .cmp_eq,
2867 => false,
2868 else => unreachable,
2869 };
2870 const rhs_immediate_ok = switch (tag) {
2871 .add,
2872 .sub,
2873 .cmp_eq,
2874 => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null,
2875 else => unreachable,
2876 };
3270 switch (lhs_ty.zigTypeTag()) {
3271 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
3272 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3273 .Int => {
3274 const mod = self.bin_file.options.module.?;
3275 assert(lhs_ty.eql(rhs_ty, mod));
3276 const int_info = lhs_ty.intInfo(self.target.*);
3277 if (int_info.bits <= 32) {
3278 const lhs_immediate = try lhs_bind.resolveToImmediate(self);
3279 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
3280
3281 // Only say yes if the operation is
3282 // commutative, i.e. we can swap both of the
3283 // operands
3284 const lhs_immediate_ok = switch (tag) {
3285 .add => if (lhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false,
3286 .sub => false,
3287 else => unreachable,
3288 };
3289 const rhs_immediate_ok = switch (tag) {
3290 .add,
3291 .sub,
3292 => if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false,
3293 else => unreachable,
3294 };
28773295
2878 const mir_tag: Mir.Inst.Tag = switch (tag) {
2879 .add => .add,
2880 .sub => .sub,
2881 .cmp_eq => .cmp,
2882 else => unreachable,
2883 };
3296 const mir_tag: Mir.Inst.Tag = switch (tag) {
3297 .add => .add,
3298 .sub => .sub,
3299 else => unreachable,
3300 };
28843301
2885 if (rhs_immediate_ok) {
2886 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
2887 } else if (lhs_immediate_ok) {
2888 // swap lhs and rhs
2889 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
2890 } else {
2891 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2892 }
2893 } else {
2894 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
2895 }
2896 },
2897 else => unreachable,
2898 }
2899 },
2900 .mul => {
2901 switch (lhs_ty.zigTypeTag()) {
2902 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
2903 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
2904 .Int => {
2905 const mod = self.bin_file.options.module.?;
2906 assert(lhs_ty.eql(rhs_ty, mod));
2907 const int_info = lhs_ty.intInfo(self.target.*);
2908 if (int_info.bits <= 32) {
2909 // TODO add optimisations for multiplication
2910 // with immediates, for example a * 2 can be
2911 // lowered to a << 1
2912 return try self.binOpRegister(.mul, lhs, rhs, lhs_ty, rhs_ty, metadata);
2913 } else {
2914 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
2915 }
2916 },
2917 else => unreachable,
3302 if (rhs_immediate_ok) {
3303 return try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst);
3304 } else if (lhs_immediate_ok) {
3305 // swap lhs and rhs
3306 return try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst);
3307 } else {
3308 return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3309 }
3310 } else {
3311 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
29183312 }
29193313 },
2920 .div_float => {
2921 switch (lhs_ty.zigTypeTag()) {
2922 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
2923 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
2924 else => unreachable,
3314 else => unreachable,
3315 }
3316}
3317
3318fn mul(
3319 self: *Self,
3320 lhs_bind: ReadArg.Bind,
3321 rhs_bind: ReadArg.Bind,
3322 lhs_ty: Type,
3323 rhs_ty: Type,
3324 maybe_inst: ?Air.Inst.Index,
3325) InnerError!MCValue {
3326 switch (lhs_ty.zigTypeTag()) {
3327 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
3328 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3329 .Int => {
3330 const mod = self.bin_file.options.module.?;
3331 assert(lhs_ty.eql(rhs_ty, mod));
3332 const int_info = lhs_ty.intInfo(self.target.*);
3333 if (int_info.bits <= 32) {
3334 // TODO add optimisations for multiplication
3335 // with immediates, for example a * 2 can be
3336 // lowered to a << 1
3337 return try self.binOpRegisterNew(.mul, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3338 } else {
3339 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
29253340 }
29263341 },
2927 .div_trunc, .div_floor => {
2928 switch (lhs_ty.zigTypeTag()) {
2929 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
2930 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
2931 .Int => {
2932 const mod = self.bin_file.options.module.?;
2933 assert(lhs_ty.eql(rhs_ty, mod));
2934 const int_info = lhs_ty.intInfo(self.target.*);
2935 if (int_info.bits <= 32) {
2936 switch (int_info.signedness) {
2937 .signed => {
2938 return self.fail("TODO ARM signed integer division", .{});
2939 },
2940 .unsigned => {
2941 switch (rhs) {
2942 .immediate => |imm| {
2943 if (std.math.isPowerOfTwo(imm)) {
2944 const shift = MCValue{ .immediate = std.math.log2_int(u32, imm) };
2945 return try self.binOp(.shr, lhs, shift, lhs_ty, rhs_ty, metadata);
2946 } else {
2947 return self.fail("TODO ARM integer division by constants", .{});
2948 }
2949 },
2950 else => return self.fail("TODO ARM integer division", .{}),
2951 }
2952 },
3342 else => unreachable,
3343 }
3344}
3345
3346fn divFloat(
3347 self: *Self,
3348 lhs_bind: ReadArg.Bind,
3349 rhs_bind: ReadArg.Bind,
3350 lhs_ty: Type,
3351 rhs_ty: Type,
3352 maybe_inst: ?Air.Inst.Index,
3353) InnerError!MCValue {
3354 _ = lhs_bind;
3355 _ = rhs_bind;
3356 _ = lhs_ty;
3357 _ = rhs_ty;
3358 _ = maybe_inst;
3359
3360 switch (lhs_ty.zigTypeTag()) {
3361 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
3362 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3363 else => unreachable,
3364 }
3365}
3366
3367fn div(
3368 self: *Self,
3369 tag: Air.Inst.Tag,
3370 lhs_bind: ReadArg.Bind,
3371 rhs_bind: ReadArg.Bind,
3372 lhs_ty: Type,
3373 rhs_ty: Type,
3374 maybe_inst: ?Air.Inst.Index,
3375) InnerError!MCValue {
3376 _ = tag;
3377
3378 switch (lhs_ty.zigTypeTag()) {
3379 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
3380 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3381 .Int => {
3382 const mod = self.bin_file.options.module.?;
3383 assert(lhs_ty.eql(rhs_ty, mod));
3384 const int_info = lhs_ty.intInfo(self.target.*);
3385 if (int_info.bits <= 32) {
3386 switch (int_info.signedness) {
3387 .signed => {
3388 return self.fail("TODO ARM signed integer division", .{});
3389 },
3390 .unsigned => {
3391 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
3392
3393 if (rhs_immediate) |imm| {
3394 if (std.math.isPowerOfTwo(imm)) {
3395 const shift = std.math.log2_int(u32, imm);
3396 return try self.binOpImmediateNew(.lsr, lhs_bind, shift, lhs_ty, false, maybe_inst);
3397 } else {
3398 return self.fail("TODO ARM integer division by constants", .{});
3399 }
3400 } else {
3401 return self.fail("TODO ARM integer division", .{});
29533402 }
2954 } else {
2955 return self.fail("TODO ARM integer division for integers > u32/i32", .{});
2956 }
2957 },
2958 else => unreachable,
2959 }
2960 },
2961 .div_exact => {
2962 switch (lhs_ty.zigTypeTag()) {
2963 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
2964 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
2965 .Int => return self.fail("TODO ARM div_exact", .{}),
2966 else => unreachable,
3403 },
3404 }
3405 } else {
3406 return self.fail("TODO ARM integer division for integers > u32/i32", .{});
29673407 }
29683408 },
2969 .rem => {
2970 switch (lhs_ty.zigTypeTag()) {
2971 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
2972 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
2973 .Int => {
2974 const mod = self.bin_file.options.module.?;
2975 assert(lhs_ty.eql(rhs_ty, mod));
2976 const int_info = lhs_ty.intInfo(self.target.*);
2977 if (int_info.bits <= 32) {
2978 switch (int_info.signedness) {
2979 .signed => {
2980 return self.fail("TODO ARM signed integer mod", .{});
2981 },
2982 .unsigned => {
2983 switch (rhs) {
2984 .immediate => |imm| {
2985 if (std.math.isPowerOfTwo(imm)) {
2986 const log2 = std.math.log2_int(u32, imm);
2987
2988 const lhs_is_register = lhs == .register;
2989
2990 const lhs_lock: ?RegisterLock = if (lhs_is_register)
2991 self.register_manager.lockReg(lhs.register)
2992 else
2993 null;
2994 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
2995
2996 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
2997 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2998 break :inst Air.refToIndex(md.lhs).?;
2999 } else null;
3000
3001 break :blk try self.prepareNewRegForMoving(track_inst, gp, lhs);
3002 };
3003 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
3004 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
3005
3006 const dest_reg = if (metadata) |md| blk: {
3007 if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) {
3008 break :blk lhs_reg;
3009 } else {
3010 break :blk try self.register_manager.allocReg(md.inst, gp);
3011 }
3012 } else try self.register_manager.allocReg(null, gp);
3013
3014 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
3015
3016 try self.truncRegister(lhs_reg, dest_reg, int_info.signedness, log2);
3017 return MCValue{ .register = dest_reg };
3018 } else {
3019 return self.fail("TODO ARM integer mod by constants", .{});
3020 }
3021 },
3022 else => return self.fail("TODO ARM integer mod", .{}),
3023 }
3024 },
3409 else => unreachable,
3410 }
3411}
3412
3413fn divExact(
3414 self: *Self,
3415 lhs_bind: ReadArg.Bind,
3416 rhs_bind: ReadArg.Bind,
3417 lhs_ty: Type,
3418 rhs_ty: Type,
3419 maybe_inst: ?Air.Inst.Index,
3420) InnerError!MCValue {
3421 _ = lhs_bind;
3422 _ = rhs_bind;
3423 _ = lhs_ty;
3424 _ = rhs_ty;
3425 _ = maybe_inst;
3426
3427 switch (lhs_ty.zigTypeTag()) {
3428 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
3429 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3430 .Int => return self.fail("TODO ARM div_exact", .{}),
3431 else => unreachable,
3432 }
3433}
3434
3435fn rem(
3436 self: *Self,
3437 lhs_bind: ReadArg.Bind,
3438 rhs_bind: ReadArg.Bind,
3439 lhs_ty: Type,
3440 rhs_ty: Type,
3441 maybe_inst: ?Air.Inst.Index,
3442) InnerError!MCValue {
3443 switch (lhs_ty.zigTypeTag()) {
3444 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
3445 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3446 .Int => {
3447 const mod = self.bin_file.options.module.?;
3448 assert(lhs_ty.eql(rhs_ty, mod));
3449 const int_info = lhs_ty.intInfo(self.target.*);
3450 if (int_info.bits <= 32) {
3451 switch (int_info.signedness) {
3452 .signed => {
3453 return self.fail("TODO ARM signed integer mod", .{});
3454 },
3455 .unsigned => {
3456 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
3457
3458 if (rhs_immediate) |imm| {
3459 if (std.math.isPowerOfTwo(imm)) {
3460 const log2 = std.math.log2_int(u32, imm);
3461
3462 var lhs_reg: Register = undefined;
3463 var dest_reg: Register = undefined;
3464
3465 const read_args = [_]ReadArg{
3466 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
3467 };
3468 const write_args = [_]WriteArg{
3469 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
3470 };
3471 try self.allocRegs(
3472 &read_args,
3473 &write_args,
3474 if (maybe_inst) |inst| .{
3475 .corresponding_inst = inst,
3476 .operand_mapping = &.{0},
3477 } else null,
3478 );
3479
3480 try self.truncRegister(lhs_reg, dest_reg, int_info.signedness, log2);
3481
3482 return MCValue{ .register = dest_reg };
3483 } else {
3484 return self.fail("TODO ARM integer mod by constants", .{});
3485 }
3486 } else {
3487 return self.fail("TODO ARM integer mod", .{});
30253488 }
3026 } else {
3027 return self.fail("TODO ARM integer division for integers > u32/i32", .{});
3028 }
3029 },
3030 else => unreachable,
3489 },
3490 }
3491 } else {
3492 return self.fail("TODO ARM integer division for integers > u32/i32", .{});
30313493 }
30323494 },
3033 .mod => {
3034 switch (lhs_ty.zigTypeTag()) {
3035 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
3036 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3037 .Int => return self.fail("TODO ARM mod", .{}),
3038 else => unreachable,
3495 else => unreachable,
3496 }
3497}
3498
3499fn modulo(
3500 self: *Self,
3501 lhs_bind: ReadArg.Bind,
3502 rhs_bind: ReadArg.Bind,
3503 lhs_ty: Type,
3504 rhs_ty: Type,
3505 maybe_inst: ?Air.Inst.Index,
3506) InnerError!MCValue {
3507 _ = lhs_bind;
3508 _ = rhs_bind;
3509 _ = lhs_ty;
3510 _ = rhs_ty;
3511 _ = maybe_inst;
3512
3513 switch (lhs_ty.zigTypeTag()) {
3514 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
3515 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3516 .Int => return self.fail("TODO ARM mod", .{}),
3517 else => unreachable,
3518 }
3519}
3520
3521fn wrappingArithmetic(
3522 self: *Self,
3523 tag: Air.Inst.Tag,
3524 lhs_bind: ReadArg.Bind,
3525 rhs_bind: ReadArg.Bind,
3526 lhs_ty: Type,
3527 rhs_ty: Type,
3528 maybe_inst: ?Air.Inst.Index,
3529) InnerError!MCValue {
3530 const base_tag: Air.Inst.Tag = switch (tag) {
3531 .addwrap => .add,
3532 .subwrap => .sub,
3533 .mulwrap => .mul,
3534 else => unreachable,
3535 };
3536
3537 // Generate an add/sub/mul
3538 const result = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3539
3540 // Truncate if necessary
3541 switch (lhs_ty.zigTypeTag()) {
3542 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3543 .Int => {
3544 const int_info = lhs_ty.intInfo(self.target.*);
3545 if (int_info.bits <= 32) {
3546 const result_reg = result.register;
3547
3548 if (int_info.bits < 32) {
3549 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
3550 return result;
3551 } else return result;
3552 } else {
3553 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
30393554 }
30403555 },
3041 .addwrap,
3042 .subwrap,
3043 .mulwrap,
3044 => {
3045 const base_tag: Air.Inst.Tag = switch (tag) {
3046 .addwrap => .add,
3047 .subwrap => .sub,
3048 .mulwrap => .mul,
3049 else => unreachable,
3050 };
3556 else => unreachable,
3557 }
3558}
3559
3560fn bitwise(
3561 self: *Self,
3562 tag: Air.Inst.Tag,
3563 lhs_bind: ReadArg.Bind,
3564 rhs_bind: ReadArg.Bind,
3565 lhs_ty: Type,
3566 rhs_ty: Type,
3567 maybe_inst: ?Air.Inst.Index,
3568) InnerError!MCValue {
3569 switch (lhs_ty.zigTypeTag()) {
3570 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3571 .Int => {
3572 const mod = self.bin_file.options.module.?;
3573 assert(lhs_ty.eql(rhs_ty, mod));
3574 const int_info = lhs_ty.intInfo(self.target.*);
3575 if (int_info.bits <= 32) {
3576 const lhs_immediate = try lhs_bind.resolveToImmediate(self);
3577 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
3578
3579 const lhs_immediate_ok = if (lhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false;
3580 const rhs_immediate_ok = if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false;
3581
3582 const mir_tag: Mir.Inst.Tag = switch (tag) {
3583 .bit_and => .@"and",
3584 .bit_or => .orr,
3585 .xor => .eor,
3586 else => unreachable,
3587 };
30513588
3052 // Generate an add/sub/mul
3053 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3054
3055 // Truncate if necessary
3056 switch (lhs_ty.zigTypeTag()) {
3057 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3058 .Int => {
3059 const int_info = lhs_ty.intInfo(self.target.*);
3060 if (int_info.bits <= 32) {
3061 const result_reg = result.register;
3062
3063 if (int_info.bits < 32) {
3064 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
3065 return result;
3066 } else return result;
3067 } else {
3068 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3069 }
3070 },
3071 else => unreachable,
3589 if (rhs_immediate_ok) {
3590 return try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst);
3591 } else if (lhs_immediate_ok) {
3592 // swap lhs and rhs
3593 return try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst);
3594 } else {
3595 return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3596 }
3597 } else {
3598 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
30723599 }
30733600 },
3074 .bit_and,
3075 .bit_or,
3076 .xor,
3077 => {
3078 switch (lhs_ty.zigTypeTag()) {
3079 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3080 .Int => {
3081 const mod = self.bin_file.options.module.?;
3082 assert(lhs_ty.eql(rhs_ty, mod));
3083 const int_info = lhs_ty.intInfo(self.target.*);
3084 if (int_info.bits <= 32) {
3085 const lhs_immediate_ok = lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null;
3086 const rhs_immediate_ok = rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null;
3087
3088 const mir_tag: Mir.Inst.Tag = switch (tag) {
3089 .bit_and => .@"and",
3090 .bit_or => .orr,
3091 .xor => .eor,
3092 else => unreachable,
3093 };
3601 else => unreachable,
3602 }
3603}
30943604
3095 if (rhs_immediate_ok) {
3096 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
3097 } else if (lhs_immediate_ok) {
3098 // swap lhs and rhs
3099 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
3100 } else {
3101 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3102 }
3103 } else {
3104 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3105 }
3106 },
3107 else => unreachable,
3108 }
3109 },
3110 .shl_exact,
3111 .shr_exact,
3112 => {
3113 switch (lhs_ty.zigTypeTag()) {
3114 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3115 .Int => {
3116 const int_info = lhs_ty.intInfo(self.target.*);
3117 if (int_info.bits <= 32) {
3118 const rhs_immediate_ok = rhs == .immediate;
3119
3120 const mir_tag: Mir.Inst.Tag = switch (tag) {
3121 .shl_exact => .lsl,
3122 .shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) {
3123 .signed => Mir.Inst.Tag.asr,
3124 .unsigned => Mir.Inst.Tag.lsr,
3125 },
3126 else => unreachable,
3127 };
3605fn shiftExact(
3606 self: *Self,
3607 tag: Air.Inst.Tag,
3608 lhs_bind: ReadArg.Bind,
3609 rhs_bind: ReadArg.Bind,
3610 lhs_ty: Type,
3611 rhs_ty: Type,
3612 maybe_inst: ?Air.Inst.Index,
3613) InnerError!MCValue {
3614 switch (lhs_ty.zigTypeTag()) {
3615 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3616 .Int => {
3617 const int_info = lhs_ty.intInfo(self.target.*);
3618 if (int_info.bits <= 32) {
3619 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
31283620
3129 if (rhs_immediate_ok) {
3130 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
3131 } else {
3132 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3133 }
3134 } else {
3135 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3136 }
3137 },
3138 else => unreachable,
3621 const mir_tag: Mir.Inst.Tag = switch (tag) {
3622 .shl_exact => .lsl,
3623 .shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) {
3624 .signed => Mir.Inst.Tag.asr,
3625 .unsigned => Mir.Inst.Tag.lsr,
3626 },
3627 else => unreachable,
3628 };
3629
3630 if (rhs_immediate) |imm| {
3631 return try self.binOpImmediateNew(mir_tag, lhs_bind, imm, lhs_ty, false, maybe_inst);
3632 } else {
3633 return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3634 }
3635 } else {
3636 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
31393637 }
31403638 },
3141 .shl,
3142 .shr,
3143 => {
3144 const base_tag: Air.Inst.Tag = switch (tag) {
3145 .shl => .shl_exact,
3146 .shr => .shr_exact,
3147 else => unreachable,
3148 };
3639 else => unreachable,
3640 }
3641}
3642
3643fn shiftNormal(
3644 self: *Self,
3645 tag: Air.Inst.Tag,
3646 lhs_bind: ReadArg.Bind,
3647 rhs_bind: ReadArg.Bind,
3648 lhs_ty: Type,
3649 rhs_ty: Type,
3650 maybe_inst: ?Air.Inst.Index,
3651) InnerError!MCValue {
3652 const base_tag: Air.Inst.Tag = switch (tag) {
3653 .shl => .shl_exact,
3654 .shr => .shr_exact,
3655 else => unreachable,
3656 };
31493657
3150 // Generate a shl_exact/shr_exact
3151 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3658 // Generate a shl_exact/shr_exact
3659 const result = try self.shiftExact(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
31523660
3153 // Truncate if necessary
3154 switch (tag) {
3155 .shr => return result,
3156 .shl => switch (lhs_ty.zigTypeTag()) {
3157 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3158 .Int => {
3159 const int_info = lhs_ty.intInfo(self.target.*);
3160 if (int_info.bits <= 32) {
3161 const result_reg = result.register;
3661 // Truncate if necessary
3662 switch (tag) {
3663 .shr => return result,
3664 .shl => switch (lhs_ty.zigTypeTag()) {
3665 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3666 .Int => {
3667 const int_info = lhs_ty.intInfo(self.target.*);
3668 if (int_info.bits <= 32) {
3669 const result_reg = result.register;
31623670
3163 if (int_info.bits < 32) {
3164 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
3165 return result;
3166 } else return result;
3167 } else {
3168 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3169 }
3170 },
3171 else => unreachable,
3172 },
3173 else => unreachable,
3174 }
3671 if (int_info.bits < 32) {
3672 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
3673 return result;
3674 } else return result;
3675 } else {
3676 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3677 }
3678 },
3679 else => unreachable,
31753680 },
3176 .bool_and,
3177 .bool_or,
3178 => {
3179 switch (lhs_ty.zigTypeTag()) {
3180 .Bool => {
3181 const lhs_immediate_ok = lhs == .immediate;
3182 const rhs_immediate_ok = rhs == .immediate;
3681 else => unreachable,
3682 }
3683}
31833684
3184 const mir_tag: Mir.Inst.Tag = switch (tag) {
3185 .bool_and => .@"and",
3186 .bool_or => .orr,
3187 else => unreachable,
3188 };
3685fn booleanOp(
3686 self: *Self,
3687 tag: Air.Inst.Tag,
3688 lhs_bind: ReadArg.Bind,
3689 rhs_bind: ReadArg.Bind,
3690 lhs_ty: Type,
3691 rhs_ty: Type,
3692 maybe_inst: ?Air.Inst.Index,
3693) InnerError!MCValue {
3694 switch (lhs_ty.zigTypeTag()) {
3695 .Bool => {
3696 const lhs_immediate = try lhs_bind.resolveToImmediate(self);
3697 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
31893698
3190 if (rhs_immediate_ok) {
3191 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
3192 } else if (lhs_immediate_ok) {
3193 // swap lhs and rhs
3194 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
3195 } else {
3196 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3197 }
3198 },
3699 const mir_tag: Mir.Inst.Tag = switch (tag) {
3700 .bool_and => .@"and",
3701 .bool_or => .orr,
31993702 else => unreachable,
3703 };
3704
3705 if (rhs_immediate) |imm| {
3706 return try self.binOpImmediateNew(mir_tag, lhs_bind, imm, lhs_ty, false, maybe_inst);
3707 } else if (lhs_immediate) |imm| {
3708 // swap lhs and rhs
3709 return try self.binOpImmediateNew(mir_tag, rhs_bind, imm, rhs_ty, true, maybe_inst);
3710 } else {
3711 return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
32003712 }
32013713 },
3202 .ptr_add,
3203 .ptr_sub,
3204 => {
3205 switch (lhs_ty.zigTypeTag()) {
3206 .Pointer => {
3207 const ptr_ty = lhs_ty;
3208 const elem_ty = switch (ptr_ty.ptrSize()) {
3209 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
3210 else => ptr_ty.childType(),
3211 };
3212 const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
3714 else => unreachable,
3715 }
3716}
32133717
3214 if (elem_size == 1) {
3215 const base_tag: Mir.Inst.Tag = switch (tag) {
3216 .ptr_add => .add,
3217 .ptr_sub => .sub,
3218 else => unreachable,
3219 };
3718fn ptrArithmetic(
3719 self: *Self,
3720 tag: Air.Inst.Tag,
3721 lhs_bind: ReadArg.Bind,
3722 rhs_bind: ReadArg.Bind,
3723 lhs_ty: Type,
3724 rhs_ty: Type,
3725 maybe_inst: ?Air.Inst.Index,
3726) InnerError!MCValue {
3727 switch (lhs_ty.zigTypeTag()) {
3728 .Pointer => {
3729 const mod = self.bin_file.options.module.?;
3730 assert(rhs_ty.eql(Type.usize, mod));
32203731
3221 return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3222 } else {
3223 // convert the offset into a byte offset by
3224 // multiplying it with elem_size
3225 const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null);
3226 const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null);
3227 return addr;
3228 }
3229 },
3732 const ptr_ty = lhs_ty;
3733 const elem_ty = switch (ptr_ty.ptrSize()) {
3734 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
3735 else => ptr_ty.childType(),
3736 };
3737 const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
3738
3739 const base_tag: Air.Inst.Tag = switch (tag) {
3740 .ptr_add => .add,
3741 .ptr_sub => .sub,
32303742 else => unreachable,
3743 };
3744
3745 if (elem_size == 1) {
3746 return try self.addSub(base_tag, lhs_bind, rhs_bind, Type.usize, Type.usize, maybe_inst);
3747 } else {
3748 // convert the offset into a byte offset by
3749 // multiplying it with elem_size
3750 const imm_bind = ReadArg.Bind{ .mcv = .{ .immediate = elem_size } };
3751
3752 const offset = try self.mul(rhs_bind, imm_bind, Type.usize, Type.usize, null);
3753 const offset_bind = ReadArg.Bind{ .mcv = offset };
3754
3755 const addr = try self.addSub(base_tag, lhs_bind, offset_bind, Type.usize, Type.usize, null);
3756 return addr;
32313757 }
32323758 },
32333759 else => unreachable,
......@@ -3312,9 +3838,8 @@ fn genInlineMemcpy(
33123838 // mov count, #0
33133839 _ = try self.addInst(.{
33143840 .tag = .mov,
3315 .data = .{ .rr_op = .{
3841 .data = .{ .r_op_mov = .{
33163842 .rd = count,
3317 .rn = .r0,
33183843 .op = Instruction.Operand.imm(0, 0),
33193844 } },
33203845 });
......@@ -3323,8 +3848,7 @@ fn genInlineMemcpy(
33233848 // cmp count, len
33243849 _ = try self.addInst(.{
33253850 .tag = .cmp,
3326 .data = .{ .rr_op = .{
3327 .rd = .r0,
3851 .data = .{ .r_op_cmp = .{
33283852 .rn = count,
33293853 .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none),
33303854 } },
......@@ -3418,9 +3942,8 @@ fn genInlineMemsetCode(
34183942 // mov count, #0
34193943 _ = try self.addInst(.{
34203944 .tag = .mov,
3421 .data = .{ .rr_op = .{
3945 .data = .{ .r_op_mov = .{
34223946 .rd = count,
3423 .rn = .r0,
34243947 .op = Instruction.Operand.imm(0, 0),
34253948 } },
34263949 });
......@@ -3429,8 +3952,7 @@ fn genInlineMemsetCode(
34293952 // cmp count, len
34303953 _ = try self.addInst(.{
34313954 .tag = .cmp,
3432 .data = .{ .rr_op = .{
3433 .rd = .r0,
3955 .data = .{ .r_op_cmp = .{
34343956 .rn = count,
34353957 .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none),
34363958 } },
......@@ -3568,7 +4090,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
35684090 .register => |reg| blk: {
35694091 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
35704092 const abi_align = ty.abiAlignment(self.target.*);
3571 const stack_offset = try self.allocMem(inst, abi_size, abi_align);
4093 const stack_offset = try self.allocMem(abi_size, abi_align, inst);
35724094 try self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
35734095
35744096 break :blk MCValue{ .stack_offset = stack_offset };
......@@ -3655,7 +4177,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
36554177 const ret_ty = fn_ty.fnReturnType();
36564178 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
36574179 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
3658 const stack_offset = try self.allocMem(inst, ret_abi_size, ret_abi_align);
4180 const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst);
36594181
36604182 var ptr_ty_payload: Type.Payload.ElemType = .{
36614183 .base = .{ .tag = .single_mut_pointer },
......@@ -3843,14 +4365,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
38434365 const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
38444366 const abi_align = ret_ty.abiAlignment(self.target.*);
38454367
3846 // This is essentially allocMem without the
3847 // instruction tracking
3848 if (abi_align > self.stack_align)
3849 self.stack_align = abi_align;
3850 // TODO find a free slot instead of always appending
3851 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
3852 self.next_stack_offset = offset;
3853 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
4368 const offset = try self.allocMem(abi_size, abi_align, null);
38544369
38554370 const tmp_mcv = MCValue{ .stack_offset = offset };
38564371 try self.load(tmp_mcv, ptr, ptr_ty);
......@@ -3871,32 +4386,16 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
38714386 const lhs_ty = self.air.typeOf(bin_op.lhs);
38724387
38734388 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
3874 const operands: BinOpOperands = .{ .inst = .{
3875 .inst = inst,
3876 .lhs = bin_op.lhs,
3877 .rhs = bin_op.rhs,
3878 } };
3879 break :blk try self.cmp(operands, lhs_ty, op);
4389 break :blk try self.cmp(.{ .inst = bin_op.lhs }, .{ .inst = bin_op.rhs }, lhs_ty, op);
38804390 };
38814391
38824392 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
38834393}
38844394
3885const BinOpOperands = union(enum) {
3886 inst: struct {
3887 inst: Air.Inst.Index,
3888 lhs: Air.Inst.Ref,
3889 rhs: Air.Inst.Ref,
3890 },
3891 mcv: struct {
3892 lhs: MCValue,
3893 rhs: MCValue,
3894 },
3895};
3896
38974395fn cmp(
38984396 self: *Self,
3899 operands: BinOpOperands,
4397 lhs: ReadArg.Bind,
4398 rhs: ReadArg.Bind,
39004399 lhs_ty: Type,
39014400 op: math.CompareOperator,
39024401) !MCValue {
......@@ -3926,22 +4425,47 @@ fn cmp(
39264425 if (int_info.bits <= 32) {
39274426 try self.spillCompareFlagsIfOccupied();
39284427
3929 switch (operands) {
3930 .inst => |inst_op| {
3931 const metadata: BinOpMetadata = .{
3932 .inst = inst_op.inst,
3933 .lhs = inst_op.lhs,
3934 .rhs = inst_op.rhs,
3935 };
3936 const lhs = try self.resolveInst(inst_op.lhs);
3937 const rhs = try self.resolveInst(inst_op.rhs);
4428 var lhs_reg: Register = undefined;
4429 var rhs_reg: Register = undefined;
39384430
3939 self.cpsr_flags_inst = inst_op.inst;
3940 _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, metadata);
3941 },
3942 .mcv => |mcv_op| {
3943 _ = try self.binOp(.cmp_eq, mcv_op.lhs, mcv_op.rhs, int_ty, int_ty, null);
3944 },
4431 const rhs_immediate = try rhs.resolveToImmediate(self);
4432 const rhs_immediate_ok = if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false;
4433
4434 if (rhs_immediate_ok) {
4435 const read_args = [_]ReadArg{
4436 .{ .ty = int_ty, .bind = lhs, .class = gp, .reg = &lhs_reg },
4437 };
4438 try self.allocRegs(
4439 &read_args,
4440 &.{},
4441 null, // we won't be able to reuse a register as there are no write_regs
4442 );
4443
4444 _ = try self.addInst(.{
4445 .tag = .cmp,
4446 .data = .{ .r_op_cmp = .{
4447 .rn = lhs_reg,
4448 .op = Instruction.Operand.fromU32(rhs_immediate.?).?,
4449 } },
4450 });
4451 } else {
4452 const read_args = [_]ReadArg{
4453 .{ .ty = int_ty, .bind = lhs, .class = gp, .reg = &lhs_reg },
4454 .{ .ty = int_ty, .bind = rhs, .class = gp, .reg = &rhs_reg },
4455 };
4456 try self.allocRegs(
4457 &read_args,
4458 &.{},
4459 null, // we won't be able to reuse a register as there are no write_regs
4460 );
4461
4462 _ = try self.addInst(.{
4463 .tag = .cmp,
4464 .data = .{ .r_op_cmp = .{
4465 .rn = lhs_reg,
4466 .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
4467 } },
4468 });
39454469 }
39464470
39474471 return switch (int_info.signedness) {
......@@ -4020,9 +4544,7 @@ fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {
40204544 // bne ...
40214545 _ = try self.addInst(.{
40224546 .tag = .cmp,
4023 .cond = .al,
4024 .data = .{ .rr_op = .{
4025 .rd = .r0,
4547 .data = .{ .r_op_cmp = .{
40264548 .rn = reg,
40274549 .op = Instruction.Operand.imm(1, 0),
40284550 } },
......@@ -4132,7 +4654,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
41324654 if (else_value == .dead)
41334655 continue;
41344656 // The instruction is only overridden in the else branch.
4135 var i: usize = self.branch_stack.items.len - 2;
4657 var i: usize = self.branch_stack.items.len - 1;
41364658 while (true) {
41374659 i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead?
41384660 if (self.branch_stack.items[i].inst_table.get(else_key)) |mcv| {
......@@ -4159,7 +4681,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
41594681 if (then_value == .dead)
41604682 continue;
41614683 const parent_mcv = blk: {
4162 var i: usize = self.branch_stack.items.len - 2;
4684 var i: usize = self.branch_stack.items.len - 1;
41634685 while (true) {
41644686 i -= 1;
41654687 if (self.branch_stack.items[i].inst_table.get(then_key)) |mcv| {
......@@ -4185,75 +4707,39 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
41854707 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
41864708}
41874709
4188fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
4189 if (ty.isPtrLikeOptional()) {
4190 assert(ty.abiSize(self.target.*) == 4);
4191
4192 const reg_mcv: MCValue = switch (operand) {
4193 .register => operand,
4194 else => .{ .register = try self.copyToTmpRegister(ty, operand) },
4195 };
4196
4197 _ = try self.addInst(.{
4198 .tag = .cmp,
4199 .data = .{ .rr_op = .{
4200 .rd = undefined,
4201 .rn = reg_mcv.register,
4202 .op = Instruction.Operand.fromU32(0).?,
4203 } },
4204 });
4710fn isNull(
4711 self: *Self,
4712 operand_bind: ReadArg.Bind,
4713 operand_ty: Type,
4714) !MCValue {
4715 if (operand_ty.isPtrLikeOptional()) {
4716 assert(operand_ty.abiSize(self.target.*) == 4);
42054717
4206 return MCValue{ .cpsr_flags = .eq };
4718 const imm_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 0 } };
4719 return self.cmp(operand_bind, imm_bind, Type.usize, .eq);
42074720 } else {
42084721 return self.fail("TODO implement non-pointer optionals", .{});
42094722 }
42104723}
42114724
4212fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
4213 const is_null_result = try self.isNull(ty, operand);
4725fn isNonNull(
4726 self: *Self,
4727 operand_bind: ReadArg.Bind,
4728 operand_ty: Type,
4729) !MCValue {
4730 const is_null_result = try self.isNull(operand_bind, operand_ty);
42144731 assert(is_null_result.cpsr_flags == .eq);
42154732
42164733 return MCValue{ .cpsr_flags = .ne };
42174734}
42184735
4219fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
4220 const error_type = ty.errorUnionSet();
4221 const error_int_type = Type.initTag(.u16);
4222
4223 if (error_type.errorSetIsEmpty()) {
4224 return MCValue{ .immediate = 0 }; // always false
4225 }
4226
4227 const error_mcv = try self.errUnionErr(operand, ty);
4228 _ = try self.binOp(.cmp_eq, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type, null);
4229 return MCValue{ .cpsr_flags = .hi };
4230}
4231
4232fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
4233 const is_err_result = try self.isErr(ty, operand);
4234 switch (is_err_result) {
4235 .cpsr_flags => |cond| {
4236 assert(cond == .hi);
4237 return MCValue{ .cpsr_flags = cond.negate() };
4238 },
4239 .immediate => |imm| {
4240 assert(imm == 0);
4241 return MCValue{ .immediate = 1 };
4242 },
4243 else => unreachable,
4244 }
4245}
4246
42474736fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
42484737 const un_op = self.air.instructions.items(.data)[inst].un_op;
4249
4250 try self.spillCompareFlagsIfOccupied();
4251 self.cpsr_flags_inst = inst;
4252
42534738 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4254 const operand = try self.resolveInst(un_op);
4255 const ty = self.air.typeOf(un_op);
4256 break :result try self.isNull(ty, operand);
4739 const operand_bind: ReadArg.Bind = .{ .inst = un_op };
4740 const operand_ty = self.air.typeOf(un_op);
4741
4742 break :result try self.isNull(operand_bind, operand_ty);
42574743 };
42584744 return self.finishAir(inst, result, .{ un_op, .none, .none });
42594745}
......@@ -4263,16 +4749,12 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
42634749 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
42644750 const operand_ptr = try self.resolveInst(un_op);
42654751 const ptr_ty = self.air.typeOf(un_op);
4266 const operand: MCValue = blk: {
4267 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4268 // The MCValue that holds the pointer can be re-used as the value.
4269 break :blk operand_ptr;
4270 } else {
4271 break :blk try self.allocRegOrMem(inst, true);
4272 }
4273 };
4752 const elem_ty = ptr_ty.elemType();
4753
4754 const operand = try self.allocRegOrMem(elem_ty, true, null);
42744755 try self.load(operand, operand_ptr, ptr_ty);
4275 break :result try self.isNull(ptr_ty.elemType(), operand);
4756
4757 break :result try self.isNull(.{ .mcv = operand }, elem_ty);
42764758 };
42774759 return self.finishAir(inst, result, .{ un_op, .none, .none });
42784760}
......@@ -4280,9 +4762,10 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
42804762fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
42814763 const un_op = self.air.instructions.items(.data)[inst].un_op;
42824764 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4283 const operand = try self.resolveInst(un_op);
4284 const ty = self.air.typeOf(un_op);
4285 break :result try self.isNonNull(ty, operand);
4765 const operand_bind: ReadArg.Bind = .{ .inst = un_op };
4766 const operand_ty = self.air.typeOf(un_op);
4767
4768 break :result try self.isNonNull(operand_bind, operand_ty);
42864769 };
42874770 return self.finishAir(inst, result, .{ un_op, .none, .none });
42884771}
......@@ -4292,26 +4775,57 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
42924775 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
42934776 const operand_ptr = try self.resolveInst(un_op);
42944777 const ptr_ty = self.air.typeOf(un_op);
4295 const operand: MCValue = blk: {
4296 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4297 // The MCValue that holds the pointer can be re-used as the value.
4298 break :blk operand_ptr;
4299 } else {
4300 break :blk try self.allocRegOrMem(inst, true);
4301 }
4302 };
4778 const elem_ty = ptr_ty.elemType();
4779
4780 const operand = try self.allocRegOrMem(elem_ty, true, null);
43034781 try self.load(operand, operand_ptr, ptr_ty);
4304 break :result try self.isNonNull(ptr_ty.elemType(), operand);
4782
4783 break :result try self.isNonNull(.{ .mcv = operand }, elem_ty);
43054784 };
43064785 return self.finishAir(inst, result, .{ un_op, .none, .none });
43074786}
43084787
4788fn isErr(
4789 self: *Self,
4790 error_union_bind: ReadArg.Bind,
4791 error_union_ty: Type,
4792) !MCValue {
4793 const error_type = error_union_ty.errorUnionSet();
4794
4795 if (error_type.errorSetIsEmpty()) {
4796 return MCValue{ .immediate = 0 }; // always false
4797 }
4798
4799 const error_mcv = try self.errUnionErr(error_union_bind, error_union_ty, null);
4800 return try self.cmp(.{ .mcv = error_mcv }, .{ .mcv = .{ .immediate = 0 } }, error_type, .gt);
4801}
4802
4803fn isNonErr(
4804 self: *Self,
4805 error_union_bind: ReadArg.Bind,
4806 error_union_ty: Type,
4807) !MCValue {
4808 const is_err_result = try self.isErr(error_union_bind, error_union_ty);
4809 switch (is_err_result) {
4810 .cpsr_flags => |cond| {
4811 assert(cond == .hi);
4812 return MCValue{ .cpsr_flags = cond.negate() };
4813 },
4814 .immediate => |imm| {
4815 assert(imm == 0);
4816 return MCValue{ .immediate = 1 };
4817 },
4818 else => unreachable,
4819 }
4820}
4821
43094822fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
43104823 const un_op = self.air.instructions.items(.data)[inst].un_op;
43114824 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4312 const operand = try self.resolveInst(un_op);
4313 const ty = self.air.typeOf(un_op);
4314 break :result try self.isErr(ty, operand);
4825 const error_union_bind: ReadArg.Bind = .{ .inst = un_op };
4826 const error_union_ty = self.air.typeOf(un_op);
4827
4828 break :result try self.isErr(error_union_bind, error_union_ty);
43154829 };
43164830 return self.finishAir(inst, result, .{ un_op, .none, .none });
43174831}
......@@ -4321,16 +4835,12 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
43214835 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
43224836 const operand_ptr = try self.resolveInst(un_op);
43234837 const ptr_ty = self.air.typeOf(un_op);
4324 const operand: MCValue = blk: {
4325 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4326 // The MCValue that holds the pointer can be re-used as the value.
4327 break :blk operand_ptr;
4328 } else {
4329 break :blk try self.allocRegOrMem(inst, true);
4330 }
4331 };
4838 const elem_ty = ptr_ty.elemType();
4839
4840 const operand = try self.allocRegOrMem(elem_ty, true, null);
43324841 try self.load(operand, operand_ptr, ptr_ty);
4333 break :result try self.isErr(ptr_ty.elemType(), operand);
4842
4843 break :result try self.isErr(.{ .mcv = operand }, elem_ty);
43344844 };
43354845 return self.finishAir(inst, result, .{ un_op, .none, .none });
43364846}
......@@ -4338,9 +4848,10 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
43384848fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
43394849 const un_op = self.air.instructions.items(.data)[inst].un_op;
43404850 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4341 const operand = try self.resolveInst(un_op);
4342 const ty = self.air.typeOf(un_op);
4343 break :result try self.isNonErr(ty, operand);
4851 const error_union_bind: ReadArg.Bind = .{ .inst = un_op };
4852 const error_union_ty = self.air.typeOf(un_op);
4853
4854 break :result try self.isNonErr(error_union_bind, error_union_ty);
43444855 };
43454856 return self.finishAir(inst, result, .{ un_op, .none, .none });
43464857}
......@@ -4350,16 +4861,12 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
43504861 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
43514862 const operand_ptr = try self.resolveInst(un_op);
43524863 const ptr_ty = self.air.typeOf(un_op);
4353 const operand: MCValue = blk: {
4354 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4355 // The MCValue that holds the pointer can be re-used as the value.
4356 break :blk operand_ptr;
4357 } else {
4358 break :blk try self.allocRegOrMem(inst, true);
4359 }
4360 };
4864 const elem_ty = ptr_ty.elemType();
4865
4866 const operand = try self.allocRegOrMem(elem_ty, true, null);
43614867 try self.load(operand, operand_ptr, ptr_ty);
4362 break :result try self.isNonErr(ptr_ty.elemType(), operand);
4868
4869 break :result try self.isNonErr(.{ .mcv = operand }, elem_ty);
43634870 };
43644871 return self.finishAir(inst, result, .{ un_op, .none, .none });
43654872}
......@@ -4456,14 +4963,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
44564963 defer self.gpa.free(branch_into_prong_relocs);
44574964
44584965 for (items) |item, idx| {
4459 const condition = try self.resolveInst(pl_op.operand);
4460 const item_mcv = try self.resolveInst(item);
4461
4462 const operands: BinOpOperands = .{ .mcv = .{
4463 .lhs = condition,
4464 .rhs = item_mcv,
4465 } };
4466 const cmp_result = try self.cmp(operands, condition_ty, .neq);
4966 const cmp_result = try self.cmp(.{ .inst = pl_op.operand }, .{ .inst = item }, condition_ty, .neq);
44674967 branch_into_prong_relocs[idx] = try self.condBr(cmp_result);
44684968 }
44694969
......@@ -4579,7 +5079,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
45795079 .none, .dead, .unreach => unreachable,
45805080 .register, .stack_offset, .memory => operand_mcv,
45815081 .immediate, .stack_argument_offset, .cpsr_flags => blk: {
4582 const new_mcv = try self.allocRegOrMem(block, true);
5082 const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block);
45835083 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
45845084 break :blk new_mcv;
45855085 },
......@@ -4832,9 +5332,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
48325332 .register_v_flag => .vs,
48335333 else => unreachable,
48345334 },
4835 .data = .{ .rr_op = .{
5335 .data = .{ .r_op_mov = .{
48365336 .rd = cond_reg,
4837 .rn = .r0,
48385337 .op = Instruction.Operand.fromU32(1).?,
48395338 } },
48405339 });
......@@ -4935,9 +5434,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
49355434 // mov reg, 0
49365435 _ = try self.addInst(.{
49375436 .tag = .mov,
4938 .data = .{ .rr_op = .{
5437 .data = .{ .r_op_mov = .{
49395438 .rd = reg,
4940 .rn = .r0,
49415439 .op = zero,
49425440 } },
49435441 });
......@@ -4946,9 +5444,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
49465444 _ = try self.addInst(.{
49475445 .tag = .mov,
49485446 .cond = condition,
4949 .data = .{ .rr_op = .{
5447 .data = .{ .r_op_mov = .{
49505448 .rd = reg,
4951 .rn = .r0,
49525449 .op = one,
49535450 } },
49545451 });
......@@ -4957,18 +5454,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
49575454 if (Instruction.Operand.fromU32(x)) |op| {
49585455 _ = try self.addInst(.{
49595456 .tag = .mov,
4960 .data = .{ .rr_op = .{
5457 .data = .{ .r_op_mov = .{
49615458 .rd = reg,
4962 .rn = .r0,
49635459 .op = op,
49645460 } },
49655461 });
49665462 } else if (Instruction.Operand.fromU32(~x)) |op| {
49675463 _ = try self.addInst(.{
49685464 .tag = .mvn,
4969 .data = .{ .rr_op = .{
5465 .data = .{ .r_op_mov = .{
49705466 .rd = reg,
4971 .rn = .r0,
49725467 .op = op,
49735468 } },
49745469 });
......@@ -4984,9 +5479,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
49845479 } else {
49855480 _ = try self.addInst(.{
49865481 .tag = .mov,
4987 .data = .{ .rr_op = .{
5482 .data = .{ .r_op_mov = .{
49885483 .rd = reg,
4989 .rn = .r0,
49905484 .op = Instruction.Operand.imm(@truncate(u8, x), 0),
49915485 } },
49925486 });
......@@ -5028,9 +5522,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
50285522 // orr reg, reg, #0xdd, 8
50295523 _ = try self.addInst(.{
50305524 .tag = .mov,
5031 .data = .{ .rr_op = .{
5525 .data = .{ .r_op_mov = .{
50325526 .rd = reg,
5033 .rn = .r0,
50345527 .op = Instruction.Operand.imm(@truncate(u8, x), 0),
50355528 } },
50365529 });
......@@ -5069,9 +5562,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
50695562 // mov reg, src_reg
50705563 _ = try self.addInst(.{
50715564 .tag = .mov,
5072 .data = .{ .rr_op = .{
5565 .data = .{ .r_op_mov = .{
50735566 .rd = reg,
5074 .rn = .r0,
50755567 .op = Instruction.Operand.reg(src_reg, Instruction.Operand.Shift.none),
50765568 } },
50775569 });
......@@ -5307,7 +5799,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
53075799 const array_ty = ptr_ty.childType();
53085800 const array_len = @intCast(u32, array_ty.arrayLen());
53095801
5310 const stack_offset = try self.allocMem(inst, 8, 8);
5802 const stack_offset = try self.allocMem(8, 8, inst);
53115803 try self.genSetStack(ptr_ty, stack_offset, ptr);
53125804 try self.genSetStack(Type.initTag(.usize), stack_offset - 4, .{ .immediate = array_len });
53135805 break :result MCValue{ .stack_offset = stack_offset };
......@@ -5461,15 +5953,24 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void {
54615953 const extra = self.air.extraData(Air.Try, pl_op.payload);
54625954 const body = self.air.extra[extra.end..][0..extra.data.body_len];
54635955 const result: MCValue = result: {
5956 const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand };
54645957 const error_union_ty = self.air.typeOf(pl_op.operand);
5465 const error_union = try self.resolveInst(pl_op.operand);
5466 const is_err_result = try self.isErr(error_union_ty, error_union);
5958 const error_union_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
5959 const error_union_align = error_union_ty.abiAlignment(self.target.*);
5960
5961 // The error union will die in the body. However, we need the
5962 // error union after the body in order to extract the payload
5963 // of the error union, so we create a copy of it
5964 const error_union_copy = try self.allocMem(error_union_size, error_union_align, null);
5965 try self.genSetStack(error_union_ty, error_union_copy, try error_union_bind.resolveToMcv(self));
5966
5967 const is_err_result = try self.isErr(error_union_bind, error_union_ty);
54675968 const reloc = try self.condBr(is_err_result);
54685969
54695970 try self.genBody(body);
5470
54715971 try self.performReloc(reloc);
5472 break :result try self.errUnionPayload(error_union, error_union_ty);
5972
5973 break :result try self.errUnionPayload(.{ .mcv = .{ .stack_offset = error_union_copy } }, error_union_ty, null);
54735974 };
54745975 return self.finishAir(inst, result, .{ pl_op.operand, .none, .none });
54755976}
src/arch/arm/Emit.zig+88-12
......@@ -11,6 +11,7 @@ const link = @import("../../link.zig");
1111const Module = @import("../../Module.zig");
1212const Type = @import("../../type.zig").Type;
1313const ErrorMsg = Module.ErrorMsg;
14const Target = std.Target;
1415const assert = std.debug.assert;
1516const DW = std.dwarf;
1617const leb128 = std.leb;
......@@ -93,6 +94,8 @@ pub fn emitMir(
9394 .sub => try emit.mirDataProcessing(inst),
9495 .subs => try emit.mirDataProcessing(inst),
9596
97 .sub_sp_scratch_r0 => try emit.mirSubStackPointer(inst),
98
9699 .asr => try emit.mirShift(inst),
97100 .lsl => try emit.mirShift(inst),
98101 .lsr => try emit.mirShift(inst),
......@@ -190,6 +193,24 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
190193 .dbg_epilogue_begin,
191194 .dbg_prologue_end,
192195 => return 0,
196
197 .sub_sp_scratch_r0 => {
198 const imm32 = emit.mir.instructions.items(.data)[inst].imm32;
199
200 if (imm32 == 0) {
201 return 0 * 4;
202 } else if (Instruction.Operand.fromU32(imm32) != null) {
203 // sub
204 return 1 * 4;
205 } else if (Target.arm.featureSetHas(emit.target.cpu.features, .has_v7)) {
206 // movw; movt; sub
207 return 3 * 4;
208 } else {
209 // mov; orr; orr; orr; sub
210 return 5 * 4;
211 }
212 },
213
193214 else => return 4,
194215 }
195216}
......@@ -385,20 +406,75 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
385406fn mirDataProcessing(emit: *Emit, inst: Mir.Inst.Index) !void {
386407 const tag = emit.mir.instructions.items(.tag)[inst];
387408 const cond = emit.mir.instructions.items(.cond)[inst];
388 const rr_op = emit.mir.instructions.items(.data)[inst].rr_op;
389409
390410 switch (tag) {
391 .add => try emit.writeInstruction(Instruction.add(cond, rr_op.rd, rr_op.rn, rr_op.op)),
392 .adds => try emit.writeInstruction(Instruction.adds(cond, rr_op.rd, rr_op.rn, rr_op.op)),
393 .@"and" => try emit.writeInstruction(Instruction.@"and"(cond, rr_op.rd, rr_op.rn, rr_op.op)),
394 .cmp => try emit.writeInstruction(Instruction.cmp(cond, rr_op.rn, rr_op.op)),
395 .eor => try emit.writeInstruction(Instruction.eor(cond, rr_op.rd, rr_op.rn, rr_op.op)),
396 .mov => try emit.writeInstruction(Instruction.mov(cond, rr_op.rd, rr_op.op)),
397 .mvn => try emit.writeInstruction(Instruction.mvn(cond, rr_op.rd, rr_op.op)),
398 .orr => try emit.writeInstruction(Instruction.orr(cond, rr_op.rd, rr_op.rn, rr_op.op)),
399 .rsb => try emit.writeInstruction(Instruction.rsb(cond, rr_op.rd, rr_op.rn, rr_op.op)),
400 .sub => try emit.writeInstruction(Instruction.sub(cond, rr_op.rd, rr_op.rn, rr_op.op)),
401 .subs => try emit.writeInstruction(Instruction.subs(cond, rr_op.rd, rr_op.rn, rr_op.op)),
411 .add,
412 .adds,
413 .@"and",
414 .eor,
415 .orr,
416 .rsb,
417 .sub,
418 .subs,
419 => {
420 const rr_op = emit.mir.instructions.items(.data)[inst].rr_op;
421 switch (tag) {
422 .add => try emit.writeInstruction(Instruction.add(cond, rr_op.rd, rr_op.rn, rr_op.op)),
423 .adds => try emit.writeInstruction(Instruction.adds(cond, rr_op.rd, rr_op.rn, rr_op.op)),
424 .@"and" => try emit.writeInstruction(Instruction.@"and"(cond, rr_op.rd, rr_op.rn, rr_op.op)),
425 .eor => try emit.writeInstruction(Instruction.eor(cond, rr_op.rd, rr_op.rn, rr_op.op)),
426 .orr => try emit.writeInstruction(Instruction.orr(cond, rr_op.rd, rr_op.rn, rr_op.op)),
427 .rsb => try emit.writeInstruction(Instruction.rsb(cond, rr_op.rd, rr_op.rn, rr_op.op)),
428 .sub => try emit.writeInstruction(Instruction.sub(cond, rr_op.rd, rr_op.rn, rr_op.op)),
429 .subs => try emit.writeInstruction(Instruction.subs(cond, rr_op.rd, rr_op.rn, rr_op.op)),
430 else => unreachable,
431 }
432 },
433 .cmp => {
434 const r_op_cmp = emit.mir.instructions.items(.data)[inst].r_op_cmp;
435 try emit.writeInstruction(Instruction.cmp(cond, r_op_cmp.rn, r_op_cmp.op));
436 },
437 .mov,
438 .mvn,
439 => {
440 const r_op_mov = emit.mir.instructions.items(.data)[inst].r_op_mov;
441 switch (tag) {
442 .mov => try emit.writeInstruction(Instruction.mov(cond, r_op_mov.rd, r_op_mov.op)),
443 .mvn => try emit.writeInstruction(Instruction.mvn(cond, r_op_mov.rd, r_op_mov.op)),
444 else => unreachable,
445 }
446 },
447 else => unreachable,
448 }
449}
450
451fn mirSubStackPointer(emit: *Emit, inst: Mir.Inst.Index) !void {
452 const tag = emit.mir.instructions.items(.tag)[inst];
453 const cond = emit.mir.instructions.items(.cond)[inst];
454 const imm32 = emit.mir.instructions.items(.data)[inst].imm32;
455
456 switch (tag) {
457 .sub_sp_scratch_r0 => {
458 if (imm32 == 0) return;
459
460 const operand = Instruction.Operand.fromU32(imm32) orelse blk: {
461 const scratch: Register = .r0;
462
463 if (Target.arm.featureSetHas(emit.target.cpu.features, .has_v7)) {
464 try emit.writeInstruction(Instruction.movw(cond, scratch, @truncate(u16, imm32)));
465 try emit.writeInstruction(Instruction.movt(cond, scratch, @truncate(u16, imm32 >> 16)));
466 } else {
467 try emit.writeInstruction(Instruction.mov(cond, scratch, Instruction.Operand.imm(@truncate(u8, imm32), 0)));
468 try emit.writeInstruction(Instruction.orr(cond, scratch, scratch, Instruction.Operand.imm(@truncate(u8, imm32 >> 8), 12)));
469 try emit.writeInstruction(Instruction.orr(cond, scratch, scratch, Instruction.Operand.imm(@truncate(u8, imm32 >> 16), 8)));
470 try emit.writeInstruction(Instruction.orr(cond, scratch, scratch, Instruction.Operand.imm(@truncate(u8, imm32 >> 24), 4)));
471 }
472
473 break :blk Instruction.Operand.reg(scratch, Instruction.Operand.Shift.none);
474 };
475
476 try emit.writeInstruction(Instruction.sub(cond, .sp, .sp, operand));
477 },
402478 else => unreachable,
403479 }
404480}
src/arch/arm/Mir.zig+23
......@@ -111,6 +111,11 @@ pub const Inst = struct {
111111 strh,
112112 /// Subtract
113113 sub,
114 /// Pseudo-instruction: Subtract 32-bit immediate from stack
115 ///
116 /// r0 can be used by Emit as a scratch register for loading
117 /// the immediate
118 sub_sp_scratch_r0,
114119 /// Subtract, update condition flags
115120 subs,
116121 /// Supervisor Call
......@@ -144,6 +149,10 @@ pub const Inst = struct {
144149 ///
145150 /// Used by e.g. svc
146151 imm24: u24,
152 /// A 32-bit immediate value.
153 ///
154 /// Used by e.g. sub_sp_scratch_r0
155 imm32: u32,
147156 /// Index into `extra`. Meaning of what can be found there is context-dependent.
148157 ///
149158 /// Used by e.g. load_memory
......@@ -166,6 +175,20 @@ pub const Inst = struct {
166175 rd: Register,
167176 imm16: u16,
168177 },
178 /// A register and an operand
179 ///
180 /// Used by mov and mvn
181 r_op_mov: struct {
182 rd: Register,
183 op: bits.Instruction.Operand,
184 },
185 /// A register and an operand
186 ///
187 /// Used by cmp
188 r_op_cmp: struct {
189 rn: Register,
190 op: bits.Instruction.Operand,
191 },
169192 /// Two registers and a shift amount
170193 ///
171194 /// Used by e.g. lsl
src/arch/x86_64/CodeGen.zig+67-141
......@@ -128,15 +128,11 @@ pub const MCValue = union(enum) {
128128 /// The value is in memory at a hard-coded address.
129129 /// If the type is a pointer, it means the pointer address is at this memory location.
130130 memory: u64,
131 /// The value is in memory referenced indirectly via a GOT entry index.
132 /// If the type is a pointer, it means the pointer is referenced indirectly via GOT.
133 /// When lowered, linker will emit a relocation of type X86_64_RELOC_GOT.
134 got_load: u32,
135 imports_load: u32,
136 /// The value is in memory referenced directly via symbol index.
137 /// If the type is a pointer, it means the pointer is referenced directly via symbol index.
138 /// When lowered, linker will emit a relocation of type X86_64_RELOC_SIGNED.
139 direct_load: u32,
131 /// The value is in memory but requires a linker relocation fixup:
132 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
133 /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
134 /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
135 linker_load: struct { @"type": enum { got, direct, import }, sym_index: u32 },
140136 /// The value is one of the stack variables.
141137 /// If the type is a pointer, it means the pointer address is in the stack at this offset.
142138 stack_offset: i32,
......@@ -150,9 +146,7 @@ pub const MCValue = union(enum) {
150146 .memory,
151147 .stack_offset,
152148 .ptr_stack_offset,
153 .direct_load,
154 .got_load,
155 .imports_load,
149 .linker_load,
156150 => true,
157151 else => false,
158152 };
......@@ -165,26 +159,6 @@ pub const MCValue = union(enum) {
165159 };
166160 }
167161
168 fn isMutable(mcv: MCValue) bool {
169 return switch (mcv) {
170 .none => unreachable,
171 .unreach => unreachable,
172 .dead => unreachable,
173
174 .immediate,
175 .memory,
176 .eflags,
177 .ptr_stack_offset,
178 .undef,
179 .register_overflow,
180 => false,
181
182 .register,
183 .stack_offset,
184 => true,
185 };
186 }
187
188162 fn isRegister(mcv: MCValue) bool {
189163 return switch (mcv) {
190164 .register => true,
......@@ -2307,11 +2281,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
23072281 .data = .{ .imm = @bitCast(u32, -off) },
23082282 });
23092283 },
2310 .memory,
2311 .got_load,
2312 .direct_load,
2313 .imports_load,
2314 => {
2284 .memory, .linker_load => {
23152285 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);
23162286 },
23172287 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
......@@ -2652,11 +2622,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
26522622 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),
26532623 }
26542624 },
2655 .memory,
2656 .got_load,
2657 .direct_load,
2658 .imports_load,
2659 => {
2625 .memory, .linker_load => {
26602626 const reg = try self.copyToTmpRegister(ptr_ty, ptr);
26612627 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
26622628 },
......@@ -2691,10 +2657,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
26912657
26922658fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue) InnerError!void {
26932659 switch (ptr) {
2694 .got_load,
2695 .direct_load,
2696 .imports_load,
2697 => |sym_index| {
2660 .linker_load => |load_struct| {
26982661 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));
26992662 const mod = self.bin_file.options.module.?;
27002663 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
......@@ -2702,11 +2665,10 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
27022665 fn_owner_decl.link.macho.sym_index
27032666 else
27042667 fn_owner_decl.link.coff.sym_index;
2705 const flags: u2 = switch (ptr) {
2706 .got_load => 0b00,
2707 .direct_load => 0b01,
2708 .imports_load => 0b10,
2709 else => unreachable,
2668 const flags: u2 = switch (load_struct.@"type") {
2669 .got => 0b00,
2670 .direct => 0b01,
2671 .import => 0b10,
27102672 };
27112673 _ = try self.addInst(.{
27122674 .tag = .lea_pic,
......@@ -2717,7 +2679,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
27172679 .data = .{
27182680 .relocation = .{
27192681 .atom_index = atom_index,
2720 .sym_index = sym_index,
2682 .sym_index = load_struct.sym_index,
27212683 },
27222684 },
27232685 });
......@@ -2801,9 +2763,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
28012763 .register => |src_reg| {
28022764 try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0);
28032765 },
2804 .got_load,
2805 .direct_load,
2806 .imports_load,
2766 .linker_load,
28072767 .memory,
28082768 .stack_offset,
28092769 => {
......@@ -2822,11 +2782,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
28222782 },
28232783 }
28242784 },
2825 .got_load,
2826 .direct_load,
2827 .imports_load,
2828 .memory,
2829 => {
2785 .linker_load, .memory => {
28302786 const value_lock: ?RegisterLock = switch (value) {
28312787 .register => |reg| self.register_manager.lockReg(reg),
28322788 else => null,
......@@ -2894,11 +2850,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
28942850 .register => {
28952851 return self.store(new_ptr, value, ptr_ty, value_ty);
28962852 },
2897 .got_load,
2898 .direct_load,
2899 .imports_load,
2900 .memory,
2901 => {
2853 .linker_load, .memory => {
29022854 if (abi_size <= 8) {
29032855 const tmp_reg = try self.register_manager.allocReg(null, gp);
29042856 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
......@@ -3606,9 +3558,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
36063558 });
36073559 },
36083560 .memory,
3609 .got_load,
3610 .direct_load,
3611 .imports_load,
3561 .linker_load,
36123562 .eflags,
36133563 => {
36143564 assert(abi_size <= 8);
......@@ -3694,10 +3644,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
36943644 => {
36953645 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});
36963646 },
3697 .got_load,
3698 .direct_load,
3699 .imports_load,
3700 => {
3647 .linker_load => {
37013648 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
37023649 },
37033650 .eflags => {
......@@ -3708,10 +3655,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
37083655 .memory => {
37093656 return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{});
37103657 },
3711 .got_load,
3712 .direct_load,
3713 .imports_load,
3714 => {
3658 .linker_load => {
37153659 return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{});
37163660 },
37173661 }
......@@ -3779,10 +3723,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
37793723 .memory => {
37803724 return self.fail("TODO implement x86 multiply source memory", .{});
37813725 },
3782 .got_load,
3783 .direct_load,
3784 .imports_load,
3785 => {
3726 .linker_load => {
37863727 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
37873728 },
37883729 .eflags => {
......@@ -3826,10 +3767,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
38263767 .memory, .stack_offset => {
38273768 return self.fail("TODO implement x86 multiply source memory", .{});
38283769 },
3829 .got_load,
3830 .direct_load,
3831 .imports_load,
3832 => {
3770 .linker_load => {
38333771 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
38343772 },
38353773 .eflags => {
......@@ -3840,10 +3778,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
38403778 .memory => {
38413779 return self.fail("TODO implement x86 multiply destination memory", .{});
38423780 },
3843 .got_load,
3844 .direct_load,
3845 .imports_load,
3846 => {
3781 .linker_load => {
38473782 return self.fail("TODO implement x86 multiply destination symbol at index in linker", .{});
38483783 },
38493784 }
......@@ -4006,9 +3941,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
40063941 .unreach => unreachable,
40073942 .dead => unreachable,
40083943 .memory => unreachable,
4009 .got_load => unreachable,
4010 .direct_load => unreachable,
4011 .imports_load => unreachable,
3944 .linker_load => unreachable,
40123945 .eflags => unreachable,
40133946 .register_overflow => unreachable,
40143947 }
......@@ -4066,7 +3999,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
40663999 const func = func_payload.data;
40674000 const fn_owner_decl = mod.declPtr(func.owner_decl);
40684001 try self.genSetReg(Type.initTag(.usize), .rax, .{
4069 .got_load = fn_owner_decl.link.coff.sym_index,
4002 .linker_load = .{
4003 .@"type" = .got,
4004 .sym_index = fn_owner_decl.link.coff.sym_index,
4005 },
40704006 });
40714007 _ = try self.addInst(.{
40724008 .tag = .call,
......@@ -4087,7 +4023,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
40874023 }
40884024 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
40894025 try self.genSetReg(Type.initTag(.usize), .rax, .{
4090 .imports_load = sym_index,
4026 .linker_load = .{
4027 .@"type" = .import,
4028 .sym_index = sym_index,
4029 },
40914030 });
40924031 _ = try self.addInst(.{
40934032 .tag = .call,
......@@ -4119,7 +4058,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
41194058 const func = func_payload.data;
41204059 const fn_owner_decl = mod.declPtr(func.owner_decl);
41214060 const sym_index = fn_owner_decl.link.macho.sym_index;
4122 try self.genSetReg(Type.initTag(.usize), .rax, .{ .got_load = sym_index });
4061 try self.genSetReg(Type.initTag(.usize), .rax, .{
4062 .linker_load = .{
4063 .@"type" = .got,
4064 .sym_index = sym_index,
4065 },
4066 });
41234067 // callq *%rax
41244068 _ = try self.addInst(.{
41254069 .tag = .call,
......@@ -4505,11 +4449,7 @@ fn genVarDbgInfo(
45054449 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
45064450 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
45074451 },
4508 .memory,
4509 .got_load,
4510 .direct_load,
4511 .imports_load,
4512 => {
4452 .memory, .linker_load => {
45134453 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
45144454 const is_ptr = switch (tag) {
45154455 .dbg_var_ptr => true,
......@@ -4540,10 +4480,11 @@ fn genVarDbgInfo(
45404480 try dbg_info.append(DW.OP.deref);
45414481 }
45424482 switch (mcv) {
4543 .got_load,
4544 .direct_load,
4545 .imports_load,
4546 => |index| try dw.addExprlocReloc(index, offset, is_ptr),
4483 .linker_load => |load_struct| try dw.addExprlocReloc(
4484 load_struct.sym_index,
4485 offset,
4486 is_ptr,
4487 ),
45474488 else => {},
45484489 }
45494490 },
......@@ -5587,11 +5528,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
55875528 else => return self.fail("TODO implement inputs on stack for {} with abi size > 8", .{mcv}),
55885529 }
55895530 },
5590 .memory,
5591 .direct_load,
5592 .got_load,
5593 .imports_load,
5594 => {
5531 .memory, .linker_load => {
55955532 if (abi_size <= 8) {
55965533 const reg = try self.copyToTmpRegister(ty, mcv);
55975534 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
......@@ -5835,11 +5772,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
58355772 },
58365773 }
58375774 },
5838 .memory,
5839 .got_load,
5840 .direct_load,
5841 .imports_load,
5842 => {
5775 .memory, .linker_load => {
58435776 if (abi_size <= 8) {
58445777 const reg = try self.copyToTmpRegister(ty, mcv);
58455778 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts);
......@@ -5959,11 +5892,7 @@ fn genInlineMemcpy(
59595892 const tmp_reg = regs[4].to8();
59605893
59615894 switch (dst_ptr) {
5962 .memory,
5963 .got_load,
5964 .direct_load,
5965 .imports_load,
5966 => {
5895 .memory, .linker_load => {
59675896 try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr);
59685897 },
59695898 .ptr_stack_offset, .stack_offset => |off| {
......@@ -5992,11 +5921,7 @@ fn genInlineMemcpy(
59925921 }
59935922
59945923 switch (src_ptr) {
5995 .memory,
5996 .got_load,
5997 .direct_load,
5998 .imports_load,
5999 => {
5924 .memory, .linker_load => {
60005925 try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_ptr);
60015926 },
60025927 .ptr_stack_offset, .stack_offset => |off| {
......@@ -6120,11 +6045,7 @@ fn genInlineMemset(
61206045 const index_reg = regs[1].to64();
61216046
61226047 switch (dst_ptr) {
6123 .memory,
6124 .got_load,
6125 .direct_load,
6126 .imports_load,
6127 => {
6048 .memory, .linker_load => {
61286049 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_ptr);
61296050 },
61306051 .ptr_stack_offset, .stack_offset => |off| {
......@@ -6356,10 +6277,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
63566277 .data = undefined,
63576278 });
63586279 },
6359 .direct_load,
6360 .got_load,
6361 .imports_load,
6362 => {
6280 .linker_load => {
63636281 switch (ty.zigTypeTag()) {
63646282 .Float => {
63656283 const base_reg = try self.register_manager.allocReg(null, gp);
......@@ -6753,11 +6671,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
67536671 // TODO Is this the only condition for pointer dereference for memcpy?
67546672 const src: MCValue = blk: {
67556673 switch (src_ptr) {
6756 .got_load,
6757 .direct_load,
6758 .imports_load,
6759 .memory,
6760 => {
6674 .linker_load, .memory => {
67616675 const reg = try self.register_manager.allocReg(null, gp);
67626676 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);
67636677 _ = try self.addInst(.{
......@@ -6997,10 +6911,16 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
69976911 return MCValue{ .memory = got_addr };
69986912 } else if (self.bin_file.cast(link.File.MachO)) |_| {
69996913 assert(decl.link.macho.sym_index != 0);
7000 return MCValue{ .got_load = decl.link.macho.sym_index };
6914 return MCValue{ .linker_load = .{
6915 .@"type" = .got,
6916 .sym_index = decl.link.macho.sym_index,
6917 } };
70016918 } else if (self.bin_file.cast(link.File.Coff)) |_| {
70026919 assert(decl.link.coff.sym_index != 0);
7003 return MCValue{ .got_load = decl.link.coff.sym_index };
6920 return MCValue{ .linker_load = .{
6921 .@"type" = .got,
6922 .sym_index = decl.link.coff.sym_index,
6923 } };
70046924 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
70056925 try p9.seeDecl(decl_index);
70066926 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
......@@ -7019,9 +6939,15 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
70196939 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
70206940 return MCValue{ .memory = vaddr };
70216941 } else if (self.bin_file.cast(link.File.MachO)) |_| {
7022 return MCValue{ .direct_load = local_sym_index };
6942 return MCValue{ .linker_load = .{
6943 .@"type" = .direct,
6944 .sym_index = local_sym_index,
6945 } };
70236946 } else if (self.bin_file.cast(link.File.Coff)) |_| {
7024 return MCValue{ .direct_load = local_sym_index };
6947 return MCValue{ .linker_load = .{
6948 .@"type" = .direct,
6949 .sym_index = local_sym_index,
6950 } };
70256951 } else if (self.bin_file.cast(link.File.Plan9)) |_| {
70266952 return self.fail("TODO lower unnamed const in Plan9", .{});
70276953 } else {
src/arch/x86_64/Emit.zig+11-8
......@@ -1021,10 +1021,14 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
10211021 .@"type" = switch (ops.flags) {
10221022 0b00 => .got,
10231023 0b01 => .direct,
1024 0b10 => .imports,
1024 0b10 => .import,
1025 else => unreachable,
1026 },
1027 .target = switch (ops.flags) {
1028 0b00, 0b01 => .{ .sym_index = relocation.sym_index, .file = null },
1029 0b10 => coff_file.getGlobalByIndex(relocation.sym_index),
10251030 else => unreachable,
10261031 },
1027 .target = .{ .sym_index = relocation.sym_index, .file = null },
10281032 .offset = @intCast(u32, end_offset - 4),
10291033 .addend = 0,
10301034 .pcrel = true,
......@@ -1142,12 +1146,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
11421146 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
11431147 // Add relocation to the decl.
11441148 const atom = macho_file.atom_by_index_table.get(relocation.atom_index).?;
1149 const target = macho_file.getGlobalByIndex(relocation.sym_index);
11451150 try atom.relocs.append(emit.bin_file.allocator, .{
11461151 .offset = offset,
1147 .target = .{
1148 .sym_index = relocation.sym_index,
1149 .file = null,
1150 },
1152 .target = target,
11511153 .addend = 0,
11521154 .subtractor = null,
11531155 .pcrel = true,
......@@ -1157,16 +1159,17 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
11571159 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
11581160 // Add relocation to the decl.
11591161 const atom = coff_file.atom_by_index_table.get(relocation.atom_index).?;
1162 const target = coff_file.getGlobalByIndex(relocation.sym_index);
11601163 try atom.addRelocation(coff_file, .{
11611164 .@"type" = .direct,
1162 .target = .{ .sym_index = relocation.sym_index, .file = null },
1165 .target = target,
11631166 .offset = offset,
11641167 .addend = 0,
11651168 .pcrel = true,
11661169 .length = 2,
11671170 });
11681171 } else {
1169 return emit.fail("TODO implement call_extern for linking backends different than MachO", .{});
1172 return emit.fail("TODO implement call_extern for linking backends different than MachO and COFF", .{});
11701173 }
11711174}
11721175
src/autodoc/render_source.zig+2-6
......@@ -137,7 +137,7 @@ pub fn genHtml(
137137 );
138138
139139 const source = try src.getSource(allocator);
140 try tokenizeAndPrintRaw(allocator, out, source.bytes);
140 try tokenizeAndPrintRaw(out, source.bytes);
141141 try out.writeAll(
142142 \\</body>
143143 \\</html>
......@@ -150,13 +150,9 @@ const end_line = "</span>\n";
150150var line_counter: usize = 1;
151151
152152pub fn tokenizeAndPrintRaw(
153 allocator: Allocator,
154153 out: anytype,
155 raw_src: [:0]const u8,
154 src: [:0]const u8,
156155) !void {
157 const src = try allocator.dupeZ(u8, raw_src);
158 defer allocator.free(src);
159
160156 line_counter = 1;
161157
162158 try out.print("<pre><code>" ++ start_line, .{line_counter});
src/glibc.zig+4-5
......@@ -719,17 +719,16 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
719719 .lt => continue,
720720 .gt => {
721721 // TODO Expose via compile error mechanism instead of log.
722 log.err("invalid target glibc version: {}", .{target_version});
722 log.warn("invalid target glibc version: {}", .{target_version});
723723 return error.InvalidTargetGLibCVersion;
724724 },
725725 }
726 } else {
726 } else blk: {
727727 const latest_index = metadata.all_versions.len - 1;
728 // TODO Expose via compile error mechanism instead of log.
729 log.err("zig does not yet provide glibc version {}, the max provided version is {}", .{
728 log.warn("zig cannot build new glibc version {}; providing instead {}", .{
730729 target_version, metadata.all_versions[latest_index],
731730 });
732 return error.InvalidTargetGLibCVersion;
731 break :blk latest_index;
733732 };
734733
735734 {
src/link/Coff.zig+61-18
......@@ -127,7 +127,7 @@ pub const Reloc = struct {
127127 @"type": enum {
128128 got,
129129 direct,
130 imports,
130 import,
131131 },
132132 target: SymbolWithLoc,
133133 offset: u32,
......@@ -141,7 +141,7 @@ pub const Reloc = struct {
141141 switch (self.@"type") {
142142 .got => return coff_file.getGotAtomForSymbol(self.target),
143143 .direct => return coff_file.getAtomForSymbol(self.target),
144 .imports => return coff_file.getImportAtomForSymbol(self.target),
144 .import => return coff_file.getImportAtomForSymbol(self.target),
145145 }
146146 }
147147};
......@@ -1423,23 +1423,22 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
14231423 const sym = self.getSymbol(current);
14241424 const sym_name = self.getSymbolName(current);
14251425
1426 const global_index = self.resolver.get(sym_name) orelse {
1427 const name = try gpa.dupe(u8, sym_name);
1428 const global_index = try self.allocateGlobal();
1429 self.globals.items[global_index] = current;
1430 try self.resolver.putNoClobber(gpa, name, global_index);
1426 const gop = try self.getOrPutGlobalPtr(sym_name);
1427 if (!gop.found_existing) {
1428 gop.value_ptr.* = current;
14311429 if (sym.section_number == .UNDEFINED) {
1432 try self.unresolved.putNoClobber(gpa, global_index, false);
1430 try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, false);
14331431 }
14341432 return;
1435 };
1433 }
14361434
14371435 log.debug("TODO finish resolveGlobalSymbols implementation", .{});
14381436
14391437 if (sym.section_number == .UNDEFINED) return;
14401438
1441 _ = self.unresolved.swapRemove(global_index);
1442 self.globals.items[global_index] = current;
1439 _ = self.unresolved.swapRemove(self.getGlobalIndex(sym_name).?);
1440
1441 gop.value_ptr.* = current;
14431442}
14441443
14451444pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {
......@@ -1544,25 +1543,26 @@ pub fn getDeclVAddr(
15441543}
15451544
15461545pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {
1547 if (self.resolver.get(name)) |global_index| {
1548 return self.globals.items[global_index].sym_index;
1546 const gop = try self.getOrPutGlobalPtr(name);
1547 const global_index = self.getGlobalIndex(name).?;
1548
1549 if (gop.found_existing) {
1550 return global_index;
15491551 }
15501552
1551 const gpa = self.base.allocator;
15521553 const sym_index = try self.allocateSymbol();
1553 const global_index = try self.allocateGlobal();
15541554 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1555 self.globals.items[global_index] = sym_loc;
1555 gop.value_ptr.* = sym_loc;
15561556
1557 const gpa = self.base.allocator;
15571558 const sym_name = try gpa.dupe(u8, name);
15581559 const sym = self.getSymbolPtr(sym_loc);
15591560 try self.setSymbolName(sym, sym_name);
15601561 sym.storage_class = .EXTERNAL;
15611562
1562 try self.resolver.putNoClobber(gpa, sym_name, global_index);
15631563 try self.unresolved.putNoClobber(gpa, global_index, true);
15641564
1565 return sym_index;
1565 return global_index;
15661566}
15671567
15681568pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !void {
......@@ -2061,6 +2061,49 @@ pub fn getSymbolName(self: *const Coff, sym_loc: SymbolWithLoc) []const u8 {
20612061 return self.strtab.get(offset).?;
20622062}
20632063
2064/// Returns pointer to the global entry for `name` if one exists.
2065pub fn getGlobalPtr(self: *Coff, name: []const u8) ?*SymbolWithLoc {
2066 const global_index = self.resolver.get(name) orelse return null;
2067 return &self.globals.items[global_index];
2068}
2069
2070/// Returns the global entry for `name` if one exists.
2071pub fn getGlobal(self: *const Coff, name: []const u8) ?SymbolWithLoc {
2072 const global_index = self.resolver.get(name) orelse return null;
2073 return self.globals.items[global_index];
2074}
2075
2076/// Returns the index of the global entry for `name` if one exists.
2077pub fn getGlobalIndex(self: *const Coff, name: []const u8) ?u32 {
2078 return self.resolver.get(name);
2079}
2080
2081/// Returns global entry at `index`.
2082pub fn getGlobalByIndex(self: *const Coff, index: u32) SymbolWithLoc {
2083 assert(index < self.globals.items.len);
2084 return self.globals.items[index];
2085}
2086
2087const GetOrPutGlobalPtrResult = struct {
2088 found_existing: bool,
2089 value_ptr: *SymbolWithLoc,
2090};
2091
2092/// Return pointer to the global entry for `name` if one exists.
2093/// Puts a new global entry for `name` if one doesn't exist, and
2094/// returns a pointer to it.
2095pub fn getOrPutGlobalPtr(self: *Coff, name: []const u8) !GetOrPutGlobalPtrResult {
2096 if (self.getGlobalPtr(name)) |ptr| {
2097 return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr };
2098 }
2099 const gpa = self.base.allocator;
2100 const global_index = try self.allocateGlobal();
2101 const global_name = try gpa.dupe(u8, name);
2102 _ = try self.resolver.put(gpa, global_name, global_index);
2103 const ptr = &self.globals.items[global_index];
2104 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };
2105}
2106
20642107/// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor.
20652108/// Returns null on failure.
20662109pub fn getAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {
src/link/Coff/Atom.zig-10
......@@ -111,13 +111,3 @@ pub fn addBaseRelocation(self: *Atom, coff_file: *Coff, offset: u32) !void {
111111 }
112112 try gop.value_ptr.append(gpa, offset);
113113}
114
115pub fn addBinding(self: *Atom, coff_file: *Coff, target: SymbolWithLoc) !void {
116 const gpa = coff_file.base.allocator;
117 log.debug(" (adding binding to target %{d} in %{d})", .{ target.sym_index, self.sym_index });
118 const gop = try coff_file.bindings.getOrPut(gpa, self);
119 if (!gop.found_existing) {
120 gop.value_ptr.* = .{};
121 }
122 try gop.value_ptr.append(gpa, target);
123}
src/link/MachO.zig+182-159
......@@ -131,17 +131,12 @@ la_symbol_ptr_section_index: ?u8 = null,
131131data_section_index: ?u8 = null,
132132
133133locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
134globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},
135// FIXME Jakub
136// TODO storing index into globals might be dangerous if we delete a global
137// while not having everything resolved. Actually, perhaps `unresolved`
138// should not be stored at the global scope? Is this possible?
139// Otherwise, audit if this can be a problem.
140// An alternative, which I still need to investigate for perf reasons is to
141// store all global names in an adapted with context strtab.
134globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
135resolver: std.StringHashMapUnmanaged(u32) = .{},
142136unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},
143137
144138locals_free_list: std.ArrayListUnmanaged(u32) = .{},
139globals_free_list: std.ArrayListUnmanaged(u32) = .{},
145140
146141dyld_stub_binder_index: ?u32 = null,
147142dyld_private_atom: ?*Atom = null,
......@@ -1917,7 +1912,7 @@ fn allocateSpecialSymbols(self: *MachO) !void {
19171912 "___dso_handle",
19181913 "__mh_execute_header",
19191914 }) |name| {
1920 const global = self.globals.get(name) orelse continue;
1915 const global = self.getGlobal(name) orelse continue;
19211916 if (global.file != null) continue;
19221917 const sym = self.getSymbolPtr(global);
19231918 const seg = self.segments.items[self.text_segment_cmd_index.?];
......@@ -2048,16 +2043,11 @@ fn writeAtomsIncremental(self: *MachO) !void {
20482043
20492044pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
20502045 const gpa = self.base.allocator;
2051 const sym_index = @intCast(u32, self.locals.items.len);
2052 try self.locals.append(gpa, .{
2053 .n_strx = 0,
2054 .n_type = macho.N_SECT,
2055 .n_sect = 0,
2056 .n_desc = 0,
2057 .n_value = 0,
2058 });
2059
2046 const sym_index = try self.allocateSymbol();
20602047 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);
2048 const sym = atom.getSymbolPtr(self);
2049 sym.n_type = macho.N_SECT;
2050
20612051 try atom.relocs.append(gpa, .{
20622052 .offset = 0,
20632053 .target = target,
......@@ -2074,7 +2064,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
20742064
20752065 const target_sym = self.getSymbol(target);
20762066 if (target_sym.undf()) {
2077 const global = self.globals.get(self.getSymbolName(target)).?;
2067 const global = self.getGlobal(self.getSymbolName(target)).?;
20782068 try atom.bindings.append(gpa, .{
20792069 .target = global,
20802070 .offset = 0,
......@@ -2093,20 +2083,15 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
20932083
20942084pub fn createTlvPtrAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
20952085 const gpa = self.base.allocator;
2096 const sym_index = @intCast(u32, self.locals.items.len);
2097 try self.locals.append(gpa, .{
2098 .n_strx = 0,
2099 .n_type = macho.N_SECT,
2100 .n_sect = 0,
2101 .n_desc = 0,
2102 .n_value = 0,
2103 });
2104
2086 const sym_index = try self.allocateSymbol();
21052087 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);
2088 const sym = atom.getSymbolPtr(self);
2089 sym.n_type = macho.N_SECT;
2090
21062091 const target_sym = self.getSymbol(target);
21072092 assert(target_sym.undf());
21082093
2109 const global = self.globals.get(self.getSymbolName(target)).?;
2094 const global = self.getGlobal(self.getSymbolName(target)).?;
21102095 try atom.bindings.append(gpa, .{
21112096 .target = global,
21122097 .offset = 0,
......@@ -2130,15 +2115,10 @@ fn createDyldPrivateAtom(self: *MachO) !void {
21302115 if (self.dyld_private_atom != null) return;
21312116
21322117 const gpa = self.base.allocator;
2133 const sym_index = @intCast(u32, self.locals.items.len);
2134 try self.locals.append(gpa, .{
2135 .n_strx = 0,
2136 .n_type = macho.N_SECT,
2137 .n_sect = 0,
2138 .n_desc = 0,
2139 .n_value = 0,
2140 });
2118 const sym_index = try self.allocateSymbol();
21412119 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);
2120 const sym = atom.getSymbolPtr(self);
2121 sym.n_type = macho.N_SECT;
21422122 self.dyld_private_atom = atom;
21432123
21442124 try self.allocateAtomCommon(atom, self.data_section_index.?);
......@@ -2163,15 +2143,11 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
21632143 .aarch64 => 2,
21642144 else => unreachable,
21652145 };
2166 const sym_index = @intCast(u32, self.locals.items.len);
2167 try self.locals.append(gpa, .{
2168 .n_strx = 0,
2169 .n_type = macho.N_SECT,
2170 .n_sect = 0,
2171 .n_desc = 0,
2172 .n_value = 0,
2173 });
2146 const sym_index = try self.allocateSymbol();
21742147 const atom = try MachO.createEmptyAtom(gpa, sym_index, size, alignment);
2148 const sym = atom.getSymbolPtr(self);
2149 sym.n_type = macho.N_SECT;
2150
21752151 const dyld_private_sym_index = self.dyld_private_atom.?.sym_index;
21762152 switch (arch) {
21772153 .x86_64 => {
......@@ -2288,15 +2264,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
22882264 .aarch64 => 2,
22892265 else => unreachable,
22902266 };
2291 const sym_index = @intCast(u32, self.locals.items.len);
2292 try self.locals.append(gpa, .{
2293 .n_strx = 0,
2294 .n_type = macho.N_SECT,
2295 .n_sect = 0,
2296 .n_desc = 0,
2297 .n_value = 0,
2298 });
2267 const sym_index = try self.allocateSymbol();
22992268 const atom = try MachO.createEmptyAtom(gpa, sym_index, stub_size, alignment);
2269 const sym = atom.getSymbolPtr(self);
2270 sym.n_type = macho.N_SECT;
2271
23002272 try atom.relocs.ensureTotalCapacity(gpa, 1);
23012273
23022274 switch (arch) {
......@@ -2352,15 +2324,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
23522324
23532325pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom {
23542326 const gpa = self.base.allocator;
2355 const sym_index = @intCast(u32, self.locals.items.len);
2356 try self.locals.append(gpa, .{
2357 .n_strx = 0,
2358 .n_type = macho.N_SECT,
2359 .n_sect = 0,
2360 .n_desc = 0,
2361 .n_value = 0,
2362 });
2327 const sym_index = try self.allocateSymbol();
23632328 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);
2329 const sym = atom.getSymbolPtr(self);
2330 sym.n_type = macho.N_SECT;
2331
23642332 try atom.relocs.append(gpa, .{
23652333 .offset = 0,
23662334 .target = .{ .sym_index = stub_sym_index, .file = null },
......@@ -2376,7 +2344,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi
23762344 });
23772345 try atom.rebases.append(gpa, 0);
23782346
2379 const global = self.globals.get(self.getSymbolName(target)).?;
2347 const global = self.getGlobal(self.getSymbolName(target)).?;
23802348 try atom.lazy_bindings.append(gpa, .{
23812349 .target = global,
23822350 .offset = 0,
......@@ -2403,15 +2371,11 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
24032371 .aarch64 => 3 * @sizeOf(u32),
24042372 else => unreachable, // unhandled architecture type
24052373 };
2406 const sym_index = @intCast(u32, self.locals.items.len);
2407 try self.locals.append(gpa, .{
2408 .n_strx = 0,
2409 .n_type = macho.N_SECT,
2410 .n_sect = 0,
2411 .n_desc = 0,
2412 .n_value = 0,
2413 });
2374 const sym_index = try self.allocateSymbol();
24142375 const atom = try MachO.createEmptyAtom(gpa, sym_index, stub_size, alignment);
2376 const sym = atom.getSymbolPtr(self);
2377 sym.n_type = macho.N_SECT;
2378
24152379 switch (arch) {
24162380 .x86_64 => {
24172381 // jmp
......@@ -2472,7 +2436,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
24722436fn createTentativeDefAtoms(self: *MachO) !void {
24732437 const gpa = self.base.allocator;
24742438
2475 for (self.globals.values()) |global| {
2439 for (self.globals.items) |global| {
24762440 const sym = self.getSymbolPtr(global);
24772441 if (!sym.tentative()) continue;
24782442
......@@ -2516,51 +2480,44 @@ fn createTentativeDefAtoms(self: *MachO) !void {
25162480
25172481fn createMhExecuteHeaderSymbol(self: *MachO) !void {
25182482 if (self.base.options.output_mode != .Exe) return;
2519 if (self.globals.get("__mh_execute_header")) |global| {
2483 if (self.getGlobal("__mh_execute_header")) |global| {
25202484 const sym = self.getSymbol(global);
25212485 if (!sym.undf() and !(sym.pext() or sym.weakDef())) return;
25222486 }
25232487
25242488 const gpa = self.base.allocator;
2525 const n_strx = try self.strtab.insert(gpa, "__mh_execute_header");
2526 const sym_index = @intCast(u32, self.locals.items.len);
2527 try self.locals.append(gpa, .{
2528 .n_strx = n_strx,
2489 const sym_index = try self.allocateSymbol();
2490 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2491 const sym = self.getSymbolPtr(sym_loc);
2492 sym.* = .{
2493 .n_strx = try self.strtab.insert(gpa, "__mh_execute_header"),
25292494 .n_type = macho.N_SECT | macho.N_EXT,
25302495 .n_sect = 0,
25312496 .n_desc = macho.REFERENCED_DYNAMICALLY,
25322497 .n_value = 0,
2533 });
2534
2535 const name = try gpa.dupe(u8, "__mh_execute_header");
2536 const gop = try self.globals.getOrPut(gpa, name);
2537 defer if (gop.found_existing) gpa.free(name);
2538 gop.value_ptr.* = .{
2539 .sym_index = sym_index,
2540 .file = null,
25412498 };
2499
2500 const gop = try self.getOrPutGlobalPtr("__mh_execute_header");
2501 gop.value_ptr.* = sym_loc;
25422502}
25432503
25442504fn createDsoHandleSymbol(self: *MachO) !void {
2545 const global = self.globals.getPtr("___dso_handle") orelse return;
2546 const sym = self.getSymbolPtr(global.*);
2547 if (!sym.undf()) return;
2505 const global = self.getGlobalPtr("___dso_handle") orelse return;
2506 if (!self.getSymbol(global.*).undf()) return;
25482507
25492508 const gpa = self.base.allocator;
2550 const n_strx = try self.strtab.insert(gpa, "___dso_handle");
2551 const sym_index = @intCast(u32, self.locals.items.len);
2552 try self.locals.append(gpa, .{
2553 .n_strx = n_strx,
2509 const sym_index = try self.allocateSymbol();
2510 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2511 const sym = self.getSymbolPtr(sym_loc);
2512 sym.* = .{
2513 .n_strx = try self.strtab.insert(gpa, "___dso_handle"),
25542514 .n_type = macho.N_SECT | macho.N_EXT,
25552515 .n_sect = 0,
25562516 .n_desc = macho.N_WEAK_DEF,
25572517 .n_value = 0,
2558 });
2559 global.* = .{
2560 .sym_index = sym_index,
2561 .file = null,
25622518 };
2563 _ = self.unresolved.swapRemove(@intCast(u32, self.globals.getIndex("___dso_handle").?));
2519 global.* = sym_loc;
2520 _ = self.unresolved.swapRemove(self.getGlobalIndex("___dso_handle").?);
25642521}
25652522
25662523fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
......@@ -2568,19 +2525,14 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
25682525 const sym = self.getSymbol(current);
25692526 const sym_name = self.getSymbolName(current);
25702527
2571 const name = try gpa.dupe(u8, sym_name);
2572 const global_index = @intCast(u32, self.globals.values().len);
2573 const gop = try self.globals.getOrPut(gpa, name);
2574 defer if (gop.found_existing) gpa.free(name);
2575
2528 const gop = try self.getOrPutGlobalPtr(sym_name);
25762529 if (!gop.found_existing) {
25772530 gop.value_ptr.* = current;
25782531 if (sym.undf() and !sym.tentative()) {
2579 try self.unresolved.putNoClobber(gpa, global_index, false);
2532 try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, false);
25802533 }
25812534 return;
25822535 }
2583
25842536 const global = gop.value_ptr.*;
25852537 const global_sym = self.getSymbol(global);
25862538
......@@ -2619,7 +2571,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
26192571 }
26202572 if (sym.undf() and !sym.tentative()) return;
26212573
2622 _ = self.unresolved.swapRemove(@intCast(u32, self.globals.getIndex(name).?));
2574 _ = self.unresolved.swapRemove(self.getGlobalIndex(sym_name).?);
26232575
26242576 gop.value_ptr.* = current;
26252577}
......@@ -2664,7 +2616,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
26642616 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id };
26652617 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
26662618 error.MultipleSymbolDefinitions => {
2667 const global = self.globals.get(sym_name).?;
2619 const global = self.getGlobal(sym_name).?;
26682620 log.err("symbol '{s}' defined multiple times", .{sym_name});
26692621 if (global.file) |file| {
26702622 log.err(" first definition in '{s}'", .{self.objects.items[file].name});
......@@ -2684,7 +2636,8 @@ fn resolveSymbolsInArchives(self: *MachO) !void {
26842636 const cpu_arch = self.base.options.target.cpu.arch;
26852637 var next_sym: usize = 0;
26862638 loop: while (next_sym < self.unresolved.count()) {
2687 const global = self.globals.values()[self.unresolved.keys()[next_sym]];
2639 const global_index = self.unresolved.keys()[next_sym];
2640 const global = self.globals.items[global_index];
26882641 const sym_name = self.getSymbolName(global);
26892642
26902643 for (self.archives.items) |archive| {
......@@ -2710,10 +2663,11 @@ fn resolveSymbolsInArchives(self: *MachO) !void {
27102663fn resolveSymbolsInDylibs(self: *MachO) !void {
27112664 if (self.dylibs.items.len == 0) return;
27122665
2666 const gpa = self.base.allocator;
27132667 var next_sym: usize = 0;
27142668 loop: while (next_sym < self.unresolved.count()) {
27152669 const global_index = self.unresolved.keys()[next_sym];
2716 const global = self.globals.values()[global_index];
2670 const global = self.globals.items[global_index];
27172671 const sym = self.getSymbolPtr(global);
27182672 const sym_name = self.getSymbolName(global);
27192673
......@@ -2722,7 +2676,7 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {
27222676
27232677 const dylib_id = @intCast(u16, id);
27242678 if (!self.referenced_dylibs.contains(dylib_id)) {
2725 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});
2679 try self.referenced_dylibs.putNoClobber(gpa, dylib_id, {});
27262680 }
27272681
27282682 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;
......@@ -2760,7 +2714,7 @@ fn resolveSymbolsAtLoading(self: *MachO) !void {
27602714 var next_sym: usize = 0;
27612715 while (next_sym < self.unresolved.count()) {
27622716 const global_index = self.unresolved.keys()[next_sym];
2763 const global = self.globals.values()[global_index];
2717 const global = self.globals.items[global_index];
27642718 const sym = self.getSymbolPtr(global);
27652719 const sym_name = self.getSymbolName(global);
27662720
......@@ -2800,26 +2754,27 @@ fn resolveDyldStubBinder(self: *MachO) !void {
28002754 if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports
28012755
28022756 const gpa = self.base.allocator;
2803 const n_strx = try self.strtab.insert(gpa, "dyld_stub_binder");
2804 const sym_index = @intCast(u32, self.locals.items.len);
2805 try self.locals.append(gpa, .{
2806 .n_strx = n_strx,
2757 const sym_index = try self.allocateSymbol();
2758 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2759 const sym = self.getSymbolPtr(sym_loc);
2760 const sym_name = "dyld_stub_binder";
2761 sym.* = .{
2762 .n_strx = try self.strtab.insert(gpa, sym_name),
28072763 .n_type = macho.N_UNDF,
28082764 .n_sect = 0,
28092765 .n_desc = 0,
28102766 .n_value = 0,
2811 });
2812 const sym_name = try gpa.dupe(u8, "dyld_stub_binder");
2813 const global = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2814 try self.globals.putNoClobber(gpa, sym_name, global);
2815 const sym = &self.locals.items[sym_index];
2767 };
2768 const gop = try self.getOrPutGlobalPtr(sym_name);
2769 gop.value_ptr.* = sym_loc;
2770 const global = gop.value_ptr.*;
28162771
28172772 for (self.dylibs.items) |dylib, id| {
28182773 if (!dylib.symbols.contains(sym_name)) continue;
28192774
28202775 const dylib_id = @intCast(u16, id);
28212776 if (!self.referenced_dylibs.contains(dylib_id)) {
2822 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});
2777 try self.referenced_dylibs.putNoClobber(gpa, dylib_id, {});
28232778 }
28242779
28252780 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;
......@@ -3050,14 +3005,20 @@ pub fn deinit(self: *MachO) void {
30503005 self.stubs_free_list.deinit(gpa);
30513006 self.stubs_table.deinit(gpa);
30523007 self.strtab.deinit(gpa);
3008
30533009 self.locals.deinit(gpa);
3010 self.globals.deinit(gpa);
30543011 self.locals_free_list.deinit(gpa);
3012 self.globals_free_list.deinit(gpa);
30553013 self.unresolved.deinit(gpa);
30563014
3057 for (self.globals.keys()) |key| {
3058 gpa.free(key);
3015 {
3016 var it = self.resolver.keyIterator();
3017 while (it.next()) |key_ptr| {
3018 gpa.free(key_ptr.*);
3019 }
3020 self.resolver.deinit(gpa);
30593021 }
3060 self.globals.deinit(gpa);
30613022
30623023 for (self.objects.items) |*object| {
30633024 object.deinit(gpa);
......@@ -3211,6 +3172,29 @@ fn allocateSymbol(self: *MachO) !u32 {
32113172 return index;
32123173}
32133174
3175fn allocateGlobal(self: *MachO) !u32 {
3176 try self.globals.ensureUnusedCapacity(self.base.allocator, 1);
3177
3178 const index = blk: {
3179 if (self.globals_free_list.popOrNull()) |index| {
3180 log.debug(" (reusing global index {d})", .{index});
3181 break :blk index;
3182 } else {
3183 log.debug(" (allocating symbol index {d})", .{self.globals.items.len});
3184 const index = @intCast(u32, self.globals.items.len);
3185 _ = self.globals.addOneAssumeCapacity();
3186 break :blk index;
3187 }
3188 };
3189
3190 self.globals.items[index] = .{
3191 .sym_index = 0,
3192 .file = null,
3193 };
3194
3195 return index;
3196}
3197
32143198pub fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {
32153199 const gpa = self.base.allocator;
32163200 try self.got_entries.ensureUnusedCapacity(gpa, 1);
......@@ -3832,7 +3816,7 @@ pub fn updateDeclExports(
38323816
38333817 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
38343818 error.MultipleSymbolDefinitions => {
3835 const global = self.globals.get(exp_name).?;
3819 const global = self.getGlobal(exp_name).?;
38363820 if (sym_loc.sym_index != global.sym_index and global.file != null) {
38373821 _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(
38383822 gpa,
......@@ -3869,11 +3853,13 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
38693853 };
38703854 self.locals_free_list.append(gpa, sym_index) catch {};
38713855
3872 if (self.globals.get(sym_name)) |global| blk: {
3873 if (global.sym_index != sym_index) break :blk;
3874 if (global.file != null) break :blk;
3875 const kv = self.globals.fetchSwapRemove(sym_name);
3876 gpa.free(kv.?.key);
3856 if (self.resolver.fetchRemove(sym_name)) |entry| {
3857 defer gpa.free(entry.key);
3858 self.globals_free_list.append(gpa, entry.value) catch {};
3859 self.globals.items[entry.value] = .{
3860 .sym_index = 0,
3861 .file = null,
3862 };
38773863 }
38783864}
38793865
......@@ -4864,32 +4850,26 @@ pub fn addAtomToSection(self: *MachO, atom: *Atom, sect_id: u8) !void {
48644850
48654851pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {
48664852 const gpa = self.base.allocator;
4853
48674854 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
4868 const global_index = @intCast(u32, self.globals.values().len);
4869 const gop = try self.globals.getOrPut(gpa, sym_name);
4870 defer if (gop.found_existing) gpa.free(sym_name);
4855 defer gpa.free(sym_name);
4856 const gop = try self.getOrPutGlobalPtr(sym_name);
4857 const global_index = self.getGlobalIndex(sym_name).?;
48714858
48724859 if (gop.found_existing) {
4873 // TODO audit this: can we ever reference anything from outside the Zig module?
4874 assert(gop.value_ptr.file == null);
4875 return gop.value_ptr.sym_index;
4860 return global_index;
48764861 }
48774862
4878 const sym_index = @intCast(u32, self.locals.items.len);
4879 try self.locals.append(gpa, .{
4880 .n_strx = try self.strtab.insert(gpa, sym_name),
4881 .n_type = macho.N_UNDF,
4882 .n_sect = 0,
4883 .n_desc = 0,
4884 .n_value = 0,
4885 });
4886 gop.value_ptr.* = .{
4887 .sym_index = sym_index,
4888 .file = null,
4889 };
4863 const sym_index = try self.allocateSymbol();
4864 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
4865 gop.value_ptr.* = sym_loc;
4866
4867 const sym = self.getSymbolPtr(sym_loc);
4868 sym.n_strx = try self.strtab.insert(gpa, sym_name);
4869
48904870 try self.unresolved.putNoClobber(gpa, global_index, true);
48914871
4892 return sym_index;
4872 return global_index;
48934873}
48944874
48954875fn getSegmentAllocBase(self: MachO, indices: []const ?u8) struct { vmaddr: u64, fileoff: u64 } {
......@@ -5055,7 +5035,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
50555035 if (self.base.options.output_mode == .Exe) {
50565036 for (&[_]SymbolWithLoc{
50575037 try self.getEntryPoint(),
5058 self.globals.get("__mh_execute_header").?,
5038 self.getGlobal("__mh_execute_header").?,
50595039 }) |global| {
50605040 const sym = self.getSymbol(global);
50615041 const sym_name = self.getSymbolName(global);
......@@ -5068,7 +5048,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
50685048 }
50695049 } else {
50705050 assert(self.base.options.output_mode == .Lib);
5071 for (self.globals.values()) |global| {
5051 for (self.globals.items) |global| {
50725052 const sym = self.getSymbol(global);
50735053
50745054 if (sym.undf()) continue;
......@@ -5271,9 +5251,9 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
52715251 // We need to sort by address first
52725252 var addresses = std.ArrayList(u64).init(gpa);
52735253 defer addresses.deinit();
5274 try addresses.ensureTotalCapacityPrecise(self.globals.count());
5254 try addresses.ensureTotalCapacityPrecise(self.globals.items.len);
52755255
5276 for (self.globals.values()) |global| {
5256 for (self.globals.items) |global| {
52775257 const sym = self.getSymbol(global);
52785258 if (sym.undf()) continue;
52795259 if (sym.n_desc == N_DESC_GCED) continue;
......@@ -5453,7 +5433,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
54535433 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip
54545434 const sym_loc = SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = null };
54555435 if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip
5456 if (self.globals.contains(self.getSymbolName(sym_loc))) continue; // global symbol is either an export or import, skip
5436 if (self.getGlobal(self.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
54575437 try locals.append(sym);
54585438 }
54595439
......@@ -5463,7 +5443,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
54635443 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip
54645444 const sym_loc = SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = @intCast(u32, object_id) };
54655445 if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip
5466 if (self.globals.contains(self.getSymbolName(sym_loc))) continue; // global symbol is either an export or import, skip
5446 if (self.getGlobal(self.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
54675447 var out_sym = sym;
54685448 out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc));
54695449 try locals.append(out_sym);
......@@ -5477,7 +5457,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
54775457 var exports = std.ArrayList(macho.nlist_64).init(gpa);
54785458 defer exports.deinit();
54795459
5480 for (self.globals.values()) |global| {
5460 for (self.globals.items) |global| {
54815461 const sym = self.getSymbol(global);
54825462 if (sym.undf()) continue; // import, skip
54835463 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip
......@@ -5491,7 +5471,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
54915471
54925472 var imports_table = std.AutoHashMap(SymbolWithLoc, u32).init(gpa);
54935473
5494 for (self.globals.values()) |global| {
5474 for (self.globals.items) |global| {
54955475 const sym = self.getSymbol(global);
54965476 if (sym.n_strx == 0) continue; // no name, skip
54975477 if (!sym.undf()) continue; // not an import, skip
......@@ -5798,6 +5778,49 @@ pub fn getSymbolName(self: *MachO, sym_with_loc: SymbolWithLoc) []const u8 {
57985778 }
57995779}
58005780
5781/// Returns pointer to the global entry for `name` if one exists.
5782pub fn getGlobalPtr(self: *MachO, name: []const u8) ?*SymbolWithLoc {
5783 const global_index = self.resolver.get(name) orelse return null;
5784 return &self.globals.items[global_index];
5785}
5786
5787/// Returns the global entry for `name` if one exists.
5788pub fn getGlobal(self: *const MachO, name: []const u8) ?SymbolWithLoc {
5789 const global_index = self.resolver.get(name) orelse return null;
5790 return self.globals.items[global_index];
5791}
5792
5793/// Returns the index of the global entry for `name` if one exists.
5794pub fn getGlobalIndex(self: *const MachO, name: []const u8) ?u32 {
5795 return self.resolver.get(name);
5796}
5797
5798/// Returns global entry at `index`.
5799pub fn getGlobalByIndex(self: *const MachO, index: u32) SymbolWithLoc {
5800 assert(index < self.globals.items.len);
5801 return self.globals.items[index];
5802}
5803
5804const GetOrPutGlobalPtrResult = struct {
5805 found_existing: bool,
5806 value_ptr: *SymbolWithLoc,
5807};
5808
5809/// Return pointer to the global entry for `name` if one exists.
5810/// Puts a new global entry for `name` if one doesn't exist, and
5811/// returns a pointer to it.
5812pub fn getOrPutGlobalPtr(self: *MachO, name: []const u8) !GetOrPutGlobalPtrResult {
5813 if (self.getGlobalPtr(name)) |ptr| {
5814 return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr };
5815 }
5816 const gpa = self.base.allocator;
5817 const global_index = try self.allocateGlobal();
5818 const global_name = try gpa.dupe(u8, name);
5819 _ = try self.resolver.put(gpa, global_name, global_index);
5820 const ptr = &self.globals.items[global_index];
5821 return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr };
5822}
5823
58015824/// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor.
58025825/// Returns null on failure.
58035826pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom {
......@@ -5834,7 +5857,7 @@ pub fn getTlvPtrAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom
58345857/// Asserts output mode is executable.
58355858pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {
58365859 const entry_name = self.base.options.entry orelse "_main";
5837 const global = self.globals.get(entry_name) orelse {
5860 const global = self.getGlobal(entry_name) orelse {
58385861 log.err("entrypoint '{s}' not found", .{entry_name});
58395862 return error.MissingMainEntrypoint;
58405863 };
......@@ -6342,9 +6365,9 @@ fn logSymtab(self: *MachO) void {
63426365 }
63436366
63446367 log.debug("globals table:", .{});
6345 for (self.globals.keys()) |name, id| {
6346 const value = self.globals.values()[id];
6347 log.debug(" {s} => %{d} in object({?d})", .{ name, value.sym_index, value.file });
6368 for (self.globals.items) |global| {
6369 const name = self.getSymbolName(global);
6370 log.debug(" {s} => %{d} in object({?d})", .{ name, global.sym_index, global.file });
63486371 }
63496372
63506373 log.debug("GOT entries:", .{});
src/link/MachO/Atom.zig+3-3
......@@ -272,7 +272,7 @@ pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info,
272272 subtractor = sym_loc;
273273 } else {
274274 const sym_name = context.macho_file.getSymbolName(sym_loc);
275 subtractor = context.macho_file.globals.get(sym_name).?;
275 subtractor = context.macho_file.getGlobal(sym_name).?;
276276 }
277277 // Verify that *_SUBTRACTOR is followed by *_UNSIGNED.
278278 if (relocs.len <= i + 1) {
......@@ -339,7 +339,7 @@ pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info,
339339 break :target sym_loc;
340340 } else {
341341 const sym_name = context.macho_file.getSymbolName(sym_loc);
342 break :target context.macho_file.globals.get(sym_name).?;
342 break :target context.macho_file.getGlobal(sym_name).?;
343343 }
344344 };
345345 const offset = @intCast(u32, rel.r_address - context.base_offset);
......@@ -579,7 +579,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
579579 // If there is no atom for target, we still need to check for special, atom-less
580580 // symbols such as `___dso_handle`.
581581 const target_name = macho_file.getSymbolName(rel.target);
582 assert(macho_file.globals.contains(target_name));
582 assert(macho_file.getGlobal(target_name) != null);
583583 const atomless_sym = macho_file.getSymbol(rel.target);
584584 log.debug(" | atomless target '{s}'", .{target_name});
585585 break :blk atomless_sym.n_value;
src/link/MachO/DebugSymbols.zig+2-2
......@@ -480,7 +480,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
480480 if (sym.n_desc == MachO.N_DESC_GCED) continue; // GCed, skip
481481 const sym_loc = MachO.SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = null };
482482 if (self.base.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip
483 if (self.base.globals.contains(self.base.getSymbolName(sym_loc))) continue; // global symbol is either an export or import, skip
483 if (self.base.getGlobal(self.base.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
484484 var out_sym = sym;
485485 out_sym.n_strx = try self.strtab.insert(gpa, self.base.getSymbolName(sym_loc));
486486 try locals.append(out_sym);
......@@ -489,7 +489,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
489489 var exports = std.ArrayList(macho.nlist_64).init(gpa);
490490 defer exports.deinit();
491491
492 for (self.base.globals.values()) |global| {
492 for (self.base.globals.items) |global| {
493493 const sym = self.base.getSymbol(global);
494494 if (sym.undf()) continue; // import, skip
495495 if (sym.n_desc == MachO.N_DESC_GCED) continue; // GCed, skip
src/link/MachO/dead_strip.zig+2-2
......@@ -62,7 +62,7 @@ fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void
6262 else => |other| {
6363 assert(other == .Lib);
6464 // Add exports as GC roots
65 for (macho_file.globals.values()) |global| {
65 for (macho_file.globals.items) |global| {
6666 const sym = macho_file.getSymbol(global);
6767 if (!sym.sect()) continue;
6868 const atom = macho_file.getAtomForSymbol(global) orelse {
......@@ -77,7 +77,7 @@ fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void
7777 }
7878
7979 // TODO just a temp until we learn how to parse unwind records
80 if (macho_file.globals.get("___gxx_personality_v0")) |global| {
80 if (macho_file.getGlobal("___gxx_personality_v0")) |global| {
8181 if (macho_file.getAtomForSymbol(global)) |atom| {
8282 _ = try roots.getOrPut(atom);
8383 log.debug("adding root", .{});
src/translate_c.zig+18-2
......@@ -5957,20 +5957,36 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
59575957 return bytes[0..i];
59585958}
59595959
5960/// non-ASCII characters (c > 127) are also treated as non-printable by fmtSliceEscapeLower.
5961/// If a C string literal or char literal in a macro is not valid UTF-8, we need to escape
5962/// non-ASCII characters so that the Zig source we output will itself be UTF-8.
5963fn escapeUnprintables(ctx: *Context, m: *MacroCtx) ![]const u8 {
5964 const zigified = try zigifyEscapeSequences(ctx, m);
5965 if (std.unicode.utf8ValidateSlice(zigified)) return zigified;
5966
5967 const formatter = std.fmt.fmtSliceEscapeLower(zigified);
5968 const encoded_size = @intCast(usize, std.fmt.count("{s}", .{formatter}));
5969 var output = try ctx.arena.alloc(u8, encoded_size);
5970 return std.fmt.bufPrint(output, "{s}", .{formatter}) catch |err| switch (err) {
5971 error.NoSpaceLeft => unreachable,
5972 else => |e| return e,
5973 };
5974}
5975
59605976fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
59615977 const tok = m.next().?;
59625978 const slice = m.slice();
59635979 switch (tok) {
59645980 .CharLiteral => {
59655981 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
5966 return Tag.char_literal.create(c.arena, try zigifyEscapeSequences(c, m));
5982 return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m));
59675983 } else {
59685984 const str = try std.fmt.allocPrint(c.arena, "0x{s}", .{std.fmt.fmtSliceHexLower(slice[1 .. slice.len - 1])});
59695985 return Tag.integer_literal.create(c.arena, str);
59705986 }
59715987 },
59725988 .StringLiteral => {
5973 return Tag.string_literal.create(c.arena, try zigifyEscapeSequences(c, m));
5989 return Tag.string_literal.create(c.arena, try escapeUnprintables(c, m));
59745990 },
59755991 .IntegerLiteral, .FloatLiteral => {
59765992 return parseCNumLit(c, m);
src/type.zig+3
......@@ -2042,6 +2042,9 @@ pub const Type = extern union {
20422042 try writer.writeAll("fn(");
20432043 for (fn_info.param_types) |param_ty, i| {
20442044 if (i != 0) try writer.writeAll(", ");
2045 if (fn_info.paramIsComptime(i)) {
2046 try writer.writeAll("comptime ");
2047 }
20452048 if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) {
20462049 try writer.writeAll("noalias ");
20472050 };
test/behavior/alignof.zig-1
......@@ -13,7 +13,6 @@ const Foo = struct {
1313test "@alignOf(T) before referencing T" {
1414 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1515 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1716 comptime try expect(@alignOf(Foo) != maxInt(usize));
1817 if (native_arch == .x86_64) {
1918 comptime try expect(@alignOf(Foo) == 4);
test/behavior/array.zig-5
......@@ -175,7 +175,6 @@ test "nested arrays of integers" {
175175
176176test "implicit comptime in array type size" {
177177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
179178
180179 var arr: [plusOne(10)]bool = undefined;
181180 try expect(arr.len == 11);
......@@ -245,7 +244,6 @@ const Sub = struct { b: u8 };
245244const Str = struct { a: []Sub };
246245test "set global var array via slice embedded in struct" {
247246 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
248 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
249247
250248 var s = Str{ .a = s_array[0..] };
251249
......@@ -298,7 +296,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 {
298296
299297test "comptime evaluating function that takes array by value" {
300298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
302299
303300 const arr = [_]u8{ 1, 2 };
304301 const x = comptime testArrayByValAtComptime(arr);
......@@ -427,7 +424,6 @@ test "anonymous literal in array" {
427424
428425test "access the null element of a null terminated array" {
429426 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
430 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
431427
432428 const S = struct {
433429 fn doTheTest() !void {
......@@ -484,7 +480,6 @@ test "sentinel element count towards the ABI size calculation" {
484480test "zero-sized array with recursive type definition" {
485481 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
486482 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
488483
489484 const U = struct {
490485 fn foo(comptime T: type, comptime n: usize) type {
test/behavior/basic.zig-4
......@@ -465,7 +465,6 @@ fn nine() u8 {
465465
466466test "struct inside function" {
467467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
468 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
469468
470469 try testStructInFn();
471470 comptime try testStructInFn();
......@@ -514,7 +513,6 @@ var global_foo: *i32 = undefined;
514513
515514test "peer result location with typed parent, runtime condition, comptime prongs" {
516515 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
517 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
518516
519517 const S = struct {
520518 fn doTheTest(arg: i32) i32 {
......@@ -643,7 +641,6 @@ test "global constant is loaded with a runtime-known index" {
643641
644642test "multiline string literal is null terminated" {
645643 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
646 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
647644
648645 const s1 =
649646 \\one
......@@ -1060,7 +1057,6 @@ comptime {
10601057
10611058test "switch inside @as gets correct type" {
10621059 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1063 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10641060
10651061 var a: u32 = 0;
10661062 var b: [2]u32 = undefined;
test/behavior/bitcast.zig-1
......@@ -138,7 +138,6 @@ test "@bitCast extern structs at runtime and comptime" {
138138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
139139 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
140140 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
141 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
142141
143142 const Full = extern struct {
144143 number: u16,
test/behavior/cast.zig-10
......@@ -523,7 +523,6 @@ fn testCastConstArrayRefToConstSlice() !void {
523523
524524test "peer type resolution: error and [N]T" {
525525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
526 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
527526
528527 try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
529528 comptime try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
......@@ -548,7 +547,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
548547test "single-item pointer of array to slice to unknown length pointer" {
549548 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
550549 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
551 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
552550
553551 try testCastPtrOfArrayToSliceAndPtr();
554552 comptime try testCastPtrOfArrayToSliceAndPtr();
......@@ -578,7 +576,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {
578576test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
579577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
580578 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
581 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
582579 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
583580
584581 const window_name = [1][*]const u8{"window name"};
......@@ -649,7 +646,6 @@ test "@floatCast cast down" {
649646test "peer type resolution: unreachable, error set, unreachable" {
650647 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
651648 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
652 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
653649
654650 const Error = error{
655651 FileDescriptorAlreadyPresentInSet,
......@@ -922,7 +918,6 @@ test "peer cast *[N:x]T to *[N]T" {
922918
923919test "peer cast [*:x]T to [*]T" {
924920 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
925 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
926921 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
927922
928923 const S = struct {
......@@ -964,7 +959,6 @@ test "peer cast [:x]T to [*:x]T" {
964959
965960test "peer type resolution implicit cast to return type" {
966961 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
968962
969963 const S = struct {
970964 fn doTheTest() !void {
......@@ -984,7 +978,6 @@ test "peer type resolution implicit cast to return type" {
984978
985979test "peer type resolution implicit cast to variable type" {
986980 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
987 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
988981 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
989982
990983 const S = struct {
......@@ -1009,7 +1002,6 @@ test "variable initialization uses result locations properly with regards to the
10091002
10101003test "cast between C pointer with different but compatible types" {
10111004 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1012 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10131005
10141006 const S = struct {
10151007 fn foo(arg: [*]c_ushort) u16 {
......@@ -1026,7 +1018,6 @@ test "cast between C pointer with different but compatible types" {
10261018
10271019test "peer type resolve string lit with sentinel-terminated mutable slice" {
10281020 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10301021 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10311022
10321023 var array: [4:0]u8 = undefined;
......@@ -1079,7 +1070,6 @@ test "comptime float casts" {
10791070test "pointer reinterpret const float to int" {
10801071 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10811072 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1082 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10831073
10841074 // The hex representation is 0x3fe3333333333303.
10851075 const float: f64 = 5.99999999999994648725e-01;
test/behavior/comptime_memory.zig-2
......@@ -87,7 +87,6 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
8787test "type pun endianness" {
8888 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
8989 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
90 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9190
9291 comptime {
9392 const StructOfBytes = extern struct { x: [4]u8 };
......@@ -398,7 +397,6 @@ test "offset field ptr by enclosing array element size" {
398397test "accessing reinterpreted memory of parent object" {
399398 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
400399 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
401 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
402400 const S = extern struct {
403401 a: f32,
404402 b: [4]u8,
test/behavior/const_slice_child.zig-1
......@@ -9,7 +9,6 @@ var argv: [*]const [*]const u8 = undefined;
99test "const slice child" {
1010 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1312
1413 const strs = [_][*]const u8{ "one", "two", "three" };
1514 argv = &strs;
test/behavior/enum.zig-6
......@@ -606,7 +606,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
606606}
607607
608608test "enum with specified tag values" {
609 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
610609 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
611610
612611 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
......@@ -614,7 +613,6 @@ test "enum with specified tag values" {
614613}
615614
616615test "non-exhaustive enum" {
617 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
618616 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
619617
620618 const S = struct {
......@@ -677,7 +675,6 @@ test "empty non-exhaustive enum" {
677675}
678676
679677test "single field non-exhaustive enum" {
680 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
681678 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
682679
683680 const S = struct {
......@@ -741,7 +738,6 @@ test "cast integer literal to enum" {
741738}
742739
743740test "enum with specified and unspecified tag values" {
744 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
745741 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
746742
747743 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
......@@ -925,7 +921,6 @@ test "enum literal casting to tagged union" {
925921const Bar = enum { A, B, C, D };
926922
927923test "enum literal casting to error union with payload enum" {
928 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
929924 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
930925
931926 var bar: error{B}!Bar = undefined;
......@@ -1132,7 +1127,6 @@ test "tag name functions are unique" {
11321127
11331128test "size of enum with only one tag which has explicit integer tag type" {
11341129 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11361130 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11371131
11381132 const E = enum(u8) { nope = 10 };
test/behavior/error.zig-4
......@@ -222,7 +222,6 @@ fn testErrorSetType() !void {
222222
223223test "explicit error set cast" {
224224 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
226225 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
227226
228227 try testExplicitErrorSetCast(Set1.A);
......@@ -282,7 +281,6 @@ test "inferred empty error set comptime catch" {
282281}
283282
284283test "error union peer type resolution" {
285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
286284 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
287285
288286 try testErrorUnionPeerTypeResolution(1);
......@@ -327,7 +325,6 @@ fn foo3(b: usize) Error!usize {
327325
328326test "error: Infer error set from literals" {
329327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
331328
332329 _ = nullLiteral("n") catch |err| handleErrors(err);
333330 _ = floatLiteral("n") catch |err| handleErrors(err);
......@@ -700,7 +697,6 @@ test "ret_ptr doesn't cause own inferred error set to be resolved" {
700697
701698test "simple else prong allowed even when all errors handled" {
702699 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
704700 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
705701
706702 const S = struct {
test/behavior/eval.zig-10
......@@ -69,7 +69,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
6969}
7070
7171test "constant expressions" {
72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7372 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7473
7574 var array: [array_size]u8 = undefined;
......@@ -138,7 +137,6 @@ test "pointer to type" {
138137test "a type constructed in a global expression" {
139138 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
140139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
141 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
142140
143141 var l: List = undefined;
144142 l.array[0] = 10;
......@@ -338,7 +336,6 @@ fn doesAlotT(comptime T: type, value: usize) T {
338336}
339337
340338test "@setEvalBranchQuota at same scope as generic function call" {
341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
342339 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343340
344341 try expect(doesAlotT(u32, 2) == 2);
......@@ -565,7 +562,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
565562}
566563
567564test "ptr to local array argument at comptime" {
568 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
569565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
570566
571567 comptime {
......@@ -806,7 +802,6 @@ test "array concatenation sets the sentinel - value" {
806802test "array concatenation sets the sentinel - pointer" {
807803 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
808804 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
809 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
810805 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
811806
812807 var a = [2]u3{ 1, 7 };
......@@ -956,7 +951,6 @@ test "const local with comptime init through array init" {
956951
957952test "closure capture type of runtime-known parameter" {
958953 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
959 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
960954
961955 const S = struct {
962956 fn b(c: anytype) !void {
......@@ -1074,7 +1068,6 @@ test "comptime break operand passing through runtime switch converted to runtime
10741068
10751069test "no dependency loop for alignment of self struct" {
10761070 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1077 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10781071
10791072 const S = struct {
10801073 fn doTheTest() !void {
......@@ -1111,7 +1104,6 @@ test "no dependency loop for alignment of self struct" {
11111104
11121105test "no dependency loop for alignment of self bare union" {
11131106 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11151107
11161108 const S = struct {
11171109 fn doTheTest() !void {
......@@ -1148,7 +1140,6 @@ test "no dependency loop for alignment of self bare union" {
11481140
11491141test "no dependency loop for alignment of self tagged union" {
11501142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11521143
11531144 const S = struct {
11541145 fn doTheTest() !void {
......@@ -1336,7 +1327,6 @@ test "lazy sizeof is resolved in division" {
13361327}
13371328
13381329test "lazy value is resolved as slice operand" {
1339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13401330 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13411331
13421332 const A = struct { a: u32 };
test/behavior/field_parent_ptr.zig-2
......@@ -2,7 +2,6 @@ const expect = @import("std").testing.expect;
22const builtin = @import("builtin");
33
44test "@fieldParentPtr non-first field" {
5 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
......@@ -11,7 +10,6 @@ test "@fieldParentPtr non-first field" {
1110}
1211
1312test "@fieldParentPtr first field" {
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1614 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1715 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
test/behavior/for.zig-4
......@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
55const mem = std.mem;
66
77test "continue in for loop" {
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109
1110 const array = [_]i32{ 1, 2, 3, 4, 5 };
......@@ -130,7 +129,6 @@ test "for with null and T peer types and inferred result location type" {
130129}
131130
132131test "2 break statements and an else" {
133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
134132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135133
136134 const S = struct {
......@@ -177,7 +175,6 @@ fn mangleString(s: []u8) void {
177175}
178176
179177test "for copies its payload" {
180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
181178 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
182179
183180 const S = struct {
......@@ -213,7 +210,6 @@ test "for on slice with allowzero ptr" {
213210
214211test "else continue outer for" {
215212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
217213
218214 var i: usize = 6;
219215 var buf: [5]u8 = undefined;
test/behavior/generics.zig-1
......@@ -91,7 +91,6 @@ fn max_f64(a: f64, b: f64) f64 {
9191
9292test "type constructed by comptime function call" {
9393 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
94 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9695
9796 var l: SimpleList(10) = undefined;
test/behavior/merge_error_sets.zig-1
......@@ -12,7 +12,6 @@ fn foo() C!void {
1212}
1313
1414test "merge error sets" {
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1615 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1716 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1817 if (foo()) {
test/behavior/pointers.zig-14
......@@ -17,8 +17,6 @@ fn testDerefPtr() !void {
1717}
1818
1919test "pointer arithmetic" {
20 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2220 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2321
2422 var ptr: [*]const u8 = "abcd";
......@@ -65,8 +63,6 @@ test "initialize const optional C pointer to null" {
6563}
6664
6765test "assigning integer to C pointer" {
68 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7066 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7167
7268 var x: i32 = 0;
......@@ -83,8 +79,6 @@ test "assigning integer to C pointer" {
8379}
8480
8581test "C pointer comparison and arithmetic" {
86 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
87
8882 const S = struct {
8983 fn doTheTest() !void {
9084 var ptr1: [*c]u32 = 0;
......@@ -150,7 +144,6 @@ test "peer type resolution with C pointer and const pointer" {
150144}
151145
152146test "implicit casting between C pointer and optional non-C pointer" {
153 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
154147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
155148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
156149
......@@ -281,8 +274,6 @@ test "array initialization types" {
281274
282275test "null terminated pointer" {
283276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
284 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
285 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
286277
287278 const S = struct {
288279 fn doTheTest() !void {
......@@ -299,8 +290,6 @@ test "null terminated pointer" {
299290
300291test "allow any sentinel" {
301292 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
302 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
304293
305294 const S = struct {
306295 fn doTheTest() !void {
......@@ -315,8 +304,6 @@ test "allow any sentinel" {
315304
316305test "pointer sentinel with enums" {
317306 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
318 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
319 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
320307
321308 const S = struct {
322309 const Number = enum {
......@@ -337,7 +324,6 @@ test "pointer sentinel with enums" {
337324test "pointer sentinel with optional element" {
338325 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
339326 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
340 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
341327
342328 const S = struct {
343329 fn doTheTest() !void {
test/behavior/ptrcast.zig-3
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44const native_endian = builtin.target.cpu.arch.endian();
55
66test "reinterpret bytes as integer with nonzero offset" {
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98
109 try testReinterpretBytesAsInteger();
......@@ -39,7 +38,6 @@ fn testReinterpretWithOffsetAndNoWellDefinedLayout() !void {
3938}
4039
4140test "reinterpret bytes inside auto-layout struct as integer with nonzero offset" {
42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4442
4543 try testReinterpretStructWrappedBytesAsInteger();
......@@ -179,7 +177,6 @@ test "lower reinterpreted comptime field ptr" {
179177}
180178
181179test "reinterpret struct field at comptime" {
182 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
183180 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
184181
185182 const numNative = comptime Bytes.init(0x12345678);
test/behavior/sizeof_and_typeof.zig-2
......@@ -18,7 +18,6 @@ test "@sizeOf on compile-time types" {
1818}
1919
2020test "@TypeOf() with multiple arguments" {
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2221 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
2322 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
2423 {
......@@ -77,7 +76,6 @@ const P = packed struct {
7776};
7877
7978test "@offsetOf" {
80 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8280
8381 // Packed structs have fixed memory layout
test/behavior/slice.zig-3
......@@ -28,7 +28,6 @@ comptime {
2828
2929test "slicing" {
3030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3231
3332 var array: [20]i32 = undefined;
3433
......@@ -269,7 +268,6 @@ fn sliceSum(comptime q: []const u8) i32 {
269268
270269test "slice type with custom alignment" {
271270 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
272 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
273271
274272 const LazilyResolvedType = struct {
275273 anything: i32,
......@@ -283,7 +281,6 @@ test "slice type with custom alignment" {
283281
284282test "obtaining a null terminated slice" {
285283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
286 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
287284
288285 // here we have a normal array
289286 var buf: [50]u8 = undefined;
test/behavior/struct.zig-8
......@@ -10,7 +10,6 @@ top_level_field: i32,
1010
1111test "top level fields" {
1212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1413
1514 var instance = @This(){
1615 .top_level_field = 1234,
......@@ -104,7 +103,6 @@ fn testMutation(foo: *StructFoo) void {
104103
105104test "struct byval assign" {
106105 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
108106
109107 var foo1: StructFoo = undefined;
110108 var foo2: StructFoo = undefined;
......@@ -240,7 +238,6 @@ test "usingnamespace within struct scope" {
240238
241239test "struct field init with catch" {
242240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
243 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
244241
245242 const S = struct {
246243 fn doTheTest() !void {
......@@ -281,7 +278,6 @@ const Val = struct {
281278test "struct point to self" {
282279 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
283280 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
284 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
285281
286282 var root: Node = undefined;
287283 root.val.x = 1;
......@@ -297,7 +293,6 @@ test "struct point to self" {
297293
298294test "void struct fields" {
299295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
300 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
301296
302297 const foo = VoidStructFieldsFoo{
303298 .a = void{},
......@@ -761,7 +756,6 @@ test "packed struct with u0 field access" {
761756}
762757
763758test "access to global struct fields" {
764 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
765759 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
766760 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
767761
......@@ -1260,7 +1254,6 @@ test "typed init through error unions and optionals" {
12601254
12611255test "initialize struct with empty literal" {
12621256 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1263 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12641257
12651258 const S = struct { x: i32 = 1234 };
12661259 var s: S = .{};
......@@ -1362,7 +1355,6 @@ test "store to comptime field" {
13621355
13631356test "struct field init value is size of the struct" {
13641357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13661358
13671359 const namespace = struct {
13681360 const S = extern struct {
test/behavior/switch.zig-2
......@@ -348,7 +348,6 @@ test "switch on const enum with var" {
348348}
349349
350350test "anon enum literal used in switch on union enum" {
351 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
352351 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
353352
354353 const Foo = union(enum) {
......@@ -490,7 +489,6 @@ test "switch prongs with error set cases make a new error set type for capture v
490489}
491490
492491test "return result loc and then switch with range implicit casted to error union" {
493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
494492 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
495493
496494 const S = struct {
test/behavior/this.zig-1
......@@ -25,7 +25,6 @@ test "this refer to module call private fn" {
2525}
2626
2727test "this refer to container" {
28 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2928 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3029
3130 var pt: Point(i32) = undefined;
test/behavior/translate_c_macros.zig+12
......@@ -5,6 +5,7 @@ const expectEqual = std.testing.expectEqual;
55const expectEqualStrings = std.testing.expectEqualStrings;
66
77const h = @cImport(@cInclude("behavior/translate_c_macros.h"));
8const latin1 = @cImport(@cInclude("behavior/translate_c_macros_not_utf8.h"));
89
910test "casting to void with a macro" {
1011 h.IGNORE_ME_1(42);
......@@ -134,3 +135,14 @@ test "string literal macro with embedded tab character" {
134135
135136 try expectEqualStrings("hello\t", h.EMBEDDED_TAB);
136137}
138
139test "string and char literals that are not UTF-8 encoded. Issue #12784" {
140 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
141 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
145
146 try expectEqual(@as(u8, '\xA9'), latin1.UNPRINTABLE_CHAR);
147 try expectEqualStrings("\xA9\xA9\xA9", latin1.UNPRINTABLE_STRING);
148}
test/behavior/translate_c_macros_not_utf8.h created+5
......@@ -0,0 +1,5 @@
1// Note: This file is encoded with ISO/IEC 8859-1 (latin1), not UTF-8.
2// Do not change the encoding
3
4#define UNPRINTABLE_STRING "���"
5#define UNPRINTABLE_CHAR '�'
test/behavior/try.zig-1
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "try on error union" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
87
98 try tryOnErrorUnionImpl();
test/behavior/typename.zig+2-2
......@@ -122,7 +122,7 @@ test "top level decl" {
122122 );
123123 // generic fn
124124 try expectEqualStrings(
125 "fn(type) type",
125 "fn(comptime type) type",
126126 @typeName(@TypeOf(TypeFromFn)),
127127 );
128128}
......@@ -244,5 +244,5 @@ test "comptime parameters not converted to anytype in function type" {
244244 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
245245
246246 const T = fn (fn (type) void, void) void;
247 try expectEqualStrings("fn(fn(type) void, void) void", @typeName(T));
247 try expectEqualStrings("fn(comptime fn(comptime type) void, void) void", @typeName(T));
248248}
test/behavior/union.zig-1
......@@ -92,7 +92,6 @@ const FooExtern = extern union {
9292};
9393
9494test "basic extern unions" {
95 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9695 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9796
9897 var foo = FooExtern{ .int = 1 };
test/behavior/usingnamespace.zig-1
......@@ -58,7 +58,6 @@ test "two files usingnamespace import each other" {
5858}
5959
6060test {
61 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6362
6463 const AA = struct {
test/behavior/while.zig-1
......@@ -175,7 +175,6 @@ test "while with optional as condition with else" {
175175
176176test "while with error union condition" {
177177 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
179178 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
180179
181180 numbers_left = 10;
test/cases/compile_errors/comptime_param_coersion.zig created+20
......@@ -0,0 +1,20 @@
1pub export fn entry() void {
2 comptime var x: fn (comptime i32, comptime i32) void = undefined;
3 x = bar;
4}
5pub export fn entry1() void {
6 comptime var x: fn (i32, i32) void = undefined;
7 x = foo;
8}
9
10fn foo(comptime _: i32, comptime _: i32) void {}
11fn bar(comptime _: i32, _: i32) void {}
12
13// error
14// backend=stage2
15// target=native
16//
17// :3:9: error: expected type 'fn(comptime i32, comptime i32) void', found 'fn(comptime i32, i32) void'
18// :3:9: note: non-comptime parameter 1 cannot cast into a comptime parameter
19// :7:9: error: expected type 'fn(i32, i32) void', found 'fn(comptime i32, comptime i32) void'
20// :7:9: note: generic function cannot cast into a non-generic function