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;...@@ -203,7 +203,7 @@ var zigAnalysis;
203 if (!("type" in resolvedExpr)) {203 if (!("type" in resolvedExpr)) {
204 return null;204 return null;
205 }205 }
206 let type = zigAnalysis.types[resolvedExpr.type];206 let type = getType(resolvedExpr.type);
207207
208 outer: for (let i = 0; i < 10000; i += 1) {208 outer: for (let i = 0; i < 10000; i += 1) {
209 switch (type.kind) {209 switch (type.kind) {
...@@ -212,7 +212,7 @@ var zigAnalysis;...@@ -212,7 +212,7 @@ var zigAnalysis;
212 let child = type.child;212 let child = type.child;
213 let resolvedChild = resolveValue(child);213 let resolvedChild = resolveValue(child);
214 if ("type" in resolvedChild) {214 if ("type" in resolvedChild) {
215 type = zigAnalysis.types[resolvedChild.type];215 type = getType(resolvedChild.type);
216 continue;216 continue;
217 } else {217 } else {
218 return null;218 return null;
...@@ -276,7 +276,7 @@ var zigAnalysis;...@@ -276,7 +276,7 @@ var zigAnalysis;
276 }276 }
277277
278 if ("declRef" in value.expr) {278 if ("declRef" in value.expr) {
279 value = zigAnalysis.decls[value.expr.declRef].value;279 value = getDecl(value.expr.declRef).value;
280 continue;280 continue;
281 }281 }
282282
...@@ -430,7 +430,7 @@ var zigAnalysis;...@@ -430,7 +430,7 @@ var zigAnalysis;
430 curNav.pkgObjs.push(pkg);430 curNav.pkgObjs.push(pkg);
431 }431 }
432432
433 let currentType = zigAnalysis.types[pkg.main];433 let currentType = getType(pkg.main);
434 curNav.declObjs = [currentType];434 curNav.declObjs = [currentType];
435 for (let i = 0; i < curNav.declNames.length; i += 1) {435 for (let i = 0; i < curNav.declNames.length; i += 1) {
436 let childDecl = findSubDecl(currentType, curNav.declNames[i]);436 let childDecl = findSubDecl(currentType, curNav.declNames[i]);
...@@ -440,7 +440,7 @@ var zigAnalysis;...@@ -440,7 +440,7 @@ var zigAnalysis;
440440
441 let childDeclValue = resolveValue(childDecl.value).expr;441 let childDeclValue = resolveValue(childDecl.value).expr;
442 if ("type" in childDeclValue) {442 if ("type" in childDeclValue) {
443 const t = zigAnalysis.types[childDeclValue.type];443 const t = getType(childDeclValue.type);
444 if (t.kind != typeKinds.Fn) {444 if (t.kind != typeKinds.Fn) {
445 childDecl = t;445 childDecl = t;
446 }446 }
...@@ -478,19 +478,21 @@ var zigAnalysis;...@@ -478,19 +478,21 @@ var zigAnalysis;
478 }478 }
479479
480 if (lastIsDecl && last.kind === "const") {480 if (lastIsDecl && last.kind === "const") {
481 let typeObj = zigAnalysis.types[resolveValue(last.value).expr.type];481 const value = resolveValue(last.value);
482 if (typeObj && typeObj.kind === typeKinds.Fn) {482 if ("type" in value.expr) {
483 return renderFn(last);483 let typeObj = getType(value.expr.type);
484 if (typeObj.kind === typeKinds.Fn) {
485 return renderFn(last);
486 }
484 }487 }
485
486 return renderValue(last);488 return renderValue(last);
487 }489 }
488 490
489 }491 }
490 492
491 function renderDocTest(decl) {493 function renderDocTest(decl) {
492 if (!("decltest" in decl)) return;494 if (!decl.decltest) return;
493 const astNode = zigAnalysis.astNodes[decl.decltest];495 const astNode = getAstNode(decl.decltest);
494 domSectDocTests.classList.remove("hidden");496 domSectDocTests.classList.remove("hidden");
495 domDocTestsCode.innerHTML = astNode.code;497 domDocTestsCode.innerHTML = astNode.code;
496 }498 }
...@@ -498,7 +500,7 @@ var zigAnalysis;...@@ -498,7 +500,7 @@ var zigAnalysis;
498 function renderUnknownDecl(decl) {500 function renderUnknownDecl(decl) {
499 domDeclNoRef.classList.remove("hidden");501 domDeclNoRef.classList.remove("hidden");
500502
501 let docs = zigAnalysis.astNodes[decl.src].docs;503 let docs = getAstNode(decl.src).docs;
502 if (docs != null) {504 if (docs != null) {
503 domTldDocs.innerHTML = markdown(docs);505 domTldDocs.innerHTML = markdown(docs);
504 } else {506 } else {
...@@ -509,18 +511,18 @@ var zigAnalysis;...@@ -509,18 +511,18 @@ var zigAnalysis;
509 }511 }
510512
511 function typeIsErrSet(typeIndex) {513 function typeIsErrSet(typeIndex) {
512 let typeObj = zigAnalysis.types[typeIndex];514 let typeObj = getType(typeIndex);
513 return typeObj.kind === typeKinds.ErrorSet;515 return typeObj.kind === typeKinds.ErrorSet;
514 }516 }
515517
516 function typeIsStructWithNoFields(typeIndex) {518 function typeIsStructWithNoFields(typeIndex) {
517 let typeObj = zigAnalysis.types[typeIndex];519 let typeObj = getType(typeIndex);
518 if (typeObj.kind !== typeKinds.Struct) return false;520 if (typeObj.kind !== typeKinds.Struct) return false;
519 return typeObj.fields.length == 0;521 return typeObj.fields.length == 0;
520 }522 }
521523
522 function typeIsGenericFn(typeIndex) {524 function typeIsGenericFn(typeIndex) {
523 let typeObj = zigAnalysis.types[typeIndex];525 let typeObj = getType(typeIndex);
524 if (typeObj.kind !== typeKinds.Fn) {526 if (typeObj.kind !== typeKinds.Fn) {
525 return false;527 return false;
526 }528 }
...@@ -532,12 +534,12 @@ var zigAnalysis;...@@ -532,12 +534,12 @@ var zigAnalysis;
532 let last = fnDecl.value.expr.refPath.length - 1;534 let last = fnDecl.value.expr.refPath.length - 1;
533 let lastExpr = fnDecl.value.expr.refPath[last];535 let lastExpr = fnDecl.value.expr.refPath[last];
534 console.assert("declRef" in lastExpr);536 console.assert("declRef" in lastExpr);
535 fnDecl = zigAnalysis.decls[lastExpr.declRef];537 fnDecl = getDecl(lastExpr.declRef);
536 }538 }
537539
538 let value = resolveValue(fnDecl.value);540 let value = resolveValue(fnDecl.value);
539 console.assert("type" in value.expr);541 console.assert("type" in value.expr);
540 let typeObj = zigAnalysis.types[value.expr.type];542 let typeObj = getType(value.expr.type);
541543
542 domFnProtoCode.innerHTML = exprName(value.expr, {544 domFnProtoCode.innerHTML = exprName(value.expr, {
543 wantHtml: true,545 wantHtml: true,
...@@ -546,7 +548,7 @@ var zigAnalysis;...@@ -546,7 +548,7 @@ var zigAnalysis;
546 });548 });
547549
548 let docsSource = null;550 let docsSource = null;
549 let srcNode = zigAnalysis.astNodes[fnDecl.src];551 let srcNode = getAstNode(fnDecl.src);
550 if (srcNode.docs != null) {552 if (srcNode.docs != null) {
551 docsSource = srcNode.docs;553 docsSource = srcNode.docs;
552 }554 }
...@@ -557,14 +559,14 @@ var zigAnalysis;...@@ -557,14 +559,14 @@ var zigAnalysis;
557 if ("type" in retExpr) {559 if ("type" in retExpr) {
558 let retIndex = retExpr.type;560 let retIndex = retExpr.type;
559 let errSetTypeIndex = null;561 let errSetTypeIndex = null;
560 let retType = zigAnalysis.types[retIndex];562 let retType = getType(retIndex);
561 if (retType.kind === typeKinds.ErrorSet) {563 if (retType.kind === typeKinds.ErrorSet) {
562 errSetTypeIndex = retIndex;564 errSetTypeIndex = retIndex;
563 } else if (retType.kind === typeKinds.ErrorUnion) {565 } else if (retType.kind === typeKinds.ErrorUnion) {
564 errSetTypeIndex = retType.err.type;566 errSetTypeIndex = retType.err.type;
565 }567 }
566 if (errSetTypeIndex != null) {568 if (errSetTypeIndex != null) {
567 let errSetType = zigAnalysis.types[errSetTypeIndex];569 let errSetType = getType(errSetTypeIndex);
568 renderErrorSet(errSetType);570 renderErrorSet(errSetType);
569 }571 }
570 }572 }
...@@ -578,7 +580,7 @@ var zigAnalysis;...@@ -578,7 +580,7 @@ var zigAnalysis;
578 let call = zigAnalysis.calls[resolvedGenericRet.expr.call];580 let call = zigAnalysis.calls[resolvedGenericRet.expr.call];
579 let resolvedFunc = resolveValue({ expr: call.func });581 let resolvedFunc = resolveValue({ expr: call.func });
580 if (!("type" in resolvedFunc.expr)) return;582 if (!("type" in resolvedFunc.expr)) return;
581 let callee = zigAnalysis.types[resolvedFunc.expr.type];583 let callee = getType(resolvedFunc.expr.type);
582 if (!callee.generic_ret) return;584 if (!callee.generic_ret) return;
583 resolvedGenericRet = resolveValue({ expr: callee.generic_ret });585 resolvedGenericRet = resolveValue({ expr: callee.generic_ret });
584 }586 }
...@@ -591,7 +593,7 @@ var zigAnalysis;...@@ -591,7 +593,7 @@ var zigAnalysis;
591 }593 }
592594
593 if (!("type" in resolvedGenericRet.expr)) return;595 if (!("type" in resolvedGenericRet.expr)) return;
594 const genericType = zigAnalysis.types[resolvedGenericRet.expr.type];596 const genericType = getType(resolvedGenericRet.expr.type);
595 if (isContainerType(genericType)) {597 if (isContainerType(genericType)) {
596 renderContainer(genericType);598 renderContainer(genericType);
597 }599 }
...@@ -621,7 +623,7 @@ var zigAnalysis;...@@ -621,7 +623,7 @@ var zigAnalysis;
621 domFnNoExamples.classList.add("hidden");623 domFnNoExamples.classList.add("hidden");
622 }624 }
623625
624 let protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];626 let protoSrcNode = getAstNode(protoSrcIndex);
625 if (627 if (
626 docsSource == null &&628 docsSource == null &&
627 protoSrcNode != null &&629 protoSrcNode != null &&
...@@ -639,13 +641,13 @@ var zigAnalysis;...@@ -639,13 +641,13 @@ var zigAnalysis;
639 function renderFnParamDocs(fnDecl, typeObj) {641 function renderFnParamDocs(fnDecl, typeObj) {
640 let docCount = 0;642 let docCount = 0;
641643
642 let fnNode = zigAnalysis.astNodes[fnDecl.src];644 let fnNode = getAstNode(fnDecl.src);
643 let fields = fnNode.fields;645 let fields = fnNode.fields;
644 let isVarArgs = fnNode.varArgs;646 let isVarArgs = fnNode.varArgs;
645647
646 for (let i = 0; i < fields.length; i += 1) {648 for (let i = 0; i < fields.length; i += 1) {
647 let field = fields[i];649 let field = fields[i];
648 let fieldNode = zigAnalysis.astNodes[field];650 let fieldNode = getAstNode(field);
649 if (fieldNode.docs != null) {651 if (fieldNode.docs != null) {
650 docCount += 1;652 docCount += 1;
651 }653 }
...@@ -659,7 +661,7 @@ var zigAnalysis;...@@ -659,7 +661,7 @@ var zigAnalysis;
659661
660 for (let i = 0; i < fields.length; i += 1) {662 for (let i = 0; i < fields.length; i += 1) {
661 let field = fields[i];663 let field = fields[i];
662 let fieldNode = zigAnalysis.astNodes[field];664 let fieldNode = getAstNode(field);
663 let docs = fieldNode.docs;665 let docs = fieldNode.docs;
664 if (fieldNode.docs == null) {666 if (fieldNode.docs == null) {
665 continue;667 continue;
...@@ -967,17 +969,17 @@ var zigAnalysis;...@@ -967,17 +969,17 @@ var zigAnalysis;
967 }969 }
968 case "switchOp": {970 case "switchOp": {
969 let condExpr = zigAnalysis.exprs[expr.switchOp.cond_index];971 let condExpr = zigAnalysis.exprs[expr.switchOp.cond_index];
970 let ast = zigAnalysis.astNodes[expr.switchOp.ast];972 let ast = getAstNode(expr.switchOp.src);
971 let file_name = expr.switchOp.file_name;973 let file_name = expr.switchOp.file_name;
972 let outer_decl_index = expr.switchOp.outer_decl;974 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);
974 let line = 0;976 let line = 0;
975 // console.log(expr.switchOp)977 // console.log(expr.switchOp)
976 // console.log(outer_decl)978 // console.log(outer_decl)
977 while (outer_decl_index !== 0 && outer_decl.line_number > 0) {979 while (outer_decl_index !== 0 && outer_decl.line_number > 0) {
978 line += outer_decl.line_number;980 line += outer_decl.line_number;
979 outer_decl_index = outer_decl.outer_decl;981 outer_decl_index = outer_decl.outer_decl;
980 outer_decl = zigAnalysis.types[outer_decl_index];982 outer_decl = getType(outer_decl_index);
981 // console.log(outer_decl)983 // console.log(outer_decl)
982 }984 }
983 line += ast.line + 1;985 line += ast.line + 1;
...@@ -1028,8 +1030,8 @@ var zigAnalysis;...@@ -1028,8 +1030,8 @@ var zigAnalysis;
1028 case "fieldRef": {1030 case "fieldRef": {
1029 const enumObj = exprName({ type: expr.fieldRef.type }, opts);1031 const enumObj = exprName({ type: expr.fieldRef.type }, opts);
1030 const field =1032 const field =
1031 zigAnalysis.astNodes[enumObj.ast].fields[expr.fieldRef.index];1033 getAstNode(enumObj.src).fields[expr.fieldRef.index];
1032 const name = zigAnalysis.astNodes[field].name;1034 const name = getAstNode(field).name;
1033 return name;1035 return name;
1034 }1036 }
1035 case "enumToInt": {1037 case "enumToInt": {
...@@ -1452,13 +1454,13 @@ var zigAnalysis;...@@ -1452,13 +1454,13 @@ var zigAnalysis;
1452 return print_lhs + " " + operator + " " + print_rhs;1454 return print_lhs + " " + operator + " " + print_rhs;
1453 }1455 }
1454 case "errorSets": {1456 case "errorSets": {
1455 const errUnionObj = zigAnalysis.types[expr.errorSets];1457 const errUnionObj = getType(expr.errorSets);
1456 let lhs = exprName(errUnionObj.lhs, opts);1458 let lhs = exprName(errUnionObj.lhs, opts);
1457 let rhs = exprName(errUnionObj.rhs, opts);1459 let rhs = exprName(errUnionObj.rhs, opts);
1458 return lhs + " || " + rhs;1460 return lhs + " || " + rhs;
1459 }1461 }
1460 case "errorUnion": {1462 case "errorUnion": {
1461 const errUnionObj = zigAnalysis.types[expr.errorUnion];1463 const errUnionObj = getType(expr.errorUnion);
1462 let lhs = exprName(errUnionObj.lhs, opts);1464 let lhs = exprName(errUnionObj.lhs, opts);
1463 let rhs = exprName(errUnionObj.rhs, opts);1465 let rhs = exprName(errUnionObj.rhs, opts);
1464 return lhs + "!" + rhs;1466 return lhs + "!" + rhs;
...@@ -1574,7 +1576,7 @@ var zigAnalysis;...@@ -1574,7 +1576,7 @@ var zigAnalysis;
1574 return exprName(exprArg, opts);1576 return exprName(exprArg, opts);
1575 }1577 }
1576 case "declRef": {1578 case "declRef": {
1577 return zigAnalysis.decls[expr.declRef].name;1579 return getDecl(expr.declRef).name;
1578 }1580 }
1579 case "refPath": {1581 case "refPath": {
1580 return expr.refPath.map((x) => exprName(x, opts)).join(".");1582 return expr.refPath.map((x) => exprName(x, opts)).join(".");
...@@ -1611,7 +1613,7 @@ var zigAnalysis;...@@ -1611,7 +1613,7 @@ var zigAnalysis;
1611 let name = "";1613 let name = "";
16121614
1613 let typeObj = expr.type;1615 let typeObj = expr.type;
1614 if (typeof typeObj === "number") typeObj = zigAnalysis.types[typeObj];1616 if (typeof typeObj === "number") typeObj = getType(typeObj);
1615 switch (typeObj.kind) {1617 switch (typeObj.kind) {
1616 default:1618 default:
1617 throw "TODO";1619 throw "TODO";
...@@ -1865,7 +1867,7 @@ var zigAnalysis;...@@ -1865,7 +1867,7 @@ var zigAnalysis;
1865 if (fnObj.params) {1867 if (fnObj.params) {
1866 let fields = null;1868 let fields = null;
1867 let isVarArgs = false;1869 let isVarArgs = false;
1868 let fnNode = zigAnalysis.astNodes[fnObj.src];1870 let fnNode = getAstNode(fnObj.src);
1869 fields = fnNode.fields;1871 fields = fnNode.fields;
1870 isVarArgs = fnNode.varArgs;1872 isVarArgs = fnNode.varArgs;
18711873
...@@ -1880,7 +1882,7 @@ var zigAnalysis;...@@ -1880,7 +1882,7 @@ var zigAnalysis;
1880 let paramValue = resolveValue({ expr: value });1882 let paramValue = resolveValue({ expr: value });
18811883
1882 if (fields != null) {1884 if (fields != null) {
1883 let paramNode = zigAnalysis.astNodes[fields[i]];1885 let paramNode = getAstNode(fields[i]);
18841886
1885 if (paramNode.varArgs) {1887 if (paramNode.varArgs) {
1886 payloadHtml += "...";1888 payloadHtml += "...";
...@@ -2046,7 +2048,7 @@ var zigAnalysis;...@@ -2046,7 +2048,7 @@ var zigAnalysis;
2046 function shouldSkipParamName(typeRef, paramName) {2048 function shouldSkipParamName(typeRef, paramName) {
2047 let resolvedTypeRef = resolveValue({ expr: typeRef });2049 let resolvedTypeRef = resolveValue({ expr: typeRef });
2048 if ("type" in resolvedTypeRef) {2050 if ("type" in resolvedTypeRef) {
2049 let typeObj = zigAnalysis.types[resolvedTypeRef.type];2051 let typeObj = getType(resolvedTypeRef.type);
2050 if (typeObj.kind === typeKinds.Pointer) {2052 if (typeObj.kind === typeKinds.Pointer) {
2051 let ptrObj = typeObj;2053 let ptrObj = typeObj;
2052 if (getPtrSize(ptrObj) === pointerSizeEnum.One) {2054 if (getPtrSize(ptrObj) === pointerSizeEnum.One) {
...@@ -2067,7 +2069,7 @@ var zigAnalysis;...@@ -2067,7 +2069,7 @@ var zigAnalysis;
2067 if (2069 if (
2068 rootIsStd &&2070 rootIsStd &&
2069 typeObj ===2071 typeObj ===
2070 zigAnalysis.types[zigAnalysis.packages[zigAnalysis.rootPkg].main]2072 getType(zigAnalysis.packages[zigAnalysis.rootPkg].main)
2071 ) {2073 ) {
2072 name = "std";2074 name = "std";
2073 } else {2075 } else {
...@@ -2189,7 +2191,7 @@ var zigAnalysis;...@@ -2189,7 +2191,7 @@ var zigAnalysis;
21892191
2190 if (resolvedValue.expr.fieldRef) {2192 if (resolvedValue.expr.fieldRef) {
2191 const declRef = decl.value.expr.refPath[0].declRef;2193 const declRef = decl.value.expr.refPath[0].declRef;
2192 const type = zigAnalysis.decls[declRef];2194 const type = getDecl(declRef);
2193 domFnProtoCode.innerHTML =2195 domFnProtoCode.innerHTML =
2194 '<span class="tok-kw">const</span> ' +2196 '<span class="tok-kw">const</span> ' +
2195 escapeHtml(decl.name) +2197 escapeHtml(decl.name) +
...@@ -2229,7 +2231,7 @@ var zigAnalysis;...@@ -2229,7 +2231,7 @@ var zigAnalysis;
2229 ";";2231 ";";
2230 }2232 }
22312233
2232 let docs = zigAnalysis.astNodes[decl.src].docs;2234 let docs = getAstNode(decl.src).docs;
2233 if (docs != null) {2235 if (docs != null) {
2234 domTldDocs.innerHTML = markdown(docs);2236 domTldDocs.innerHTML = markdown(docs);
2235 domTldDocs.classList.remove("hidden");2237 domTldDocs.classList.remove("hidden");
...@@ -2246,7 +2248,7 @@ var zigAnalysis;...@@ -2246,7 +2248,7 @@ var zigAnalysis;
2246 ": " +2248 ": " +
2247 typeValueName(declTypeRef, true, true);2249 typeValueName(declTypeRef, true, true);
22482250
2249 let docs = zigAnalysis.astNodes[decl.src].docs;2251 let docs = getAstNode(decl.src).docs;
2250 if (docs != null) {2252 if (docs != null) {
2251 domTldDocs.innerHTML = markdown(docs);2253 domTldDocs.innerHTML = markdown(docs);
2252 domTldDocs.classList.remove("hidden");2254 domTldDocs.classList.remove("hidden");
...@@ -2266,7 +2268,7 @@ var zigAnalysis;...@@ -2266,7 +2268,7 @@ var zigAnalysis;
2266 testsList2268 testsList
2267 ) {2269 ) {
2268 for (let i = 0; i < decls.length; i += 1) {2270 for (let i = 0; i < decls.length; i += 1) {
2269 let decl = zigAnalysis.decls[decls[i]];2271 let decl = getDecl(decls[i]);
2270 let declValue = resolveValue(decl.value);2272 let declValue = resolveValue(decl.value);
22712273
2272 if (decl.isTest) {2274 if (decl.isTest) {
...@@ -2282,7 +2284,7 @@ var zigAnalysis;...@@ -2282,7 +2284,7 @@ var zigAnalysis;
2282 if (decl.kind === "const") {2284 if (decl.kind === "const") {
2283 if ("type" in declValue.expr) {2285 if ("type" in declValue.expr) {
2284 // We have the actual type expression at hand.2286 // We have the actual type expression at hand.
2285 const typeExpr = zigAnalysis.types[declValue.expr.type];2287 const typeExpr = getType(declValue.expr.type);
2286 if (typeExpr.kind == typeKinds.Fn) {2288 if (typeExpr.kind == typeKinds.Fn) {
2287 const funcRetExpr = resolveValue({2289 const funcRetExpr = resolveValue({
2288 expr: typeExpr.ret,2290 expr: typeExpr.ret,
...@@ -2310,7 +2312,7 @@ var zigAnalysis;...@@ -2310,7 +2312,7 @@ var zigAnalysis;
2310 typesList.push(decl);2312 typesList.push(decl);
2311 }2313 }
2312 }2314 }
2313 } else if ("typeRef" in declValue) {2315 } else if (declValue.typeRef) {
2314 if ("type" in declValue.typeRef && declValue.typeRef == typeTypeId) {2316 if ("type" in declValue.typeRef && declValue.typeRef == typeTypeId) {
2315 // We don't know what the type expression is, but we know it's a type.2317 // We don't know what the type expression is, but we know it's a type.
2316 typesList.push(decl);2318 typesList.push(decl);
...@@ -2324,7 +2326,7 @@ var zigAnalysis;...@@ -2324,7 +2326,7 @@ var zigAnalysis;
2324 }2326 }
2325 }2327 }
2326 function renderSourceFileLink(decl) {2328 function renderSourceFileLink(decl) {
2327 let srcNode = zigAnalysis.astNodes[decl.src];2329 let srcNode = getAstNode(decl.src);
23282330
2329 return "<a style=\"float: right;\" href=\"" +2331 return "<a style=\"float: right;\" href=\"" +
2330 sourceFileUrlTemplate.replace("{{file}}",2332 sourceFileUrlTemplate.replace("{{file}}",
...@@ -2377,7 +2379,7 @@ var zigAnalysis;...@@ -2377,7 +2379,7 @@ var zigAnalysis;
2377 testsList.sort(byNameProperty);2379 testsList.sort(byNameProperty);
23782380
2379 if (container.src != null) {2381 if (container.src != null) {
2380 let docs = zigAnalysis.astNodes[container.src].docs;2382 let docs = getAstNode(container.src).docs;
2381 if (docs != null) {2383 if (docs != null) {
2382 domTldDocs.innerHTML = markdown(docs);2384 domTldDocs.innerHTML = markdown(docs);
2383 domTldDocs.classList.remove("hidden");2385 domTldDocs.classList.remove("hidden");
...@@ -2457,7 +2459,7 @@ var zigAnalysis;...@@ -2457,7 +2459,7 @@ var zigAnalysis;
2457 });2459 });
2458 tdFnSrc.innerHTML = renderSourceFileLink(decl);2460 tdFnSrc.innerHTML = renderSourceFileLink(decl);
24592461
2460 let docs = zigAnalysis.astNodes[decl.src].docs;2462 let docs = getAstNode(decl.src).docs;
2461 if (docs != null) {2463 if (docs != null) {
2462 tdDesc.innerHTML = shortDescMarkdown(docs);2464 tdDesc.innerHTML = shortDescMarkdown(docs);
2463 } else {2465 } else {
...@@ -2467,12 +2469,12 @@ var zigAnalysis;...@@ -2467,12 +2469,12 @@ var zigAnalysis;
2467 domSectFns.classList.remove("hidden");2469 domSectFns.classList.remove("hidden");
2468 }2470 }
24692471
2470 let containerNode = zigAnalysis.astNodes[container.src];2472 let containerNode = getAstNode(container.src);
2471 if (containerNode.fields && containerNode.fields.length > 0) {2473 if (containerNode.fields && containerNode.fields.length > 0) {
2472 resizeDomList(domListFields, containerNode.fields.length, "<div></div>");2474 resizeDomList(domListFields, containerNode.fields.length, "<div></div>");
24732475
2474 for (let i = 0; i < containerNode.fields.length; i += 1) {2476 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]);
2476 let divDom = domListFields.children[i];2478 let divDom = domListFields.children[i];
2477 let fieldName = fieldNode.name;2479 let fieldName = fieldNode.name;
2478 let docs = fieldNode.docs;2480 let docs = fieldNode.docs;
...@@ -2528,7 +2530,7 @@ var zigAnalysis;...@@ -2528,7 +2530,7 @@ var zigAnalysis;
25282530
2529 tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);2531 tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
25302532
2531 let docs = zigAnalysis.astNodes[decl.src].docs;2533 let docs = getAstNode(decl.src).docs;
2532 if (docs != null) {2534 if (docs != null) {
2533 tdDesc.innerHTML = shortDescMarkdown(docs);2535 tdDesc.innerHTML = shortDescMarkdown(docs);
2534 } else {2536 } else {
...@@ -2561,7 +2563,7 @@ var zigAnalysis;...@@ -2561,7 +2563,7 @@ var zigAnalysis;
2561 wantLink: true,2563 wantLink: true,
2562 });2564 });
25632565
2564 let docs = zigAnalysis.astNodes[decl.src].docs;2566 let docs = getAstNode(decl.src).docs;
2565 if (docs != null) {2567 if (docs != null) {
2566 tdDesc.innerHTML = shortDescMarkdown(docs);2568 tdDesc.innerHTML = shortDescMarkdown(docs);
2567 } else {2569 } else {
...@@ -2594,7 +2596,7 @@ var zigAnalysis;...@@ -2594,7 +2596,7 @@ var zigAnalysis;
2594 wantLink: true,2596 wantLink: true,
2595 });2597 });
25962598
2597 let docs = zigAnalysis.astNodes[decl.src].docs;2599 let docs = getAstNode(decl.src).docs;
2598 if (docs != null) {2600 if (docs != null) {
2599 tdDesc.innerHTML = shortDescMarkdown(docs);2601 tdDesc.innerHTML = shortDescMarkdown(docs);
2600 } else {2602 } else {
...@@ -2668,7 +2670,7 @@ var zigAnalysis;...@@ -2668,7 +2670,7 @@ var zigAnalysis;
26682670
2669 function findTypeTypeId() {2671 function findTypeTypeId() {
2670 for (let i = 0; i < zigAnalysis.types.length; i += 1) {2672 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) {
2672 return i;2674 return i;
2673 }2675 }
2674 }2676 }
...@@ -2732,11 +2734,11 @@ var zigAnalysis;...@@ -2732,11 +2734,11 @@ var zigAnalysis;
2732 if ("value" in parentType) {2734 if ("value" in parentType) {
2733 const rv = resolveValue(parentType.value);2735 const rv = resolveValue(parentType.value);
2734 if ("type" in rv.expr) {2736 if ("type" in rv.expr) {
2735 const t = zigAnalysis.types[rv.expr.type];2737 const t = getType(rv.expr.type);
2736 if (t.kind == typeKinds.Fn && t.generic_ret != null) {2738 if (t.kind == typeKinds.Fn && t.generic_ret != null) {
2737 const rgr = resolveValue({ expr: t.generic_ret });2739 const rgr = resolveValue({ expr: t.generic_ret });
2738 if ("type" in rgr.expr) {2740 if ("type" in rgr.expr) {
2739 parentType = zigAnalysis.types[rgr.expr.type];2741 parentType = getType(rgr.expr.type);
2740 }2742 }
2741 }2743 }
2742 }2744 }
...@@ -2746,7 +2748,7 @@ var zigAnalysis;...@@ -2746,7 +2748,7 @@ var zigAnalysis;
2746 if (!parentType.pubDecls) return null;2748 if (!parentType.pubDecls) return null;
2747 for (let i = 0; i < parentType.pubDecls.length; i += 1) {2749 for (let i = 0; i < parentType.pubDecls.length; i += 1) {
2748 let declIndex = parentType.pubDecls[i];2750 let declIndex = parentType.pubDecls[i];
2749 let childDecl = zigAnalysis.decls[declIndex];2751 let childDecl = getDecl(declIndex);
2750 if (childDecl.name === childName) {2752 if (childDecl.name === childName) {
2751 return childDecl;2753 return childDecl;
2752 }2754 }
...@@ -2754,7 +2756,7 @@ var zigAnalysis;...@@ -2754,7 +2756,7 @@ var zigAnalysis;
2754 if (!parentType.privDecls) return null;2756 if (!parentType.privDecls) return null;
2755 for (let i = 0; i < parentType.privDecls.length; i += 1) {2757 for (let i = 0; i < parentType.privDecls.length; i += 1) {
2756 let declIndex = parentType.privDecls[i];2758 let declIndex = parentType.privDecls[i];
2757 let childDecl = zigAnalysis.decls[declIndex];2759 let childDecl = getDecl(declIndex);
2758 if (childDecl.name === childName) {2760 if (childDecl.name === childName) {
2759 return childDecl;2761 return childDecl;
2760 }2762 }
...@@ -2805,7 +2807,7 @@ var zigAnalysis;...@@ -2805,7 +2807,7 @@ var zigAnalysis;
2805 let stack = [2807 let stack = [
2806 {2808 {
2807 declNames: [],2809 declNames: [],
2808 type: zigAnalysis.types[pkg.main],2810 type: getType(pkg.main),
2809 },2811 },
2810 ];2812 ];
2811 while (stack.length !== 0) {2813 while (stack.length !== 0) {
...@@ -2819,7 +2821,7 @@ var zigAnalysis;...@@ -2819,7 +2821,7 @@ var zigAnalysis;
2819 let mainDeclIndex = t.pubDecls[declI];2821 let mainDeclIndex = t.pubDecls[declI];
2820 if (list[mainDeclIndex] != null) continue;2822 if (list[mainDeclIndex] != null) continue;
28212823
2822 let decl = zigAnalysis.decls[mainDeclIndex];2824 let decl = getDecl(mainDeclIndex);
2823 let declVal = resolveValue(decl.value);2825 let declVal = resolveValue(decl.value);
2824 let declNames = item.declNames.concat([decl.name]);2826 let declNames = item.declNames.concat([decl.name]);
2825 list[mainDeclIndex] = {2827 list[mainDeclIndex] = {
...@@ -2827,7 +2829,7 @@ var zigAnalysis;...@@ -2827,7 +2829,7 @@ var zigAnalysis;
2827 declNames: declNames,2829 declNames: declNames,
2828 };2830 };
2829 if ("type" in declVal.expr) {2831 if ("type" in declVal.expr) {
2830 let value = zigAnalysis.types[declVal.expr.type];2832 let value = getType(declVal.expr.type);
2831 if (declCanRepresentTypeKind(value.kind)) {2833 if (declCanRepresentTypeKind(value.kind)) {
2832 canonTypeDecls[declVal.type] = mainDeclIndex;2834 canonTypeDecls[declVal.type] = mainDeclIndex;
2833 }2835 }
...@@ -2843,7 +2845,7 @@ var zigAnalysis;...@@ -2843,7 +2845,7 @@ var zigAnalysis;
2843 if (value.kind == typeKinds.Fn && value.generic_ret != null) {2845 if (value.kind == typeKinds.Fn && value.generic_ret != null) {
2844 let resolvedVal = resolveValue({ expr: value.generic_ret });2846 let resolvedVal = resolveValue({ expr: value.generic_ret });
2845 if ("type" in resolvedVal.expr) {2847 if ("type" in resolvedVal.expr) {
2846 let generic_type = zigAnalysis.types[resolvedVal.expr.type];2848 let generic_type = getType(resolvedVal.expr.type);
2847 if (isContainerType(generic_type)) {2849 if (isContainerType(generic_type)) {
2848 stack.push({2850 stack.push({
2849 declNames: declNames,2851 declNames: declNames,
...@@ -3394,11 +3396,11 @@ var zigAnalysis;...@@ -3394,11 +3396,11 @@ var zigAnalysis;
3394 let canonPath = getCanonDeclPath(declIndex);3396 let canonPath = getCanonDeclPath(declIndex);
3395 if (canonPath == null) continue;3397 if (canonPath == null) continue;
33963398
3397 let decl = zigAnalysis.decls[declIndex];3399 let decl = getDecl(declIndex);
3398 let lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];3400 let lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];
3399 let fullPathSearchText =3401 let fullPathSearchText =
3400 lastPkgName + "." + canonPath.declNames.join(".");3402 lastPkgName + "." + canonPath.declNames.join(".");
3401 let astNode = zigAnalysis.astNodes[decl.src];3403 let astNode = getAstNode(decl.src);
3402 let fileAndDocs = ""; //zigAnalysis.files[astNode.file];3404 let fileAndDocs = ""; //zigAnalysis.files[astNode.file];
3403 // TODO: understand what this piece of code is trying to achieve3405 // TODO: understand what this piece of code is trying to achieve
3404 // also right now `files` are expressed as a hashmap.3406 // also right now `files` are expressed as a hashmap.
...@@ -3513,4 +3515,169 @@ var zigAnalysis;...@@ -3513,4 +3515,169 @@ var zigAnalysis;
3513 function byNameProperty(a, b) {3515 function byNameProperty(a, b) {
3514 return operatorCompare(a.name, b.name);3516 return operatorCompare(a.name, b.name);
3515 }3517 }
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
3516})();3680})();
3681
3682
3683
lib/std/child_process.zig+1-1
...@@ -508,7 +508,7 @@ pub const ChildProcess = struct {...@@ -508,7 +508,7 @@ pub const ChildProcess = struct {
508 // it, that's the error code returned by the child process.508 // it, that's the error code returned by the child process.
509 _ = std.os.poll(&fd, 0) catch unreachable;509 _ = std.os.poll(&fd, 0) catch unreachable;
510510
511 // According to eventfd(2) the descriptro is readable if the counter511 // According to eventfd(2) the descriptor is readable if the counter
512 // has a value greater than 0512 // has a value greater than 0
513 if ((fd[0].revents & std.os.POLL.IN) != 0) {513 if ((fd[0].revents & std.os.POLL.IN) != 0) {
514 const err_int = try readIntFd(err_pipe[0]);514 const err_int = try readIntFd(err_pipe[0]);
lib/std/linked_list.zig-2
...@@ -2,8 +2,6 @@ const std = @import("std.zig");...@@ -2,8 +2,6 @@ const std = @import("std.zig");
2const debug = std.debug;2const debug = std.debug;
3const assert = debug.assert;3const assert = debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const mem = std.mem;
6const Allocator = mem.Allocator;
75
8/// A singly-linked list is headed by a single forward pointer. The elements6/// A singly-linked list is headed by a single forward pointer. The elements
9/// are singly linked for minimum space and pointer manipulation overhead at7/// 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 {...@@ -280,8 +280,8 @@ pub fn generateZirData(self: *Autodoc) !void {
280 try std.json.stringify(280 try std.json.stringify(
281 data,281 data,
282 .{282 .{
283 .whitespace = .{ .indent = if (builtin.mode == .Debug) .{ .Space = 4 } else .None },283 .whitespace = .{ .indent = .None, .separator = false },
284 .emit_null_optional_fields = false,284 .emit_null_optional_fields = true,
285 },285 },
286 out,286 out,
287 );287 );
...@@ -404,6 +404,7 @@ const DocData = struct {...@@ -404,6 +404,7 @@ const DocData = struct {
404 w: anytype,404 w: anytype,
405 ) !void {405 ) !void {
406 var jsw = std.json.writeStream(w, 15);406 var jsw = std.json.writeStream(w, 15);
407 if (opts.whitespace) |ws| jsw.whitespace = ws;
407 try jsw.beginObject();408 try jsw.beginObject();
408 inline for (comptime std.meta.tags(std.meta.FieldEnum(DocData))) |f| {409 inline for (comptime std.meta.tags(std.meta.FieldEnum(DocData))) |f| {
409 const f_name = @tagName(f);410 const f_name = @tagName(f);
...@@ -449,6 +450,8 @@ const DocData = struct {...@@ -449,6 +450,8 @@ const DocData = struct {
449 w: anytype,450 w: anytype,
450 ) !void {451 ) !void {
451 var jsw = std.json.writeStream(w, 15);452 var jsw = std.json.writeStream(w, 15);
453 if (opts.whitespace) |ws| jsw.whitespace = ws;
454
452 try jsw.beginObject();455 try jsw.beginObject();
453 inline for (comptime std.meta.tags(std.meta.FieldEnum(DocPackage))) |f| {456 inline for (comptime std.meta.tags(std.meta.FieldEnum(DocPackage))) |f| {
454 const f_name = @tagName(f);457 const f_name = @tagName(f);
...@@ -474,6 +477,22 @@ const DocData = struct {...@@ -474,6 +477,22 @@ const DocData = struct {
474 // The index in astNodes of the `test declname { }` node477 // The index in astNodes of the `test declname { }` node
475 decltest: ?usize = null,478 decltest: ?usize = null,
476 _analyzed: bool, // omitted in json data479 _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 }
477 };496 };
478497
479 const AstNode = struct {498 const AstNode = struct {
...@@ -485,6 +504,22 @@ const DocData = struct {...@@ -485,6 +504,22 @@ const DocData = struct {
485 docs: ?[]const u8 = null,504 docs: ?[]const u8 = null,
486 fields: ?[]usize = null, // index into astNodes505 fields: ?[]usize = null, // index into astNodes
487 @"comptime": bool = false,506 @"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 }
488 };523 };
489524
490 const Type = union(enum) {525 const Type = union(enum) {
...@@ -525,7 +560,6 @@ const DocData = struct {...@@ -525,7 +560,6 @@ const DocData = struct {
525 fields: ?[]Expr = null, // (use src->fields to find names)560 fields: ?[]Expr = null, // (use src->fields to find names)
526 line_number: usize,561 line_number: usize,
527 outer_decl: usize,562 outer_decl: usize,
528 ast: usize,
529 },563 },
530 ComptimeExpr: struct { name: []const u8 },564 ComptimeExpr: struct { name: []const u8 },
531 ComptimeFloat: struct { name: []const u8 },565 ComptimeFloat: struct { name: []const u8 },
...@@ -548,7 +582,6 @@ const DocData = struct {...@@ -548,7 +582,6 @@ const DocData = struct {
548 src: usize, // index into astNodes582 src: usize, // index into astNodes
549 privDecls: []usize = &.{}, // index into decls583 privDecls: []usize = &.{}, // index into decls
550 pubDecls: []usize = &.{}, // index into decls584 pubDecls: []usize = &.{}, // index into decls
551 ast: usize,
552 // (use src->fields to find field names)585 // (use src->fields to find field names)
553 },586 },
554 Union: struct {587 Union: struct {
...@@ -557,7 +590,6 @@ const DocData = struct {...@@ -557,7 +590,6 @@ const DocData = struct {
557 privDecls: []usize = &.{}, // index into decls590 privDecls: []usize = &.{}, // index into decls
558 pubDecls: []usize = &.{}, // index into decls591 pubDecls: []usize = &.{}, // index into decls
559 fields: []Expr = &.{}, // (use src->fields to find names)592 fields: []Expr = &.{}, // (use src->fields to find names)
560 ast: usize,
561 },593 },
562 Fn: struct {594 Fn: struct {
563 name: []const u8,595 name: []const u8,
...@@ -582,7 +614,6 @@ const DocData = struct {...@@ -582,7 +614,6 @@ const DocData = struct {
582 src: usize, // index into astNodes614 src: usize, // index into astNodes
583 privDecls: []usize = &.{}, // index into decls615 privDecls: []usize = &.{}, // index into decls
584 pubDecls: []usize = &.{}, // index into decls616 pubDecls: []usize = &.{}, // index into decls
585 ast: usize,
586 },617 },
587 Frame: struct { name: []const u8 },618 Frame: struct { name: []const u8 },
588 AnyFrame: struct { name: []const u8 },619 AnyFrame: struct { name: []const u8 },
...@@ -601,14 +632,15 @@ const DocData = struct {...@@ -601,14 +632,15 @@ const DocData = struct {
601 ) !void {632 ) !void {
602 const active_tag = std.meta.activeTag(self);633 const active_tag = std.meta.activeTag(self);
603 var jsw = std.json.writeStream(w, 15);634 var jsw = std.json.writeStream(w, 15);
604 try jsw.beginObject();635 if (opts.whitespace) |ws| jsw.whitespace = ws;
605 try jsw.objectField("kind");636 try jsw.beginArray();
637 try jsw.arrayElem();
606 try jsw.emitNumber(@enumToInt(active_tag));638 try jsw.emitNumber(@enumToInt(active_tag));
607 inline for (comptime std.meta.fields(Type)) |case| {639 inline for (comptime std.meta.fields(Type)) |case| {
608 if (@field(Type, case.name) == active_tag) {640 if (@field(Type, case.name) == active_tag) {
609 const current_value = @field(self, case.name);641 const current_value = @field(self, case.name);
610 inline for (comptime std.meta.fields(case.field_type)) |f| {642 inline for (comptime std.meta.fields(case.field_type)) |f| {
611 try jsw.objectField(f.name);643 try jsw.arrayElem();
612 if (f.field_type == std.builtin.TypeInfo.Pointer.Size) {644 if (f.field_type == std.builtin.TypeInfo.Pointer.Size) {
613 try jsw.emitNumber(@enumToInt(@field(current_value, f.name)));645 try jsw.emitNumber(@enumToInt(@field(current_value, f.name)));
614 } else {646 } else {
...@@ -618,7 +650,7 @@ const DocData = struct {...@@ -618,7 +650,7 @@ const DocData = struct {
618 }650 }
619 }651 }
620 }652 }
621 try jsw.endObject();653 try jsw.endArray();
622 }654 }
623 };655 };
624656
...@@ -686,7 +718,7 @@ const DocData = struct {...@@ -686,7 +718,7 @@ const DocData = struct {
686 const SwitchOp = struct {718 const SwitchOp = struct {
687 cond_index: usize,719 cond_index: usize,
688 file_name: []const u8,720 file_name: []const u8,
689 ast: usize,721 src: usize,
690 outer_decl: usize, // index in `types`722 outer_decl: usize, // index in `types`
691 };723 };
692 const BuiltinBin = struct {724 const BuiltinBin = struct {
...@@ -704,7 +736,15 @@ const DocData = struct {...@@ -704,7 +736,15 @@ const DocData = struct {
704 end: ?usize = null,736 end: ?usize = null,
705 sentinel: ?usize = null, // index in `exprs`737 sentinel: ?usize = null, // index in `exprs`
706 };738 };
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 };
708 const As = struct {748 const As = struct {
709 typeRefArg: ?usize, // index in `exprs`749 typeRefArg: ?usize, // index in `exprs`
710 exprArg: usize, // index in `exprs`750 exprArg: usize, // index in `exprs`
...@@ -721,11 +761,12 @@ const DocData = struct {...@@ -721,11 +761,12 @@ const DocData = struct {
721761
722 pub fn jsonStringify(762 pub fn jsonStringify(
723 self: Expr,763 self: Expr,
724 opt: std.json.StringifyOptions,764 opts: std.json.StringifyOptions,
725 w: anytype,765 w: anytype,
726 ) !void {766 ) !void {
727 const active_tag = std.meta.activeTag(self);767 const active_tag = std.meta.activeTag(self);
728 var jsw = std.json.writeStream(w, 15);768 var jsw = std.json.writeStream(w, 15);
769 if (opts.whitespace) |ws| jsw.whitespace = ws;
729 try jsw.beginObject();770 try jsw.beginObject();
730 try jsw.objectField(@tagName(active_tag));771 try jsw.objectField(@tagName(active_tag));
731 switch (self) {772 switch (self) {
...@@ -742,7 +783,7 @@ const DocData = struct {...@@ -742,7 +783,7 @@ const DocData = struct {
742 if (comptime std.mem.eql(u8, case.name, "builtinField"))783 if (comptime std.mem.eql(u8, case.name, "builtinField"))
743 continue;784 continue;
744 if (@field(Expr, case.name) == active_tag) {785 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);
746 jsw.state_index -= 1;787 jsw.state_index -= 1;
747 // TODO: we should not reach into the state of the788 // TODO: we should not reach into the state of the
748 // json writer, but alas, this is what's789 // json writer, but alas, this is what's
...@@ -1874,7 +1915,12 @@ fn walkInstruction(...@@ -1874,7 +1915,12 @@ fn walkInstruction(
1874 // log.debug("{s}", .{sep});1915 // log.debug("{s}", .{sep});
18751916
1876 const switch_index = self.exprs.items.len;1917 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
1879 return DocData.WalkResult{1925 return DocData.WalkResult{
1880 .typeRef = .{ .type = @enumToInt(Ref.type_type) },1926 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
...@@ -2505,7 +2551,6 @@ fn walkInstruction(...@@ -2505,7 +2551,6 @@ fn walkInstruction(
2505 .src = self_ast_node_index,2551 .src = self_ast_node_index,
2506 .privDecls = priv_decl_indexes.items,2552 .privDecls = priv_decl_indexes.items,
2507 .pubDecls = decl_indexes.items,2553 .pubDecls = decl_indexes.items,
2508 .ast = self_ast_node_index,
2509 },2554 },
2510 };2555 };
2511 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {2556 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
...@@ -2644,7 +2689,13 @@ fn walkInstruction(...@@ -2644,7 +2689,13 @@ fn walkInstruction(
2644 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;2689 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
26452690
2646 self.types.items[type_slot_index] = .{2691 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 },
2648 };2699 };
26492700
2650 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {2701 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
...@@ -2796,7 +2847,12 @@ fn walkInstruction(...@@ -2796,7 +2847,12 @@ fn walkInstruction(
2796 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;2847 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
27972848
2798 self.types.items[type_slot_index] = .{2849 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 },
2800 };2856 };
2801 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {2857 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
2802 for (paths.items) |resume_info| {2858 for (paths.items) |resume_info| {
...@@ -2910,7 +2966,15 @@ fn walkInstruction(...@@ -2910,7 +2966,15 @@ fn walkInstruction(
2910 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;2966 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
29112967
2912 self.types.items[type_slot_index] = .{2968 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 },
2914 };2978 };
2915 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {2979 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
2916 for (paths.items) |resume_info| {2980 for (paths.items) |resume_info| {
src/Compilation.zig+87-65
...@@ -1238,7 +1238,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1238,7 +1238,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1238 options.target,1238 options.target,
1239 options.is_native_abi,1239 options.is_native_abi,
1240 link_libc,1240 link_libc,
1241 options.system_lib_names.len != 0 or options.frameworks.count() != 0,
1242 options.libc_installation,1241 options.libc_installation,
1243 options.native_darwin_sdk != null,1242 options.native_darwin_sdk != null,
1244 );1243 );
...@@ -4522,7 +4521,6 @@ fn detectLibCIncludeDirs(...@@ -4522,7 +4521,6 @@ fn detectLibCIncludeDirs(
4522 target: Target,4521 target: Target,
4523 is_native_abi: bool,4522 is_native_abi: bool,
4524 link_libc: bool,4523 link_libc: bool,
4525 link_system_libs: bool,
4526 libc_installation: ?*const LibCInstallation,4524 libc_installation: ?*const LibCInstallation,
4527 has_macos_sdk: bool,4525 has_macos_sdk: bool,
4528) !LibCDirs {4526) !LibCDirs {
...@@ -4539,7 +4537,7 @@ fn detectLibCIncludeDirs(...@@ -4539,7 +4537,7 @@ fn detectLibCIncludeDirs(
45394537
4540 // If linking system libraries and targeting the native abi, default to4538 // If linking system libraries and targeting the native abi, default to
4541 // using the system libc installation.4539 // 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()) {
4543 if (target.isDarwin()) {4541 if (target.isDarwin()) {
4544 return if (has_macos_sdk)4542 return if (has_macos_sdk)
4545 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.4543 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.
...@@ -4551,74 +4549,29 @@ fn detectLibCIncludeDirs(...@@ -4551,74 +4549,29 @@ fn detectLibCIncludeDirs(
4551 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target);4549 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target);
4552 }4550 }
4553 const libc = try arena.create(LibCInstallation);4551 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 };
4555 return detectLibCFromLibCInstallation(arena, target, libc);4568 return detectLibCFromLibCInstallation(arena, target, libc);
4556 }4569 }
45574570
4558 // If not linking system libraries, build and provide our own libc by4571 // If not linking system libraries, build and provide our own libc by
4559 // default if possible.4572 // default if possible.
4560 if (target_util.canBuildLibC(target)) {4573 if (target_util.canBuildLibC(target)) {
4561 switch (target.os.tag) {4574 return detectLibCFromBuilding(arena, zig_lib_dir, target, has_macos_sdk);
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 }
4622 }4575 }
46234576
4624 // If zig can't build the libc for the target and we are targeting the4577 // 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...@@ -4677,6 +4630,75 @@ fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const
4677 };4630 };
4678}4631}
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
4680pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {4702pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
4681 if (comp.wantBuildGLibCFromSource() or4703 if (comp.wantBuildGLibCFromSource() or
4682 comp.wantBuildMuslFromSource() or4704 comp.wantBuildMuslFromSource() or
src/arch/aarch64/CodeGen.zig+35-50
...@@ -139,21 +139,10 @@ const MCValue = union(enum) {...@@ -139,21 +139,10 @@ const MCValue = union(enum) {
139 /// If the type is a pointer, it means the pointer address is at139 /// If the type is a pointer, it means the pointer address is at
140 /// this memory location.140 /// this memory location.
141 memory: u64,141 memory: u64,
142 /// The value is in memory referenced indirectly via a GOT entry142 /// The value is in memory but requires a linker relocation fixup:
143 /// index.143 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
144 ///144 /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
145 /// If the type is a pointer, it means the pointer is referenced145 linker_load: struct { @"type": enum { got, direct }, sym_index: u32 },
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,
157 /// The value is one of the stack variables.146 /// The value is one of the stack variables.
158 ///147 ///
159 /// If the type is a pointer, it means the pointer address is in148 /// 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...@@ -2959,8 +2948,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2959 .memory,2948 .memory,
2960 .stack_offset,2949 .stack_offset,
2961 .stack_argument_offset,2950 .stack_argument_offset,
2962 .got_load,2951 .linker_load,
2963 .direct_load,
2964 => {2952 => {
2965 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr);2953 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr);
2966 try self.load(dst_mcv, .{ .register = addr_reg }, ptr_ty);2954 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...@@ -3197,8 +3185,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3197 .memory,3185 .memory,
3198 .stack_offset,3186 .stack_offset,
3199 .stack_argument_offset,3187 .stack_argument_offset,
3200 .got_load,3188 .linker_load,
3201 .direct_load,
3202 => {3189 => {
3203 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr);3190 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr);
3204 try self.store(.{ .register = addr_reg }, value, ptr_ty, value_ty);3191 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....@@ -3493,7 +3480,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3493 const func = func_payload.data;3480 const func = func_payload.data;
3494 const fn_owner_decl = mod.declPtr(func.owner_decl);3481 const fn_owner_decl = mod.declPtr(func.owner_decl);
3495 try self.genSetReg(Type.initTag(.u64), .x30, .{3482 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 },
3497 });3487 });
3498 // blr x303488 // blr x30
3499 _ = try self.addInst(.{3489 _ = try self.addInst(.{
...@@ -4427,8 +4417,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4427,8 +4417,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4427 .register = cond_reg,4417 .register = cond_reg,
4428 });4418 });
4429 },4419 },
4430 .got_load,4420 .linker_load,
4431 .direct_load,
4432 .memory,4421 .memory,
4433 .stack_argument_offset,4422 .stack_argument_offset,
4434 .stack_offset,4423 .stack_offset,
...@@ -4479,13 +4468,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4479,13 +4468,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4479 });4468 });
4480 },4469 },
4481 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),4470 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),
4482 .got_load,4471 .linker_load => |load_struct| {
4483 .direct_load,4472 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
4484 => |sym_index| {4473 .got => .load_memory_ptr_got,
4485 const tag: Mir.Inst.Tag = switch (mcv) {4474 .direct => .load_memory_ptr_direct,
4486 .got_load => .load_memory_ptr_got,
4487 .direct_load => .load_memory_ptr_direct,
4488 else => unreachable,
4489 };4475 };
4490 const mod = self.bin_file.options.module.?;4476 const mod = self.bin_file.options.module.?;
4491 _ = try self.addInst(.{4477 _ = try self.addInst(.{
...@@ -4494,7 +4480,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4494,7 +4480,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4494 .payload = try self.addExtra(Mir.LoadMemoryPie{4480 .payload = try self.addExtra(Mir.LoadMemoryPie{
4495 .register = @enumToInt(src_reg),4481 .register = @enumToInt(src_reg),
4496 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,4482 .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,
4498 }),4484 }),
4499 },4485 },
4500 });4486 });
...@@ -4594,13 +4580,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4594,13 +4580,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4594 });4580 });
4595 },4581 },
4596 .register_with_overflow => unreachable, // doesn't fit into a register4582 .register_with_overflow => unreachable, // doesn't fit into a register
4597 .got_load,4583 .linker_load => |load_struct| {
4598 .direct_load,4584 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
4599 => |sym_index| {4585 .got => .load_memory_got,
4600 const tag: Mir.Inst.Tag = switch (mcv) {4586 .direct => .load_memory_direct,
4601 .got_load => .load_memory_got,
4602 .direct_load => .load_memory_direct,
4603 else => unreachable,
4604 };4587 };
4605 const mod = self.bin_file.options.module.?;4588 const mod = self.bin_file.options.module.?;
4606 _ = try self.addInst(.{4589 _ = try self.addInst(.{
...@@ -4609,7 +4592,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4609,7 +4592,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4609 .payload = try self.addExtra(Mir.LoadMemoryPie{4592 .payload = try self.addExtra(Mir.LoadMemoryPie{
4610 .register = @enumToInt(reg),4593 .register = @enumToInt(reg),
4611 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,4594 .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,
4613 }),4596 }),
4614 },4597 },
4615 });4598 });
...@@ -4741,8 +4724,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -4741,8 +4724,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4741 .register_with_overflow => {4724 .register_with_overflow => {
4742 return self.fail("TODO implement genSetStackArgument {}", .{mcv});4725 return self.fail("TODO implement genSetStackArgument {}", .{mcv});
4743 },4726 },
4744 .got_load,4727 .linker_load,
4745 .direct_load,
4746 .memory,4728 .memory,
4747 .stack_argument_offset,4729 .stack_argument_offset,
4748 .stack_offset,4730 .stack_offset,
...@@ -4785,13 +4767,10 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -4785,13 +4767,10 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4785 });4767 });
4786 },4768 },
4787 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),4769 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
4788 .got_load,4770 .linker_load => |load_struct| {
4789 .direct_load,4771 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
4790 => |sym_index| {4772 .got => .load_memory_ptr_got,
4791 const tag: Mir.Inst.Tag = switch (mcv) {4773 .direct => .load_memory_ptr_direct,
4792 .got_load => .load_memory_ptr_got,
4793 .direct_load => .load_memory_ptr_direct,
4794 else => unreachable,
4795 };4774 };
4796 const mod = self.bin_file.options.module.?;4775 const mod = self.bin_file.options.module.?;
4797 _ = try self.addInst(.{4776 _ = try self.addInst(.{
...@@ -4800,7 +4779,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -4800,7 +4779,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4800 .payload = try self.addExtra(Mir.LoadMemoryPie{4779 .payload = try self.addExtra(Mir.LoadMemoryPie{
4801 .register = @enumToInt(src_reg),4780 .register = @enumToInt(src_reg),
4802 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,4781 .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,
4804 }),4783 }),
4805 },4784 },
4806 });4785 });
...@@ -5107,7 +5086,10 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -5107,7 +5086,10 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
5107 // Because MachO is PIE-always-on, we defer memory address resolution until5086 // Because MachO is PIE-always-on, we defer memory address resolution until
5108 // the linker has enough info to perform relocations.5087 // the linker has enough info to perform relocations.
5109 assert(decl.link.macho.sym_index != 0);5088 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 } };
5111 } else if (self.bin_file.cast(link.File.Coff)) |_| {5093 } else if (self.bin_file.cast(link.File.Coff)) |_| {
5112 return self.fail("TODO codegen COFF const Decl pointer", .{});5094 return self.fail("TODO codegen COFF const Decl pointer", .{});
5113 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {5095 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
...@@ -5129,7 +5111,10 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {...@@ -5129,7 +5111,10 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
5129 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;5111 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
5130 return MCValue{ .memory = vaddr };5112 return MCValue{ .memory = vaddr };
5131 } else if (self.bin_file.cast(link.File.MachO)) |_| {5113 } 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 } };
5133 } else if (self.bin_file.cast(link.File.Coff)) |_| {5118 } else if (self.bin_file.cast(link.File.Coff)) |_| {
5134 return self.fail("TODO lower unnamed const in COFF", .{});5119 return self.fail("TODO lower unnamed const in COFF", .{});
5135 } else if (self.bin_file.cast(link.File.Plan9)) |_| {5120 } 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 {...@@ -681,12 +681,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
681 };681 };
682 // Add relocation to the decl.682 // Add relocation to the decl.
683 const atom = macho_file.atom_by_index_table.get(relocation.atom_index).?;683 const atom = macho_file.atom_by_index_table.get(relocation.atom_index).?;
684 const target = macho_file.getGlobalByIndex(relocation.sym_index);
684 try atom.relocs.append(emit.bin_file.allocator, .{685 try atom.relocs.append(emit.bin_file.allocator, .{
685 .offset = offset,686 .offset = offset,
686 .target = .{687 .target = target,
687 .sym_index = relocation.sym_index,
688 .file = null,
689 },
690 .addend = 0,688 .addend = 0,
691 .subtractor = null,689 .subtractor = null,
692 .pcrel = true,690 .pcrel = true,
src/arch/arm/CodeGen.zig+1558-1057
...@@ -438,9 +438,8 @@ fn gen(self: *Self) !void {...@@ -438,9 +438,8 @@ fn gen(self: *Self) !void {
438 // mov fp, sp438 // mov fp, sp
439 _ = try self.addInst(.{439 _ = try self.addInst(.{
440 .tag = .mov,440 .tag = .mov,
441 .data = .{ .rr_op = .{441 .data = .{ .r_op_mov = .{
442 .rd = .fp,442 .rd = .fp,
443 .rn = .r0,
444 .op = Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none),443 .op = Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none),
445 } },444 } },
446 });445 });
...@@ -452,9 +451,7 @@ fn gen(self: *Self) !void {...@@ -452,9 +451,7 @@ fn gen(self: *Self) !void {
452 // The address of where to store the return value is in451 // The address of where to store the return value is in
453 // r0. As this register might get overwritten along the452 // r0. As this register might get overwritten along the
454 // way, save the address to the stack.453 // way, save the address to the stack.
455 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, 4) + 4;454 const stack_offset = try self.allocMem(4, 4, null);
456 self.next_stack_offset = stack_offset;
457 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
458455
459 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 });456 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 });
460 self.ret_mcv = MCValue{ .stack_offset = stack_offset };457 self.ret_mcv = MCValue{ .stack_offset = stack_offset };
...@@ -491,14 +488,10 @@ fn gen(self: *Self) !void {...@@ -491,14 +488,10 @@ fn gen(self: *Self) !void {
491 const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);488 const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);
492 const stack_size = aligned_total_stack_end - self.saved_regs_stack_space;489 const stack_size = aligned_total_stack_end - self.saved_regs_stack_space;
493 self.max_end_stack = stack_size;490 self.max_end_stack = stack_size;
494 if (Instruction.Operand.fromU32(stack_size)) |op| {491 self.mir_instructions.set(sub_reloc, .{
495 self.mir_instructions.set(sub_reloc, .{492 .tag = .sub_sp_scratch_r0,
496 .tag = .sub,493 .data = .{ .imm32 = stack_size },
497 .data = .{ .rr_op = .{ .rd = .sp, .rn = .sp, .op = op } },494 });
498 });
499 } else {
500 return self.failSymbol("TODO ARM: allow larger stacks", .{});
501 }
502495
503 _ = try self.addInst(.{496 _ = try self.addInst(.{
504 .tag = .dbg_epilogue_begin,497 .tag = .dbg_epilogue_begin,
...@@ -531,9 +524,8 @@ fn gen(self: *Self) !void {...@@ -531,9 +524,8 @@ fn gen(self: *Self) !void {
531 // mov sp, fp524 // mov sp, fp
532 _ = try self.addInst(.{525 _ = try self.addInst(.{
533 .tag = .mov,526 .tag = .mov,
534 .data = .{ .rr_op = .{527 .data = .{ .r_op_mov = .{
535 .rd = .sp,528 .rd = .sp,
536 .rn = .r0,
537 .op = Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none),529 .op = Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none),
538 } },530 } },
539 });531 });
...@@ -895,17 +887,30 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -895,17 +887,30 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
895 try table.ensureUnusedCapacity(self.gpa, additional_count);887 try table.ensureUnusedCapacity(self.gpa, additional_count);
896}888}
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
899 if (abi_align > self.stack_align)899 if (abi_align > self.stack_align)
900 self.stack_align = abi_align;900 self.stack_align = abi_align;
901
901 // TODO find a free slot instead of always appending902 // TODO find a free slot instead of always appending
902 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;903 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
903 self.next_stack_offset = offset;904 self.next_stack_offset = offset;
904 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);905 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
905 try self.stack.putNoClobber(self.gpa, offset, .{906
906 .inst = inst,907 if (maybe_inst) |inst| {
907 .size = abi_size,908 try self.stack.putNoClobber(self.gpa, offset, .{
908 });909 .inst = inst,
910 .size = abi_size,
911 });
912 }
913
909 return offset;914 return offset;
910}915}
911916
...@@ -927,35 +932,34 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {...@@ -927,35 +932,34 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
927 };932 };
928 // TODO swap this for inst.ty.ptrAlign933 // TODO swap this for inst.ty.ptrAlign
929 const abi_align = elem_ty.abiAlignment(self.target.*);934 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);
931}937}
932938
933fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {939fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue {
934 const elem_ty = self.air.typeOfIndex(inst);
935 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {940 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {
936 const mod = self.bin_file.options.module.?;941 const mod = self.bin_file.options.module.?;
937 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});942 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
938 };943 };
939 const abi_align = elem_ty.abiAlignment(self.target.*);944 const abi_align = elem_ty.abiAlignment(self.target.*);
940 if (abi_align > self.stack_align)
941 self.stack_align = abi_align;
942945
943 if (reg_ok) {946 if (reg_ok) {
944 // Make sure the type can fit in a register before we try to allocate one.947 // Make sure the type can fit in a register before we try to allocate one.
945 const ptr_bits = self.target.cpu.arch.ptrBitWidth();948 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
946 const ptr_bytes: u64 = @divExact(ptr_bits, 8);949 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
947 if (abi_size <= ptr_bytes) {950 if (abi_size <= ptr_bytes) {
948 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {951 if (self.register_manager.tryAllocReg(maybe_inst, gp)) |reg| {
949 return MCValue{ .register = reg };952 return MCValue{ .register = reg };
950 }953 }
951 }954 }
952 }955 }
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);
954 return MCValue{ .stack_offset = stack_offset };958 return MCValue{ .stack_offset = stack_offset };
955}959}
956960
957pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {961pub 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);
959 log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv });963 log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv });
960964
961 const reg_mcv = self.getResolvedInstValue(inst);965 const reg_mcv = self.getResolvedInstValue(inst);
...@@ -976,12 +980,13 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -976,12 +980,13 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
976/// occupied980/// occupied
977fn spillCompareFlagsIfOccupied(self: *Self) !void {981fn spillCompareFlagsIfOccupied(self: *Self) !void {
978 if (self.cpsr_flags_inst) |inst_to_save| {982 if (self.cpsr_flags_inst) |inst_to_save| {
983 const ty = self.air.typeOfIndex(inst_to_save);
979 const mcv = self.getResolvedInstValue(inst_to_save);984 const mcv = self.getResolvedInstValue(inst_to_save);
980 const new_mcv = switch (mcv) {985 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),
982 .register_c_flag,987 .register_c_flag,
983 .register_v_flag,988 .register_v_flag,
984 => try self.allocRegOrMem(inst_to_save, false),989 => try self.allocRegOrMem(ty, false, inst_to_save),
985 else => unreachable, // mcv doesn't occupy the compare flags990 else => unreachable, // mcv doesn't occupy the compare flags
986 };991 };
987992
...@@ -1112,10 +1117,11 @@ fn truncRegister(...@@ -1112,10 +1117,11 @@ fn truncRegister(
1112 });1117 });
1113}1118}
11141119
1120/// Asserts that both operand_ty and dest_ty are integer types
1115fn trunc(1121fn trunc(
1116 self: *Self,1122 self: *Self,
1117 maybe_inst: ?Air.Inst.Index,1123 maybe_inst: ?Air.Inst.Index,
1118 operand: MCValue,1124 operand_bind: ReadArg.Bind,
1119 operand_ty: Type,1125 operand_ty: Type,
1120 dest_ty: Type,1126 dest_ty: Type,
1121) !MCValue {1127) !MCValue {
...@@ -1123,39 +1129,38 @@ fn trunc(...@@ -1123,39 +1129,38 @@ fn trunc(
1123 const info_b = dest_ty.intInfo(self.target.*);1129 const info_b = dest_ty.intInfo(self.target.*);
11241130
1125 if (info_b.bits <= 32) {1131 if (info_b.bits <= 32) {
1126 const operand_reg = switch (operand) {1132 if (info_a.bits > 32) {
1127 .register => |r| r,1133 return self.fail("TODO load least significant word into register", .{});
1128 else => operand_reg: {1134 }
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);
11381135
1139 const dest_reg = if (maybe_inst) |inst| blk: {1136 var operand_reg: Register = undefined;
1140 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1137 var dest_reg: Register = undefined;
11411138
1142 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {1139 const read_args = [_]ReadArg{
1143 break :blk operand_reg;1140 .{ .ty = operand_ty, .bind = operand_bind, .class = gp, .reg = &operand_reg },
1144 } else {1141 };
1145 break :blk try self.register_manager.allocReg(inst, gp);1142 const write_args = [_]WriteArg{
1146 }1143 .{ .ty = dest_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1147 } else try self.register_manager.allocReg(null, gp);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
1149 switch (info_b.bits) {1154 switch (info_b.bits) {
1150 32 => {1155 32 => {
1151 try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg });1156 try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg });
1152 return MCValue{ .register = dest_reg };
1153 },1157 },
1154 else => {1158 else => {
1155 try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);1159 try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);
1156 return MCValue{ .register = dest_reg };
1157 },1160 },
1158 }1161 }
1162
1163 return MCValue{ .register = dest_reg };
1159 } else {1164 } else {
1160 return self.fail("TODO: truncate to ints > 32 bits", .{});1165 return self.fail("TODO: truncate to ints > 32 bits", .{});
1161 }1166 }
...@@ -1163,12 +1168,12 @@ fn trunc(...@@ -1163,12 +1168,12 @@ fn trunc(
11631168
1164fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {1169fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
1165 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1170 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 };
1167 const operand_ty = self.air.typeOf(ty_op.operand);1172 const operand_ty = self.air.typeOf(ty_op.operand);
1168 const dest_ty = self.air.typeOfIndex(inst);1173 const dest_ty = self.air.typeOfIndex(inst);
11691174
1170 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {1175 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);
1172 };1177 };
11731178
1174 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1179 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -1184,29 +1189,32 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -1184,29 +1189,32 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
1184fn airNot(self: *Self, inst: Air.Inst.Index) !void {1189fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1185 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1190 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1186 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1191 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 };
1188 const operand_ty = self.air.typeOf(ty_op.operand);1193 const operand_ty = self.air.typeOf(ty_op.operand);
1189 switch (operand) {1194 switch (try operand_bind.resolveToMcv(self)) {
1190 .dead => unreachable,1195 .dead => unreachable,
1191 .unreach => unreachable,1196 .unreach => unreachable,
1192 .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() },1197 .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() },
1193 else => {1198 else => {
1194 switch (operand_ty.zigTypeTag()) {1199 switch (operand_ty.zigTypeTag()) {
1195 .Bool => {1200 .Bool => {
1196 const op_reg = switch (operand) {1201 var op_reg: Register = undefined;
1197 .register => |r| r,1202 var dest_reg: Register = undefined;
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);
12021203
1203 const dest_reg = blk: {1204 const read_args = [_]ReadArg{
1204 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {1205 .{ .ty = operand_ty, .bind = operand_bind, .class = gp, .reg = &op_reg },
1205 break :blk op_reg;
1206 }
1207
1208 break :blk try self.register_manager.allocReg(null, gp);
1209 };1206 };
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
1211 _ = try self.addInst(.{1219 _ = try self.addInst(.{
1212 .tag = .eor,1220 .tag = .eor,
...@@ -1223,26 +1231,28 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1223,26 +1231,28 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1223 .Int => {1231 .Int => {
1224 const int_info = operand_ty.intInfo(self.target.*);1232 const int_info = operand_ty.intInfo(self.target.*);
1225 if (int_info.bits <= 32) {1233 if (int_info.bits <= 32) {
1226 const op_reg = switch (operand) {1234 var op_reg: Register = undefined;
1227 .register => |r| r,1235 var dest_reg: Register = undefined;
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 }
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 },
1239 };1239 };
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
1241 _ = try self.addInst(.{1252 _ = try self.addInst(.{
1242 .tag = .mvn,1253 .tag = .mvn,
1243 .data = .{ .rr_op = .{1254 .data = .{ .r_op_mov = .{
1244 .rd = dest_reg,1255 .rd = dest_reg,
1245 .rn = undefined,
1246 .op = Instruction.Operand.reg(op_reg, Instruction.Operand.Shift.none),1256 .op = Instruction.Operand.reg(op_reg, Instruction.Operand.Shift.none),
1247 } },1257 } },
1248 });1258 });
...@@ -1267,11 +1277,11 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1267,11 +1277,11 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1267fn minMax(1277fn minMax(
1268 self: *Self,1278 self: *Self,
1269 tag: Air.Inst.Tag,1279 tag: Air.Inst.Tag,
1270 maybe_inst: ?Air.Inst.Index,1280 lhs_bind: ReadArg.Bind,
1271 lhs: MCValue,1281 rhs_bind: ReadArg.Bind,
1272 rhs: MCValue,
1273 lhs_ty: Type,1282 lhs_ty: Type,
1274 rhs_ty: Type,1283 rhs_ty: Type,
1284 maybe_inst: ?Air.Inst.Index,
1275) !MCValue {1285) !MCValue {
1276 switch (lhs_ty.zigTypeTag()) {1286 switch (lhs_ty.zigTypeTag()) {
1277 .Float => return self.fail("TODO ARM min/max on floats", .{}),1287 .Float => return self.fail("TODO ARM min/max on floats", .{}),
...@@ -1281,34 +1291,25 @@ fn minMax(...@@ -1281,34 +1291,25 @@ fn minMax(
1281 assert(lhs_ty.eql(rhs_ty, mod));1291 assert(lhs_ty.eql(rhs_ty, mod));
1282 const int_info = lhs_ty.intInfo(self.target.*);1292 const int_info = lhs_ty.intInfo(self.target.*);
1283 if (int_info.bits <= 32) {1293 if (int_info.bits <= 32) {
1284 const lhs_is_register = lhs == .register;1294 var lhs_reg: Register = undefined;
1285 const rhs_is_register = rhs == .register;1295 var rhs_reg: Register = undefined;
1296 var dest_reg: Register = undefined;
12861297
1287 const lhs_reg = switch (lhs) {1298 const read_args = [_]ReadArg{
1288 .register => |r| r,1299 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
1289 else => try self.copyToTmpRegister(lhs_ty, lhs),1300 .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
1290 };1301 };
1291 const lhs_reg_lock = self.register_manager.lockReg(lhs_reg);1302 const write_args = [_]WriteArg{
1292 defer if (lhs_reg_lock) |reg| self.register_manager.unlockReg(reg);1303 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1293
1294 const rhs_reg = switch (rhs) {
1295 .register => |r| r,
1296 else => try self.copyToTmpRegister(rhs_ty, rhs),
1297 };1304 };
1298 const rhs_reg_lock = self.register_manager.lockReg(rhs_reg);1305 try self.allocRegs(
1299 defer if (rhs_reg_lock) |reg| self.register_manager.unlockReg(reg);1306 &read_args,
13001307 &write_args,
1301 const dest_reg = if (maybe_inst) |inst| blk: {1308 if (maybe_inst) |inst| .{
1302 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1309 .corresponding_inst = inst,
13031310 .operand_mapping = &.{ 0, 1 },
1304 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {1311 } else null,
1305 break :blk lhs_reg;1312 );
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);
13121313
1313 // lhs == reg should have been checked by airMinMax1314 // lhs == reg should have been checked by airMinMax
1314 //1315 //
...@@ -1318,7 +1319,13 @@ fn minMax(...@@ -1318,7 +1319,13 @@ fn minMax(
1318 // register.1319 // register.
1319 assert(lhs_reg != rhs_reg); // see note above1320 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
1323 const cond_choose_lhs: Condition = switch (tag) {1330 const cond_choose_lhs: Condition = switch (tag) {
1324 .max => switch (int_info.signedness) {1331 .max => switch (int_info.signedness) {
...@@ -1337,9 +1344,8 @@ fn minMax(...@@ -1337,9 +1344,8 @@ fn minMax(
1337 _ = try self.addInst(.{1344 _ = try self.addInst(.{
1338 .tag = .mov,1345 .tag = .mov,
1339 .cond = cond_choose_lhs,1346 .cond = cond_choose_lhs,
1340 .data = .{ .rr_op = .{1347 .data = .{ .r_op_mov = .{
1341 .rd = dest_reg,1348 .rd = dest_reg,
1342 .rn = .r0,
1343 .op = Instruction.Operand.reg(lhs_reg, Instruction.Operand.Shift.none),1349 .op = Instruction.Operand.reg(lhs_reg, Instruction.Operand.Shift.none),
1344 } },1350 } },
1345 });1351 });
...@@ -1348,9 +1354,8 @@ fn minMax(...@@ -1348,9 +1354,8 @@ fn minMax(
1348 _ = try self.addInst(.{1354 _ = try self.addInst(.{
1349 .tag = .mov,1355 .tag = .mov,
1350 .cond = cond_choose_rhs,1356 .cond = cond_choose_rhs,
1351 .data = .{ .rr_op = .{1357 .data = .{ .r_op_mov = .{
1352 .rd = dest_reg,1358 .rd = dest_reg,
1353 .rn = .r0,
1354 .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),1359 .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
1355 } },1360 } },
1356 });1361 });
...@@ -1368,15 +1373,17 @@ fn minMax(...@@ -1368,15 +1373,17 @@ fn minMax(
1368fn airMinMax(self: *Self, inst: Air.Inst.Index) !void {1373fn airMinMax(self: *Self, inst: Air.Inst.Index) !void {
1369 const tag = self.air.instructions.items(.tag)[inst];1374 const tag = self.air.instructions.items(.tag)[inst];
1370 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1375 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);
1373 const lhs_ty = self.air.typeOf(bin_op.lhs);1376 const lhs_ty = self.air.typeOf(bin_op.lhs);
1374 const rhs_ty = self.air.typeOf(bin_op.rhs);1377 const rhs_ty = self.air.typeOf(bin_op.rhs);
13751378
1376 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1379 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);
1377 if (bin_op.lhs == bin_op.rhs) break :result lhs;1384 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);
1380 };1387 };
1381 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1388 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1382}1389}
...@@ -1390,7 +1397,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1390,7 +1397,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1390 const len = try self.resolveInst(bin_op.rhs);1397 const len = try self.resolveInst(bin_op.rhs);
1391 const len_ty = self.air.typeOf(bin_op.rhs);1398 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);
1394 try self.genSetStack(ptr_ty, stack_offset, ptr);1401 try self.genSetStack(ptr_ty, stack_offset, ptr);
1395 try self.genSetStack(len_ty, stack_offset - 4, len);1402 try self.genSetStack(len_ty, stack_offset - 4, len);
1396 break :result MCValue{ .stack_offset = stack_offset };1403 break :result MCValue{ .stack_offset = stack_offset };
...@@ -1400,38 +1407,65 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1400,38 +1407,65 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
14001407
1401fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {1408fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1402 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1409 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);
1405 const lhs_ty = self.air.typeOf(bin_op.lhs);1410 const lhs_ty = self.air.typeOf(bin_op.lhs);
1406 const rhs_ty = self.air.typeOf(bin_op.rhs);1411 const rhs_ty = self.air.typeOf(bin_op.rhs);
14071412
1408 const result: MCValue = if (self.liveness.isUnused(inst))1413 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1409 .dead1414 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
1410 else1415 const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
1411 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{1416
1412 .lhs = bin_op.lhs,1417 break :result switch (tag) {
1413 .rhs = bin_op.rhs,1418 .add => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1414 .inst = inst,1419 .sub => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1415 });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 };
1416 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1454 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1417}1455}
14181456
1419fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {1457fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1420 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1458 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1421 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;1459 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);
1424 const lhs_ty = self.air.typeOf(bin_op.lhs);1460 const lhs_ty = self.air.typeOf(bin_op.lhs);
1425 const rhs_ty = self.air.typeOf(bin_op.rhs);1461 const rhs_ty = self.air.typeOf(bin_op.rhs);
14261462
1427 const result: MCValue = if (self.liveness.isUnused(inst))1463 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1428 .dead1464 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
1429 else1465 const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
1430 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{1466
1431 .lhs = bin_op.lhs,1467 break :result try self.ptrArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst);
1432 .rhs = bin_op.rhs,1468 };
1433 .inst = inst,
1434 });
1435 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1469 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1436}1470}
14371471
...@@ -1458,8 +1492,8 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1458,8 +1492,8 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1458 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1492 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1459 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;1493 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
1460 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1494 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1461 const lhs = try self.resolveInst(extra.lhs);1495 const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
1462 const rhs = try self.resolveInst(extra.rhs);1496 const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
1463 const lhs_ty = self.air.typeOf(extra.lhs);1497 const lhs_ty = self.air.typeOf(extra.lhs);
1464 const rhs_ty = self.air.typeOf(extra.rhs);1498 const rhs_ty = self.air.typeOf(extra.rhs);
14651499
...@@ -1475,17 +1509,16 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1475,17 +1509,16 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1475 assert(lhs_ty.eql(rhs_ty, mod));1509 assert(lhs_ty.eql(rhs_ty, mod));
1476 const int_info = lhs_ty.intInfo(self.target.*);1510 const int_info = lhs_ty.intInfo(self.target.*);
1477 if (int_info.bits < 32) {1511 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
1480 try self.spillCompareFlagsIfOccupied();1514 try self.spillCompareFlagsIfOccupied();
1481 self.cpsr_flags_inst = null;
14821515
1483 const base_tag: Air.Inst.Tag = switch (tag) {1516 const base_tag: Air.Inst.Tag = switch (tag) {
1484 .add_with_overflow => .add,1517 .add_with_overflow => .add,
1485 .sub_with_overflow => .sub,1518 .sub_with_overflow => .sub,
1486 else => unreachable,1519 else => unreachable,
1487 };1520 };
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);
1489 const dest_reg = dest.register;1522 const dest_reg = dest.register;
1490 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1523 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1491 defer self.register_manager.unlockReg(dest_reg_lock);1524 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -1498,25 +1531,34 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1498,25 +1531,34 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1498 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);1531 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
14991532
1500 // cmp dest, truncated1533 // 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
1503 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1542 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1504 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });1543 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });
15051544
1506 break :result MCValue{ .stack_offset = stack_offset };1545 break :result MCValue{ .stack_offset = stack_offset };
1507 } else if (int_info.bits == 32) {1546 } 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
1508 // Only say yes if the operation is1550 // Only say yes if the operation is
1509 // commutative, i.e. we can swap both of the1551 // commutative, i.e. we can swap both of the
1510 // operands1552 // operands
1511 const lhs_immediate_ok = switch (tag) {1553 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,
1513 .sub_with_overflow => false,1555 .sub_with_overflow => false,
1514 else => unreachable,1556 else => unreachable,
1515 };1557 };
1516 const rhs_immediate_ok = switch (tag) {1558 const rhs_immediate_ok = switch (tag) {
1517 .add_with_overflow,1559 .add_with_overflow,
1518 .sub_with_overflow,1560 .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,
1520 else => unreachable,1562 else => unreachable,
1521 };1563 };
15221564
...@@ -1531,12 +1573,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1531,12 +1573,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
15311573
1532 const dest = blk: {1574 const dest = blk: {
1533 if (rhs_immediate_ok) {1575 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);
1535 } else if (lhs_immediate_ok) {1577 } else if (lhs_immediate_ok) {
1536 // swap lhs and rhs1578 // 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);
1538 } else {1580 } 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);
1540 }1582 }
1541 };1583 };
15421584
...@@ -1563,8 +1605,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1563,8 +1605,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1563 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;1605 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
1564 if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });1606 if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
1565 const result: MCValue = result: {1607 const result: MCValue = result: {
1566 const lhs = try self.resolveInst(extra.lhs);1608 const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
1567 const rhs = try self.resolveInst(extra.rhs);1609 const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
1568 const lhs_ty = self.air.typeOf(extra.lhs);1610 const lhs_ty = self.air.typeOf(extra.lhs);
1569 const rhs_ty = self.air.typeOf(extra.rhs);1611 const rhs_ty = self.air.typeOf(extra.rhs);
15701612
...@@ -1580,17 +1622,16 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1580,17 +1622,16 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1580 assert(lhs_ty.eql(rhs_ty, mod));1622 assert(lhs_ty.eql(rhs_ty, mod));
1581 const int_info = lhs_ty.intInfo(self.target.*);1623 const int_info = lhs_ty.intInfo(self.target.*);
1582 if (int_info.bits <= 16) {1624 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
1585 try self.spillCompareFlagsIfOccupied();1627 try self.spillCompareFlagsIfOccupied();
1586 self.cpsr_flags_inst = null;
15871628
1588 const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {1629 const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {
1589 .signed => .smulbb,1630 .signed => .smulbb,
1590 .unsigned => .mul,1631 .unsigned => .mul,
1591 };1632 };
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);
1594 const dest_reg = dest.register;1635 const dest_reg = dest.register;
1595 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1636 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1596 defer self.register_manager.unlockReg(dest_reg_lock);1637 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -1603,62 +1644,48 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1603,62 +1644,48 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1603 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);1644 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
16041645
1605 // cmp dest, truncated1646 // 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
1608 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1655 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1609 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });1656 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });
16101657
1611 break :result MCValue{ .stack_offset = stack_offset };1658 break :result MCValue{ .stack_offset = stack_offset };
1612 } else if (int_info.bits <= 32) {1659 } 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
1615 try self.spillCompareFlagsIfOccupied();1662 try self.spillCompareFlagsIfOccupied();
1616 self.cpsr_flags_inst = null;
16171663
1618 const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {1664 const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {
1619 .signed => .smull,1665 .signed => .smull,
1620 .unsigned => .umull,1666 .unsigned => .umull,
1621 };1667 };
16221668
1623 // TODO extract umull etc. to binOpTwoRegister1669 var lhs_reg: Register = undefined;
1624 // once MCValue.rr is implemented1670 var rhs_reg: Register = undefined;
1625 const lhs_is_register = lhs == .register;1671 var rdhi: Register = undefined;
1626 const rhs_is_register = rhs == .register;1672 var rdlo: Register = undefined;
16271673 var truncated_reg: Register = undefined;
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);
16581674
1659 const truncated_reg = try self.register_manager.allocReg(null, gp);1675 const read_args = [_]ReadArg{
1660 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);1676 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
1661 defer self.register_manager.unlockReg(truncated_reg_lock);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
1663 _ = try self.addInst(.{1690 _ = try self.addInst(.{
1664 .tag = base_tag,1691 .tag = base_tag,
...@@ -1677,14 +1704,19 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1677,14 +1704,19 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1677 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1704 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
16781705
1679 // cmp truncated, rdlo1706 // 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
1682 // mov rdlo, #01715 // mov rdlo, #0
1683 _ = try self.addInst(.{1716 _ = try self.addInst(.{
1684 .tag = .mov,1717 .tag = .mov,
1685 .data = .{ .rr_op = .{1718 .data = .{ .r_op_mov = .{
1686 .rd = rdlo,1719 .rd = rdlo,
1687 .rn = .r0,
1688 .op = Instruction.Operand.fromU32(0).?,1720 .op = Instruction.Operand.fromU32(0).?,
1689 } },1721 } },
1690 });1722 });
...@@ -1693,23 +1725,27 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1693,23 +1725,27 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1693 _ = try self.addInst(.{1725 _ = try self.addInst(.{
1694 .tag = .mov,1726 .tag = .mov,
1695 .cond = .ne,1727 .cond = .ne,
1696 .data = .{ .rr_op = .{1728 .data = .{ .r_op_mov = .{
1697 .rd = rdlo,1729 .rd = rdlo,
1698 .rn = .r0,
1699 .op = Instruction.Operand.fromU32(1).?,1730 .op = Instruction.Operand.fromU32(1).?,
1700 } },1731 } },
1701 });1732 });
17021733
1703 // cmp rdhi, #01734 // 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
1706 // movne rdlo, #11743 // movne rdlo, #1
1707 _ = try self.addInst(.{1744 _ = try self.addInst(.{
1708 .tag = .mov,1745 .tag = .mov,
1709 .cond = .ne,1746 .cond = .ne,
1710 .data = .{ .rr_op = .{1747 .data = .{ .r_op_mov = .{
1711 .rd = rdlo,1748 .rd = rdlo,
1712 .rn = .r0,
1713 .op = Instruction.Operand.fromU32(1).?,1749 .op = Instruction.Operand.fromU32(1).?,
1714 } },1750 } },
1715 });1751 });
...@@ -1733,8 +1769,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1733,8 +1769,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1733 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;1769 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
1734 if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });1770 if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
1735 const result: MCValue = result: {1771 const result: MCValue = result: {
1736 const lhs = try self.resolveInst(extra.lhs);
1737 const rhs = try self.resolveInst(extra.rhs);
1738 const lhs_ty = self.air.typeOf(extra.lhs);1772 const lhs_ty = self.air.typeOf(extra.lhs);
1739 const rhs_ty = self.air.typeOf(extra.rhs);1773 const rhs_ty = self.air.typeOf(extra.rhs);
17401774
...@@ -1748,30 +1782,109 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1748,30 +1782,109 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1748 .Int => {1782 .Int => {
1749 const int_info = lhs_ty.intInfo(self.target.*);1783 const int_info = lhs_ty.intInfo(self.target.*);
1750 if (int_info.bits <= 32) {1784 if (int_info.bits <= 32) {
1751 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);1785 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
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);
17581786
1759 try self.spillCompareFlagsIfOccupied();1787 try self.spillCompareFlagsIfOccupied();
1760 self.cpsr_flags_inst = null;
17611788
1762 // lsl dest, lhs, rhs1789 const shr_mir_tag: Mir.Inst.Tag = switch (int_info.signedness) {
1763 const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null);1790 .signed => Mir.Inst.Tag.asr,
1764 const dest_reg = dest.register;1791 .unsigned => Mir.Inst.Tag.lsr,
1765 const dest_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1792 };
1766 defer self.register_manager.unlockReg(dest_lock);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, rhs1867 // asr/lsr reconstructed, dest, rhs
1769 const reconstructed = try self.binOp(.shr, dest, rhs, lhs_ty, rhs_ty, null);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
1771 // cmp lhs, reconstructed1878 // 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 });
1775 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });1888 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne });
17761889
1777 break :result MCValue{ .stack_offset = stack_offset };1890 break :result MCValue{ .stack_offset = stack_offset };
...@@ -1826,19 +1939,57 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {...@@ -1826,19 +1939,57 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1826}1939}
18271940
1828/// Given an error union, returns the error1941/// 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 {
1830 const err_ty = error_union_ty.errorUnionSet();1948 const err_ty = error_union_ty.errorUnionSet();
1831 const payload_ty = error_union_ty.errorUnionPayload();1949 const payload_ty = error_union_ty.errorUnionPayload();
1832 if (err_ty.errorSetIsEmpty()) {1950 if (err_ty.errorSetIsEmpty()) {
1833 return MCValue{ .immediate = 0 };1951 return MCValue{ .immediate = 0 };
1834 }1952 }
1835 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {1953 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1836 return error_union_mcv;1954 return try error_union_bind.resolveToMcv(self);
1837 }1955 }
18381956
1839 const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));1957 const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));
1840 switch (error_union_mcv) {1958 switch (try error_union_bind.resolveToMcv(self)) {
1841 .register => return self.fail("TODO errUnionErr for registers", .{}),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 },
1842 .stack_argument_offset => |off| {1993 .stack_argument_offset => |off| {
1843 return MCValue{ .stack_argument_offset = off + err_offset };1994 return MCValue{ .stack_argument_offset = off + err_offset };
1844 },1995 },
...@@ -1855,27 +2006,66 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV...@@ -1855,27 +2006,66 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV
1855fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {2006fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
1856 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2007 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1857 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2008 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2009 const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand };
1858 const error_union_ty = self.air.typeOf(ty_op.operand);2010 const error_union_ty = self.air.typeOf(ty_op.operand);
1859 const mcv = try self.resolveInst(ty_op.operand);2011
1860 break :result try self.errUnionErr(mcv, error_union_ty);2012 break :result try self.errUnionErr(error_union_bind, error_union_ty, inst);
1861 };2013 };
1862 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2014 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1863}2015}
18642016
1865/// Given an error union, returns the payload2017/// 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 {
1867 const err_ty = error_union_ty.errorUnionSet();2024 const err_ty = error_union_ty.errorUnionSet();
1868 const payload_ty = error_union_ty.errorUnionPayload();2025 const payload_ty = error_union_ty.errorUnionPayload();
1869 if (err_ty.errorSetIsEmpty()) {2026 if (err_ty.errorSetIsEmpty()) {
1870 return error_union_mcv;2027 return try error_union_bind.resolveToMcv(self);
1871 }2028 }
1872 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {2029 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1873 return MCValue.none;2030 return MCValue.none;
1874 }2031 }
18752032
1876 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));2033 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));
1877 switch (error_union_mcv) {2034 switch (try error_union_bind.resolveToMcv(self)) {
1878 .register => return self.fail("TODO errUnionPayload for registers", .{}),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 },
1879 .stack_argument_offset => |off| {2069 .stack_argument_offset => |off| {
1880 return MCValue{ .stack_argument_offset = off + payload_offset };2070 return MCValue{ .stack_argument_offset = off + payload_offset };
1881 },2071 },
...@@ -1892,9 +2082,10 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)...@@ -1892,9 +2082,10 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
1892fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {2082fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1893 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2083 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1894 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2084 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2085 const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand };
1895 const error_union_ty = self.air.typeOf(ty_op.operand);2086 const error_union_ty = self.air.typeOf(ty_op.operand);
1896 const error_union = try self.resolveInst(ty_op.operand);2087
1897 break :result try self.errUnionPayload(error_union, error_union_ty);2088 break :result try self.errUnionPayload(error_union_bind, error_union_ty, inst);
1898 };2089 };
1899 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2090 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1900}2091}
...@@ -1938,17 +2129,18 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1938,17 +2129,18 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
1938 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2129 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1939 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2130 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1940 const error_union_ty = self.air.getRefType(ty_op.ty);2131 const error_union_ty = self.air.getRefType(ty_op.ty);
2132 const error_ty = error_union_ty.errorUnionSet();
1941 const payload_ty = error_union_ty.errorUnionPayload();2133 const payload_ty = error_union_ty.errorUnionPayload();
1942 const operand = try self.resolveInst(ty_op.operand);2134 const operand = try self.resolveInst(ty_op.operand);
1943 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand;2135 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand;
19442136
1945 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));2137 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
1946 const abi_align = error_union_ty.abiAlignment(self.target.*);2138 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));
1948 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);2140 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
1949 const err_off = errUnionErrorOffset(payload_ty, self.target.*);2141 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
1950 try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand);2142 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
1953 break :result MCValue{ .stack_offset = stack_offset };2145 break :result MCValue{ .stack_offset = stack_offset };
1954 };2146 };
...@@ -1960,16 +2152,17 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1960,16 +2152,17 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
1960 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2152 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1961 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2153 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1962 const error_union_ty = self.air.getRefType(ty_op.ty);2154 const error_union_ty = self.air.getRefType(ty_op.ty);
2155 const error_ty = error_union_ty.errorUnionSet();
1963 const payload_ty = error_union_ty.errorUnionPayload();2156 const payload_ty = error_union_ty.errorUnionPayload();
1964 const operand = try self.resolveInst(ty_op.operand);2157 const operand = try self.resolveInst(ty_op.operand);
1965 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand;2158 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand;
19662159
1967 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));2160 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
1968 const abi_align = error_union_ty.abiAlignment(self.target.*);2161 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));
1970 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);2163 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
1971 const err_off = errUnionErrorOffset(payload_ty, self.target.*);2164 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);
1973 try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef);2166 try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef);
19742167
1975 break :result MCValue{ .stack_offset = stack_offset };2168 break :result MCValue{ .stack_offset = stack_offset };
...@@ -2008,7 +2201,6 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -2008,7 +2201,6 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
2008 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2201 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2009 const mcv = try self.resolveInst(ty_op.operand);2202 const mcv = try self.resolveInst(ty_op.operand);
2010 switch (mcv) {2203 switch (mcv) {
2011 .dead, .unreach => unreachable,
2012 .register => unreachable, // a slice doesn't fit in one register2204 .register => unreachable, // a slice doesn't fit in one register
2013 .stack_argument_offset => |off| {2205 .stack_argument_offset => |off| {
2014 break :result MCValue{ .stack_argument_offset = off + 4 };2206 break :result MCValue{ .stack_argument_offset = off + 4 };
...@@ -2019,7 +2211,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -2019,7 +2211,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
2019 .memory => |addr| {2211 .memory => |addr| {
2020 break :result MCValue{ .memory = addr + 4 };2212 break :result MCValue{ .memory = addr + 4 };
2021 },2213 },
2022 else => return self.fail("TODO implement slice_len for {}", .{mcv}),2214 else => unreachable, // invalid MCValue for a slice
2023 }2215 }
2024 };2216 };
2025 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2217 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -2034,7 +2226,12 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2034,7 +2226,12 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
2034 .ptr_stack_offset => |off| {2226 .ptr_stack_offset => |off| {
2035 break :result MCValue{ .ptr_stack_offset = off - 4 };2227 break :result MCValue{ .ptr_stack_offset = off - 4 };
2036 },2228 },
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 },
2038 }2235 }
2039 };2236 };
2040 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2237 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -2049,91 +2246,96 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2049,91 +2246,96 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
2049 .ptr_stack_offset => |off| {2246 .ptr_stack_offset => |off| {
2050 break :result MCValue{ .ptr_stack_offset = off };2247 break :result MCValue{ .ptr_stack_offset = off };
2051 },2248 },
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 },
2053 }2256 }
2054 };2257 };
2055 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2258 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2056}2259}
20572260
2058fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {2261fn ptrElemVal(
2059 const is_volatile = false; // TODO2262 self: *Self,
2060 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2263 ptr_bind: ReadArg.Bind,
20612264 index_bind: ReadArg.Bind,
2062 if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });2265 ptr_ty: Type,
2063 const result: MCValue = result: {2266 maybe_inst: ?Air.Inst.Index,
2064 const slice_mcv = try self.resolveInst(bin_op.lhs);2267) !MCValue {
20652268 const elem_ty = ptr_ty.childType();
2066 // TODO optimize for the case where the index is a constant,2269 const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
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);
20772270
2078 const index_lock: ?RegisterLock = if (index_is_register)2271 switch (elem_size) {
2079 self.register_manager.lockRegAssumeUnused(index_mcv.register)2272 1, 4 => {
2080 else2273 var base_reg: Register = undefined;
2081 null;2274 var index_reg: Register = undefined;
2082 defer if (index_lock) |reg| self.register_manager.unlockReg(reg);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) {2304 _ = try self.addInst(.{
2087 1, 4 => {2305 .tag = tag,
2088 const base_reg = switch (base_mcv) {2306 .data = .{ .rr_offset = .{
2089 .register => |r| r,2307 .rt = dest_reg,
2090 else => try self.copyToTmpRegister(slice_ptr_field_type, base_mcv),2308 .rn = base_reg,
2091 };2309 .offset = .{ .offset = Instruction.Offset.reg(index_reg, .{ .lsl = shift }) },
2092 const base_reg_lock = self.register_manager.lockRegAssumeUnused(base_reg);2310 } },
2093 defer self.register_manager.unlockReg(base_reg_lock);2311 });
20942312
2095 const dst_reg = try self.register_manager.allocReg(inst, gp);2313 return MCValue{ .register = dest_reg };
2096 const dst_mcv = MCValue{ .register = dst_reg };2314 },
2097 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);2315 else => {
2098 defer self.register_manager.unlockReg(dst_reg_lock);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) {2318 const dest = try self.allocRegOrMem(elem_ty, true, maybe_inst);
2101 .register => |reg| reg,2319 try self.load(dest, addr, ptr_ty);
2102 else => try self.copyToTmpRegister(Type.usize, index_mcv),2320 return dest;
2103 };2321 },
2104 const index_reg_lock = self.register_manager.lockReg(index_reg);2322 }
2105 defer if (index_reg_lock) |lock| self.register_manager.unlockReg(lock);2323}
21062324
2107 const tag: Mir.Inst.Tag = switch (elem_size) {2325fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2108 1 => .ldrb,2326 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2109 4 => .ldr,2327 const slice_ty = self.air.typeOf(bin_op.lhs);
2110 else => unreachable,2328 const result: MCValue = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
2111 };2329 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
2112 const shift: u5 = switch (elem_size) {2330 const ptr_ty = slice_ty.slicePtrFieldType(&buf);
2113 1 => 0,
2114 4 => 2,
2115 else => unreachable,
2116 };
21172331
2118 _ = try self.addInst(.{2332 const slice_mcv = try self.resolveInst(bin_op.lhs);
2119 .tag = tag,2333 const base_mcv = slicePtr(slice_mcv);
2120 .data = .{ .rr_offset = .{
2121 .rt = dst_reg,
2122 .rn = base_reg,
2123 .offset = .{ .offset = Instruction.Offset.reg(index_reg, .{ .lsl = shift }) },
2124 } },
2125 });
21262334
2127 break :result dst_mcv;2335 const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };
2128 },2336 const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
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);
21332337
2134 break :result dest;2338 break :result try self.ptrElemVal(base_bind, index_bind, ptr_ty, inst);
2135 },
2136 }
2137 };2339 };
2138 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2340 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2139}2341}
...@@ -2143,40 +2345,108 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2143,40 +2345,108 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2143 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;2345 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2144 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2346 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2145 const slice_mcv = try self.resolveInst(extra.lhs);2347 const slice_mcv = try self.resolveInst(extra.lhs);
2146 const index_mcv = try self.resolveInst(extra.rhs);
2147 const base_mcv = slicePtr(slice_mcv);2348 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
2149 const slice_ty = self.air.typeOf(extra.lhs);2353 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);
2152 break :result addr;2357 break :result addr;
2153 };2358 };
2154 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2359 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
2155}2360}
21562361
2157fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {2362fn arrayElemVal(
2158 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2363 self: *Self,
2159 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch});2364 array_bind: ReadArg.Bind,
2160 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2365 index_bind: ReadArg.Bind,
2161}2366 array_ty: Type,
21622367 maybe_inst: ?Air.Inst.Index,
2163fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {2368) InnerError!MCValue {
2164 const is_volatile = false; // TODO2369 const elem_ty = array_ty.childType();
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}
21692370
2170fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {2371 const mcv = try array_bind.resolveToMcv(self);
2171 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2372 switch (mcv) {
2172 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;2373 .stack_offset,
2173 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2374 .memory,
2174 const ptr_mcv = try self.resolveInst(extra.lhs);2375 .stack_argument_offset,
2175 const index_mcv = try self.resolveInst(extra.rhs);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);
2180 break :result addr;2450 break :result addr;
2181 };2451 };
2182 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2452 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
...@@ -2240,7 +2510,13 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {...@@ -2240,7 +2510,13 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
2240 return self.finishAir(inst, result, .{ un_op, .none, .none });2510 return self.finishAir(inst, result, .{ un_op, .none, .none });
2241}2511}
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 {
2244 if (!self.liveness.operandDies(inst, op_index))2520 if (!self.liveness.operandDies(inst, op_index))
2245 return false;2521 return false;
22462522
...@@ -2362,16 +2638,18 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -2362,16 +2638,18 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
2362 if (self.liveness.isUnused(inst) and !is_volatile)2638 if (self.liveness.isUnused(inst) and !is_volatile)
2363 break :result MCValue.dead;2639 break :result MCValue.dead;
23642640
2365 const dst_mcv: MCValue = blk: {2641 const dest_mcv: MCValue = blk: {
2366 if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) {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)) {
2367 // The MCValue that holds the pointer can be re-used as the value.2644 // The MCValue that holds the pointer can be re-used as the value.
2368 break :blk ptr;2645 break :blk ptr;
2369 } else {2646 } else {
2370 break :blk try self.allocRegOrMem(inst, true);2647 break :blk try self.allocRegOrMem(elem_ty, true, inst);
2371 }2648 }
2372 };2649 };
2373 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));2650 try self.load(dest_mcv, ptr, self.air.typeOf(ty_op.operand));
2374 break :result dst_mcv;2651
2652 break :result dest_mcv;
2375 };2653 };
2376 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2654 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2377}2655}
...@@ -2498,26 +2776,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2498,26 +2776,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
2498 break :result MCValue{ .ptr_stack_offset = off - struct_field_offset };2776 break :result MCValue{ .ptr_stack_offset = off - struct_field_offset };
2499 },2777 },
2500 else => {2778 else => {
2501 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{2779 const lhs_bind: ReadArg.Bind = .{ .mcv = mcv };
2502 .immediate = struct_field_offset,2780 const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .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 );
25192781
2520 break :result dest;2782 break :result try self.addSub(.add, lhs_bind, rhs_bind, Type.usize, Type.usize, null);
2521 },2783 },
2522 }2784 }
2523 };2785 };
...@@ -2532,6 +2794,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2532,6 +2794,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2532 const mcv = try self.resolveInst(operand);2794 const mcv = try self.resolveInst(operand);
2533 const struct_ty = self.air.typeOf(operand);2795 const struct_ty = self.air.typeOf(operand);
2534 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));2796 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
2797 const struct_field_ty = struct_ty.structFieldType(index);
25352798
2536 switch (mcv) {2799 switch (mcv) {
2537 .dead, .unreach => unreachable,2800 .dead, .unreach => unreachable,
...@@ -2569,11 +2832,45 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2569,11 +2832,45 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2569 } else {2832 } else {
2570 // Copy to new register2833 // Copy to new register
2571 const dest_reg = try self.register_manager.allocReg(null, gp);2834 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
2574 break :result MCValue{ .register = dest_reg };2837 break :result MCValue{ .register = dest_reg };
2575 }2838 }
2576 },2839 },
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 },
2577 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),2874 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
2578 }2875 }
2579 };2876 };
...@@ -2583,114 +2880,285 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2583,114 +2880,285 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
25832880
2584fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {2881fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
2585 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2882 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2586 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;2883 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
2587 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFieldParentPtr", .{});2884 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2588 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });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 });
2589}2901}
25902902
2591/// Allocates a new register. If Inst in non-null, additionally tracks2903/// An argument to a Mir instruction which is read (and possibly also
2592/// this register and the corresponding int and removes all previous2904/// written to) by the respective instruction
2593/// tracking. Does not do the actual moving (that is handled by2905const ReadArg = struct {
2594/// genSetReg).2906 ty: Type,
2595fn prepareNewRegForMoving(2907 bind: Bind,
2596 self: *Self,2908 class: RegisterManager.RegisterBitSet,
2597 track_inst: ?Air.Inst.Index,2909 reg: *Register,
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);
26032910
2604 if (track_inst) |inst| {2911 const Bind = union(enum) {
2605 // Overwrite the MCValue associated with this inst2912 inst: Air.Inst.Ref,
2606 branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });2913 mcv: MCValue,
26072914
2608 // If the previous MCValue occupied some space we track, we2915 fn resolveToMcv(bind: Bind, function: *Self) InnerError!MCValue {
2609 // need to make sure it is marked as free now.2916 return switch (bind) {
2610 switch (mcv) {2917 .inst => |inst| try function.resolveInst(inst),
2611 .cpsr_flags => {2918 .mcv => |mcv| mcv,
2612 assert(self.cpsr_flags_inst.? == inst);2919 };
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 => {},
2620 }2920 }
2621 }
26222921
2623 return reg;2922 fn resolveToImmediate(bind: Bind, function: *Self) InnerError!?u32 {
2624}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
2627///2976///
2628/// Calling this function signals an intention to generate a Mir2977/// If the Mir instruction these registers are allocated for
2629/// instruction of the form2978/// 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).
2630///2982///
2631/// op dest, lhs, rhs2983/// 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.
2632///2987///
2633/// Asserts that generating an instruction of that form is possible.2988/// Furthermore, allocReg guarantees that all arguments which are
2634fn binOpRegister(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(
2635 self: *Self,2993 self: *Self,
2636 mir_tag: Mir.Inst.Tag,2994 read_args: []const ReadArg,
2637 lhs: MCValue,2995 write_args: []const WriteArg,
2638 rhs: MCValue,2996 reuse_metadata: ?ReuseMetadata,
2639 lhs_ty: Type,2997) InnerError!void {
2640 rhs_ty: Type,2998 // Air instructions have exactly one output
2641 metadata: ?BinOpMetadata,2999 assert(!(reuse_metadata != null and write_args.len != 1)); // see note above
2642) !MCValue {3000
2643 const lhs_is_register = lhs == .register;3001 // The operand mapping is a 1:1 mapping of read args to their
2644 const rhs_is_register = rhs == .register;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)3015 // When we reuse a read_arg as a destination, the corresponding
2647 self.register_manager.lockReg(lhs.register)3016 // MCValue of the read_arg will be set to .dead. In that case, we
2648 else3017 // skip allocating this read_arg.
2649 null;3018 var reused_read_arg: ?usize = null;
2650 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
26513019
2652 const lhs_reg = if (lhs_is_register) lhs.register else blk: {3020 // Lock all args which are already allocated to registers
2653 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {3021 for (read_args) |arg, i| {
2654 break :inst Air.refToIndex(md.lhs).?;3022 const mcv = try arg.bind.resolveToMcv(self);
2655 } else null;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);3028 for (write_args) |arg, i| {
2658 };3029 if (arg.bind == .reg) {
2659 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);3030 write_locks[i] = self.register_manager.lockReg(arg.bind.reg);
2660 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);3031 }
3032 }
26613033
2662 const rhs_reg = if (rhs_is_register) rhs.register else blk: {3034 // Allocate registers for all args which aren't allocated to
2663 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {3035 // registers yet
2664 break :inst Air.refToIndex(md.rhs).?;3036 for (read_args) |arg, i| {
2665 } else null;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);3050 if (reuse_metadata != null) {
2668 };3051 const inst = reuse_metadata.?.corresponding_inst;
2669 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);3052 const operand_mapping = reuse_metadata.?.operand_mapping;
2670 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);3053 const arg = write_args[0];
26713054 if (arg.bind == .reg) {
2672 const dest_reg = switch (mir_tag) {3055 arg.reg.* = arg.bind.reg;
2673 .cmp => .r0, // cmp has no destination regardless3056 } else {
2674 else => if (metadata) |md| blk: {3057 reuse_operand: for (read_args) |read_arg, i| {
2675 if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) {3058 if (read_arg.bind == .inst) {
2676 break :blk lhs_reg;3059 const operand = read_arg.bind.inst;
2677 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {3060 const mcv = try self.resolveInst(operand);
2678 break :blk rhs_reg;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 }
2679 } else {3071 } 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.*);
2681 }3074 }
2682 } else try self.register_manager.allocReg(null, gp),3075 }
2683 };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);3124/// Wrapper around allocRegs and addInst tailored for specific Mir
2686 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);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
2688 const mir_data: Mir.Inst.Data = switch (mir_tag) {3157 const mir_data: Mir.Inst.Data = switch (mir_tag) {
2689 .add,3158 .add,
2690 .adds,3159 .adds,
2691 .sub,3160 .sub,
2692 .subs,3161 .subs,
2693 .cmp,
2694 .@"and",3162 .@"and",
2695 .orr,3163 .orr,
2696 .eor,3164 .eor,
...@@ -2725,78 +3193,51 @@ fn binOpRegister(...@@ -2725,78 +3193,51 @@ fn binOpRegister(
2725 return MCValue{ .register = dest_reg };3193 return MCValue{ .register = dest_reg };
2726}3194}
27273195
2728/// Don't call this function directly. Use binOp instead.3196/// Wrapper around allocRegs and addInst tailored for specific Mir
2729///3197/// instructions which are binary operations acting on a register and
2730/// Calling this function signals an intention to generate a Mir3198/// an immediate
2731/// instruction of the form
2732///
2733/// op dest, lhs, #rhs_imm
2734///3199///
2735/// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to3200/// Returns the destination register
2736/// rhs and vice versa. This parameter is only used when maybe_inst !=3201fn binOpImmediateNew(
2737/// null.
2738///
2739/// Asserts that generating an instruction of that form is possible.
2740fn binOpImmediate(
2741 self: *Self,3202 self: *Self,
2742 mir_tag: Mir.Inst.Tag,3203 mir_tag: Mir.Inst.Tag,
2743 lhs: MCValue,3204 lhs_bind: ReadArg.Bind,
2744 rhs: MCValue,3205 rhs_immediate: u32,
2745 lhs_ty: Type,3206 lhs_ty: Type,
2746 lhs_and_rhs_swapped: bool,3207 lhs_and_rhs_swapped: bool,
2747 metadata: ?BinOpMetadata,3208 maybe_inst: ?Air.Inst.Index,
2748) !MCValue {3209) !MCValue {
2749 const lhs_is_register = lhs == .register;3210 var lhs_reg: Register = undefined;
27503211 var dest_reg: Register = undefined;
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;
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 },
2765 };3215 };
2766 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);3216 const write_args = [_]WriteArg{
2767 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);3217 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_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),
2783 };3218 };
27843219 const operand_mapping: []const Liveness.OperandInt = if (lhs_and_rhs_swapped) &.{1} else &.{0};
2785 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);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
2787 const mir_data: Mir.Inst.Data = switch (mir_tag) {3229 const mir_data: Mir.Inst.Data = switch (mir_tag) {
2788 .add,3230 .add,
2789 .adds,3231 .adds,
2790 .sub,3232 .sub,
2791 .subs,3233 .subs,
2792 .cmp,
2793 .@"and",3234 .@"and",
2794 .orr,3235 .orr,
2795 .eor,3236 .eor,
2796 => .{ .rr_op = .{3237 => .{ .rr_op = .{
2797 .rd = dest_reg,3238 .rd = dest_reg,
2798 .rn = lhs_reg,3239 .rn = lhs_reg,
2799 .op = Instruction.Operand.fromU32(rhs.immediate).?,3240 .op = Instruction.Operand.fromU32(rhs_immediate).?,
2800 } },3241 } },
2801 .lsl,3242 .lsl,
2802 .asr,3243 .asr,
...@@ -2804,7 +3245,7 @@ fn binOpImmediate(...@@ -2804,7 +3245,7 @@ fn binOpImmediate(
2804 => .{ .rr_shift = .{3245 => .{ .rr_shift = .{
2805 .rd = dest_reg,3246 .rd = dest_reg,
2806 .rm = lhs_reg,3247 .rm = lhs_reg,
2807 .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs.immediate)),3248 .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs_immediate)),
2808 } },3249 } },
2809 else => unreachable,3250 else => unreachable,
2810 };3251 };
...@@ -2817,417 +3258,502 @@ fn binOpImmediate(...@@ -2817,417 +3258,502 @@ fn binOpImmediate(
2817 return MCValue{ .register = dest_reg };3258 return MCValue{ .register = dest_reg };
2818}3259}
28193260
2820const BinOpMetadata = struct {3261fn addSub(
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(
2839 self: *Self,3262 self: *Self,
2840 tag: Air.Inst.Tag,3263 tag: Air.Inst.Tag,
2841 lhs: MCValue,3264 lhs_bind: ReadArg.Bind,
2842 rhs: MCValue,3265 rhs_bind: ReadArg.Bind,
2843 lhs_ty: Type,3266 lhs_ty: Type,
2844 rhs_ty: Type,3267 rhs_ty: Type,
2845 metadata: ?BinOpMetadata,3268 maybe_inst: ?Air.Inst.Index,
2846) InnerError!MCValue {3269) InnerError!MCValue {
2847 switch (tag) {3270 switch (lhs_ty.zigTypeTag()) {
2848 .add,3271 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
2849 .sub,3272 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
2850 .cmp_eq,3273 .Int => {
2851 => {3274 const mod = self.bin_file.options.module.?;
2852 switch (lhs_ty.zigTypeTag()) {3275 assert(lhs_ty.eql(rhs_ty, mod));
2853 .Float => return self.fail("TODO ARM binary operations on floats", .{}),3276 const int_info = lhs_ty.intInfo(self.target.*);
2854 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),3277 if (int_info.bits <= 32) {
2855 .Int => {3278 const lhs_immediate = try lhs_bind.resolveToImmediate(self);
2856 const mod = self.bin_file.options.module.?;3279 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
2857 assert(lhs_ty.eql(rhs_ty, mod));3280
2858 const int_info = lhs_ty.intInfo(self.target.*);3281 // Only say yes if the operation is
2859 if (int_info.bits <= 32) {3282 // commutative, i.e. we can swap both of the
2860 // Only say yes if the operation is3283 // operands
2861 // commutative, i.e. we can swap both of the3284 const lhs_immediate_ok = switch (tag) {
2862 // operands3285 .add => if (lhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false,
2863 const lhs_immediate_ok = switch (tag) {3286 .sub => false,
2864 .add => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null,3287 else => unreachable,
2865 .sub,3288 };
2866 .cmp_eq,3289 const rhs_immediate_ok = switch (tag) {
2867 => false,3290 .add,
2868 else => unreachable,3291 .sub,
2869 };3292 => if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false,
2870 const rhs_immediate_ok = switch (tag) {3293 else => unreachable,
2871 .add,3294 };
2872 .sub,
2873 .cmp_eq,
2874 => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null,
2875 else => unreachable,
2876 };
28773295
2878 const mir_tag: Mir.Inst.Tag = switch (tag) {3296 const mir_tag: Mir.Inst.Tag = switch (tag) {
2879 .add => .add,3297 .add => .add,
2880 .sub => .sub,3298 .sub => .sub,
2881 .cmp_eq => .cmp,3299 else => unreachable,
2882 else => unreachable,3300 };
2883 };
28843301
2885 if (rhs_immediate_ok) {3302 if (rhs_immediate_ok) {
2886 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);3303 return try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst);
2887 } else if (lhs_immediate_ok) {3304 } else if (lhs_immediate_ok) {
2888 // swap lhs and rhs3305 // swap lhs and rhs
2889 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);3306 return try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst);
2890 } else {3307 } else {
2891 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);3308 return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
2892 }3309 }
2893 } else {3310 } else {
2894 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});3311 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,
2918 }3312 }
2919 },3313 },
2920 .div_float => {3314 else => unreachable,
2921 switch (lhs_ty.zigTypeTag()) {3315 }
2922 .Float => return self.fail("TODO ARM binary operations on floats", .{}),3316}
2923 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),3317
2924 else => unreachable,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", .{});
2925 }3340 }
2926 },3341 },
2927 .div_trunc, .div_floor => {3342 else => unreachable,
2928 switch (lhs_ty.zigTypeTag()) {3343 }
2929 .Float => return self.fail("TODO ARM binary operations on floats", .{}),3344}
2930 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),3345
2931 .Int => {3346fn divFloat(
2932 const mod = self.bin_file.options.module.?;3347 self: *Self,
2933 assert(lhs_ty.eql(rhs_ty, mod));3348 lhs_bind: ReadArg.Bind,
2934 const int_info = lhs_ty.intInfo(self.target.*);3349 rhs_bind: ReadArg.Bind,
2935 if (int_info.bits <= 32) {3350 lhs_ty: Type,
2936 switch (int_info.signedness) {3351 rhs_ty: Type,
2937 .signed => {3352 maybe_inst: ?Air.Inst.Index,
2938 return self.fail("TODO ARM signed integer division", .{});3353) InnerError!MCValue {
2939 },3354 _ = lhs_bind;
2940 .unsigned => {3355 _ = rhs_bind;
2941 switch (rhs) {3356 _ = lhs_ty;
2942 .immediate => |imm| {3357 _ = rhs_ty;
2943 if (std.math.isPowerOfTwo(imm)) {3358 _ = maybe_inst;
2944 const shift = MCValue{ .immediate = std.math.log2_int(u32, imm) };3359
2945 return try self.binOp(.shr, lhs, shift, lhs_ty, rhs_ty, metadata);3360 switch (lhs_ty.zigTypeTag()) {
2946 } else {3361 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
2947 return self.fail("TODO ARM integer division by constants", .{});3362 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
2948 }3363 else => unreachable,
2949 },3364 }
2950 else => return self.fail("TODO ARM integer division", .{}),3365}
2951 }3366
2952 },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", .{});
2953 }3402 }
2954 } else {3403 },
2955 return self.fail("TODO ARM integer division for integers > u32/i32", .{});3404 }
2956 }3405 } else {
2957 },3406 return self.fail("TODO ARM integer division for integers > u32/i32", .{});
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,
2967 }3407 }
2968 },3408 },
2969 .rem => {3409 else => unreachable,
2970 switch (lhs_ty.zigTypeTag()) {3410 }
2971 .Float => return self.fail("TODO ARM binary operations on floats", .{}),3411}
2972 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),3412
2973 .Int => {3413fn divExact(
2974 const mod = self.bin_file.options.module.?;3414 self: *Self,
2975 assert(lhs_ty.eql(rhs_ty, mod));3415 lhs_bind: ReadArg.Bind,
2976 const int_info = lhs_ty.intInfo(self.target.*);3416 rhs_bind: ReadArg.Bind,
2977 if (int_info.bits <= 32) {3417 lhs_ty: Type,
2978 switch (int_info.signedness) {3418 rhs_ty: Type,
2979 .signed => {3419 maybe_inst: ?Air.Inst.Index,
2980 return self.fail("TODO ARM signed integer mod", .{});3420) InnerError!MCValue {
2981 },3421 _ = lhs_bind;
2982 .unsigned => {3422 _ = rhs_bind;
2983 switch (rhs) {3423 _ = lhs_ty;
2984 .immediate => |imm| {3424 _ = rhs_ty;
2985 if (std.math.isPowerOfTwo(imm)) {3425 _ = maybe_inst;
2986 const log2 = std.math.log2_int(u32, imm);3426
29873427 switch (lhs_ty.zigTypeTag()) {
2988 const lhs_is_register = lhs == .register;3428 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
29893429 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
2990 const lhs_lock: ?RegisterLock = if (lhs_is_register)3430 .Int => return self.fail("TODO ARM div_exact", .{}),
2991 self.register_manager.lockReg(lhs.register)3431 else => unreachable,
2992 else3432 }
2993 null;3433}
2994 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);3434
29953435fn rem(
2996 const lhs_reg = if (lhs_is_register) lhs.register else blk: {3436 self: *Self,
2997 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {3437 lhs_bind: ReadArg.Bind,
2998 break :inst Air.refToIndex(md.lhs).?;3438 rhs_bind: ReadArg.Bind,
2999 } else null;3439 lhs_ty: Type,
30003440 rhs_ty: Type,
3001 break :blk try self.prepareNewRegForMoving(track_inst, gp, lhs);3441 maybe_inst: ?Air.Inst.Index,
3002 };3442) InnerError!MCValue {
3003 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);3443 switch (lhs_ty.zigTypeTag()) {
3004 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);3444 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
30053445 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3006 const dest_reg = if (metadata) |md| blk: {3446 .Int => {
3007 if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) {3447 const mod = self.bin_file.options.module.?;
3008 break :blk lhs_reg;3448 assert(lhs_ty.eql(rhs_ty, mod));
3009 } else {3449 const int_info = lhs_ty.intInfo(self.target.*);
3010 break :blk try self.register_manager.allocReg(md.inst, gp);3450 if (int_info.bits <= 32) {
3011 }3451 switch (int_info.signedness) {
3012 } else try self.register_manager.allocReg(null, gp);3452 .signed => {
30133453 return self.fail("TODO ARM signed integer mod", .{});
3014 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);3454 },
30153455 .unsigned => {
3016 try self.truncRegister(lhs_reg, dest_reg, int_info.signedness, log2);3456 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
3017 return MCValue{ .register = dest_reg };3457
3018 } else {3458 if (rhs_immediate) |imm| {
3019 return self.fail("TODO ARM integer mod by constants", .{});3459 if (std.math.isPowerOfTwo(imm)) {
3020 }3460 const log2 = std.math.log2_int(u32, imm);
3021 },3461
3022 else => return self.fail("TODO ARM integer mod", .{}),3462 var lhs_reg: Register = undefined;
3023 }3463 var dest_reg: Register = undefined;
3024 },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", .{});
3025 }3488 }
3026 } else {3489 },
3027 return self.fail("TODO ARM integer division for integers > u32/i32", .{});3490 }
3028 }3491 } else {
3029 },3492 return self.fail("TODO ARM integer division for integers > u32/i32", .{});
3030 else => unreachable,
3031 }3493 }
3032 },3494 },
3033 .mod => {3495 else => unreachable,
3034 switch (lhs_ty.zigTypeTag()) {3496 }
3035 .Float => return self.fail("TODO ARM binary operations on floats", .{}),3497}
3036 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),3498
3037 .Int => return self.fail("TODO ARM mod", .{}),3499fn modulo(
3038 else => unreachable,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", .{});
3039 }3554 }
3040 },3555 },
3041 .addwrap,3556 else => unreachable,
3042 .subwrap,3557 }
3043 .mulwrap,3558}
3044 => {3559
3045 const base_tag: Air.Inst.Tag = switch (tag) {3560fn bitwise(
3046 .addwrap => .add,3561 self: *Self,
3047 .subwrap => .sub,3562 tag: Air.Inst.Tag,
3048 .mulwrap => .mul,3563 lhs_bind: ReadArg.Bind,
3049 else => unreachable,3564 rhs_bind: ReadArg.Bind,
3050 };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/mul3589 if (rhs_immediate_ok) {
3053 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);3590 return try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst);
30543591 } else if (lhs_immediate_ok) {
3055 // Truncate if necessary3592 // swap lhs and rhs
3056 switch (lhs_ty.zigTypeTag()) {3593 return try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst);
3057 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),3594 } else {
3058 .Int => {3595 return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3059 const int_info = lhs_ty.intInfo(self.target.*);3596 }
3060 if (int_info.bits <= 32) {3597 } else {
3061 const result_reg = result.register;3598 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
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,
3072 }3599 }
3073 },3600 },
3074 .bit_and,3601 else => unreachable,
3075 .bit_or,3602 }
3076 .xor,3603}
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 };
30943604
3095 if (rhs_immediate_ok) {3605fn shiftExact(
3096 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);3606 self: *Self,
3097 } else if (lhs_immediate_ok) {3607 tag: Air.Inst.Tag,
3098 // swap lhs and rhs3608 lhs_bind: ReadArg.Bind,
3099 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);3609 rhs_bind: ReadArg.Bind,
3100 } else {3610 lhs_ty: Type,
3101 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);3611 rhs_ty: Type,
3102 }3612 maybe_inst: ?Air.Inst.Index,
3103 } else {3613) InnerError!MCValue {
3104 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});3614 switch (lhs_ty.zigTypeTag()) {
3105 }3615 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3106 },3616 .Int => {
3107 else => unreachable,3617 const int_info = lhs_ty.intInfo(self.target.*);
3108 }3618 if (int_info.bits <= 32) {
3109 },3619 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
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 };
31283620
3129 if (rhs_immediate_ok) {3621 const mir_tag: Mir.Inst.Tag = switch (tag) {
3130 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);3622 .shl_exact => .lsl,
3131 } else {3623 .shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) {
3132 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);3624 .signed => Mir.Inst.Tag.asr,
3133 }3625 .unsigned => Mir.Inst.Tag.lsr,
3134 } else {3626 },
3135 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});3627 else => unreachable,
3136 }3628 };
3137 },3629
3138 else => unreachable,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", .{});
3139 }3637 }
3140 },3638 },
3141 .shl,3639 else => unreachable,
3142 .shr,3640 }
3143 => {3641}
3144 const base_tag: Air.Inst.Tag = switch (tag) {3642
3145 .shl => .shl_exact,3643fn shiftNormal(
3146 .shr => .shr_exact,3644 self: *Self,
3147 else => unreachable,3645 tag: Air.Inst.Tag,
3148 };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_exact3658 // Generate a shl_exact/shr_exact
3151 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);3659 const result = try self.shiftExact(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
31523660
3153 // Truncate if necessary3661 // Truncate if necessary
3154 switch (tag) {3662 switch (tag) {
3155 .shr => return result,3663 .shr => return result,
3156 .shl => switch (lhs_ty.zigTypeTag()) {3664 .shl => switch (lhs_ty.zigTypeTag()) {
3157 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),3665 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3158 .Int => {3666 .Int => {
3159 const int_info = lhs_ty.intInfo(self.target.*);3667 const int_info = lhs_ty.intInfo(self.target.*);
3160 if (int_info.bits <= 32) {3668 if (int_info.bits <= 32) {
3161 const result_reg = result.register;3669 const result_reg = result.register;
31623670
3163 if (int_info.bits < 32) {3671 if (int_info.bits < 32) {
3164 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);3672 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
3165 return result;3673 return result;
3166 } else return result;3674 } else return result;
3167 } else {3675 } else {
3168 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});3676 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3169 }3677 }
3170 },3678 },
3171 else => unreachable,3679 else => unreachable,
3172 },
3173 else => unreachable,
3174 }
3175 },3680 },
3176 .bool_and,3681 else => unreachable,
3177 .bool_or,3682 }
3178 => {3683}
3179 switch (lhs_ty.zigTypeTag()) {
3180 .Bool => {
3181 const lhs_immediate_ok = lhs == .immediate;
3182 const rhs_immediate_ok = rhs == .immediate;
31833684
3184 const mir_tag: Mir.Inst.Tag = switch (tag) {3685fn booleanOp(
3185 .bool_and => .@"and",3686 self: *Self,
3186 .bool_or => .orr,3687 tag: Air.Inst.Tag,
3187 else => unreachable,3688 lhs_bind: ReadArg.Bind,
3188 };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) {3699 const mir_tag: Mir.Inst.Tag = switch (tag) {
3191 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);3700 .bool_and => .@"and",
3192 } else if (lhs_immediate_ok) {3701 .bool_or => .orr,
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 },
3199 else => unreachable,3702 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);
3200 }3712 }
3201 },3713 },
3202 .ptr_add,3714 else => unreachable,
3203 .ptr_sub,3715 }
3204 => {3716}
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.*));
32133717
3214 if (elem_size == 1) {3718fn ptrArithmetic(
3215 const base_tag: Mir.Inst.Tag = switch (tag) {3719 self: *Self,
3216 .ptr_add => .add,3720 tag: Air.Inst.Tag,
3217 .ptr_sub => .sub,3721 lhs_bind: ReadArg.Bind,
3218 else => unreachable,3722 rhs_bind: ReadArg.Bind,
3219 };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);3732 const ptr_ty = lhs_ty;
3222 } else {3733 const elem_ty = switch (ptr_ty.ptrSize()) {
3223 // convert the offset into a byte offset by3734 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
3224 // multiplying it with elem_size3735 else => ptr_ty.childType(),
3225 const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null);3736 };
3226 const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null);3737 const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
3227 return addr;3738
3228 }3739 const base_tag: Air.Inst.Tag = switch (tag) {
3229 },3740 .ptr_add => .add,
3741 .ptr_sub => .sub,
3230 else => unreachable,3742 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;
3231 }3757 }
3232 },3758 },
3233 else => unreachable,3759 else => unreachable,
...@@ -3312,9 +3838,8 @@ fn genInlineMemcpy(...@@ -3312,9 +3838,8 @@ fn genInlineMemcpy(
3312 // mov count, #03838 // mov count, #0
3313 _ = try self.addInst(.{3839 _ = try self.addInst(.{
3314 .tag = .mov,3840 .tag = .mov,
3315 .data = .{ .rr_op = .{3841 .data = .{ .r_op_mov = .{
3316 .rd = count,3842 .rd = count,
3317 .rn = .r0,
3318 .op = Instruction.Operand.imm(0, 0),3843 .op = Instruction.Operand.imm(0, 0),
3319 } },3844 } },
3320 });3845 });
...@@ -3323,8 +3848,7 @@ fn genInlineMemcpy(...@@ -3323,8 +3848,7 @@ fn genInlineMemcpy(
3323 // cmp count, len3848 // cmp count, len
3324 _ = try self.addInst(.{3849 _ = try self.addInst(.{
3325 .tag = .cmp,3850 .tag = .cmp,
3326 .data = .{ .rr_op = .{3851 .data = .{ .r_op_cmp = .{
3327 .rd = .r0,
3328 .rn = count,3852 .rn = count,
3329 .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none),3853 .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none),
3330 } },3854 } },
...@@ -3418,9 +3942,8 @@ fn genInlineMemsetCode(...@@ -3418,9 +3942,8 @@ fn genInlineMemsetCode(
3418 // mov count, #03942 // mov count, #0
3419 _ = try self.addInst(.{3943 _ = try self.addInst(.{
3420 .tag = .mov,3944 .tag = .mov,
3421 .data = .{ .rr_op = .{3945 .data = .{ .r_op_mov = .{
3422 .rd = count,3946 .rd = count,
3423 .rn = .r0,
3424 .op = Instruction.Operand.imm(0, 0),3947 .op = Instruction.Operand.imm(0, 0),
3425 } },3948 } },
3426 });3949 });
...@@ -3429,8 +3952,7 @@ fn genInlineMemsetCode(...@@ -3429,8 +3952,7 @@ fn genInlineMemsetCode(
3429 // cmp count, len3952 // cmp count, len
3430 _ = try self.addInst(.{3953 _ = try self.addInst(.{
3431 .tag = .cmp,3954 .tag = .cmp,
3432 .data = .{ .rr_op = .{3955 .data = .{ .r_op_cmp = .{
3433 .rd = .r0,
3434 .rn = count,3956 .rn = count,
3435 .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none),3957 .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none),
3436 } },3958 } },
...@@ -3568,7 +4090,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -3568,7 +4090,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
3568 .register => |reg| blk: {4090 .register => |reg| blk: {
3569 const abi_size = @intCast(u32, ty.abiSize(self.target.*));4091 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
3570 const abi_align = ty.abiAlignment(self.target.*);4092 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);
3572 try self.genSetStack(ty, stack_offset, MCValue{ .register = reg });4094 try self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
35734095
3574 break :blk MCValue{ .stack_offset = stack_offset };4096 break :blk MCValue{ .stack_offset = stack_offset };
...@@ -3655,7 +4177,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3655,7 +4177,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3655 const ret_ty = fn_ty.fnReturnType();4177 const ret_ty = fn_ty.fnReturnType();
3656 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));4178 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
3657 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));4179 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
3660 var ptr_ty_payload: Type.Payload.ElemType = .{4182 var ptr_ty_payload: Type.Payload.ElemType = .{
3661 .base = .{ .tag = .single_mut_pointer },4183 .base = .{ .tag = .single_mut_pointer },
...@@ -3843,14 +4365,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -3843,14 +4365,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
3843 const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));4365 const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
3844 const abi_align = ret_ty.abiAlignment(self.target.*);4366 const abi_align = ret_ty.abiAlignment(self.target.*);
38454367
3846 // This is essentially allocMem without the4368 const offset = try self.allocMem(abi_size, abi_align, null);
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);
38544369
3855 const tmp_mcv = MCValue{ .stack_offset = offset };4370 const tmp_mcv = MCValue{ .stack_offset = offset };
3856 try self.load(tmp_mcv, ptr, ptr_ty);4371 try self.load(tmp_mcv, ptr, ptr_ty);
...@@ -3871,32 +4386,16 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -3871,32 +4386,16 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
3871 const lhs_ty = self.air.typeOf(bin_op.lhs);4386 const lhs_ty = self.air.typeOf(bin_op.lhs);
38724387
3873 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {4388 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
3874 const operands: BinOpOperands = .{ .inst = .{4389 break :blk try self.cmp(.{ .inst = bin_op.lhs }, .{ .inst = bin_op.rhs }, lhs_ty, op);
3875 .inst = inst,
3876 .lhs = bin_op.lhs,
3877 .rhs = bin_op.rhs,
3878 } };
3879 break :blk try self.cmp(operands, lhs_ty, op);
3880 };4390 };
38814391
3882 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });4392 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
3883}4393}
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
3897fn cmp(4395fn cmp(
3898 self: *Self,4396 self: *Self,
3899 operands: BinOpOperands,4397 lhs: ReadArg.Bind,
4398 rhs: ReadArg.Bind,
3900 lhs_ty: Type,4399 lhs_ty: Type,
3901 op: math.CompareOperator,4400 op: math.CompareOperator,
3902) !MCValue {4401) !MCValue {
...@@ -3926,22 +4425,47 @@ fn cmp(...@@ -3926,22 +4425,47 @@ fn cmp(
3926 if (int_info.bits <= 32) {4425 if (int_info.bits <= 32) {
3927 try self.spillCompareFlagsIfOccupied();4426 try self.spillCompareFlagsIfOccupied();
39284427
3929 switch (operands) {4428 var lhs_reg: Register = undefined;
3930 .inst => |inst_op| {4429 var rhs_reg: Register = undefined;
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);
39384430
3939 self.cpsr_flags_inst = inst_op.inst;4431 const rhs_immediate = try rhs.resolveToImmediate(self);
3940 _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, metadata);4432 const rhs_immediate_ok = if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false;
3941 },4433
3942 .mcv => |mcv_op| {4434 if (rhs_immediate_ok) {
3943 _ = try self.binOp(.cmp_eq, mcv_op.lhs, mcv_op.rhs, int_ty, int_ty, null);4435 const read_args = [_]ReadArg{
3944 },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 });
3945 }4469 }
39464470
3947 return switch (int_info.signedness) {4471 return switch (int_info.signedness) {
...@@ -4020,9 +4544,7 @@ fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {...@@ -4020,9 +4544,7 @@ fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {
4020 // bne ...4544 // bne ...
4021 _ = try self.addInst(.{4545 _ = try self.addInst(.{
4022 .tag = .cmp,4546 .tag = .cmp,
4023 .cond = .al,4547 .data = .{ .r_op_cmp = .{
4024 .data = .{ .rr_op = .{
4025 .rd = .r0,
4026 .rn = reg,4548 .rn = reg,
4027 .op = Instruction.Operand.imm(1, 0),4549 .op = Instruction.Operand.imm(1, 0),
4028 } },4550 } },
...@@ -4132,7 +4654,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4132,7 +4654,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4132 if (else_value == .dead)4654 if (else_value == .dead)
4133 continue;4655 continue;
4134 // The instruction is only overridden in the else branch.4656 // 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;
4136 while (true) {4658 while (true) {
4137 i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead?4659 i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead?
4138 if (self.branch_stack.items[i].inst_table.get(else_key)) |mcv| {4660 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 {...@@ -4159,7 +4681,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4159 if (then_value == .dead)4681 if (then_value == .dead)
4160 continue;4682 continue;
4161 const parent_mcv = blk: {4683 const parent_mcv = blk: {
4162 var i: usize = self.branch_stack.items.len - 2;4684 var i: usize = self.branch_stack.items.len - 1;
4163 while (true) {4685 while (true) {
4164 i -= 1;4686 i -= 1;
4165 if (self.branch_stack.items[i].inst_table.get(then_key)) |mcv| {4687 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 {...@@ -4185,75 +4707,39 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4185 return self.finishAir(inst, .unreach, .{ .none, .none, .none });4707 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
4186}4708}
41874709
4188fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue {4710fn isNull(
4189 if (ty.isPtrLikeOptional()) {4711 self: *Self,
4190 assert(ty.abiSize(self.target.*) == 4);4712 operand_bind: ReadArg.Bind,
41914713 operand_ty: Type,
4192 const reg_mcv: MCValue = switch (operand) {4714) !MCValue {
4193 .register => operand,4715 if (operand_ty.isPtrLikeOptional()) {
4194 else => .{ .register = try self.copyToTmpRegister(ty, operand) },4716 assert(operand_ty.abiSize(self.target.*) == 4);
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 });
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);
4207 } else {4720 } else {
4208 return self.fail("TODO implement non-pointer optionals", .{});4721 return self.fail("TODO implement non-pointer optionals", .{});
4209 }4722 }
4210}4723}
42114724
4212fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {4725fn isNonNull(
4213 const is_null_result = try self.isNull(ty, operand);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);
4214 assert(is_null_result.cpsr_flags == .eq);4731 assert(is_null_result.cpsr_flags == .eq);
42154732
4216 return MCValue{ .cpsr_flags = .ne };4733 return MCValue{ .cpsr_flags = .ne };
4217}4734}
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
4247fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {4736fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
4248 const un_op = self.air.instructions.items(.data)[inst].un_op;4737 const un_op = self.air.instructions.items(.data)[inst].un_op;
4249
4250 try self.spillCompareFlagsIfOccupied();
4251 self.cpsr_flags_inst = inst;
4252
4253 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4738 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4254 const operand = try self.resolveInst(un_op);4739 const operand_bind: ReadArg.Bind = .{ .inst = un_op };
4255 const ty = self.air.typeOf(un_op);4740 const operand_ty = self.air.typeOf(un_op);
4256 break :result try self.isNull(ty, operand);4741
4742 break :result try self.isNull(operand_bind, operand_ty);
4257 };4743 };
4258 return self.finishAir(inst, result, .{ un_op, .none, .none });4744 return self.finishAir(inst, result, .{ un_op, .none, .none });
4259}4745}
...@@ -4263,16 +4749,12 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4263,16 +4749,12 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
4263 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4749 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4264 const operand_ptr = try self.resolveInst(un_op);4750 const operand_ptr = try self.resolveInst(un_op);
4265 const ptr_ty = self.air.typeOf(un_op);4751 const ptr_ty = self.air.typeOf(un_op);
4266 const operand: MCValue = blk: {4752 const elem_ty = ptr_ty.elemType();
4267 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {4753
4268 // The MCValue that holds the pointer can be re-used as the value.4754 const operand = try self.allocRegOrMem(elem_ty, true, null);
4269 break :blk operand_ptr;
4270 } else {
4271 break :blk try self.allocRegOrMem(inst, true);
4272 }
4273 };
4274 try self.load(operand, operand_ptr, ptr_ty);4755 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);
4276 };4758 };
4277 return self.finishAir(inst, result, .{ un_op, .none, .none });4759 return self.finishAir(inst, result, .{ un_op, .none, .none });
4278}4760}
...@@ -4280,9 +4762,10 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4280,9 +4762,10 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
4280fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {4762fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
4281 const un_op = self.air.instructions.items(.data)[inst].un_op;4763 const un_op = self.air.instructions.items(.data)[inst].un_op;
4282 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4764 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4283 const operand = try self.resolveInst(un_op);4765 const operand_bind: ReadArg.Bind = .{ .inst = un_op };
4284 const ty = self.air.typeOf(un_op);4766 const operand_ty = self.air.typeOf(un_op);
4285 break :result try self.isNonNull(ty, operand);4767
4768 break :result try self.isNonNull(operand_bind, operand_ty);
4286 };4769 };
4287 return self.finishAir(inst, result, .{ un_op, .none, .none });4770 return self.finishAir(inst, result, .{ un_op, .none, .none });
4288}4771}
...@@ -4292,26 +4775,57 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4292,26 +4775,57 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
4292 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4775 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4293 const operand_ptr = try self.resolveInst(un_op);4776 const operand_ptr = try self.resolveInst(un_op);
4294 const ptr_ty = self.air.typeOf(un_op);4777 const ptr_ty = self.air.typeOf(un_op);
4295 const operand: MCValue = blk: {4778 const elem_ty = ptr_ty.elemType();
4296 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {4779
4297 // The MCValue that holds the pointer can be re-used as the value.4780 const operand = try self.allocRegOrMem(elem_ty, true, null);
4298 break :blk operand_ptr;
4299 } else {
4300 break :blk try self.allocRegOrMem(inst, true);
4301 }
4302 };
4303 try self.load(operand, operand_ptr, ptr_ty);4781 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);
4305 };4784 };
4306 return self.finishAir(inst, result, .{ un_op, .none, .none });4785 return self.finishAir(inst, result, .{ un_op, .none, .none });
4307}4786}
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
4309fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {4822fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
4310 const un_op = self.air.instructions.items(.data)[inst].un_op;4823 const un_op = self.air.instructions.items(.data)[inst].un_op;
4311 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4824 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4312 const operand = try self.resolveInst(un_op);4825 const error_union_bind: ReadArg.Bind = .{ .inst = un_op };
4313 const ty = self.air.typeOf(un_op);4826 const error_union_ty = self.air.typeOf(un_op);
4314 break :result try self.isErr(ty, operand);4827
4828 break :result try self.isErr(error_union_bind, error_union_ty);
4315 };4829 };
4316 return self.finishAir(inst, result, .{ un_op, .none, .none });4830 return self.finishAir(inst, result, .{ un_op, .none, .none });
4317}4831}
...@@ -4321,16 +4835,12 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4321,16 +4835,12 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
4321 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4835 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4322 const operand_ptr = try self.resolveInst(un_op);4836 const operand_ptr = try self.resolveInst(un_op);
4323 const ptr_ty = self.air.typeOf(un_op);4837 const ptr_ty = self.air.typeOf(un_op);
4324 const operand: MCValue = blk: {4838 const elem_ty = ptr_ty.elemType();
4325 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {4839
4326 // The MCValue that holds the pointer can be re-used as the value.4840 const operand = try self.allocRegOrMem(elem_ty, true, null);
4327 break :blk operand_ptr;
4328 } else {
4329 break :blk try self.allocRegOrMem(inst, true);
4330 }
4331 };
4332 try self.load(operand, operand_ptr, ptr_ty);4841 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);
4334 };4844 };
4335 return self.finishAir(inst, result, .{ un_op, .none, .none });4845 return self.finishAir(inst, result, .{ un_op, .none, .none });
4336}4846}
...@@ -4338,9 +4848,10 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4338,9 +4848,10 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
4338fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {4848fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
4339 const un_op = self.air.instructions.items(.data)[inst].un_op;4849 const un_op = self.air.instructions.items(.data)[inst].un_op;
4340 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4850 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4341 const operand = try self.resolveInst(un_op);4851 const error_union_bind: ReadArg.Bind = .{ .inst = un_op };
4342 const ty = self.air.typeOf(un_op);4852 const error_union_ty = self.air.typeOf(un_op);
4343 break :result try self.isNonErr(ty, operand);4853
4854 break :result try self.isNonErr(error_union_bind, error_union_ty);
4344 };4855 };
4345 return self.finishAir(inst, result, .{ un_op, .none, .none });4856 return self.finishAir(inst, result, .{ un_op, .none, .none });
4346}4857}
...@@ -4350,16 +4861,12 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4350,16 +4861,12 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
4350 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4861 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4351 const operand_ptr = try self.resolveInst(un_op);4862 const operand_ptr = try self.resolveInst(un_op);
4352 const ptr_ty = self.air.typeOf(un_op);4863 const ptr_ty = self.air.typeOf(un_op);
4353 const operand: MCValue = blk: {4864 const elem_ty = ptr_ty.elemType();
4354 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {4865
4355 // The MCValue that holds the pointer can be re-used as the value.4866 const operand = try self.allocRegOrMem(elem_ty, true, null);
4356 break :blk operand_ptr;
4357 } else {
4358 break :blk try self.allocRegOrMem(inst, true);
4359 }
4360 };
4361 try self.load(operand, operand_ptr, ptr_ty);4867 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);
4363 };4870 };
4364 return self.finishAir(inst, result, .{ un_op, .none, .none });4871 return self.finishAir(inst, result, .{ un_op, .none, .none });
4365}4872}
...@@ -4456,14 +4963,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -4456,14 +4963,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
4456 defer self.gpa.free(branch_into_prong_relocs);4963 defer self.gpa.free(branch_into_prong_relocs);
44574964
4458 for (items) |item, idx| {4965 for (items) |item, idx| {
4459 const condition = try self.resolveInst(pl_op.operand);4966 const cmp_result = try self.cmp(.{ .inst = pl_op.operand }, .{ .inst = item }, condition_ty, .neq);
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);
4467 branch_into_prong_relocs[idx] = try self.condBr(cmp_result);4967 branch_into_prong_relocs[idx] = try self.condBr(cmp_result);
4468 }4968 }
44694969
...@@ -4579,7 +5079,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {...@@ -4579,7 +5079,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
4579 .none, .dead, .unreach => unreachable,5079 .none, .dead, .unreach => unreachable,
4580 .register, .stack_offset, .memory => operand_mcv,5080 .register, .stack_offset, .memory => operand_mcv,
4581 .immediate, .stack_argument_offset, .cpsr_flags => blk: {5081 .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);
4583 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);5083 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
4584 break :blk new_mcv;5084 break :blk new_mcv;
4585 },5085 },
...@@ -4832,9 +5332,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4832,9 +5332,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4832 .register_v_flag => .vs,5332 .register_v_flag => .vs,
4833 else => unreachable,5333 else => unreachable,
4834 },5334 },
4835 .data = .{ .rr_op = .{5335 .data = .{ .r_op_mov = .{
4836 .rd = cond_reg,5336 .rd = cond_reg,
4837 .rn = .r0,
4838 .op = Instruction.Operand.fromU32(1).?,5337 .op = Instruction.Operand.fromU32(1).?,
4839 } },5338 } },
4840 });5339 });
...@@ -4935,9 +5434,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4935,9 +5434,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4935 // mov reg, 05434 // mov reg, 0
4936 _ = try self.addInst(.{5435 _ = try self.addInst(.{
4937 .tag = .mov,5436 .tag = .mov,
4938 .data = .{ .rr_op = .{5437 .data = .{ .r_op_mov = .{
4939 .rd = reg,5438 .rd = reg,
4940 .rn = .r0,
4941 .op = zero,5439 .op = zero,
4942 } },5440 } },
4943 });5441 });
...@@ -4946,9 +5444,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4946,9 +5444,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4946 _ = try self.addInst(.{5444 _ = try self.addInst(.{
4947 .tag = .mov,5445 .tag = .mov,
4948 .cond = condition,5446 .cond = condition,
4949 .data = .{ .rr_op = .{5447 .data = .{ .r_op_mov = .{
4950 .rd = reg,5448 .rd = reg,
4951 .rn = .r0,
4952 .op = one,5449 .op = one,
4953 } },5450 } },
4954 });5451 });
...@@ -4957,18 +5454,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4957,18 +5454,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4957 if (Instruction.Operand.fromU32(x)) |op| {5454 if (Instruction.Operand.fromU32(x)) |op| {
4958 _ = try self.addInst(.{5455 _ = try self.addInst(.{
4959 .tag = .mov,5456 .tag = .mov,
4960 .data = .{ .rr_op = .{5457 .data = .{ .r_op_mov = .{
4961 .rd = reg,5458 .rd = reg,
4962 .rn = .r0,
4963 .op = op,5459 .op = op,
4964 } },5460 } },
4965 });5461 });
4966 } else if (Instruction.Operand.fromU32(~x)) |op| {5462 } else if (Instruction.Operand.fromU32(~x)) |op| {
4967 _ = try self.addInst(.{5463 _ = try self.addInst(.{
4968 .tag = .mvn,5464 .tag = .mvn,
4969 .data = .{ .rr_op = .{5465 .data = .{ .r_op_mov = .{
4970 .rd = reg,5466 .rd = reg,
4971 .rn = .r0,
4972 .op = op,5467 .op = op,
4973 } },5468 } },
4974 });5469 });
...@@ -4984,9 +5479,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4984,9 +5479,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4984 } else {5479 } else {
4985 _ = try self.addInst(.{5480 _ = try self.addInst(.{
4986 .tag = .mov,5481 .tag = .mov,
4987 .data = .{ .rr_op = .{5482 .data = .{ .r_op_mov = .{
4988 .rd = reg,5483 .rd = reg,
4989 .rn = .r0,
4990 .op = Instruction.Operand.imm(@truncate(u8, x), 0),5484 .op = Instruction.Operand.imm(@truncate(u8, x), 0),
4991 } },5485 } },
4992 });5486 });
...@@ -5028,9 +5522,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -5028,9 +5522,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
5028 // orr reg, reg, #0xdd, 85522 // orr reg, reg, #0xdd, 8
5029 _ = try self.addInst(.{5523 _ = try self.addInst(.{
5030 .tag = .mov,5524 .tag = .mov,
5031 .data = .{ .rr_op = .{5525 .data = .{ .r_op_mov = .{
5032 .rd = reg,5526 .rd = reg,
5033 .rn = .r0,
5034 .op = Instruction.Operand.imm(@truncate(u8, x), 0),5527 .op = Instruction.Operand.imm(@truncate(u8, x), 0),
5035 } },5528 } },
5036 });5529 });
...@@ -5069,9 +5562,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -5069,9 +5562,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
5069 // mov reg, src_reg5562 // mov reg, src_reg
5070 _ = try self.addInst(.{5563 _ = try self.addInst(.{
5071 .tag = .mov,5564 .tag = .mov,
5072 .data = .{ .rr_op = .{5565 .data = .{ .r_op_mov = .{
5073 .rd = reg,5566 .rd = reg,
5074 .rn = .r0,
5075 .op = Instruction.Operand.reg(src_reg, Instruction.Operand.Shift.none),5567 .op = Instruction.Operand.reg(src_reg, Instruction.Operand.Shift.none),
5076 } },5568 } },
5077 });5569 });
...@@ -5307,7 +5799,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -5307,7 +5799,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
5307 const array_ty = ptr_ty.childType();5799 const array_ty = ptr_ty.childType();
5308 const array_len = @intCast(u32, array_ty.arrayLen());5800 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);
5311 try self.genSetStack(ptr_ty, stack_offset, ptr);5803 try self.genSetStack(ptr_ty, stack_offset, ptr);
5312 try self.genSetStack(Type.initTag(.usize), stack_offset - 4, .{ .immediate = array_len });5804 try self.genSetStack(Type.initTag(.usize), stack_offset - 4, .{ .immediate = array_len });
5313 break :result MCValue{ .stack_offset = stack_offset };5805 break :result MCValue{ .stack_offset = stack_offset };
...@@ -5461,15 +5953,24 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void {...@@ -5461,15 +5953,24 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void {
5461 const extra = self.air.extraData(Air.Try, pl_op.payload);5953 const extra = self.air.extraData(Air.Try, pl_op.payload);
5462 const body = self.air.extra[extra.end..][0..extra.data.body_len];5954 const body = self.air.extra[extra.end..][0..extra.data.body_len];
5463 const result: MCValue = result: {5955 const result: MCValue = result: {
5956 const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand };
5464 const error_union_ty = self.air.typeOf(pl_op.operand);5957 const error_union_ty = self.air.typeOf(pl_op.operand);
5465 const error_union = try self.resolveInst(pl_op.operand);5958 const error_union_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
5466 const is_err_result = try self.isErr(error_union_ty, error_union);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);
5467 const reloc = try self.condBr(is_err_result);5968 const reloc = try self.condBr(is_err_result);
54685969
5469 try self.genBody(body);5970 try self.genBody(body);
5470
5471 try self.performReloc(reloc);5971 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);
5473 };5974 };
5474 return self.finishAir(inst, result, .{ pl_op.operand, .none, .none });5975 return self.finishAir(inst, result, .{ pl_op.operand, .none, .none });
5475}5976}
src/arch/arm/Emit.zig+88-12
...@@ -11,6 +11,7 @@ const link = @import("../../link.zig");...@@ -11,6 +11,7 @@ const link = @import("../../link.zig");
11const Module = @import("../../Module.zig");11const Module = @import("../../Module.zig");
12const Type = @import("../../type.zig").Type;12const Type = @import("../../type.zig").Type;
13const ErrorMsg = Module.ErrorMsg;13const ErrorMsg = Module.ErrorMsg;
14const Target = std.Target;
14const assert = std.debug.assert;15const assert = std.debug.assert;
15const DW = std.dwarf;16const DW = std.dwarf;
16const leb128 = std.leb;17const leb128 = std.leb;
...@@ -93,6 +94,8 @@ pub fn emitMir(...@@ -93,6 +94,8 @@ pub fn emitMir(
93 .sub => try emit.mirDataProcessing(inst),94 .sub => try emit.mirDataProcessing(inst),
94 .subs => try emit.mirDataProcessing(inst),95 .subs => try emit.mirDataProcessing(inst),
9596
97 .sub_sp_scratch_r0 => try emit.mirSubStackPointer(inst),
98
96 .asr => try emit.mirShift(inst),99 .asr => try emit.mirShift(inst),
97 .lsl => try emit.mirShift(inst),100 .lsl => try emit.mirShift(inst),
98 .lsr => try emit.mirShift(inst),101 .lsr => try emit.mirShift(inst),
...@@ -190,6 +193,24 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {...@@ -190,6 +193,24 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
190 .dbg_epilogue_begin,193 .dbg_epilogue_begin,
191 .dbg_prologue_end,194 .dbg_prologue_end,
192 => return 0,195 => 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
193 else => return 4,214 else => return 4,
194 }215 }
195}216}
...@@ -385,20 +406,75 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {...@@ -385,20 +406,75 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
385fn mirDataProcessing(emit: *Emit, inst: Mir.Inst.Index) !void {406fn mirDataProcessing(emit: *Emit, inst: Mir.Inst.Index) !void {
386 const tag = emit.mir.instructions.items(.tag)[inst];407 const tag = emit.mir.instructions.items(.tag)[inst];
387 const cond = emit.mir.instructions.items(.cond)[inst];408 const cond = emit.mir.instructions.items(.cond)[inst];
388 const rr_op = emit.mir.instructions.items(.data)[inst].rr_op;
389409
390 switch (tag) {410 switch (tag) {
391 .add => try emit.writeInstruction(Instruction.add(cond, rr_op.rd, rr_op.rn, rr_op.op)),411 .add,
392 .adds => try emit.writeInstruction(Instruction.adds(cond, rr_op.rd, rr_op.rn, rr_op.op)),412 .adds,
393 .@"and" => try emit.writeInstruction(Instruction.@"and"(cond, rr_op.rd, rr_op.rn, rr_op.op)),413 .@"and",
394 .cmp => try emit.writeInstruction(Instruction.cmp(cond, rr_op.rn, rr_op.op)),414 .eor,
395 .eor => try emit.writeInstruction(Instruction.eor(cond, rr_op.rd, rr_op.rn, rr_op.op)),415 .orr,
396 .mov => try emit.writeInstruction(Instruction.mov(cond, rr_op.rd, rr_op.op)),416 .rsb,
397 .mvn => try emit.writeInstruction(Instruction.mvn(cond, rr_op.rd, rr_op.op)),417 .sub,
398 .orr => try emit.writeInstruction(Instruction.orr(cond, rr_op.rd, rr_op.rn, rr_op.op)),418 .subs,
399 .rsb => try emit.writeInstruction(Instruction.rsb(cond, rr_op.rd, rr_op.rn, rr_op.op)),419 => {
400 .sub => try emit.writeInstruction(Instruction.sub(cond, rr_op.rd, rr_op.rn, rr_op.op)),420 const rr_op = emit.mir.instructions.items(.data)[inst].rr_op;
401 .subs => try emit.writeInstruction(Instruction.subs(cond, rr_op.rd, rr_op.rn, rr_op.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 },
402 else => unreachable,478 else => unreachable,
403 }479 }
404}480}
src/arch/arm/Mir.zig+23
...@@ -111,6 +111,11 @@ pub const Inst = struct {...@@ -111,6 +111,11 @@ pub const Inst = struct {
111 strh,111 strh,
112 /// Subtract112 /// Subtract
113 sub,113 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,
114 /// Subtract, update condition flags119 /// Subtract, update condition flags
115 subs,120 subs,
116 /// Supervisor Call121 /// Supervisor Call
...@@ -144,6 +149,10 @@ pub const Inst = struct {...@@ -144,6 +149,10 @@ pub const Inst = struct {
144 ///149 ///
145 /// Used by e.g. svc150 /// Used by e.g. svc
146 imm24: u24,151 imm24: u24,
152 /// A 32-bit immediate value.
153 ///
154 /// Used by e.g. sub_sp_scratch_r0
155 imm32: u32,
147 /// Index into `extra`. Meaning of what can be found there is context-dependent.156 /// Index into `extra`. Meaning of what can be found there is context-dependent.
148 ///157 ///
149 /// Used by e.g. load_memory158 /// Used by e.g. load_memory
...@@ -166,6 +175,20 @@ pub const Inst = struct {...@@ -166,6 +175,20 @@ pub const Inst = struct {
166 rd: Register,175 rd: Register,
167 imm16: u16,176 imm16: u16,
168 },177 },
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 },
169 /// Two registers and a shift amount192 /// Two registers and a shift amount
170 ///193 ///
171 /// Used by e.g. lsl194 /// Used by e.g. lsl
src/arch/x86_64/CodeGen.zig+67-141
...@@ -128,15 +128,11 @@ pub const MCValue = union(enum) {...@@ -128,15 +128,11 @@ pub const MCValue = union(enum) {
128 /// The value is in memory at a hard-coded address.128 /// The value is in memory at a hard-coded address.
129 /// If the type is a pointer, it means the pointer address is at this memory location.129 /// If the type is a pointer, it means the pointer address is at this memory location.
130 memory: u64,130 memory: u64,
131 /// The value is in memory referenced indirectly via a GOT entry index.131 /// The value is in memory but requires a linker relocation fixup:
132 /// If the type is a pointer, it means the pointer is referenced indirectly via GOT.132 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
133 /// When lowered, linker will emit a relocation of type X86_64_RELOC_GOT.133 /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
134 got_load: u32,134 /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
135 imports_load: u32,135 linker_load: struct { @"type": enum { got, direct, import }, sym_index: 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,
140 /// The value is one of the stack variables.136 /// The value is one of the stack variables.
141 /// If the type is a pointer, it means the pointer address is in the stack at this offset.137 /// If the type is a pointer, it means the pointer address is in the stack at this offset.
142 stack_offset: i32,138 stack_offset: i32,
...@@ -150,9 +146,7 @@ pub const MCValue = union(enum) {...@@ -150,9 +146,7 @@ pub const MCValue = union(enum) {
150 .memory,146 .memory,
151 .stack_offset,147 .stack_offset,
152 .ptr_stack_offset,148 .ptr_stack_offset,
153 .direct_load,149 .linker_load,
154 .got_load,
155 .imports_load,
156 => true,150 => true,
157 else => false,151 else => false,
158 };152 };
...@@ -165,26 +159,6 @@ pub const MCValue = union(enum) {...@@ -165,26 +159,6 @@ pub const MCValue = union(enum) {
165 };159 };
166 }160 }
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
188 fn isRegister(mcv: MCValue) bool {162 fn isRegister(mcv: MCValue) bool {
189 return switch (mcv) {163 return switch (mcv) {
190 .register => true,164 .register => true,
...@@ -2307,11 +2281,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2307,11 +2281,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2307 .data = .{ .imm = @bitCast(u32, -off) },2281 .data = .{ .imm = @bitCast(u32, -off) },
2308 });2282 });
2309 },2283 },
2310 .memory,2284 .memory, .linker_load => {
2311 .got_load,
2312 .direct_load,
2313 .imports_load,
2314 => {
2315 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);2285 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);
2316 },2286 },
2317 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),2287 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...@@ -2652,11 +2622,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2652 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),2622 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),
2653 }2623 }
2654 },2624 },
2655 .memory,2625 .memory, .linker_load => {
2656 .got_load,
2657 .direct_load,
2658 .imports_load,
2659 => {
2660 const reg = try self.copyToTmpRegister(ptr_ty, ptr);2626 const reg = try self.copyToTmpRegister(ptr_ty, ptr);
2661 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);2627 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
2662 },2628 },
...@@ -2691,10 +2657,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -2691,10 +2657,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
26912657
2692fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue) InnerError!void {2658fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue) InnerError!void {
2693 switch (ptr) {2659 switch (ptr) {
2694 .got_load,2660 .linker_load => |load_struct| {
2695 .direct_load,
2696 .imports_load,
2697 => |sym_index| {
2698 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));2661 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));
2699 const mod = self.bin_file.options.module.?;2662 const mod = self.bin_file.options.module.?;
2700 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);2663 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...@@ -2702,11 +2665,10 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
2702 fn_owner_decl.link.macho.sym_index2665 fn_owner_decl.link.macho.sym_index
2703 else2666 else
2704 fn_owner_decl.link.coff.sym_index;2667 fn_owner_decl.link.coff.sym_index;
2705 const flags: u2 = switch (ptr) {2668 const flags: u2 = switch (load_struct.@"type") {
2706 .got_load => 0b00,2669 .got => 0b00,
2707 .direct_load => 0b01,2670 .direct => 0b01,
2708 .imports_load => 0b10,2671 .import => 0b10,
2709 else => unreachable,
2710 };2672 };
2711 _ = try self.addInst(.{2673 _ = try self.addInst(.{
2712 .tag = .lea_pic,2674 .tag = .lea_pic,
...@@ -2717,7 +2679,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue...@@ -2717,7 +2679,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
2717 .data = .{2679 .data = .{
2718 .relocation = .{2680 .relocation = .{
2719 .atom_index = atom_index,2681 .atom_index = atom_index,
2720 .sym_index = sym_index,2682 .sym_index = load_struct.sym_index,
2721 },2683 },
2722 },2684 },
2723 });2685 });
...@@ -2801,9 +2763,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2801,9 +2763,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2801 .register => |src_reg| {2763 .register => |src_reg| {
2802 try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0);2764 try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0);
2803 },2765 },
2804 .got_load,2766 .linker_load,
2805 .direct_load,
2806 .imports_load,
2807 .memory,2767 .memory,
2808 .stack_offset,2768 .stack_offset,
2809 => {2769 => {
...@@ -2822,11 +2782,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2822,11 +2782,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2822 },2782 },
2823 }2783 }
2824 },2784 },
2825 .got_load,2785 .linker_load, .memory => {
2826 .direct_load,
2827 .imports_load,
2828 .memory,
2829 => {
2830 const value_lock: ?RegisterLock = switch (value) {2786 const value_lock: ?RegisterLock = switch (value) {
2831 .register => |reg| self.register_manager.lockReg(reg),2787 .register => |reg| self.register_manager.lockReg(reg),
2832 else => null,2788 else => null,
...@@ -2894,11 +2850,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2894,11 +2850,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2894 .register => {2850 .register => {
2895 return self.store(new_ptr, value, ptr_ty, value_ty);2851 return self.store(new_ptr, value, ptr_ty, value_ty);
2896 },2852 },
2897 .got_load,2853 .linker_load, .memory => {
2898 .direct_load,
2899 .imports_load,
2900 .memory,
2901 => {
2902 if (abi_size <= 8) {2854 if (abi_size <= 8) {
2903 const tmp_reg = try self.register_manager.allocReg(null, gp);2855 const tmp_reg = try self.register_manager.allocReg(null, gp);
2904 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);2856 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...@@ -3606,9 +3558,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3606 });3558 });
3607 },3559 },
3608 .memory,3560 .memory,
3609 .got_load,3561 .linker_load,
3610 .direct_load,
3611 .imports_load,
3612 .eflags,3562 .eflags,
3613 => {3563 => {
3614 assert(abi_size <= 8);3564 assert(abi_size <= 8);
...@@ -3694,10 +3644,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3694,10 +3644,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3694 => {3644 => {
3695 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});3645 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});
3696 },3646 },
3697 .got_load,3647 .linker_load => {
3698 .direct_load,
3699 .imports_load,
3700 => {
3701 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});3648 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
3702 },3649 },
3703 .eflags => {3650 .eflags => {
...@@ -3708,10 +3655,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3708,10 +3655,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3708 .memory => {3655 .memory => {
3709 return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{});3656 return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{});
3710 },3657 },
3711 .got_load,3658 .linker_load => {
3712 .direct_load,
3713 .imports_load,
3714 => {
3715 return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{});3659 return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{});
3716 },3660 },
3717 }3661 }
...@@ -3779,10 +3723,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3779,10 +3723,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3779 .memory => {3723 .memory => {
3780 return self.fail("TODO implement x86 multiply source memory", .{});3724 return self.fail("TODO implement x86 multiply source memory", .{});
3781 },3725 },
3782 .got_load,3726 .linker_load => {
3783 .direct_load,
3784 .imports_load,
3785 => {
3786 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});3727 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
3787 },3728 },
3788 .eflags => {3729 .eflags => {
...@@ -3826,10 +3767,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3826,10 +3767,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3826 .memory, .stack_offset => {3767 .memory, .stack_offset => {
3827 return self.fail("TODO implement x86 multiply source memory", .{});3768 return self.fail("TODO implement x86 multiply source memory", .{});
3828 },3769 },
3829 .got_load,3770 .linker_load => {
3830 .direct_load,
3831 .imports_load,
3832 => {
3833 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});3771 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
3834 },3772 },
3835 .eflags => {3773 .eflags => {
...@@ -3840,10 +3778,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3840,10 +3778,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3840 .memory => {3778 .memory => {
3841 return self.fail("TODO implement x86 multiply destination memory", .{});3779 return self.fail("TODO implement x86 multiply destination memory", .{});
3842 },3780 },
3843 .got_load,3781 .linker_load => {
3844 .direct_load,
3845 .imports_load,
3846 => {
3847 return self.fail("TODO implement x86 multiply destination symbol at index in linker", .{});3782 return self.fail("TODO implement x86 multiply destination symbol at index in linker", .{});
3848 },3783 },
3849 }3784 }
...@@ -4006,9 +3941,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4006,9 +3941,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4006 .unreach => unreachable,3941 .unreach => unreachable,
4007 .dead => unreachable,3942 .dead => unreachable,
4008 .memory => unreachable,3943 .memory => unreachable,
4009 .got_load => unreachable,3944 .linker_load => unreachable,
4010 .direct_load => unreachable,
4011 .imports_load => unreachable,
4012 .eflags => unreachable,3945 .eflags => unreachable,
4013 .register_overflow => unreachable,3946 .register_overflow => unreachable,
4014 }3947 }
...@@ -4066,7 +3999,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4066,7 +3999,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4066 const func = func_payload.data;3999 const func = func_payload.data;
4067 const fn_owner_decl = mod.declPtr(func.owner_decl);4000 const fn_owner_decl = mod.declPtr(func.owner_decl);
4068 try self.genSetReg(Type.initTag(.usize), .rax, .{4001 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 },
4070 });4006 });
4071 _ = try self.addInst(.{4007 _ = try self.addInst(.{
4072 .tag = .call,4008 .tag = .call,
...@@ -4087,7 +4023,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4087,7 +4023,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4087 }4023 }
4088 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));4024 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
4089 try self.genSetReg(Type.initTag(.usize), .rax, .{4025 try self.genSetReg(Type.initTag(.usize), .rax, .{
4090 .imports_load = sym_index,4026 .linker_load = .{
4027 .@"type" = .import,
4028 .sym_index = sym_index,
4029 },
4091 });4030 });
4092 _ = try self.addInst(.{4031 _ = try self.addInst(.{
4093 .tag = .call,4032 .tag = .call,
...@@ -4119,7 +4058,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4119,7 +4058,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4119 const func = func_payload.data;4058 const func = func_payload.data;
4120 const fn_owner_decl = mod.declPtr(func.owner_decl);4059 const fn_owner_decl = mod.declPtr(func.owner_decl);
4121 const sym_index = fn_owner_decl.link.macho.sym_index;4060 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 });
4123 // callq *%rax4067 // callq *%rax
4124 _ = try self.addInst(.{4068 _ = try self.addInst(.{
4125 .tag = .call,4069 .tag = .call,
...@@ -4505,11 +4449,7 @@ fn genVarDbgInfo(...@@ -4505,11 +4449,7 @@ fn genVarDbgInfo(
4505 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;4449 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
4506 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);4450 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
4507 },4451 },
4508 .memory,4452 .memory, .linker_load => {
4509 .got_load,
4510 .direct_load,
4511 .imports_load,
4512 => {
4513 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));4453 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
4514 const is_ptr = switch (tag) {4454 const is_ptr = switch (tag) {
4515 .dbg_var_ptr => true,4455 .dbg_var_ptr => true,
...@@ -4540,10 +4480,11 @@ fn genVarDbgInfo(...@@ -4540,10 +4480,11 @@ fn genVarDbgInfo(
4540 try dbg_info.append(DW.OP.deref);4480 try dbg_info.append(DW.OP.deref);
4541 }4481 }
4542 switch (mcv) {4482 switch (mcv) {
4543 .got_load,4483 .linker_load => |load_struct| try dw.addExprlocReloc(
4544 .direct_load,4484 load_struct.sym_index,
4545 .imports_load,4485 offset,
4546 => |index| try dw.addExprlocReloc(index, offset, is_ptr),4486 is_ptr,
4487 ),
4547 else => {},4488 else => {},
4548 }4489 }
4549 },4490 },
...@@ -5587,11 +5528,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -5587,11 +5528,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
5587 else => return self.fail("TODO implement inputs on stack for {} with abi size > 8", .{mcv}),5528 else => return self.fail("TODO implement inputs on stack for {} with abi size > 8", .{mcv}),
5588 }5529 }
5589 },5530 },
5590 .memory,5531 .memory, .linker_load => {
5591 .direct_load,
5592 .got_load,
5593 .imports_load,
5594 => {
5595 if (abi_size <= 8) {5532 if (abi_size <= 8) {
5596 const reg = try self.copyToTmpRegister(ty, mcv);5533 const reg = try self.copyToTmpRegister(ty, mcv);
5597 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });5534 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...@@ -5835,11 +5772,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5835 },5772 },
5836 }5773 }
5837 },5774 },
5838 .memory,5775 .memory, .linker_load => {
5839 .got_load,
5840 .direct_load,
5841 .imports_load,
5842 => {
5843 if (abi_size <= 8) {5776 if (abi_size <= 8) {
5844 const reg = try self.copyToTmpRegister(ty, mcv);5777 const reg = try self.copyToTmpRegister(ty, mcv);
5845 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts);5778 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts);
...@@ -5959,11 +5892,7 @@ fn genInlineMemcpy(...@@ -5959,11 +5892,7 @@ fn genInlineMemcpy(
5959 const tmp_reg = regs[4].to8();5892 const tmp_reg = regs[4].to8();
59605893
5961 switch (dst_ptr) {5894 switch (dst_ptr) {
5962 .memory,5895 .memory, .linker_load => {
5963 .got_load,
5964 .direct_load,
5965 .imports_load,
5966 => {
5967 try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr);5896 try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr);
5968 },5897 },
5969 .ptr_stack_offset, .stack_offset => |off| {5898 .ptr_stack_offset, .stack_offset => |off| {
...@@ -5992,11 +5921,7 @@ fn genInlineMemcpy(...@@ -5992,11 +5921,7 @@ fn genInlineMemcpy(
5992 }5921 }
59935922
5994 switch (src_ptr) {5923 switch (src_ptr) {
5995 .memory,5924 .memory, .linker_load => {
5996 .got_load,
5997 .direct_load,
5998 .imports_load,
5999 => {
6000 try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_ptr);5925 try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_ptr);
6001 },5926 },
6002 .ptr_stack_offset, .stack_offset => |off| {5927 .ptr_stack_offset, .stack_offset => |off| {
...@@ -6120,11 +6045,7 @@ fn genInlineMemset(...@@ -6120,11 +6045,7 @@ fn genInlineMemset(
6120 const index_reg = regs[1].to64();6045 const index_reg = regs[1].to64();
61216046
6122 switch (dst_ptr) {6047 switch (dst_ptr) {
6123 .memory,6048 .memory, .linker_load => {
6124 .got_load,
6125 .direct_load,
6126 .imports_load,
6127 => {
6128 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_ptr);6049 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_ptr);
6129 },6050 },
6130 .ptr_stack_offset, .stack_offset => |off| {6051 .ptr_stack_offset, .stack_offset => |off| {
...@@ -6356,10 +6277,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6356,10 +6277,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6356 .data = undefined,6277 .data = undefined,
6357 });6278 });
6358 },6279 },
6359 .direct_load,6280 .linker_load => {
6360 .got_load,
6361 .imports_load,
6362 => {
6363 switch (ty.zigTypeTag()) {6281 switch (ty.zigTypeTag()) {
6364 .Float => {6282 .Float => {
6365 const base_reg = try self.register_manager.allocReg(null, gp);6283 const base_reg = try self.register_manager.allocReg(null, gp);
...@@ -6753,11 +6671,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -6753,11 +6671,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
6753 // TODO Is this the only condition for pointer dereference for memcpy?6671 // TODO Is this the only condition for pointer dereference for memcpy?
6754 const src: MCValue = blk: {6672 const src: MCValue = blk: {
6755 switch (src_ptr) {6673 switch (src_ptr) {
6756 .got_load,6674 .linker_load, .memory => {
6757 .direct_load,
6758 .imports_load,
6759 .memory,
6760 => {
6761 const reg = try self.register_manager.allocReg(null, gp);6675 const reg = try self.register_manager.allocReg(null, gp);
6762 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);6676 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);
6763 _ = try self.addInst(.{6677 _ = try self.addInst(.{
...@@ -6997,10 +6911,16 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6997,10 +6911,16 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6997 return MCValue{ .memory = got_addr };6911 return MCValue{ .memory = got_addr };
6998 } else if (self.bin_file.cast(link.File.MachO)) |_| {6912 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6999 assert(decl.link.macho.sym_index != 0);6913 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 } };
7001 } else if (self.bin_file.cast(link.File.Coff)) |_| {6918 } else if (self.bin_file.cast(link.File.Coff)) |_| {
7002 assert(decl.link.coff.sym_index != 0);6919 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 } };
7004 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {6924 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
7005 try p9.seeDecl(decl_index);6925 try p9.seeDecl(decl_index);
7006 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;6926 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 {...@@ -7019,9 +6939,15 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
7019 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;6939 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
7020 return MCValue{ .memory = vaddr };6940 return MCValue{ .memory = vaddr };
7021 } else if (self.bin_file.cast(link.File.MachO)) |_| {6941 } 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 } };
7023 } else if (self.bin_file.cast(link.File.Coff)) |_| {6946 } 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 } };
7025 } else if (self.bin_file.cast(link.File.Plan9)) |_| {6951 } else if (self.bin_file.cast(link.File.Plan9)) |_| {
7026 return self.fail("TODO lower unnamed const in Plan9", .{});6952 return self.fail("TODO lower unnamed const in Plan9", .{});
7027 } else {6953 } else {
src/arch/x86_64/Emit.zig+11-8
...@@ -1021,10 +1021,14 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1021,10 +1021,14 @@ fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1021 .@"type" = switch (ops.flags) {1021 .@"type" = switch (ops.flags) {
1022 0b00 => .got,1022 0b00 => .got,
1023 0b01 => .direct,1023 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),
1025 else => unreachable,1030 else => unreachable,
1026 },1031 },
1027 .target = .{ .sym_index = relocation.sym_index, .file = null },
1028 .offset = @intCast(u32, end_offset - 4),1032 .offset = @intCast(u32, end_offset - 4),
1029 .addend = 0,1033 .addend = 0,
1030 .pcrel = true,1034 .pcrel = true,
...@@ -1142,12 +1146,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1142,12 +1146,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1142 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {1146 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
1143 // Add relocation to the decl.1147 // Add relocation to the decl.
1144 const atom = macho_file.atom_by_index_table.get(relocation.atom_index).?;1148 const atom = macho_file.atom_by_index_table.get(relocation.atom_index).?;
1149 const target = macho_file.getGlobalByIndex(relocation.sym_index);
1145 try atom.relocs.append(emit.bin_file.allocator, .{1150 try atom.relocs.append(emit.bin_file.allocator, .{
1146 .offset = offset,1151 .offset = offset,
1147 .target = .{1152 .target = target,
1148 .sym_index = relocation.sym_index,
1149 .file = null,
1150 },
1151 .addend = 0,1153 .addend = 0,
1152 .subtractor = null,1154 .subtractor = null,
1153 .pcrel = true,1155 .pcrel = true,
...@@ -1157,16 +1159,17 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1157,16 +1159,17 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1157 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {1159 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
1158 // Add relocation to the decl.1160 // Add relocation to the decl.
1159 const atom = coff_file.atom_by_index_table.get(relocation.atom_index).?;1161 const atom = coff_file.atom_by_index_table.get(relocation.atom_index).?;
1162 const target = coff_file.getGlobalByIndex(relocation.sym_index);
1160 try atom.addRelocation(coff_file, .{1163 try atom.addRelocation(coff_file, .{
1161 .@"type" = .direct,1164 .@"type" = .direct,
1162 .target = .{ .sym_index = relocation.sym_index, .file = null },1165 .target = target,
1163 .offset = offset,1166 .offset = offset,
1164 .addend = 0,1167 .addend = 0,
1165 .pcrel = true,1168 .pcrel = true,
1166 .length = 2,1169 .length = 2,
1167 });1170 });
1168 } else {1171 } 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", .{});
1170 }1173 }
1171}1174}
11721175
src/autodoc/render_source.zig+2-6
...@@ -137,7 +137,7 @@ pub fn genHtml(...@@ -137,7 +137,7 @@ pub fn genHtml(
137 );137 );
138138
139 const source = try src.getSource(allocator);139 const source = try src.getSource(allocator);
140 try tokenizeAndPrintRaw(allocator, out, source.bytes);140 try tokenizeAndPrintRaw(out, source.bytes);
141 try out.writeAll(141 try out.writeAll(
142 \\</body>142 \\</body>
143 \\</html>143 \\</html>
...@@ -150,13 +150,9 @@ const end_line = "</span>\n";...@@ -150,13 +150,9 @@ const end_line = "</span>\n";
150var line_counter: usize = 1;150var line_counter: usize = 1;
151151
152pub fn tokenizeAndPrintRaw(152pub fn tokenizeAndPrintRaw(
153 allocator: Allocator,
154 out: anytype,153 out: anytype,
155 raw_src: [:0]const u8,154 src: [:0]const u8,
156) !void {155) !void {
157 const src = try allocator.dupeZ(u8, raw_src);
158 defer allocator.free(src);
159
160 line_counter = 1;156 line_counter = 1;
161157
162 try out.print("<pre><code>" ++ start_line, .{line_counter});158 try out.print("<pre><code>" ++ start_line, .{line_counter});
src/glibc.zig+4-5
...@@ -719,17 +719,16 @@ pub fn buildSharedObjects(comp: *Compilation) !void {...@@ -719,17 +719,16 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
719 .lt => continue,719 .lt => continue,
720 .gt => {720 .gt => {
721 // TODO Expose via compile error mechanism instead of log.721 // 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});
723 return error.InvalidTargetGLibCVersion;723 return error.InvalidTargetGLibCVersion;
724 },724 },
725 }725 }
726 } else {726 } else blk: {
727 const latest_index = metadata.all_versions.len - 1;727 const latest_index = metadata.all_versions.len - 1;
728 // TODO Expose via compile error mechanism instead of log.728 log.warn("zig cannot build new glibc version {}; providing instead {}", .{
729 log.err("zig does not yet provide glibc version {}, the max provided version is {}", .{
730 target_version, metadata.all_versions[latest_index],729 target_version, metadata.all_versions[latest_index],
731 });730 });
732 return error.InvalidTargetGLibCVersion;731 break :blk latest_index;
733 };732 };
734733
735 {734 {
src/link/Coff.zig+61-18
...@@ -127,7 +127,7 @@ pub const Reloc = struct {...@@ -127,7 +127,7 @@ pub const Reloc = struct {
127 @"type": enum {127 @"type": enum {
128 got,128 got,
129 direct,129 direct,
130 imports,130 import,
131 },131 },
132 target: SymbolWithLoc,132 target: SymbolWithLoc,
133 offset: u32,133 offset: u32,
...@@ -141,7 +141,7 @@ pub const Reloc = struct {...@@ -141,7 +141,7 @@ pub const Reloc = struct {
141 switch (self.@"type") {141 switch (self.@"type") {
142 .got => return coff_file.getGotAtomForSymbol(self.target),142 .got => return coff_file.getGotAtomForSymbol(self.target),
143 .direct => return coff_file.getAtomForSymbol(self.target),143 .direct => return coff_file.getAtomForSymbol(self.target),
144 .imports => return coff_file.getImportAtomForSymbol(self.target),144 .import => return coff_file.getImportAtomForSymbol(self.target),
145 }145 }
146 }146 }
147};147};
...@@ -1423,23 +1423,22 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {...@@ -1423,23 +1423,22 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
1423 const sym = self.getSymbol(current);1423 const sym = self.getSymbol(current);
1424 const sym_name = self.getSymbolName(current);1424 const sym_name = self.getSymbolName(current);
14251425
1426 const global_index = self.resolver.get(sym_name) orelse {1426 const gop = try self.getOrPutGlobalPtr(sym_name);
1427 const name = try gpa.dupe(u8, sym_name);1427 if (!gop.found_existing) {
1428 const global_index = try self.allocateGlobal();1428 gop.value_ptr.* = current;
1429 self.globals.items[global_index] = current;
1430 try self.resolver.putNoClobber(gpa, name, global_index);
1431 if (sym.section_number == .UNDEFINED) {1429 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);
1433 }1431 }
1434 return;1432 return;
1435 };1433 }
14361434
1437 log.debug("TODO finish resolveGlobalSymbols implementation", .{});1435 log.debug("TODO finish resolveGlobalSymbols implementation", .{});
14381436
1439 if (sym.section_number == .UNDEFINED) return;1437 if (sym.section_number == .UNDEFINED) return;
14401438
1441 _ = self.unresolved.swapRemove(global_index);1439 _ = self.unresolved.swapRemove(self.getGlobalIndex(sym_name).?);
1442 self.globals.items[global_index] = current;1440
1441 gop.value_ptr.* = current;
1443}1442}
14441443
1445pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {1444pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {
...@@ -1544,25 +1543,26 @@ pub fn getDeclVAddr(...@@ -1544,25 +1543,26 @@ pub fn getDeclVAddr(
1544}1543}
15451544
1546pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {1545pub fn getGlobalSymbol(self: *Coff, name: []const u8) !u32 {
1547 if (self.resolver.get(name)) |global_index| {1546 const gop = try self.getOrPutGlobalPtr(name);
1548 return self.globals.items[global_index].sym_index;1547 const global_index = self.getGlobalIndex(name).?;
1548
1549 if (gop.found_existing) {
1550 return global_index;
1549 }1551 }
15501552
1551 const gpa = self.base.allocator;
1552 const sym_index = try self.allocateSymbol();1553 const sym_index = try self.allocateSymbol();
1553 const global_index = try self.allocateGlobal();
1554 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };1554 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;
1557 const sym_name = try gpa.dupe(u8, name);1558 const sym_name = try gpa.dupe(u8, name);
1558 const sym = self.getSymbolPtr(sym_loc);1559 const sym = self.getSymbolPtr(sym_loc);
1559 try self.setSymbolName(sym, sym_name);1560 try self.setSymbolName(sym, sym_name);
1560 sym.storage_class = .EXTERNAL;1561 sym.storage_class = .EXTERNAL;
15611562
1562 try self.resolver.putNoClobber(gpa, sym_name, global_index);
1563 try self.unresolved.putNoClobber(gpa, global_index, true);1563 try self.unresolved.putNoClobber(gpa, global_index, true);
15641564
1565 return sym_index;1565 return global_index;
1566}1566}
15671567
1568pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !void {1568pub 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 {...@@ -2061,6 +2061,49 @@ pub fn getSymbolName(self: *const Coff, sym_loc: SymbolWithLoc) []const u8 {
2061 return self.strtab.get(offset).?;2061 return self.strtab.get(offset).?;
2062}2062}
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
2064/// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor.2107/// Returns atom if there is an atom referenced by the symbol described by `sym_loc` descriptor.
2065/// Returns null on failure.2108/// Returns null on failure.
2066pub fn getAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {2109pub 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 {...@@ -111,13 +111,3 @@ pub fn addBaseRelocation(self: *Atom, coff_file: *Coff, offset: u32) !void {
111 }111 }
112 try gop.value_ptr.append(gpa, offset);112 try gop.value_ptr.append(gpa, offset);
113}113}
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,...@@ -131,17 +131,12 @@ la_symbol_ptr_section_index: ?u8 = null,
131data_section_index: ?u8 = null,131data_section_index: ?u8 = null,
132132
133locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},133locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
134globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},134globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
135// FIXME Jakub135resolver: std.StringHashMapUnmanaged(u32) = .{},
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.
142unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},136unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},
143137
144locals_free_list: std.ArrayListUnmanaged(u32) = .{},138locals_free_list: std.ArrayListUnmanaged(u32) = .{},
139globals_free_list: std.ArrayListUnmanaged(u32) = .{},
145140
146dyld_stub_binder_index: ?u32 = null,141dyld_stub_binder_index: ?u32 = null,
147dyld_private_atom: ?*Atom = null,142dyld_private_atom: ?*Atom = null,
...@@ -1917,7 +1912,7 @@ fn allocateSpecialSymbols(self: *MachO) !void {...@@ -1917,7 +1912,7 @@ fn allocateSpecialSymbols(self: *MachO) !void {
1917 "___dso_handle",1912 "___dso_handle",
1918 "__mh_execute_header",1913 "__mh_execute_header",
1919 }) |name| {1914 }) |name| {
1920 const global = self.globals.get(name) orelse continue;1915 const global = self.getGlobal(name) orelse continue;
1921 if (global.file != null) continue;1916 if (global.file != null) continue;
1922 const sym = self.getSymbolPtr(global);1917 const sym = self.getSymbolPtr(global);
1923 const seg = self.segments.items[self.text_segment_cmd_index.?];1918 const seg = self.segments.items[self.text_segment_cmd_index.?];
...@@ -2048,16 +2043,11 @@ fn writeAtomsIncremental(self: *MachO) !void {...@@ -2048,16 +2043,11 @@ fn writeAtomsIncremental(self: *MachO) !void {
20482043
2049pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {2044pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
2050 const gpa = self.base.allocator;2045 const gpa = self.base.allocator;
2051 const sym_index = @intCast(u32, self.locals.items.len);2046 const sym_index = try self.allocateSymbol();
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
2060 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);2047 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
2061 try atom.relocs.append(gpa, .{2051 try atom.relocs.append(gpa, .{
2062 .offset = 0,2052 .offset = 0,
2063 .target = target,2053 .target = target,
...@@ -2074,7 +2064,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {...@@ -2074,7 +2064,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
20742064
2075 const target_sym = self.getSymbol(target);2065 const target_sym = self.getSymbol(target);
2076 if (target_sym.undf()) {2066 if (target_sym.undf()) {
2077 const global = self.globals.get(self.getSymbolName(target)).?;2067 const global = self.getGlobal(self.getSymbolName(target)).?;
2078 try atom.bindings.append(gpa, .{2068 try atom.bindings.append(gpa, .{
2079 .target = global,2069 .target = global,
2080 .offset = 0,2070 .offset = 0,
...@@ -2093,20 +2083,15 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {...@@ -2093,20 +2083,15 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
20932083
2094pub fn createTlvPtrAtom(self: *MachO, target: SymbolWithLoc) !*Atom {2084pub fn createTlvPtrAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
2095 const gpa = self.base.allocator;2085 const gpa = self.base.allocator;
2096 const sym_index = @intCast(u32, self.locals.items.len);2086 const sym_index = try self.allocateSymbol();
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
2105 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);2087 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
2106 const target_sym = self.getSymbol(target);2091 const target_sym = self.getSymbol(target);
2107 assert(target_sym.undf());2092 assert(target_sym.undf());
21082093
2109 const global = self.globals.get(self.getSymbolName(target)).?;2094 const global = self.getGlobal(self.getSymbolName(target)).?;
2110 try atom.bindings.append(gpa, .{2095 try atom.bindings.append(gpa, .{
2111 .target = global,2096 .target = global,
2112 .offset = 0,2097 .offset = 0,
...@@ -2130,15 +2115,10 @@ fn createDyldPrivateAtom(self: *MachO) !void {...@@ -2130,15 +2115,10 @@ fn createDyldPrivateAtom(self: *MachO) !void {
2130 if (self.dyld_private_atom != null) return;2115 if (self.dyld_private_atom != null) return;
21312116
2132 const gpa = self.base.allocator;2117 const gpa = self.base.allocator;
2133 const sym_index = @intCast(u32, self.locals.items.len);2118 const sym_index = try self.allocateSymbol();
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 });
2141 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);2119 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);
2120 const sym = atom.getSymbolPtr(self);
2121 sym.n_type = macho.N_SECT;
2142 self.dyld_private_atom = atom;2122 self.dyld_private_atom = atom;
21432123
2144 try self.allocateAtomCommon(atom, self.data_section_index.?);2124 try self.allocateAtomCommon(atom, self.data_section_index.?);
...@@ -2163,15 +2143,11 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -2163,15 +2143,11 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
2163 .aarch64 => 2,2143 .aarch64 => 2,
2164 else => unreachable,2144 else => unreachable,
2165 };2145 };
2166 const sym_index = @intCast(u32, self.locals.items.len);2146 const sym_index = try self.allocateSymbol();
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 });
2174 const atom = try MachO.createEmptyAtom(gpa, sym_index, size, alignment);2147 const atom = try MachO.createEmptyAtom(gpa, sym_index, size, alignment);
2148 const sym = atom.getSymbolPtr(self);
2149 sym.n_type = macho.N_SECT;
2150
2175 const dyld_private_sym_index = self.dyld_private_atom.?.sym_index;2151 const dyld_private_sym_index = self.dyld_private_atom.?.sym_index;
2176 switch (arch) {2152 switch (arch) {
2177 .x86_64 => {2153 .x86_64 => {
...@@ -2288,15 +2264,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -2288,15 +2264,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
2288 .aarch64 => 2,2264 .aarch64 => 2,
2289 else => unreachable,2265 else => unreachable,
2290 };2266 };
2291 const sym_index = @intCast(u32, self.locals.items.len);2267 const sym_index = try self.allocateSymbol();
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 });
2299 const atom = try MachO.createEmptyAtom(gpa, sym_index, stub_size, alignment);2268 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
2300 try atom.relocs.ensureTotalCapacity(gpa, 1);2272 try atom.relocs.ensureTotalCapacity(gpa, 1);
23012273
2302 switch (arch) {2274 switch (arch) {
...@@ -2352,15 +2324,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -2352,15 +2324,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
23522324
2353pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom {2325pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom {
2354 const gpa = self.base.allocator;2326 const gpa = self.base.allocator;
2355 const sym_index = @intCast(u32, self.locals.items.len);2327 const sym_index = try self.allocateSymbol();
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 });
2363 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);2328 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
2364 try atom.relocs.append(gpa, .{2332 try atom.relocs.append(gpa, .{
2365 .offset = 0,2333 .offset = 0,
2366 .target = .{ .sym_index = stub_sym_index, .file = null },2334 .target = .{ .sym_index = stub_sym_index, .file = null },
...@@ -2376,7 +2344,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi...@@ -2376,7 +2344,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi
2376 });2344 });
2377 try atom.rebases.append(gpa, 0);2345 try atom.rebases.append(gpa, 0);
23782346
2379 const global = self.globals.get(self.getSymbolName(target)).?;2347 const global = self.getGlobal(self.getSymbolName(target)).?;
2380 try atom.lazy_bindings.append(gpa, .{2348 try atom.lazy_bindings.append(gpa, .{
2381 .target = global,2349 .target = global,
2382 .offset = 0,2350 .offset = 0,
...@@ -2403,15 +2371,11 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -2403,15 +2371,11 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
2403 .aarch64 => 3 * @sizeOf(u32),2371 .aarch64 => 3 * @sizeOf(u32),
2404 else => unreachable, // unhandled architecture type2372 else => unreachable, // unhandled architecture type
2405 };2373 };
2406 const sym_index = @intCast(u32, self.locals.items.len);2374 const sym_index = try self.allocateSymbol();
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 });
2414 const atom = try MachO.createEmptyAtom(gpa, sym_index, stub_size, alignment);2375 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
2415 switch (arch) {2379 switch (arch) {
2416 .x86_64 => {2380 .x86_64 => {
2417 // jmp2381 // jmp
...@@ -2472,7 +2436,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -2472,7 +2436,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
2472fn createTentativeDefAtoms(self: *MachO) !void {2436fn createTentativeDefAtoms(self: *MachO) !void {
2473 const gpa = self.base.allocator;2437 const gpa = self.base.allocator;
24742438
2475 for (self.globals.values()) |global| {2439 for (self.globals.items) |global| {
2476 const sym = self.getSymbolPtr(global);2440 const sym = self.getSymbolPtr(global);
2477 if (!sym.tentative()) continue;2441 if (!sym.tentative()) continue;
24782442
...@@ -2516,51 +2480,44 @@ fn createTentativeDefAtoms(self: *MachO) !void {...@@ -2516,51 +2480,44 @@ fn createTentativeDefAtoms(self: *MachO) !void {
25162480
2517fn createMhExecuteHeaderSymbol(self: *MachO) !void {2481fn createMhExecuteHeaderSymbol(self: *MachO) !void {
2518 if (self.base.options.output_mode != .Exe) return;2482 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| {
2520 const sym = self.getSymbol(global);2484 const sym = self.getSymbol(global);
2521 if (!sym.undf() and !(sym.pext() or sym.weakDef())) return;2485 if (!sym.undf() and !(sym.pext() or sym.weakDef())) return;
2522 }2486 }
25232487
2524 const gpa = self.base.allocator;2488 const gpa = self.base.allocator;
2525 const n_strx = try self.strtab.insert(gpa, "__mh_execute_header");2489 const sym_index = try self.allocateSymbol();
2526 const sym_index = @intCast(u32, self.locals.items.len);2490 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2527 try self.locals.append(gpa, .{2491 const sym = self.getSymbolPtr(sym_loc);
2528 .n_strx = n_strx,2492 sym.* = .{
2493 .n_strx = try self.strtab.insert(gpa, "__mh_execute_header"),
2529 .n_type = macho.N_SECT | macho.N_EXT,2494 .n_type = macho.N_SECT | macho.N_EXT,
2530 .n_sect = 0,2495 .n_sect = 0,
2531 .n_desc = macho.REFERENCED_DYNAMICALLY,2496 .n_desc = macho.REFERENCED_DYNAMICALLY,
2532 .n_value = 0,2497 .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,
2541 };2498 };
2499
2500 const gop = try self.getOrPutGlobalPtr("__mh_execute_header");
2501 gop.value_ptr.* = sym_loc;
2542}2502}
25432503
2544fn createDsoHandleSymbol(self: *MachO) !void {2504fn createDsoHandleSymbol(self: *MachO) !void {
2545 const global = self.globals.getPtr("___dso_handle") orelse return;2505 const global = self.getGlobalPtr("___dso_handle") orelse return;
2546 const sym = self.getSymbolPtr(global.*);2506 if (!self.getSymbol(global.*).undf()) return;
2547 if (!sym.undf()) return;
25482507
2549 const gpa = self.base.allocator;2508 const gpa = self.base.allocator;
2550 const n_strx = try self.strtab.insert(gpa, "___dso_handle");2509 const sym_index = try self.allocateSymbol();
2551 const sym_index = @intCast(u32, self.locals.items.len);2510 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2552 try self.locals.append(gpa, .{2511 const sym = self.getSymbolPtr(sym_loc);
2553 .n_strx = n_strx,2512 sym.* = .{
2513 .n_strx = try self.strtab.insert(gpa, "___dso_handle"),
2554 .n_type = macho.N_SECT | macho.N_EXT,2514 .n_type = macho.N_SECT | macho.N_EXT,
2555 .n_sect = 0,2515 .n_sect = 0,
2556 .n_desc = macho.N_WEAK_DEF,2516 .n_desc = macho.N_WEAK_DEF,
2557 .n_value = 0,2517 .n_value = 0,
2558 });
2559 global.* = .{
2560 .sym_index = sym_index,
2561 .file = null,
2562 };2518 };
2563 _ = self.unresolved.swapRemove(@intCast(u32, self.globals.getIndex("___dso_handle").?));2519 global.* = sym_loc;
2520 _ = self.unresolved.swapRemove(self.getGlobalIndex("___dso_handle").?);
2564}2521}
25652522
2566fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {2523fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
...@@ -2568,19 +2525,14 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {...@@ -2568,19 +2525,14 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
2568 const sym = self.getSymbol(current);2525 const sym = self.getSymbol(current);
2569 const sym_name = self.getSymbolName(current);2526 const sym_name = self.getSymbolName(current);
25702527
2571 const name = try gpa.dupe(u8, sym_name);2528 const gop = try self.getOrPutGlobalPtr(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
2576 if (!gop.found_existing) {2529 if (!gop.found_existing) {
2577 gop.value_ptr.* = current;2530 gop.value_ptr.* = current;
2578 if (sym.undf() and !sym.tentative()) {2531 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);
2580 }2533 }
2581 return;2534 return;
2582 }2535 }
2583
2584 const global = gop.value_ptr.*;2536 const global = gop.value_ptr.*;
2585 const global_sym = self.getSymbol(global);2537 const global_sym = self.getSymbol(global);
25862538
...@@ -2619,7 +2571,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {...@@ -2619,7 +2571,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
2619 }2571 }
2620 if (sym.undf() and !sym.tentative()) return;2572 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
2624 gop.value_ptr.* = current;2576 gop.value_ptr.* = current;
2625}2577}
...@@ -2664,7 +2616,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2664,7 +2616,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2664 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id };2616 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id };
2665 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {2617 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
2666 error.MultipleSymbolDefinitions => {2618 error.MultipleSymbolDefinitions => {
2667 const global = self.globals.get(sym_name).?;2619 const global = self.getGlobal(sym_name).?;
2668 log.err("symbol '{s}' defined multiple times", .{sym_name});2620 log.err("symbol '{s}' defined multiple times", .{sym_name});
2669 if (global.file) |file| {2621 if (global.file) |file| {
2670 log.err(" first definition in '{s}'", .{self.objects.items[file].name});2622 log.err(" first definition in '{s}'", .{self.objects.items[file].name});
...@@ -2684,7 +2636,8 @@ fn resolveSymbolsInArchives(self: *MachO) !void {...@@ -2684,7 +2636,8 @@ fn resolveSymbolsInArchives(self: *MachO) !void {
2684 const cpu_arch = self.base.options.target.cpu.arch;2636 const cpu_arch = self.base.options.target.cpu.arch;
2685 var next_sym: usize = 0;2637 var next_sym: usize = 0;
2686 loop: while (next_sym < self.unresolved.count()) {2638 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];
2688 const sym_name = self.getSymbolName(global);2641 const sym_name = self.getSymbolName(global);
26892642
2690 for (self.archives.items) |archive| {2643 for (self.archives.items) |archive| {
...@@ -2710,10 +2663,11 @@ fn resolveSymbolsInArchives(self: *MachO) !void {...@@ -2710,10 +2663,11 @@ fn resolveSymbolsInArchives(self: *MachO) !void {
2710fn resolveSymbolsInDylibs(self: *MachO) !void {2663fn resolveSymbolsInDylibs(self: *MachO) !void {
2711 if (self.dylibs.items.len == 0) return;2664 if (self.dylibs.items.len == 0) return;
27122665
2666 const gpa = self.base.allocator;
2713 var next_sym: usize = 0;2667 var next_sym: usize = 0;
2714 loop: while (next_sym < self.unresolved.count()) {2668 loop: while (next_sym < self.unresolved.count()) {
2715 const global_index = self.unresolved.keys()[next_sym];2669 const global_index = self.unresolved.keys()[next_sym];
2716 const global = self.globals.values()[global_index];2670 const global = self.globals.items[global_index];
2717 const sym = self.getSymbolPtr(global);2671 const sym = self.getSymbolPtr(global);
2718 const sym_name = self.getSymbolName(global);2672 const sym_name = self.getSymbolName(global);
27192673
...@@ -2722,7 +2676,7 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {...@@ -2722,7 +2676,7 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {
27222676
2723 const dylib_id = @intCast(u16, id);2677 const dylib_id = @intCast(u16, id);
2724 if (!self.referenced_dylibs.contains(dylib_id)) {2678 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, {});
2726 }2680 }
27272681
2728 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;2682 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;
...@@ -2760,7 +2714,7 @@ fn resolveSymbolsAtLoading(self: *MachO) !void {...@@ -2760,7 +2714,7 @@ fn resolveSymbolsAtLoading(self: *MachO) !void {
2760 var next_sym: usize = 0;2714 var next_sym: usize = 0;
2761 while (next_sym < self.unresolved.count()) {2715 while (next_sym < self.unresolved.count()) {
2762 const global_index = self.unresolved.keys()[next_sym];2716 const global_index = self.unresolved.keys()[next_sym];
2763 const global = self.globals.values()[global_index];2717 const global = self.globals.items[global_index];
2764 const sym = self.getSymbolPtr(global);2718 const sym = self.getSymbolPtr(global);
2765 const sym_name = self.getSymbolName(global);2719 const sym_name = self.getSymbolName(global);
27662720
...@@ -2800,26 +2754,27 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -2800,26 +2754,27 @@ fn resolveDyldStubBinder(self: *MachO) !void {
2800 if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports2754 if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports
28012755
2802 const gpa = self.base.allocator;2756 const gpa = self.base.allocator;
2803 const n_strx = try self.strtab.insert(gpa, "dyld_stub_binder");2757 const sym_index = try self.allocateSymbol();
2804 const sym_index = @intCast(u32, self.locals.items.len);2758 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2805 try self.locals.append(gpa, .{2759 const sym = self.getSymbolPtr(sym_loc);
2806 .n_strx = n_strx,2760 const sym_name = "dyld_stub_binder";
2761 sym.* = .{
2762 .n_strx = try self.strtab.insert(gpa, sym_name),
2807 .n_type = macho.N_UNDF,2763 .n_type = macho.N_UNDF,
2808 .n_sect = 0,2764 .n_sect = 0,
2809 .n_desc = 0,2765 .n_desc = 0,
2810 .n_value = 0,2766 .n_value = 0,
2811 });2767 };
2812 const sym_name = try gpa.dupe(u8, "dyld_stub_binder");2768 const gop = try self.getOrPutGlobalPtr(sym_name);
2813 const global = SymbolWithLoc{ .sym_index = sym_index, .file = null };2769 gop.value_ptr.* = sym_loc;
2814 try self.globals.putNoClobber(gpa, sym_name, global);2770 const global = gop.value_ptr.*;
2815 const sym = &self.locals.items[sym_index];
28162771
2817 for (self.dylibs.items) |dylib, id| {2772 for (self.dylibs.items) |dylib, id| {
2818 if (!dylib.symbols.contains(sym_name)) continue;2773 if (!dylib.symbols.contains(sym_name)) continue;
28192774
2820 const dylib_id = @intCast(u16, id);2775 const dylib_id = @intCast(u16, id);
2821 if (!self.referenced_dylibs.contains(dylib_id)) {2776 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, {});
2823 }2778 }
28242779
2825 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;2780 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;
...@@ -3050,14 +3005,20 @@ pub fn deinit(self: *MachO) void {...@@ -3050,14 +3005,20 @@ pub fn deinit(self: *MachO) void {
3050 self.stubs_free_list.deinit(gpa);3005 self.stubs_free_list.deinit(gpa);
3051 self.stubs_table.deinit(gpa);3006 self.stubs_table.deinit(gpa);
3052 self.strtab.deinit(gpa);3007 self.strtab.deinit(gpa);
3008
3053 self.locals.deinit(gpa);3009 self.locals.deinit(gpa);
3010 self.globals.deinit(gpa);
3054 self.locals_free_list.deinit(gpa);3011 self.locals_free_list.deinit(gpa);
3012 self.globals_free_list.deinit(gpa);
3055 self.unresolved.deinit(gpa);3013 self.unresolved.deinit(gpa);
30563014
3057 for (self.globals.keys()) |key| {3015 {
3058 gpa.free(key);3016 var it = self.resolver.keyIterator();
3017 while (it.next()) |key_ptr| {
3018 gpa.free(key_ptr.*);
3019 }
3020 self.resolver.deinit(gpa);
3059 }3021 }
3060 self.globals.deinit(gpa);
30613022
3062 for (self.objects.items) |*object| {3023 for (self.objects.items) |*object| {
3063 object.deinit(gpa);3024 object.deinit(gpa);
...@@ -3211,6 +3172,29 @@ fn allocateSymbol(self: *MachO) !u32 {...@@ -3211,6 +3172,29 @@ fn allocateSymbol(self: *MachO) !u32 {
3211 return index;3172 return index;
3212}3173}
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
3214pub fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {3198pub fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {
3215 const gpa = self.base.allocator;3199 const gpa = self.base.allocator;
3216 try self.got_entries.ensureUnusedCapacity(gpa, 1);3200 try self.got_entries.ensureUnusedCapacity(gpa, 1);
...@@ -3832,7 +3816,7 @@ pub fn updateDeclExports(...@@ -3832,7 +3816,7 @@ pub fn updateDeclExports(
38323816
3833 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {3817 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
3834 error.MultipleSymbolDefinitions => {3818 error.MultipleSymbolDefinitions => {
3835 const global = self.globals.get(exp_name).?;3819 const global = self.getGlobal(exp_name).?;
3836 if (sym_loc.sym_index != global.sym_index and global.file != null) {3820 if (sym_loc.sym_index != global.sym_index and global.file != null) {
3837 _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(3821 _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(
3838 gpa,3822 gpa,
...@@ -3869,11 +3853,13 @@ pub fn deleteExport(self: *MachO, exp: Export) void {...@@ -3869,11 +3853,13 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
3869 };3853 };
3870 self.locals_free_list.append(gpa, sym_index) catch {};3854 self.locals_free_list.append(gpa, sym_index) catch {};
38713855
3872 if (self.globals.get(sym_name)) |global| blk: {3856 if (self.resolver.fetchRemove(sym_name)) |entry| {
3873 if (global.sym_index != sym_index) break :blk;3857 defer gpa.free(entry.key);
3874 if (global.file != null) break :blk;3858 self.globals_free_list.append(gpa, entry.value) catch {};
3875 const kv = self.globals.fetchSwapRemove(sym_name);3859 self.globals.items[entry.value] = .{
3876 gpa.free(kv.?.key);3860 .sym_index = 0,
3861 .file = null,
3862 };
3877 }3863 }
3878}3864}
38793865
...@@ -4864,32 +4850,26 @@ pub fn addAtomToSection(self: *MachO, atom: *Atom, sect_id: u8) !void {...@@ -4864,32 +4850,26 @@ pub fn addAtomToSection(self: *MachO, atom: *Atom, sect_id: u8) !void {
48644850
4865pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {4851pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {
4866 const gpa = self.base.allocator;4852 const gpa = self.base.allocator;
4853
4867 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});4854 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
4868 const global_index = @intCast(u32, self.globals.values().len);4855 defer gpa.free(sym_name);
4869 const gop = try self.globals.getOrPut(gpa, sym_name);4856 const gop = try self.getOrPutGlobalPtr(sym_name);
4870 defer if (gop.found_existing) gpa.free(sym_name);4857 const global_index = self.getGlobalIndex(sym_name).?;
48714858
4872 if (gop.found_existing) {4859 if (gop.found_existing) {
4873 // TODO audit this: can we ever reference anything from outside the Zig module?4860 return global_index;
4874 assert(gop.value_ptr.file == null);
4875 return gop.value_ptr.sym_index;
4876 }4861 }
48774862
4878 const sym_index = @intCast(u32, self.locals.items.len);4863 const sym_index = try self.allocateSymbol();
4879 try self.locals.append(gpa, .{4864 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
4880 .n_strx = try self.strtab.insert(gpa, sym_name),4865 gop.value_ptr.* = sym_loc;
4881 .n_type = macho.N_UNDF,4866
4882 .n_sect = 0,4867 const sym = self.getSymbolPtr(sym_loc);
4883 .n_desc = 0,4868 sym.n_strx = try self.strtab.insert(gpa, sym_name);
4884 .n_value = 0,4869
4885 });
4886 gop.value_ptr.* = .{
4887 .sym_index = sym_index,
4888 .file = null,
4889 };
4890 try self.unresolved.putNoClobber(gpa, global_index, true);4870 try self.unresolved.putNoClobber(gpa, global_index, true);
48914871
4892 return sym_index;4872 return global_index;
4893}4873}
48944874
4895fn getSegmentAllocBase(self: MachO, indices: []const ?u8) struct { vmaddr: u64, fileoff: u64 } {4875fn 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 {...@@ -5055,7 +5035,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5055 if (self.base.options.output_mode == .Exe) {5035 if (self.base.options.output_mode == .Exe) {
5056 for (&[_]SymbolWithLoc{5036 for (&[_]SymbolWithLoc{
5057 try self.getEntryPoint(),5037 try self.getEntryPoint(),
5058 self.globals.get("__mh_execute_header").?,5038 self.getGlobal("__mh_execute_header").?,
5059 }) |global| {5039 }) |global| {
5060 const sym = self.getSymbol(global);5040 const sym = self.getSymbol(global);
5061 const sym_name = self.getSymbolName(global);5041 const sym_name = self.getSymbolName(global);
...@@ -5068,7 +5048,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {...@@ -5068,7 +5048,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5068 }5048 }
5069 } else {5049 } else {
5070 assert(self.base.options.output_mode == .Lib);5050 assert(self.base.options.output_mode == .Lib);
5071 for (self.globals.values()) |global| {5051 for (self.globals.items) |global| {
5072 const sym = self.getSymbol(global);5052 const sym = self.getSymbol(global);
50735053
5074 if (sym.undf()) continue;5054 if (sym.undf()) continue;
...@@ -5271,9 +5251,9 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {...@@ -5271,9 +5251,9 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5271 // We need to sort by address first5251 // We need to sort by address first
5272 var addresses = std.ArrayList(u64).init(gpa);5252 var addresses = std.ArrayList(u64).init(gpa);
5273 defer addresses.deinit();5253 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| {
5277 const sym = self.getSymbol(global);5257 const sym = self.getSymbol(global);
5278 if (sym.undf()) continue;5258 if (sym.undf()) continue;
5279 if (sym.n_desc == N_DESC_GCED) continue;5259 if (sym.n_desc == N_DESC_GCED) continue;
...@@ -5453,7 +5433,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -5453,7 +5433,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
5453 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip5433 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip
5454 const sym_loc = SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = null };5434 const sym_loc = SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = null };
5455 if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip5435 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, skip5436 if (self.getGlobal(self.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
5457 try locals.append(sym);5437 try locals.append(sym);
5458 }5438 }
54595439
...@@ -5463,7 +5443,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -5463,7 +5443,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
5463 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip5443 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip
5464 const sym_loc = SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = @intCast(u32, object_id) };5444 const sym_loc = SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = @intCast(u32, object_id) };
5465 if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip5445 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, skip5446 if (self.getGlobal(self.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
5467 var out_sym = sym;5447 var out_sym = sym;
5468 out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc));5448 out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc));
5469 try locals.append(out_sym);5449 try locals.append(out_sym);
...@@ -5477,7 +5457,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -5477,7 +5457,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
5477 var exports = std.ArrayList(macho.nlist_64).init(gpa);5457 var exports = std.ArrayList(macho.nlist_64).init(gpa);
5478 defer exports.deinit();5458 defer exports.deinit();
54795459
5480 for (self.globals.values()) |global| {5460 for (self.globals.items) |global| {
5481 const sym = self.getSymbol(global);5461 const sym = self.getSymbol(global);
5482 if (sym.undf()) continue; // import, skip5462 if (sym.undf()) continue; // import, skip
5483 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip5463 if (sym.n_desc == N_DESC_GCED) continue; // GCed, skip
...@@ -5491,7 +5471,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -5491,7 +5471,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
54915471
5492 var imports_table = std.AutoHashMap(SymbolWithLoc, u32).init(gpa);5472 var imports_table = std.AutoHashMap(SymbolWithLoc, u32).init(gpa);
54935473
5494 for (self.globals.values()) |global| {5474 for (self.globals.items) |global| {
5495 const sym = self.getSymbol(global);5475 const sym = self.getSymbol(global);
5496 if (sym.n_strx == 0) continue; // no name, skip5476 if (sym.n_strx == 0) continue; // no name, skip
5497 if (!sym.undf()) continue; // not an import, skip5477 if (!sym.undf()) continue; // not an import, skip
...@@ -5798,6 +5778,49 @@ pub fn getSymbolName(self: *MachO, sym_with_loc: SymbolWithLoc) []const u8 {...@@ -5798,6 +5778,49 @@ pub fn getSymbolName(self: *MachO, sym_with_loc: SymbolWithLoc) []const u8 {
5798 }5778 }
5799}5779}
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
5801/// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor.5824/// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor.
5802/// Returns null on failure.5825/// Returns null on failure.
5803pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom {5826pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom {
...@@ -5834,7 +5857,7 @@ pub fn getTlvPtrAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom...@@ -5834,7 +5857,7 @@ pub fn getTlvPtrAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom
5834/// Asserts output mode is executable.5857/// Asserts output mode is executable.
5835pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {5858pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {
5836 const entry_name = self.base.options.entry orelse "_main";5859 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 {
5838 log.err("entrypoint '{s}' not found", .{entry_name});5861 log.err("entrypoint '{s}' not found", .{entry_name});
5839 return error.MissingMainEntrypoint;5862 return error.MissingMainEntrypoint;
5840 };5863 };
...@@ -6342,9 +6365,9 @@ fn logSymtab(self: *MachO) void {...@@ -6342,9 +6365,9 @@ fn logSymtab(self: *MachO) void {
6342 }6365 }
63436366
6344 log.debug("globals table:", .{});6367 log.debug("globals table:", .{});
6345 for (self.globals.keys()) |name, id| {6368 for (self.globals.items) |global| {
6346 const value = self.globals.values()[id];6369 const name = self.getSymbolName(global);
6347 log.debug(" {s} => %{d} in object({?d})", .{ name, value.sym_index, value.file });6370 log.debug(" {s} => %{d} in object({?d})", .{ name, global.sym_index, global.file });
6348 }6371 }
63496372
6350 log.debug("GOT entries:", .{});6373 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,...@@ -272,7 +272,7 @@ pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info,
272 subtractor = sym_loc;272 subtractor = sym_loc;
273 } else {273 } else {
274 const sym_name = context.macho_file.getSymbolName(sym_loc);274 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).?;
276 }276 }
277 // Verify that *_SUBTRACTOR is followed by *_UNSIGNED.277 // Verify that *_SUBTRACTOR is followed by *_UNSIGNED.
278 if (relocs.len <= i + 1) {278 if (relocs.len <= i + 1) {
...@@ -339,7 +339,7 @@ pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info,...@@ -339,7 +339,7 @@ pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info,
339 break :target sym_loc;339 break :target sym_loc;
340 } else {340 } else {
341 const sym_name = context.macho_file.getSymbolName(sym_loc);341 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).?;
343 }343 }
344 };344 };
345 const offset = @intCast(u32, rel.r_address - context.base_offset);345 const offset = @intCast(u32, rel.r_address - context.base_offset);
...@@ -579,7 +579,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {...@@ -579,7 +579,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
579 // If there is no atom for target, we still need to check for special, atom-less579 // If there is no atom for target, we still need to check for special, atom-less
580 // symbols such as `___dso_handle`.580 // symbols such as `___dso_handle`.
581 const target_name = macho_file.getSymbolName(rel.target);581 const target_name = macho_file.getSymbolName(rel.target);
582 assert(macho_file.globals.contains(target_name));582 assert(macho_file.getGlobal(target_name) != null);
583 const atomless_sym = macho_file.getSymbol(rel.target);583 const atomless_sym = macho_file.getSymbol(rel.target);
584 log.debug(" | atomless target '{s}'", .{target_name});584 log.debug(" | atomless target '{s}'", .{target_name});
585 break :blk atomless_sym.n_value;585 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 {...@@ -480,7 +480,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
480 if (sym.n_desc == MachO.N_DESC_GCED) continue; // GCed, skip480 if (sym.n_desc == MachO.N_DESC_GCED) continue; // GCed, skip
481 const sym_loc = MachO.SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = null };481 const sym_loc = MachO.SymbolWithLoc{ .sym_index = @intCast(u32, sym_id), .file = null };
482 if (self.base.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip482 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, skip483 if (self.base.getGlobal(self.base.getSymbolName(sym_loc)) != null) continue; // global symbol is either an export or import, skip
484 var out_sym = sym;484 var out_sym = sym;
485 out_sym.n_strx = try self.strtab.insert(gpa, self.base.getSymbolName(sym_loc));485 out_sym.n_strx = try self.strtab.insert(gpa, self.base.getSymbolName(sym_loc));
486 try locals.append(out_sym);486 try locals.append(out_sym);
...@@ -489,7 +489,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {...@@ -489,7 +489,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
489 var exports = std.ArrayList(macho.nlist_64).init(gpa);489 var exports = std.ArrayList(macho.nlist_64).init(gpa);
490 defer exports.deinit();490 defer exports.deinit();
491491
492 for (self.base.globals.values()) |global| {492 for (self.base.globals.items) |global| {
493 const sym = self.base.getSymbol(global);493 const sym = self.base.getSymbol(global);
494 if (sym.undf()) continue; // import, skip494 if (sym.undf()) continue; // import, skip
495 if (sym.n_desc == MachO.N_DESC_GCED) continue; // GCed, skip495 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...@@ -62,7 +62,7 @@ fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void
62 else => |other| {62 else => |other| {
63 assert(other == .Lib);63 assert(other == .Lib);
64 // Add exports as GC roots64 // Add exports as GC roots
65 for (macho_file.globals.values()) |global| {65 for (macho_file.globals.items) |global| {
66 const sym = macho_file.getSymbol(global);66 const sym = macho_file.getSymbol(global);
67 if (!sym.sect()) continue;67 if (!sym.sect()) continue;
68 const atom = macho_file.getAtomForSymbol(global) orelse {68 const atom = macho_file.getAtomForSymbol(global) orelse {
...@@ -77,7 +77,7 @@ fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void...@@ -77,7 +77,7 @@ fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void
77 }77 }
7878
79 // TODO just a temp until we learn how to parse unwind records79 // 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| {
81 if (macho_file.getAtomForSymbol(global)) |atom| {81 if (macho_file.getAtomForSymbol(global)) |atom| {
82 _ = try roots.getOrPut(atom);82 _ = try roots.getOrPut(atom);
83 log.debug("adding root", .{});83 log.debug("adding root", .{});
src/translate_c.zig+18-2
...@@ -5957,20 +5957,36 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5957,20 +5957,36 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5957 return bytes[0..i];5957 return bytes[0..i];
5958}5958}
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
5960fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {5976fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5961 const tok = m.next().?;5977 const tok = m.next().?;
5962 const slice = m.slice();5978 const slice = m.slice();
5963 switch (tok) {5979 switch (tok) {
5964 .CharLiteral => {5980 .CharLiteral => {
5965 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {5981 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));
5967 } else {5983 } else {
5968 const str = try std.fmt.allocPrint(c.arena, "0x{s}", .{std.fmt.fmtSliceHexLower(slice[1 .. slice.len - 1])});5984 const str = try std.fmt.allocPrint(c.arena, "0x{s}", .{std.fmt.fmtSliceHexLower(slice[1 .. slice.len - 1])});
5969 return Tag.integer_literal.create(c.arena, str);5985 return Tag.integer_literal.create(c.arena, str);
5970 }5986 }
5971 },5987 },
5972 .StringLiteral => {5988 .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));
5974 },5990 },
5975 .IntegerLiteral, .FloatLiteral => {5991 .IntegerLiteral, .FloatLiteral => {
5976 return parseCNumLit(c, m);5992 return parseCNumLit(c, m);
src/type.zig+3
...@@ -2042,6 +2042,9 @@ pub const Type = extern union {...@@ -2042,6 +2042,9 @@ pub const Type = extern union {
2042 try writer.writeAll("fn(");2042 try writer.writeAll("fn(");
2043 for (fn_info.param_types) |param_ty, i| {2043 for (fn_info.param_types) |param_ty, i| {
2044 if (i != 0) try writer.writeAll(", ");2044 if (i != 0) try writer.writeAll(", ");
2045 if (fn_info.paramIsComptime(i)) {
2046 try writer.writeAll("comptime ");
2047 }
2045 if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) {2048 if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) {
2046 try writer.writeAll("noalias ");2049 try writer.writeAll("noalias ");
2047 };2050 };
test/behavior/alignof.zig-1
...@@ -13,7 +13,6 @@ const Foo = struct {...@@ -13,7 +13,6 @@ const Foo = struct {
13test "@alignOf(T) before referencing T" {13test "@alignOf(T) before referencing T" {
14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
17 comptime try expect(@alignOf(Foo) != maxInt(usize));16 comptime try expect(@alignOf(Foo) != maxInt(usize));
18 if (native_arch == .x86_64) {17 if (native_arch == .x86_64) {
19 comptime try expect(@alignOf(Foo) == 4);18 comptime try expect(@alignOf(Foo) == 4);
test/behavior/array.zig-5
...@@ -175,7 +175,6 @@ test "nested arrays of integers" {...@@ -175,7 +175,6 @@ test "nested arrays of integers" {
175175
176test "implicit comptime in array type size" {176test "implicit comptime in array type size" {
177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
179178
180 var arr: [plusOne(10)]bool = undefined;179 var arr: [plusOne(10)]bool = undefined;
181 try expect(arr.len == 11);180 try expect(arr.len == 11);
...@@ -245,7 +244,6 @@ const Sub = struct { b: u8 };...@@ -245,7 +244,6 @@ const Sub = struct { b: u8 };
245const Str = struct { a: []Sub };244const Str = struct { a: []Sub };
246test "set global var array via slice embedded in struct" {245test "set global var array via slice embedded in struct" {
247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;246 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
248 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
249247
250 var s = Str{ .a = s_array[0..] };248 var s = Str{ .a = s_array[0..] };
251249
...@@ -298,7 +296,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 {...@@ -298,7 +296,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 {
298296
299test "comptime evaluating function that takes array by value" {297test "comptime evaluating function that takes array by value" {
300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
302299
303 const arr = [_]u8{ 1, 2 };300 const arr = [_]u8{ 1, 2 };
304 const x = comptime testArrayByValAtComptime(arr);301 const x = comptime testArrayByValAtComptime(arr);
...@@ -427,7 +424,6 @@ test "anonymous literal in array" {...@@ -427,7 +424,6 @@ test "anonymous literal in array" {
427424
428test "access the null element of a null terminated array" {425test "access the null element of a null terminated array" {
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;426 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
430 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
431427
432 const S = struct {428 const S = struct {
433 fn doTheTest() !void {429 fn doTheTest() !void {
...@@ -484,7 +480,6 @@ test "sentinel element count towards the ABI size calculation" {...@@ -484,7 +480,6 @@ test "sentinel element count towards the ABI size calculation" {
484test "zero-sized array with recursive type definition" {480test "zero-sized array with recursive type definition" {
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO481 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO482 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
488483
489 const U = struct {484 const U = struct {
490 fn foo(comptime T: type, comptime n: usize) type {485 fn foo(comptime T: type, comptime n: usize) type {
test/behavior/basic.zig-4
...@@ -465,7 +465,6 @@ fn nine() u8 {...@@ -465,7 +465,6 @@ fn nine() u8 {
465465
466test "struct inside function" {466test "struct inside function" {
467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
468 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
469468
470 try testStructInFn();469 try testStructInFn();
471 comptime try testStructInFn();470 comptime try testStructInFn();
...@@ -514,7 +513,6 @@ var global_foo: *i32 = undefined;...@@ -514,7 +513,6 @@ var global_foo: *i32 = undefined;
514513
515test "peer result location with typed parent, runtime condition, comptime prongs" {514test "peer result location with typed parent, runtime condition, comptime prongs" {
516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;515 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
517 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
518516
519 const S = struct {517 const S = struct {
520 fn doTheTest(arg: i32) i32 {518 fn doTheTest(arg: i32) i32 {
...@@ -643,7 +641,6 @@ test "global constant is loaded with a runtime-known index" {...@@ -643,7 +641,6 @@ test "global constant is loaded with a runtime-known index" {
643641
644test "multiline string literal is null terminated" {642test "multiline string literal is null terminated" {
645 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;643 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
646 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
647644
648 const s1 =645 const s1 =
649 \\one646 \\one
...@@ -1060,7 +1057,6 @@ comptime {...@@ -1060,7 +1057,6 @@ comptime {
10601057
1061test "switch inside @as gets correct type" {1058test "switch inside @as gets correct type" {
1062 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1059 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1063 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10641060
1065 var a: u32 = 0;1061 var a: u32 = 0;
1066 var b: [2]u32 = undefined;1062 var b: [2]u32 = undefined;
test/behavior/bitcast.zig-1
...@@ -138,7 +138,6 @@ test "@bitCast extern structs at runtime and comptime" {...@@ -138,7 +138,6 @@ test "@bitCast extern structs at runtime and comptime" {
138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
139 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;139 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
140 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;140 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
141 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
142141
143 const Full = extern struct {142 const Full = extern struct {
144 number: u16,143 number: u16,
test/behavior/cast.zig-10
...@@ -523,7 +523,6 @@ fn testCastConstArrayRefToConstSlice() !void {...@@ -523,7 +523,6 @@ fn testCastConstArrayRefToConstSlice() !void {
523523
524test "peer type resolution: error and [N]T" {524test "peer type resolution: error and [N]T" {
525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
526 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
527526
528 try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));527 try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
529 comptime try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));528 comptime try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
...@@ -548,7 +547,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {...@@ -548,7 +547,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
548test "single-item pointer of array to slice to unknown length pointer" {547test "single-item pointer of array to slice to unknown length pointer" {
549 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;548 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
550 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO549 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
551 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
552550
553 try testCastPtrOfArrayToSliceAndPtr();551 try testCastPtrOfArrayToSliceAndPtr();
554 comptime try testCastPtrOfArrayToSliceAndPtr();552 comptime try testCastPtrOfArrayToSliceAndPtr();
...@@ -578,7 +576,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {...@@ -578,7 +576,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {
578test "cast *[1][*]const u8 to [*]const ?[*]const u8" {576test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
579 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
580 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO578 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
581 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
582 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO579 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
583580
584 const window_name = [1][*]const u8{"window name"};581 const window_name = [1][*]const u8{"window name"};
...@@ -649,7 +646,6 @@ test "@floatCast cast down" {...@@ -649,7 +646,6 @@ test "@floatCast cast down" {
649test "peer type resolution: unreachable, error set, unreachable" {646test "peer type resolution: unreachable, error set, unreachable" {
650 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO647 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
651 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO648 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
652 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
653649
654 const Error = error{650 const Error = error{
655 FileDescriptorAlreadyPresentInSet,651 FileDescriptorAlreadyPresentInSet,
...@@ -922,7 +918,6 @@ test "peer cast *[N:x]T to *[N]T" {...@@ -922,7 +918,6 @@ test "peer cast *[N:x]T to *[N]T" {
922918
923test "peer cast [*:x]T to [*]T" {919test "peer cast [*:x]T to [*]T" {
924 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO920 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
925 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
926 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO921 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
927922
928 const S = struct {923 const S = struct {
...@@ -964,7 +959,6 @@ test "peer cast [:x]T to [*:x]T" {...@@ -964,7 +959,6 @@ test "peer cast [:x]T to [*:x]T" {
964959
965test "peer type resolution implicit cast to return type" {960test "peer type resolution implicit cast to return type" {
966 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;961 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
968962
969 const S = struct {963 const S = struct {
970 fn doTheTest() !void {964 fn doTheTest() !void {
...@@ -984,7 +978,6 @@ test "peer type resolution implicit cast to return type" {...@@ -984,7 +978,6 @@ test "peer type resolution implicit cast to return type" {
984978
985test "peer type resolution implicit cast to variable type" {979test "peer type resolution implicit cast to variable type" {
986 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;980 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
987 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
988 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO981 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
989982
990 const S = struct {983 const S = struct {
...@@ -1009,7 +1002,6 @@ test "variable initialization uses result locations properly with regards to the...@@ -1009,7 +1002,6 @@ test "variable initialization uses result locations properly with regards to the
10091002
1010test "cast between C pointer with different but compatible types" {1003test "cast between C pointer with different but compatible types" {
1011 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1004 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1012 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10131005
1014 const S = struct {1006 const S = struct {
1015 fn foo(arg: [*]c_ushort) u16 {1007 fn foo(arg: [*]c_ushort) u16 {
...@@ -1026,7 +1018,6 @@ test "cast between C pointer with different but compatible types" {...@@ -1026,7 +1018,6 @@ test "cast between C pointer with different but compatible types" {
10261018
1027test "peer type resolve string lit with sentinel-terminated mutable slice" {1019test "peer type resolve string lit with sentinel-terminated mutable slice" {
1028 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1020 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1030 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1021 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10311022
1032 var array: [4:0]u8 = undefined;1023 var array: [4:0]u8 = undefined;
...@@ -1079,7 +1070,6 @@ test "comptime float casts" {...@@ -1079,7 +1070,6 @@ test "comptime float casts" {
1079test "pointer reinterpret const float to int" {1070test "pointer reinterpret const float to int" {
1080 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1071 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1081 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1072 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1082 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10831073
1084 // The hex representation is 0x3fe3333333333303.1074 // The hex representation is 0x3fe3333333333303.
1085 const float: f64 = 5.99999999999994648725e-01;1075 const float: f64 = 5.99999999999994648725e-01;
test/behavior/comptime_memory.zig-2
...@@ -87,7 +87,6 @@ fn bigToNativeEndian(comptime T: type, v: T) T {...@@ -87,7 +87,6 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
87test "type pun endianness" {87test "type pun endianness" {
88 if (builtin.zig_backend == .stage1) return error.SkipZigTest;88 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
89 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO89 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
90 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9190
92 comptime {91 comptime {
93 const StructOfBytes = extern struct { x: [4]u8 };92 const StructOfBytes = extern struct { x: [4]u8 };
...@@ -398,7 +397,6 @@ test "offset field ptr by enclosing array element size" {...@@ -398,7 +397,6 @@ test "offset field ptr by enclosing array element size" {
398test "accessing reinterpreted memory of parent object" {397test "accessing reinterpreted memory of parent object" {
399 if (builtin.zig_backend == .stage1) return error.SkipZigTest;398 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
400 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO399 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
401 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
402 const S = extern struct {400 const S = extern struct {
403 a: f32,401 a: f32,
404 b: [4]u8,402 b: [4]u8,
test/behavior/const_slice_child.zig-1
...@@ -9,7 +9,6 @@ var argv: [*]const [*]const u8 = undefined;...@@ -9,7 +9,6 @@ var argv: [*]const [*]const u8 = undefined;
9test "const slice child" {9test "const slice child" {
10 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1312
14 const strs = [_][*]const u8{ "one", "two", "three" };13 const strs = [_][*]const u8{ "one", "two", "three" };
15 argv = &strs;14 argv = &strs;
test/behavior/enum.zig-6
...@@ -606,7 +606,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {...@@ -606,7 +606,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
606}606}
607607
608test "enum with specified tag values" {608test "enum with specified tag values" {
609 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
610 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;609 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
611610
612 try testEnumWithSpecifiedTagValues(MultipleChoice.C);611 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
...@@ -614,7 +613,6 @@ test "enum with specified tag values" {...@@ -614,7 +613,6 @@ test "enum with specified tag values" {
614}613}
615614
616test "non-exhaustive enum" {615test "non-exhaustive enum" {
617 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
618 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;616 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
619617
620 const S = struct {618 const S = struct {
...@@ -677,7 +675,6 @@ test "empty non-exhaustive enum" {...@@ -677,7 +675,6 @@ test "empty non-exhaustive enum" {
677}675}
678676
679test "single field non-exhaustive enum" {677test "single field non-exhaustive enum" {
680 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
681 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;678 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
682679
683 const S = struct {680 const S = struct {
...@@ -741,7 +738,6 @@ test "cast integer literal to enum" {...@@ -741,7 +738,6 @@ test "cast integer literal to enum" {
741}738}
742739
743test "enum with specified and unspecified tag values" {740test "enum with specified and unspecified tag values" {
744 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
745 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;741 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
746742
747 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);743 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
...@@ -925,7 +921,6 @@ test "enum literal casting to tagged union" {...@@ -925,7 +921,6 @@ test "enum literal casting to tagged union" {
925const Bar = enum { A, B, C, D };921const Bar = enum { A, B, C, D };
926922
927test "enum literal casting to error union with payload enum" {923test "enum literal casting to error union with payload enum" {
928 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;924 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
930925
931 var bar: error{B}!Bar = undefined;926 var bar: error{B}!Bar = undefined;
...@@ -1132,7 +1127,6 @@ test "tag name functions are unique" {...@@ -1132,7 +1127,6 @@ test "tag name functions are unique" {
11321127
1133test "size of enum with only one tag which has explicit integer tag type" {1128test "size of enum with only one tag which has explicit integer tag type" {
1134 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;1129 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1130 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11371131
1138 const E = enum(u8) { nope = 10 };1132 const E = enum(u8) { nope = 10 };
test/behavior/error.zig-4
...@@ -222,7 +222,6 @@ fn testErrorSetType() !void {...@@ -222,7 +222,6 @@ fn testErrorSetType() !void {
222222
223test "explicit error set cast" {223test "explicit error set cast" {
224 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO224 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
226 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO225 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
227226
228 try testExplicitErrorSetCast(Set1.A);227 try testExplicitErrorSetCast(Set1.A);
...@@ -282,7 +281,6 @@ test "inferred empty error set comptime catch" {...@@ -282,7 +281,6 @@ test "inferred empty error set comptime catch" {
282}281}
283282
284test "error union peer type resolution" {283test "error union peer type resolution" {
285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
286 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO284 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
287285
288 try testErrorUnionPeerTypeResolution(1);286 try testErrorUnionPeerTypeResolution(1);
...@@ -327,7 +325,6 @@ fn foo3(b: usize) Error!usize {...@@ -327,7 +325,6 @@ fn foo3(b: usize) Error!usize {
327325
328test "error: Infer error set from literals" {326test "error: Infer error set from literals" {
329 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
331328
332 _ = nullLiteral("n") catch |err| handleErrors(err);329 _ = nullLiteral("n") catch |err| handleErrors(err);
333 _ = floatLiteral("n") catch |err| handleErrors(err);330 _ = floatLiteral("n") catch |err| handleErrors(err);
...@@ -700,7 +697,6 @@ test "ret_ptr doesn't cause own inferred error set to be resolved" {...@@ -700,7 +697,6 @@ test "ret_ptr doesn't cause own inferred error set to be resolved" {
700697
701test "simple else prong allowed even when all errors handled" {698test "simple else prong allowed even when all errors handled" {
702 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO699 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
704 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO700 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
705701
706 const S = struct {702 const S = struct {
test/behavior/eval.zig-10
...@@ -69,7 +69,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {...@@ -69,7 +69,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
69}69}
7070
71test "constant expressions" {71test "constant expressions" {
72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
73 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7473
75 var array: [array_size]u8 = undefined;74 var array: [array_size]u8 = undefined;
...@@ -138,7 +137,6 @@ test "pointer to type" {...@@ -138,7 +137,6 @@ test "pointer to type" {
138test "a type constructed in a global expression" {137test "a type constructed in a global expression" {
139 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO138 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
140 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
141 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
142140
143 var l: List = undefined;141 var l: List = undefined;
144 l.array[0] = 10;142 l.array[0] = 10;
...@@ -338,7 +336,6 @@ fn doesAlotT(comptime T: type, value: usize) T {...@@ -338,7 +336,6 @@ fn doesAlotT(comptime T: type, value: usize) T {
338}336}
339337
340test "@setEvalBranchQuota at same scope as generic function call" {338test "@setEvalBranchQuota at same scope as generic function call" {
341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO339 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343340
344 try expect(doesAlotT(u32, 2) == 2);341 try expect(doesAlotT(u32, 2) == 2);
...@@ -565,7 +562,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio...@@ -565,7 +562,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
565}562}
566563
567test "ptr to local array argument at comptime" {564test "ptr to local array argument at comptime" {
568 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
569 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
570566
571 comptime {567 comptime {
...@@ -806,7 +802,6 @@ test "array concatenation sets the sentinel - value" {...@@ -806,7 +802,6 @@ test "array concatenation sets the sentinel - value" {
806test "array concatenation sets the sentinel - pointer" {802test "array concatenation sets the sentinel - pointer" {
807 if (builtin.zig_backend == .stage1) return error.SkipZigTest;803 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
808 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;804 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
809 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
810 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;805 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
811806
812 var a = [2]u3{ 1, 7 };807 var a = [2]u3{ 1, 7 };
...@@ -956,7 +951,6 @@ test "const local with comptime init through array init" {...@@ -956,7 +951,6 @@ test "const local with comptime init through array init" {
956951
957test "closure capture type of runtime-known parameter" {952test "closure capture type of runtime-known parameter" {
958 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO953 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
959 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
960954
961 const S = struct {955 const S = struct {
962 fn b(c: anytype) !void {956 fn b(c: anytype) !void {
...@@ -1074,7 +1068,6 @@ test "comptime break operand passing through runtime switch converted to runtime...@@ -1074,7 +1068,6 @@ test "comptime break operand passing through runtime switch converted to runtime
10741068
1075test "no dependency loop for alignment of self struct" {1069test "no dependency loop for alignment of self struct" {
1076 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1070 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1077 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10781071
1079 const S = struct {1072 const S = struct {
1080 fn doTheTest() !void {1073 fn doTheTest() !void {
...@@ -1111,7 +1104,6 @@ test "no dependency loop for alignment of self struct" {...@@ -1111,7 +1104,6 @@ test "no dependency loop for alignment of self struct" {
11111104
1112test "no dependency loop for alignment of self bare union" {1105test "no dependency loop for alignment of self bare union" {
1113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1106 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11151107
1116 const S = struct {1108 const S = struct {
1117 fn doTheTest() !void {1109 fn doTheTest() !void {
...@@ -1148,7 +1140,6 @@ test "no dependency loop for alignment of self bare union" {...@@ -1148,7 +1140,6 @@ test "no dependency loop for alignment of self bare union" {
11481140
1149test "no dependency loop for alignment of self tagged union" {1141test "no dependency loop for alignment of self tagged union" {
1150 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11521143
1153 const S = struct {1144 const S = struct {
1154 fn doTheTest() !void {1145 fn doTheTest() !void {
...@@ -1336,7 +1327,6 @@ test "lazy sizeof is resolved in division" {...@@ -1336,7 +1327,6 @@ test "lazy sizeof is resolved in division" {
1336}1327}
13371328
1338test "lazy value is resolved as slice operand" {1329test "lazy value is resolved as slice operand" {
1339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1330 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13411331
1342 const A = struct { a: u32 };1332 const A = struct { a: u32 };
test/behavior/field_parent_ptr.zig-2
...@@ -2,7 +2,6 @@ const expect = @import("std").testing.expect;...@@ -2,7 +2,6 @@ const expect = @import("std").testing.expect;
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4test "@fieldParentPtr non-first field" {4test "@fieldParentPtr non-first field" {
5 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;5 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
...@@ -11,7 +10,6 @@ test "@fieldParentPtr non-first field" {...@@ -11,7 +10,6 @@ test "@fieldParentPtr non-first field" {
11}10}
1211
13test "@fieldParentPtr first field" {12test "@fieldParentPtr first field" {
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;13 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;14 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
test/behavior/for.zig-4
...@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;...@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
5const mem = std.mem;5const mem = std.mem;
66
7test "continue in for loop" {7test "continue in for loop" {
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109
11 const array = [_]i32{ 1, 2, 3, 4, 5 };10 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" {...@@ -130,7 +129,6 @@ test "for with null and T peer types and inferred result location type" {
130}129}
131130
132test "2 break statements and an else" {131test "2 break statements and an else" {
133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135133
136 const S = struct {134 const S = struct {
...@@ -177,7 +175,6 @@ fn mangleString(s: []u8) void {...@@ -177,7 +175,6 @@ fn mangleString(s: []u8) void {
177}175}
178176
179test "for copies its payload" {177test "for copies its payload" {
180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
181 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO178 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
182179
183 const S = struct {180 const S = struct {
...@@ -213,7 +210,6 @@ test "for on slice with allowzero ptr" {...@@ -213,7 +210,6 @@ test "for on slice with allowzero ptr" {
213210
214test "else continue outer for" {211test "else continue outer for" {
215 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
217213
218 var i: usize = 6;214 var i: usize = 6;
219 var buf: [5]u8 = undefined;215 var buf: [5]u8 = undefined;
test/behavior/generics.zig-1
...@@ -91,7 +91,6 @@ fn max_f64(a: f64, b: f64) f64 {...@@ -91,7 +91,6 @@ fn max_f64(a: f64, b: f64) f64 {
9191
92test "type constructed by comptime function call" {92test "type constructed by comptime function call" {
93 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;93 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
94 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;94 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9695
97 var l: SimpleList(10) = undefined;96 var l: SimpleList(10) = undefined;
test/behavior/merge_error_sets.zig-1
...@@ -12,7 +12,6 @@ fn foo() C!void {...@@ -12,7 +12,6 @@ fn foo() C!void {
12}12}
1313
14test "merge error sets" {14test "merge error sets" {
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;16 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
18 if (foo()) {17 if (foo()) {
test/behavior/pointers.zig-14
...@@ -17,8 +17,6 @@ fn testDerefPtr() !void {...@@ -17,8 +17,6 @@ fn testDerefPtr() !void {
17}17}
1818
19test "pointer arithmetic" {19test "pointer arithmetic" {
20 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2321
24 var ptr: [*]const u8 = "abcd";22 var ptr: [*]const u8 = "abcd";
...@@ -65,8 +63,6 @@ test "initialize const optional C pointer to null" {...@@ -65,8 +63,6 @@ test "initialize const optional C pointer to null" {
65}63}
6664
67test "assigning integer to C pointer" {65test "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;
70 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7167
72 var x: i32 = 0;68 var x: i32 = 0;
...@@ -83,8 +79,6 @@ test "assigning integer to C pointer" {...@@ -83,8 +79,6 @@ test "assigning integer to C pointer" {
83}79}
8480
85test "C pointer comparison and arithmetic" {81test "C pointer comparison and arithmetic" {
86 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
87
88 const S = struct {82 const S = struct {
89 fn doTheTest() !void {83 fn doTheTest() !void {
90 var ptr1: [*c]u32 = 0;84 var ptr1: [*c]u32 = 0;
...@@ -150,7 +144,6 @@ test "peer type resolution with C pointer and const pointer" {...@@ -150,7 +144,6 @@ test "peer type resolution with C pointer and const pointer" {
150}144}
151145
152test "implicit casting between C pointer and optional non-C pointer" {146test "implicit casting between C pointer and optional non-C pointer" {
153 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
156149
...@@ -281,8 +274,6 @@ test "array initialization types" {...@@ -281,8 +274,6 @@ test "array initialization types" {
281274
282test "null terminated pointer" {275test "null terminated pointer" {
283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;276 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
287 const S = struct {278 const S = struct {
288 fn doTheTest() !void {279 fn doTheTest() !void {
...@@ -299,8 +290,6 @@ test "null terminated pointer" {...@@ -299,8 +290,6 @@ test "null terminated pointer" {
299290
300test "allow any sentinel" {291test "allow any sentinel" {
301 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;292 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
305 const S = struct {294 const S = struct {
306 fn doTheTest() !void {295 fn doTheTest() !void {
...@@ -315,8 +304,6 @@ test "allow any sentinel" {...@@ -315,8 +304,6 @@ test "allow any sentinel" {
315304
316test "pointer sentinel with enums" {305test "pointer sentinel with enums" {
317 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;306 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
321 const S = struct {308 const S = struct {
322 const Number = enum {309 const Number = enum {
...@@ -337,7 +324,6 @@ test "pointer sentinel with enums" {...@@ -337,7 +324,6 @@ test "pointer sentinel with enums" {
337test "pointer sentinel with optional element" {324test "pointer sentinel with optional element" {
338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;325 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO326 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
340 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
341327
342 const S = struct {328 const S = struct {
343 fn doTheTest() !void {329 fn doTheTest() !void {
test/behavior/ptrcast.zig-3
...@@ -4,7 +4,6 @@ const expect = std.testing.expect;...@@ -4,7 +4,6 @@ const expect = std.testing.expect;
4const native_endian = builtin.target.cpu.arch.endian();4const native_endian = builtin.target.cpu.arch.endian();
55
6test "reinterpret bytes as integer with nonzero offset" {6test "reinterpret bytes as integer with nonzero offset" {
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98
10 try testReinterpretBytesAsInteger();9 try testReinterpretBytesAsInteger();
...@@ -39,7 +38,6 @@ fn testReinterpretWithOffsetAndNoWellDefinedLayout() !void {...@@ -39,7 +38,6 @@ fn testReinterpretWithOffsetAndNoWellDefinedLayout() !void {
39}38}
4039
41test "reinterpret bytes inside auto-layout struct as integer with nonzero offset" {40test "reinterpret bytes inside auto-layout struct as integer with nonzero offset" {
42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4442
45 try testReinterpretStructWrappedBytesAsInteger();43 try testReinterpretStructWrappedBytesAsInteger();
...@@ -179,7 +177,6 @@ test "lower reinterpreted comptime field ptr" {...@@ -179,7 +177,6 @@ test "lower reinterpreted comptime field ptr" {
179}177}
180178
181test "reinterpret struct field at comptime" {179test "reinterpret struct field at comptime" {
182 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
183 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO180 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
184181
185 const numNative = comptime Bytes.init(0x12345678);182 const numNative = comptime Bytes.init(0x12345678);
test/behavior/sizeof_and_typeof.zig-2
...@@ -18,7 +18,6 @@ test "@sizeOf on compile-time types" {...@@ -18,7 +18,6 @@ test "@sizeOf on compile-time types" {
18}18}
1919
20test "@TypeOf() with multiple arguments" {20test "@TypeOf() with multiple arguments" {
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
22 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;21 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;22 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
24 {23 {
...@@ -77,7 +76,6 @@ const P = packed struct {...@@ -77,7 +76,6 @@ const P = packed struct {
77};76};
7877
79test "@offsetOf" {78test "@offsetOf" {
80 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;79 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8280
83 // Packed structs have fixed memory layout81 // Packed structs have fixed memory layout
test/behavior/slice.zig-3
...@@ -28,7 +28,6 @@ comptime {...@@ -28,7 +28,6 @@ comptime {
2828
29test "slicing" {29test "slicing" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3231
33 var array: [20]i32 = undefined;32 var array: [20]i32 = undefined;
3433
...@@ -269,7 +268,6 @@ fn sliceSum(comptime q: []const u8) i32 {...@@ -269,7 +268,6 @@ fn sliceSum(comptime q: []const u8) i32 {
269268
270test "slice type with custom alignment" {269test "slice type with custom alignment" {
271 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;270 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
272 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
273271
274 const LazilyResolvedType = struct {272 const LazilyResolvedType = struct {
275 anything: i32,273 anything: i32,
...@@ -283,7 +281,6 @@ test "slice type with custom alignment" {...@@ -283,7 +281,6 @@ test "slice type with custom alignment" {
283281
284test "obtaining a null terminated slice" {282test "obtaining a null terminated slice" {
285 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
286 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
287284
288 // here we have a normal array285 // here we have a normal array
289 var buf: [50]u8 = undefined;286 var buf: [50]u8 = undefined;
test/behavior/struct.zig-8
...@@ -10,7 +10,6 @@ top_level_field: i32,...@@ -10,7 +10,6 @@ top_level_field: i32,
1010
11test "top level fields" {11test "top level fields" {
12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1413
15 var instance = @This(){14 var instance = @This(){
16 .top_level_field = 1234,15 .top_level_field = 1234,
...@@ -104,7 +103,6 @@ fn testMutation(foo: *StructFoo) void {...@@ -104,7 +103,6 @@ fn testMutation(foo: *StructFoo) void {
104103
105test "struct byval assign" {104test "struct byval assign" {
106 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;105 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
108106
109 var foo1: StructFoo = undefined;107 var foo1: StructFoo = undefined;
110 var foo2: StructFoo = undefined;108 var foo2: StructFoo = undefined;
...@@ -240,7 +238,6 @@ test "usingnamespace within struct scope" {...@@ -240,7 +238,6 @@ test "usingnamespace within struct scope" {
240238
241test "struct field init with catch" {239test "struct field init with catch" {
242 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
243 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
244241
245 const S = struct {242 const S = struct {
246 fn doTheTest() !void {243 fn doTheTest() !void {
...@@ -281,7 +278,6 @@ const Val = struct {...@@ -281,7 +278,6 @@ const Val = struct {
281test "struct point to self" {278test "struct point to self" {
282 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;279 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
283 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO280 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
284 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
285281
286 var root: Node = undefined;282 var root: Node = undefined;
287 root.val.x = 1;283 root.val.x = 1;
...@@ -297,7 +293,6 @@ test "struct point to self" {...@@ -297,7 +293,6 @@ test "struct point to self" {
297293
298test "void struct fields" {294test "void struct fields" {
299 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
300 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
301296
302 const foo = VoidStructFieldsFoo{297 const foo = VoidStructFieldsFoo{
303 .a = void{},298 .a = void{},
...@@ -761,7 +756,6 @@ test "packed struct with u0 field access" {...@@ -761,7 +756,6 @@ test "packed struct with u0 field access" {
761}756}
762757
763test "access to global struct fields" {758test "access to global struct fields" {
764 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
765 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO759 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
766 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO760 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
767761
...@@ -1260,7 +1254,6 @@ test "typed init through error unions and optionals" {...@@ -1260,7 +1254,6 @@ test "typed init through error unions and optionals" {
12601254
1261test "initialize struct with empty literal" {1255test "initialize struct with empty literal" {
1262 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1256 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1263 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12641257
1265 const S = struct { x: i32 = 1234 };1258 const S = struct { x: i32 = 1234 };
1266 var s: S = .{};1259 var s: S = .{};
...@@ -1362,7 +1355,6 @@ test "store to comptime field" {...@@ -1362,7 +1355,6 @@ test "store to comptime field" {
13621355
1363test "struct field init value is size of the struct" {1356test "struct field init value is size of the struct" {
1364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13661358
1367 const namespace = struct {1359 const namespace = struct {
1368 const S = extern struct {1360 const S = extern struct {
test/behavior/switch.zig-2
...@@ -348,7 +348,6 @@ test "switch on const enum with var" {...@@ -348,7 +348,6 @@ test "switch on const enum with var" {
348}348}
349349
350test "anon enum literal used in switch on union enum" {350test "anon enum literal used in switch on union enum" {
351 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
352 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO351 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
353352
354 const Foo = union(enum) {353 const Foo = union(enum) {
...@@ -490,7 +489,6 @@ test "switch prongs with error set cases make a new error set type for capture v...@@ -490,7 +489,6 @@ test "switch prongs with error set cases make a new error set type for capture v
490}489}
491490
492test "return result loc and then switch with range implicit casted to error union" {491test "return result loc and then switch with range implicit casted to error union" {
493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO492 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
495493
496 const S = struct {494 const S = struct {
test/behavior/this.zig-1
...@@ -25,7 +25,6 @@ test "this refer to module call private fn" {...@@ -25,7 +25,6 @@ test "this refer to module call private fn" {
25}25}
2626
27test "this refer to container" {27test "this refer to container" {
28 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3029
31 var pt: Point(i32) = undefined;30 var pt: Point(i32) = undefined;
test/behavior/translate_c_macros.zig+12
...@@ -5,6 +5,7 @@ const expectEqual = std.testing.expectEqual;...@@ -5,6 +5,7 @@ const expectEqual = std.testing.expectEqual;
5const expectEqualStrings = std.testing.expectEqualStrings;5const expectEqualStrings = std.testing.expectEqualStrings;
66
7const h = @cImport(@cInclude("behavior/translate_c_macros.h"));7const h = @cImport(@cInclude("behavior/translate_c_macros.h"));
8const latin1 = @cImport(@cInclude("behavior/translate_c_macros_not_utf8.h"));
89
9test "casting to void with a macro" {10test "casting to void with a macro" {
10 h.IGNORE_ME_1(42);11 h.IGNORE_ME_1(42);
...@@ -134,3 +135,14 @@ test "string literal macro with embedded tab character" {...@@ -134,3 +135,14 @@ test "string literal macro with embedded tab character" {
134135
135 try expectEqualStrings("hello\t", h.EMBEDDED_TAB);136 try expectEqualStrings("hello\t", h.EMBEDDED_TAB);
136}137}
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");...@@ -3,7 +3,6 @@ const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "try on error union" {5test "try on error union" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
87
9 try tryOnErrorUnionImpl();8 try tryOnErrorUnionImpl();
test/behavior/typename.zig+2-2
...@@ -122,7 +122,7 @@ test "top level decl" {...@@ -122,7 +122,7 @@ test "top level decl" {
122 );122 );
123 // generic fn123 // generic fn
124 try expectEqualStrings(124 try expectEqualStrings(
125 "fn(type) type",125 "fn(comptime type) type",
126 @typeName(@TypeOf(TypeFromFn)),126 @typeName(@TypeOf(TypeFromFn)),
127 );127 );
128}128}
...@@ -244,5 +244,5 @@ test "comptime parameters not converted to anytype in function type" {...@@ -244,5 +244,5 @@ test "comptime parameters not converted to anytype in function type" {
244 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO244 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
245245
246 const T = fn (fn (type) void, void) void;246 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));
248}248}
test/behavior/union.zig-1
...@@ -92,7 +92,6 @@ const FooExtern = extern union {...@@ -92,7 +92,6 @@ const FooExtern = extern union {
92};92};
9393
94test "basic extern unions" {94test "basic extern unions" {
95 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
96 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9796
98 var foo = FooExtern{ .int = 1 };97 var foo = FooExtern{ .int = 1 };
test/behavior/usingnamespace.zig-1
...@@ -58,7 +58,6 @@ test "two files usingnamespace import each other" {...@@ -58,7 +58,6 @@ test "two files usingnamespace import each other" {
58}58}
5959
60test {60test {
61 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
62 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO61 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6362
64 const AA = struct {63 const AA = struct {
test/behavior/while.zig-1
...@@ -175,7 +175,6 @@ test "while with optional as condition with else" {...@@ -175,7 +175,6 @@ test "while with optional as condition with else" {
175175
176test "while with error union condition" {176test "while with error union condition" {
177 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;177 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;178 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
180179
181 numbers_left = 10;180 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