Skip to content

Commit 6651c5f

Browse files
authored
Merge pull request #490 from rustcoreutils/updates
Various bug fixes
2 parents 600b9a2 + c4e1123 commit 6651c5f

File tree

10 files changed

+2239
-55
lines changed

10 files changed

+2239
-55
lines changed

cc/doc/BUILTIN.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ Builtin functions supported by pcc. GCC/Clang compatible.
5353
|---------|-------------|
5454
| `__builtin_unreachable()` | Mark code path as unreachable (traps if reached) |
5555

56+
## Structure Layout
57+
58+
| Builtin | Description |
59+
|---------|-------------|
60+
| `__builtin_offsetof(type, member)` | Byte offset of member within struct/union |
61+
| `offsetof(type, member)` | Alias for `__builtin_offsetof` |
62+
63+
The member can be a chain like `field.subfield` or `arr[index].field`.
64+
5665
## Not Yet Implemented
5766

5867
| Builtin | Description |

cc/ir/linearize.rs

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use super::{
1818
use crate::diag::{error, Position};
1919
use 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
};
2323
use crate::strings::{StringId, StringTable};
2424
use 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

Comments
 (0)