@@ -18,7 +18,7 @@ use super::{
1818use crate :: diag:: { error, Position } ;
1919use crate :: parse:: ast:: {
2020 AsmOperand , AssignOp , BinaryOp , BlockItem , Declaration , Designator , Expr , ExprKind ,
21- ExternalDecl , ForInit , FunctionDef , InitElement , Stmt , TranslationUnit , UnaryOp ,
21+ ExternalDecl , ForInit , FunctionDef , InitElement , OffsetOfPath , Stmt , TranslationUnit , UnaryOp ,
2222} ;
2323use crate :: strings:: { StringId , StringTable } ;
2424use crate :: symbol:: SymbolTable ;
@@ -470,6 +470,20 @@ impl<'a> Linearizer<'a> {
470470 false
471471 }
472472
473+ /// Link current block to merge block if not terminated.
474+ /// Used after linearizing then/else branches to connect to merge block.
475+ fn link_to_merge_if_needed ( & mut self , merge_bb : BasicBlockId ) {
476+ if self . is_terminated ( ) {
477+ return ;
478+ }
479+ if let Some ( current) = self . current_bb {
480+ // If the block isn't terminated, it needs a branch to the merge block.
481+ // Any unreachable blocks will be cleaned up by dead code elimination.
482+ self . emit ( Instruction :: br ( merge_bb) ) ;
483+ self . link_bb ( current, merge_bb) ;
484+ }
485+ }
486+
473487 /// Link two basic blocks (parent -> child)
474488 fn link_bb ( & mut self , from : BasicBlockId , to : BasicBlockId ) {
475489 let func = self . current_func . as_mut ( ) . unwrap ( ) ;
@@ -1747,19 +1761,13 @@ impl<'a> Linearizer<'a> {
17471761 // Then block
17481762 self . switch_bb ( then_bb) ;
17491763 self . linearize_stmt ( then_stmt) ;
1750- if !self . is_terminated ( ) {
1751- self . emit ( Instruction :: br ( merge_bb) ) ;
1752- self . link_bb ( then_bb, merge_bb) ;
1753- }
1764+ self . link_to_merge_if_needed ( merge_bb) ;
17541765
17551766 // Else block
17561767 if let Some ( else_s) = else_stmt {
17571768 self . switch_bb ( else_bb) ;
17581769 self . linearize_stmt ( else_s) ;
1759- if !self . is_terminated ( ) {
1760- self . emit ( Instruction :: br ( merge_bb) ) ;
1761- self . link_bb ( else_bb, merge_bb) ;
1762- }
1770+ self . link_to_merge_if_needed ( merge_bb) ;
17631771 }
17641772
17651773 // Merge block
@@ -4429,6 +4437,54 @@ impl<'a> Linearizer<'a> {
44294437 self . emit ( insn) ;
44304438 result
44314439 }
4440+
4441+ ExprKind :: OffsetOf { type_id, path } => {
4442+ // __builtin_offsetof(type, member-designator)
4443+ // Compute the byte offset of the member within the struct
4444+ let mut offset: u64 = 0 ;
4445+ let mut current_type = * type_id;
4446+
4447+ for element in path {
4448+ match element {
4449+ OffsetOfPath :: Field ( field_id) => {
4450+ // Look up the field in the current struct type
4451+ let struct_type = self . resolve_struct_type ( current_type) ;
4452+ let member_info = self
4453+ . types
4454+ . find_member ( struct_type, * field_id)
4455+ . expect ( "offsetof: field not found in struct type" ) ;
4456+ offset += member_info. offset as u64 ;
4457+ current_type = member_info. typ ;
4458+ }
4459+ OffsetOfPath :: Index ( index) => {
4460+ // Array indexing: offset += index * sizeof(element)
4461+ let elem_type = self
4462+ . types
4463+ . base_type ( current_type)
4464+ . expect ( "offsetof: array index on non-array type" ) ;
4465+ let elem_size = self . types . size_bytes ( elem_type) ;
4466+ offset += ( * index as u64 ) * ( elem_size as u64 ) ;
4467+ current_type = elem_type;
4468+ }
4469+ }
4470+ }
4471+
4472+ // Return the offset as a constant
4473+ self . emit_const ( offset as i64 , self . types . ulong_id )
4474+ }
4475+
4476+ ExprKind :: StmtExpr { stmts, result } => {
4477+ // GNU statement expression: ({ stmt; stmt; expr; })
4478+ // Linearize all the statements first
4479+ for item in stmts {
4480+ match item {
4481+ BlockItem :: Declaration ( decl) => self . linearize_local_decl ( decl) ,
4482+ BlockItem :: Statement ( s) => self . linearize_stmt ( s) ,
4483+ }
4484+ }
4485+ // The result is the value of the final expression
4486+ self . linearize_expr ( result)
4487+ }
44324488 }
44334489 }
44344490
0 commit comments