summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2009-01-24 22:38:55 +0000
committerEli Friedman <eli.friedman@gmail.com>2009-01-24 22:38:55 +0000
commit8549e5dcc868f1c6c75ecd11bd8762a018af9f1d (patch)
treede2b1182833afa037da69928c226dc5444f48389 /clang
parent2aa38fea3545e31642c048ebac0f7362b4831946 (diff)
downloadbcm5719-llvm-8549e5dcc868f1c6c75ecd11bd8762a018af9f1d.tar.gz
bcm5719-llvm-8549e5dcc868f1c6c75ecd11bd8762a018af9f1d.zip
Fix for PR2910: implement CodeGen for non-constant offsetof.
Note that there are still other issues in this area; see PR3396. llvm-svn: 62942
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp49
-rw-r--r--clang/test/CodeGen/offsetof.c12
2 files changed, 54 insertions, 7 deletions
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 766721e96b4..33c5a6124bd 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -15,6 +15,7 @@
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Constants.h"
@@ -711,13 +712,47 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E)
{
- int64_t Val = E->evaluateOffsetOf(CGF.getContext());
-
- assert(E->getType()->isIntegerType() && "Result type must be an integer!");
-
- uint32_t ResultWidth =
- static_cast<uint32_t>(CGF.getContext().getTypeSize(E->getType()));
- return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val));
+ const Expr* SubExpr = E->getSubExpr();
+ const llvm::Type* ResultType = ConvertType(E->getType());
+ llvm::Value* Result = llvm::Constant::getNullValue(ResultType);
+ while (!isa<CompoundLiteralExpr>(SubExpr)) {
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(SubExpr)) {
+ SubExpr = ME->getBase();
+ QualType Ty = SubExpr->getType();
+
+ RecordDecl *RD = Ty->getAsRecordType()->getDecl();
+ const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD);
+ FieldDecl *FD = cast<FieldDecl>(ME->getMemberDecl());
+
+ // FIXME: This is linear time. And the fact that we're indexing
+ // into the layout by position in the record means that we're
+ // either stuck numbering the fields in the AST or we have to keep
+ // the linear search (yuck and yuck).
+ unsigned i = 0;
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end();
+ Field != FieldEnd; (void)++Field, ++i) {
+ if (*Field == FD)
+ break;
+ }
+
+ llvm::Value* Offset =
+ llvm::ConstantInt::get(ResultType, RL.getFieldOffset(i) / 8);
+ Result = Builder.CreateAdd(Result, Offset);
+ } else if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(SubExpr)) {
+ SubExpr = ASE->getBase();
+ int64_t size = CGF.getContext().getTypeSize(ASE->getType()) / 8;
+ llvm::Value* ElemSize = llvm::ConstantInt::get(ResultType, size);
+ llvm::Value* ElemIndex = CGF.EmitScalarExpr(ASE->getIdx());
+ bool IndexSigned = ASE->getIdx()->getType()->isSignedIntegerType();
+ ElemIndex = Builder.CreateIntCast(ElemIndex, ResultType, IndexSigned);
+ llvm::Value* Offset = Builder.CreateMul(ElemSize, ElemIndex);
+ Result = Builder.CreateAdd(Result, Offset);
+ } else {
+ assert(0 && "This should be impossible!");
+ }
+ }
+ return Result;
}
//===----------------------------------------------------------------------===//
diff --git a/clang/test/CodeGen/offsetof.c b/clang/test/CodeGen/offsetof.c
new file mode 100644
index 00000000000..7b6f5039f8c
--- /dev/null
+++ b/clang/test/CodeGen/offsetof.c
@@ -0,0 +1,12 @@
+// RUN: clang %s -emit-llvm -o %t
+
+// PR2910
+struct sockaddr_un {
+ unsigned char sun_len;
+ char sun_path[104];
+};
+
+int test(int len) {
+ return __builtin_offsetof(struct sockaddr_un, sun_path[len+1]);
+}
+
OpenPOWER on IntegriCloud