From da3964ef8edc2535dc3b146241ce419919649579 Mon Sep 17 00:00:00 2001 From: kntkymt Date: Thu, 21 Dec 2023 22:29:40 +0900 Subject: [PATCH] Support char (byte integer) on Gen --- Sources/Generator/Generator.swift | 74 ++++++++++++++++++++++++++----- test_exectable.sh | 7 +++ 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/Sources/Generator/Generator.swift b/Sources/Generator/Generator.swift index 9e865c1..94c3e58 100644 --- a/Sources/Generator/Generator.swift +++ b/Sources/Generator/Generator.swift @@ -60,7 +60,8 @@ public final class Generator { var result = "" // g: .zeroじゃApple Clangは動かない? - result += ".comm g,\(node.type.memorySize),8\n" + let alignment = isElementOrReferenceTypeMemorySizeOf(1, identifierName: node.identifierName) ? 0 : 8 + result += ".comm \(node.identifierName),\(node.type.memorySize),\(alignment)\n" globalVariables[node.identifierName] = node.type @@ -86,13 +87,17 @@ public final class Generator { // 配列の場合は先頭アドレスのまま返す // 配列以外の場合はアドレスの中身を返す - if variables[casted.identifierName]?.type.kind != .arrayType { + if let variableType = getVariableType(name: casted.identifierName), variableType.kind != .arrayType { // アドレスをpop result += " ldr x0, [sp]\n" result += " add sp, sp, #16\n" // アドレスを値に変換してpush - result += " ldr x0, [x0]\n" + if variableType.memorySize == 1 { + result += " ldrb w0, [x0]\n" + } else { + result += " ldr x0, [x0]\n" + } result += " str x0, [sp, #-16]!\n" } @@ -180,7 +185,12 @@ public final class Generator { // 結果のアドレスの値をロードしてスタックに積む result += " ldr x0, [sp]\n" result += " add sp, sp, #16\n" - result += " ldr x0, [x0]\n" + + if isElementOrReferenceTypeMemorySizeOf(1, identifierName: casted.identifierNode.identifierName) { + result += " ldrb w0, [x0]\n" + } else { + result += " ldr x0, [x0]\n" + } result += " str x0, [sp, #-16]!\n" return result @@ -335,7 +345,12 @@ public final class Generator { result += " add sp, sp, #16\n" // 値をアドレスとして読み、アドレスが指す値をロード - result += " ldr x0, [x0]\n" + if let identifier = casted.right as? IdentifierNode, isElementOrReferenceTypeMemorySizeOf(1, identifierName: identifier.identifierName) { + result += " ldrb w0, [x0]\n" + } else { + result += " ldr x0, [x0]\n" + } + result += " str x0, [sp, #-16]!\n" case .address: @@ -374,7 +389,16 @@ public final class Generator { result += " add sp, sp, #16\n" // assign - result += " str x0, [x1]\n" + if let identifier = casted.left as? IdentifierNode, getVariableType(name: identifier.identifierName)?.memorySize == 1 { + result += " strb w0, [x1]\n" + } else if let pointer = casted.left as? PrefixOperatorExpressionNode, pointer.operatorKind == .reference, let identifier = pointer.right as? IdentifierNode, isElementOrReferenceTypeMemorySizeOf(1, identifierName: identifier.identifierName) { + result += " strb w0, [x1]\n" + } else if let subscriptCall = casted.left as? SubscriptCallExpressionNode, + isElementOrReferenceTypeMemorySizeOf(1, identifierName: subscriptCall.identifierNode.identifierName) { + result += " strb w0, [x1]\n" + } else { + result += " str x0, [x1]\n" + } result += " str x0, [sp, #-16]!\n" @@ -392,10 +416,9 @@ public final class Generator { if binaryOperator.operatorKind == .add || binaryOperator.operatorKind == .sub { // addまたはsubの時、一方が変数でポインタ型または配列だったら、他方を8倍する // 8は8バイト(ポインタの指すサイズ、今は全部8バイトなので) - if let identifier = casted.left as? IdentifierNode, - variables[identifier.identifierName]?.type is PointerTypeNode || variables[identifier.identifierName]?.type is ArrayTypeNode { + if let identifier = casted.left as? IdentifierNode, isElementOrReferenceTypeMemorySizeOf(8, identifierName: identifier.identifierName) { result += " lsl x0, x0, #3\n" - } else if let identifier = casted.right as? IdentifierNode, variables[identifier.identifierName]?.type is PointerTypeNode || variables[identifier.identifierName]?.type is ArrayTypeNode { + } else if let identifier = casted.right as? IdentifierNode, isElementOrReferenceTypeMemorySizeOf(8, identifierName: identifier.identifierName) { result += " lsl x1, x1, #3\n" } } @@ -459,6 +482,31 @@ public final class Generator { // MARK: - Private + /// local or global variableから変数を検索する + private func getVariableType(name: String) -> (any TypeNodeProtocol)? { + if let type = variables[name]?.type { + type + } else if let type = globalVariables[name] { + type + } else { + nil + } + } + + private func isElementOrReferenceTypeMemorySizeOf(_ size: Int, identifierName: String) -> Bool { + guard let identifierType = getVariableType(name: identifierName) else { return false } + + if let pointerType = identifierType as? PointerTypeNode { + return pointerType.referenceType.memorySize == size + } + + if let arrayType = identifierType as? ArrayTypeNode { + return arrayType.elementType.memorySize == size + } + + return false + } + /// nameの変数のアドレスをスタックにpushするコードを生成する private func generatePushVariableAddress(node: IdentifierNode) throws -> String { var result = "" @@ -487,8 +535,12 @@ public final class Generator { result += " ldr x0, [sp]\n" result += " add sp, sp, #16\n" - // subscriptの方は8倍 - result += " lsl x0, x0, 3\n" + // subscript内の値は要素のメモリサイズに応じてn倍する + if let arrayType = getVariableType(name: node.identifierNode.identifierName) as? ArrayTypeNode, arrayType.elementType.memorySize == 8 { + result += " lsl x0, x0, 3\n" + } else if let pointerType = getVariableType(name: node.identifierNode.identifierName) as? PointerTypeNode, pointerType.referenceType.memorySize == 8 { + result += " lsl x0, x0, 3\n" + } result += " ldr x1, [sp]\n" result += " add sp, sp, #16\n" diff --git a/test_exectable.sh b/test_exectable.sh index 48d2066..94eb4e5 100755 --- a/test_exectable.sh +++ b/test_exectable.sh @@ -83,5 +83,12 @@ assert 10 "int g; int main() { g = 10; return g; }" assert 100 "int g; int main() { g = 10; return g * 10; }" assert 30 "int g; int sub() { g = 30; return 0; } int main() { g = 20; sub(); return g; }" assert 30 "int g[10]; int main() { g[2] = 10; g[3] = 20; return g[2] + g[2 + 1]; }" +assert 10 "int main() { char x; x = 10; return x; }" +assert 30 "int main() { char x; x = 10; char* p; p = &x; *p = 30; return x; }" +assert 3 "int main() { char x[3]; x[0] = -1; x[1] = 2; int y; y = 4; return x[0] + y; }" +assert 15 "char x; int main() { x = 15; return x; }" +assert 3 "char x[3]; int main() { x[0] = -1; x[1] = 2; int y; y = 4; return x[0] + y; }" +assert 150 "int main() { int x; x = 300; return x / 2; }" +assert 22 "int main() { char x; x = 300; return x / 2; }" echo OK