Commit 36da8d02b5

Evan Haas <evan@lagerdata.com>
2021-05-13 08:06:28
translate-c: translate global (file scope) assembly
1 parent 607abb5
src/translate_c/ast.zig
@@ -161,6 +161,8 @@ pub const Node = extern union {
         /// @shuffle(type, a, b, mask)
         shuffle,
 
+        asm_simple,
+
         negate,
         negate_wrap,
         bit_not,
@@ -245,6 +247,7 @@ pub const Node = extern union {
                 .std_mem_zeroes,
                 .@"return",
                 .@"comptime",
+                .asm_simple,
                 .discard,
                 .std_math_Log2Int,
                 .negate,
@@ -1017,6 +1020,19 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
                 },
             });
         },
+        .asm_simple => {
+            const payload = node.castTag(.asm_simple).?.data;
+            const asm_token = try c.addToken(.keyword_asm, "asm");
+            _ = try c.addToken(.l_paren, "(");
+            return c.addNode(.{
+                .tag = .asm_simple,
+                .main_token = asm_token,
+                .data = .{
+                    .lhs = try renderNode(c, payload),
+                    .rhs = try c.addToken(.r_paren, ")"),
+                },
+            });
+        },
         .type => {
             const payload = node.castTag(.type).?.data;
             return c.addNode(.{
@@ -2257,6 +2273,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
         .@"continue",
         .@"return",
         .@"comptime",
+        .asm_simple,
         .usingnamespace_builtins,
         .while_true,
         .if_not_break,
src/clang.zig
@@ -905,6 +905,11 @@ pub const TypedefNameDecl = opaque {
     extern fn ZigClangTypedefNameDecl_getLocation(*const TypedefNameDecl) SourceLocation;
 };
 
+pub const FileScopeAsmDecl = opaque {
+    pub const getAsmString = ZigClangFileScopeAsmDecl_getAsmString;
+    extern fn ZigClangFileScopeAsmDecl_getAsmString(*const FileScopeAsmDecl) *const StringLiteral;
+};
+
 pub const TypedefType = opaque {
     pub const getDecl = ZigClangTypedefType_getDecl;
     extern fn ZigClangTypedefType_getDecl(*const TypedefType) *const TypedefNameDecl;
src/translate_c.zig
@@ -480,6 +480,9 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
         .Empty => {
             // Do nothing
         },
+        .FileScopeAsm => {
+            try transFileScopeAsm(c, &c.global_scope.base, @ptrCast(*const clang.FileScopeAsmDecl, decl));
+        },
         else => {
             const decl_name = try c.str(decl.getDeclKindName());
             try warn(c, &c.global_scope.base, decl.getLocation(), "ignoring {s} declaration", .{decl_name});
@@ -487,6 +490,21 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
     }
 }
 
+fn transFileScopeAsm(c: *Context, scope: *Scope, file_scope_asm: *const clang.FileScopeAsmDecl) Error!void {
+    const asm_string = file_scope_asm.getAsmString();
+    var len: usize = undefined;
+    const bytes_ptr = asm_string.getString_bytes_begin_size(&len);
+
+    const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])});
+    const str_node = try Tag.string_literal.create(c.arena, str);
+
+    const asm_node = try Tag.asm_simple.create(c.arena, str_node);
+    const block = try Tag.block_single.create(c.arena, asm_node);
+    const comptime_node = try Tag.@"comptime".create(c.arena, block);
+
+    try scope.appendNode(comptime_node);
+}
+
 fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
     const fn_name = try c.str(@ptrCast(*const clang.NamedDecl, fn_decl).getName_bytes_begin());
     if (c.global_scope.sym_table.contains(fn_name))
src/zig_clang.cpp
@@ -1820,6 +1820,11 @@ const ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const ZigClangEnumDecl *z
     return reinterpret_cast<const ZigClangEnumDecl *>(definition);
 }
 
+const ZigClangStringLiteral *ZigClangFileScopeAsmDecl_getAsmString(const ZigClangFileScopeAsmDecl *self) {
+    const clang::StringLiteral *result = reinterpret_cast<const clang::FileScopeAsmDecl*>(self)->getAsmString();
+    return reinterpret_cast<const ZigClangStringLiteral *>(result);
+}
+
 bool ZigClangRecordDecl_isUnion(const ZigClangRecordDecl *record_decl) {
     return reinterpret_cast<const clang::RecordDecl*>(record_decl)->isUnion();
 }
src/zig_clang.h
@@ -124,6 +124,7 @@ struct ZigClangEnumType;
 struct ZigClangExpr;
 struct ZigClangFieldDecl;
 struct ZigClangFileID;
+struct ZigClangFileScopeAsmDecl;
 struct ZigClangFloatingLiteral;
 struct ZigClangForStmt;
 struct ZigClangFullSourceLoc;
@@ -1000,6 +1001,8 @@ ZIG_EXTERN_C unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangV
 ZIG_EXTERN_C unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionDecl *self, const ZigClangASTContext* ctx);
 ZIG_EXTERN_C unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx);
 
+ZIG_EXTERN_C const struct ZigClangStringLiteral *ZigClangFileScopeAsmDecl_getAsmString(const struct ZigClangFileScopeAsmDecl *self);
+
 ZIG_EXTERN_C struct ZigClangQualType ZigClangParmVarDecl_getOriginalType(const struct ZigClangParmVarDecl *self);
 
 ZIG_EXTERN_C bool ZigClangRecordDecl_getPackedAttribute(const struct ZigClangRecordDecl *);
test/translate_c.zig
@@ -3499,4 +3499,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    '\u{1f4af}',
         \\};
     });
+
+    cases.add("global assembly",
+       \\__asm__(".globl func\n\t"
+       \\        ".type func, @function\n\t"
+       \\        "func:\n\t"
+       \\        ".cfi_startproc\n\t"
+       \\        "movl $42, %eax\n\t"
+       \\        "ret\n\t"
+       \\        ".cfi_endproc");
+    , &[_][]const u8{
+       \\comptime {
+       \\    asm (".globl func\n\t.type func, @function\n\tfunc:\n\t.cfi_startproc\n\tmovl $42, %eax\n\tret\n\t.cfi_endproc");
+       \\}
+    });
 }